Address Contract Partially Verified
Address
0x3FeD135c3d8fFe36ce0CB835cef57C4566F25852
Balance
0 ETH
Nonce
1
Code Size
7246 bytes
Creator
0xC8fC994F...5Cc3 at tx 0x0a1ac075...c0aa3d
Indexed Transactions
0
Contract Bytecode
7246 bytes
0x6080604052600436106101445760003560e01c806366836b7c116100c0578063c5f956af11610074578063e1ae8f0511610059578063e1ae8f05146103ad578063f10c974f146103cd578063ff186b2e146103ed57600080fd5b8063c5f956af14610360578063cc7b0bd81461038057600080fd5b8063a8f6c913116100a5578063a8f6c913146102fb578063aad2b72314610320578063b14f2a391461034057600080fd5b806366836b7c146102bb578063906ea24b146102e857600080fd5b80631f10caa311610117578063330227bf116100fc578063330227bf1461022e5780634adccde51461026d57806355a373d61461028357600080fd5b80631f10caa3146101e057806322f0e36f146101f357600080fd5b806306394c9b14610149578063144cb4521461016b57806316c38b3c1461018b5780631c4b41bf146101ab575b600080fd5b34801561015557600080fd5b5061016961016436600461186b565b610403565b005b34801561017757600080fd5b50610169610186366004611886565b6104d6565b34801561019757600080fd5b506101696101a63660046118be565b610653565b3480156101b757600080fd5b506101cb6101c6366004611886565b6106af565b60405190151581526020015b60405180910390f35b6101696101ee36600461191d565b6106da565b3480156101ff57600080fd5b5061022061020e36600461186b565b60006020819052908152604090205481565b6040519081526020016101d7565b34801561023a57600080fd5b5060045460055460065460408051938452602084019290925261010090046001600160a01b0316908201526060016101d7565b34801561027957600080fd5b5061022060055481565b34801561028f57600080fd5b506007546102a3906001600160a01b031681565b6040516001600160a01b0390911681526020016101d7565b3480156102c757600080fd5b506102db6102d636600461186b565b610a0c565b6040516101d79190611997565b6101696102f63660046119db565b610a30565b34801561030757600080fd5b506006546102a39061010090046001600160a01b031681565b34801561032c57600080fd5b5061016961033b36600461186b565b610d5e565b34801561034c57600080fd5b5061016961035b36600461186b565b610e2c565b34801561036c57600080fd5b506003546102a3906001600160a01b031681565b34801561038c57600080fd5b506103a061039b366004611a58565b610efa565b6040516101d79190611b29565b3480156103b957600080fd5b506101696103c8366004611b63565b6110a9565b3480156103d957600080fd5b506102206103e836600461186b565b61113a565b3480156103f957600080fd5b5061022060045481565b6002546001600160a01b031633146104515760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b60448201526064015b60405180910390fd5b6001600160a01b0381166104a75760405162461bcd60e51b815260206004820152601760248201527f416464726573732063616e6e6f7420626520656d7074790000000000000000006044820152606401610448565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6002546001600160a01b0316331461051f5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b61052982826106af565b6105755760405162461bcd60e51b815260206004820152600b60248201527f696e76616c6964205f746f0000000000000000000000000000000000000000006044820152606401610448565b6001600160a01b0382166000908152600860205260409020610597908261115b565b6105e35760405162461bcd60e51b815260206004820152601460248201527f636f756c64206e6f742072656d6f7665205f69640000000000000000000000006044820152606401610448565b6007546040516323b872dd60e01b81523060048201526001600160a01b03848116602483015260448201849052909116906323b872dd90606401600060405180830381600087803b15801561063757600080fd5b505af115801561064b573d6000803e3d6000fd5b505050505050565b6002546001600160a01b0316331461069c5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b6006805460ff1916911515919091179055565b6001600160a01b03821660009081526008602052604081206106d19083611167565b90505b92915050565b60065460ff161561072d5760405162461bcd60e51b815260206004820152601260248201527f436f6e74726163742069732070617573656400000000000000000000000000006044820152606401610448565b336000818152602081815260408083205481519283018690526bffffffffffffffffffffffff19606086811b821693850193909352309283901b166054840152606883018a9052608883015284939290918991899189919060a80160408051601f198184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c0160405160208183030381529060405280519060200120905061082b83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250859392505061117f9050565b6001546001600160a01b039081169116146108885760405162461bcd60e51b815260206004820152601660248201527f556e617574686f72697a6564205369676e6174757265000000000000000000006044820152606401610448565b50336000908152602081905260409020805460010190556007546001600160a01b038d81169116146108fc5760405162461bcd60e51b815260206004820152601760248201527f484f4c4445523a20696e636f727265637420746f6b656e0000000000000000006044820152606401610448565b336000908152600860205260409020610915908c6111a3565b6109615760405162461bcd60e51b815260206004820152601260248201527f436f756c64206e6f7420616464205f69642100000000000000000000000000006044820152606401610448565b60405160019088907fbb80fa3c17d62b43b2e024f76d7876cd98f6c7584e0e5d540325f5d36916380390600090a36040516323b872dd60e01b8152336004820152306024820152604481018c90526001600160a01b038d16906323b872dd90606401600060405180830381600087803b1580156109dd57600080fd5b505af11580156109f1573d6000803e3d6000fd5b505050506109fe886111af565b505050505050505050505050565b6001600160a01b03811660009081526008602052604090206060906106d490611425565b60065460ff1615610a835760405162461bcd60e51b815260206004820152601260248201527f436f6e74726163742069732070617573656400000000000000000000000000006044820152606401610448565b336000818152602081815260408083205481519283018690526bffffffffffffffffffffffff1930606081811b8316948601949094529286901b166054840152606883018a905260888301528493909290918991899189919060a80160408051601f198184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c01604051602081830303815290604052805190602001209050610b8283838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250859392505061117f9050565b6001546001600160a01b03908116911614610bdf5760405162461bcd60e51b815260206004820152601660248201527f556e617574686f72697a6564205369676e6174757265000000000000000000006044820152606401610448565b5033600081815260208190526040902080546001019055610c00908c6106af565b610c4c5760405162461bcd60e51b815260206004820152600960248201527f6e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610448565b336000908152600860205260409020610c65908c61115b565b610cb15760405162461bcd60e51b815260206004820152600f60248201527f746f6b656e206e6f7420666f756e6400000000000000000000000000000000006044820152606401610448565b60405160009088907fbb80fa3c17d62b43b2e024f76d7876cd98f6c7584e0e5d540325f5d369163803908390a36007546040516323b872dd60e01b8152306004820152336024820152604481018d90526001600160a01b03909116906323b872dd90606401600060405180830381600087803b158015610d3057600080fd5b505af1158015610d44573d6000803e3d6000fd5b50505050610d51886111af565b5050505050505050505050565b6002546001600160a01b03163314610da75760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b6001600160a01b038116610dfd5760405162461bcd60e51b815260206004820152601760248201527f416464726573732063616e6e6f7420626520656d7074790000000000000000006044820152606401610448565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6002546001600160a01b03163314610e755760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b6001600160a01b038116610ecb5760405162461bcd60e51b815260206004820152601760248201527f416464726573732063616e6e6f7420626520656d7074790000000000000000006044820152606401610448565b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6002546060906001600160a01b03163314610f465760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b815160008167ffffffffffffffff811115610f6357610f63611a42565b604051908082528060200260200182016040528015610f8c578160200160208202803683370190505b50925060005b828110156110a057602081026020860101519150610fb086836106af565b8015610fd957506001600160a01b0386166000908152600860205260409020610fd9908361115b565b15611073576001848281518110610ff257610ff2611b98565b911515602092830291909101909101526007546040516323b872dd60e01b81523060048201526001600160a01b03888116602483015260448201859052909116906323b872dd90606401600060405180830381600087803b15801561105657600080fd5b505af115801561106a573d6000803e3d6000fd5b50505050611098565b600084828151811061108757611087611b98565b911515602092830291909101909101525b600101610f92565b50505092915050565b6002546001600160a01b031633146110f25760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610448565b600492909255600555600680546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b6001600160a01b03811660009081526008602052604081206106d490611439565b60006106d18383611443565b600081815260018301602052604081205415156106d1565b600080600061118e8585611536565b9150915061119b8161157b565b509392505050565b60006106d183836116e0565b80156113085734156112035760405162461bcd60e51b815260206004820152601460248201527f484f4c4445523a20746f6f206d756368204554480000000000000000000000006044820152606401610448565b6006546003546005546040516323b872dd60e01b81523360048201526001600160a01b03928316602482015260448101919091526000926101009004909116906323b872dd906064016020604051808303816000875af115801561126b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128f9190611bae565b9050806113045760405162461bcd60e51b815260206004820152602360248201527f484f4c4445523a204552433230207472616e7366657220756e7375636365737360448201527f66756c00000000000000000000000000000000000000000000000000000000006064820152608401610448565b5050565b60045434146113595760405162461bcd60e51b815260206004820152601a60248201527f484f4c4445523a20696e73756666696369656e742066756e64730000000000006044820152606401610448565b6003546040516000916001600160a01b03169034908381818185875af1925050503d80600081146113a6576040519150601f19603f3d011682016040523d82523d6000602084013e6113ab565b606091505b50509050806113045760405162461bcd60e51b815260206004820152602160248201527f484f4c4445523a20455448207472616e7366657220756e73756363657373667560448201527f6c000000000000000000000000000000000000000000000000000000000000006064820152608401610448565b50565b606060006114328361172f565b9392505050565b60006106d4825490565b6000818152600183016020526040812054801561152c576000611467600183611bcb565b855490915060009061147b90600190611bcb565b90508181146114e057600086600001828154811061149b5761149b611b98565b90600052602060002001549050808760000184815481106114be576114be611b98565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806114f1576114f1611bec565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106d4565b60009150506106d4565b600080825160410361156c5760208301516040840151606085015160001a6115608782858561178b565b94509450505050611574565b506000905060025b9250929050565b600081600481111561158f5761158f611c02565b036115975750565b60018160048111156115ab576115ab611c02565b036115f85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610448565b600281600481111561160c5761160c611c02565b036116595760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610448565b600381600481111561166d5761166d611c02565b036114225760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610448565b6000818152600183016020526040812054611727575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106d4565b5060006106d4565b60608160000180548060200260200160405190810160405280929190818152602001828054801561177f57602002820191906000526020600020905b81548152602001906001019080831161176b575b50505050509050919050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156117c25750600090506003611846565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611816573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661183f57600060019250925050611846565b9150600090505b94509492505050565b80356001600160a01b038116811461186657600080fd5b919050565b60006020828403121561187d57600080fd5b6106d18261184f565b6000806040838503121561189957600080fd5b6118a28361184f565b946020939093013593505050565b801515811461142257600080fd5b6000602082840312156118d057600080fd5b8135611432816118b0565b60008083601f8401126118ed57600080fd5b50813567ffffffffffffffff81111561190557600080fd5b60208301915083602082850101111561157457600080fd5b60008060008060008060a0878903121561193657600080fd5b61193f8761184f565b955060208701359450604087013567ffffffffffffffff81111561196257600080fd5b61196e89828a016118db565b9095509350506060870135611982816118b0565b80925050608087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b818110156119cf578351835292840192918401916001016119b3565b50909695505050505050565b6000806000806000608086880312156119f357600080fd5b85359450602086013567ffffffffffffffff811115611a1157600080fd5b611a1d888289016118db565b9095509350506040860135611a31816118b0565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215611a6b57600080fd5b611a748361184f565b915060208084013567ffffffffffffffff80821115611a9257600080fd5b818601915086601f830112611aa657600080fd5b813581811115611ab857611ab8611a42565b8060051b604051601f19603f83011681018181108582111715611add57611add611a42565b604052918252848201925083810185019189831115611afb57600080fd5b938501935b82851015611b1957843584529385019392850192611b00565b8096505050505050509250929050565b6020808252825182820181905260009190848201906040850190845b818110156119cf578351151583529284019291840191600101611b45565b600080600060608486031215611b7857600080fd5b8335925060208401359150611b8f6040850161184f565b90509250925092565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611bc057600080fd5b8151611432816118b0565b818103818111156106d457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220e191d14ea7e05980a89b426618cf597e6d2b41075d88ddbcf91bbad544f01d4464736f6c63430008110033
Verified Source Code Partial Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (1000 runs)
PAHolder.sol 824 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.14;
// File: @openzeppelin\contracts\utils\introspection\IERC165.sol
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: @openzeppelin\contracts\token\ERC721\IERC721.sol
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// File: @openzeppelin\contracts\token\ERC20\IERC20.sol
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
// File: @openzeppelin\contracts\utils\structs\EnumerableSet.sol
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
// File: @openzeppelin\contracts\utils\cryptography\ECDSA.sol
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature)
internal
pure
returns (address, RecoverError)
{
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
}
// File: contracts\PAHolder.sol
contract PAHolder {
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.UintSet;
mapping(address => uint256) public signerNonce;
address private signer;
address private operator;
address public treasuryAddress;
uint256 public ethPrice;
uint256 public erc20Price;
bool paused;
IERC20 public erc20Contract;
IERC721 public tokenContract;
mapping(address => EnumerableSet.UintSet) internal tokenOwner;
event HolderAction(uint256 indexed transactionId, bool indexed sentToHolder);
constructor(
address _tokenContract,
address _operator,
address _signer,
uint256 _ethPrice,
uint256 _erc20Price,
address _erc20Addr,
address _treasuryAddr
) {
require(_treasuryAddr != address(0), "treasury address cannot be empty");
require(_signer != address(0), "signer address cannot be empty");
require(_erc20Addr != address(0), "erc20 address cannot be empty");
require(_operator != address(0), "operator address cannot be empty");
require(_tokenContract != address(0), "token contract address cannot be empty");
tokenContract = IERC721(_tokenContract);
operator = _operator;
signer = _signer;
ethPrice = _ethPrice;
erc20Price = _erc20Price;
erc20Contract = IERC20(_erc20Addr);
treasuryAddress = _treasuryAddr;
}
modifier isPaused() {
require(!paused, "Contract is paused");
_;
}
modifier isValidSignature(
uint256 _txId,
address _from,
address _to,
uint256 _id,
bytes calldata _signature
) {
{
bytes32 hash = keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(abi.encodePacked(_txId, _from, _to, _id, signerNonce[msg.sender]))
)
);
require(signer == hash.recover(_signature), "Unauthorized Signature");
unchecked {
++signerNonce[msg.sender];
}
}
_;
}
function isPayable(bool _isERC20) private {
if (_isERC20) {
require(msg.value == 0, "HOLDER: too much ETH");
bool _success = erc20Contract.transferFrom(msg.sender, treasuryAddress, erc20Price);
require(_success, "HOLDER: ERC20 transfer unsuccessful");
} else {
require(msg.value == ethPrice, "HOLDER: insufficient funds");
(bool _success, ) = payable(treasuryAddress).call{value: msg.value}("");
require(_success, "HOLDER: ETH transfer unsuccessful");
}
}
modifier onlyOperator() {
require(msg.sender == operator, "Not operator");
_;
}
/************************/
/* USER */
/************************/
function isHeld(address _owner, uint256 _id) public view returns (bool) {
return tokenOwner[_owner].contains(_id);
}
function heldBalance(address _owner) external view returns (uint256) {
return tokenOwner[_owner].length();
}
function getHeldTokens(address _owner) external view returns (uint256[] memory) {
return tokenOwner[_owner].values();
}
function getPriceInfo()
external
view
returns (
uint256,
uint256,
address
)
{
return (ethPrice, erc20Price, address(erc20Contract));
}
/// @notice Transfers '_id' of '_tokenContract' to this contract
/// **REQUIRES APPROVAL BEFOREHAND**
/// @param _tokenContract Address token contract to send to holder contract
/// @param _id Token id of the token to be sent
/// @param _signature Signature signed by 'signer'
/// @param _isERC20 chooses whether to use native ETH or ERC20
/// @param _transactionId random integer generated from the backend
function transferToHolder(
address _tokenContract,
uint256 _id,
bytes calldata _signature,
bool _isERC20,
uint256 _transactionId
)
external
payable
isPaused
isValidSignature(_transactionId, msg.sender, address(this), _id, _signature)
{
require(_tokenContract == address(tokenContract), "HOLDER: incorrect token");
require(tokenOwner[msg.sender].add(_id), "Could not add _id!");
emit HolderAction(_transactionId, true);
IERC721(_tokenContract).transferFrom(msg.sender, address(this), _id);
isPayable(_isERC20);
}
/// @notice Transfers '_id' back to its original owner
/// **REQUIRES APPROVAL BEFOREHAND**
/// @param _id Token id of the token sent
/// @param _signature Signature signed by 'signer'
/// @param _isERC20 chooses whether to use native ETH or ERC20
/// @param _transactionId random integer generated from the backend
function returnToken(
uint256 _id,
bytes calldata _signature,
bool _isERC20,
uint256 _transactionId
)
external
payable
isPaused
isValidSignature(_transactionId, address(this), msg.sender, _id, _signature)
{
require(isHeld(msg.sender, _id), "not owner");
require(tokenOwner[msg.sender].remove(_id), "token not found");
emit HolderAction(_transactionId, false);
tokenContract.transferFrom(address(this), msg.sender, _id);
isPayable(_isERC20);
}
/************************/
/* OPERATOR */
/************************/
function forceReturnToken(address _to, uint256 _id) external onlyOperator {
require(isHeld(_to, _id), "invalid _to");
require(tokenOwner[_to].remove(_id), "could not remove _id");
tokenContract.transferFrom(address(this), _to, _id);
}
/**
* @return success - if each id by index of input failed or succeded
*/
function forceReturnAllTokens(address _to, uint256[] memory ids)
external
onlyOperator
returns (bool[] memory success)
{
uint256 length = ids.length;
uint256 _id;
success = new bool[](length);
for (uint256 i; i < length; ) {
assembly {
_id := mload(add(add(ids, 0x20), mul(i, 0x20)))
}
if (isHeld(_to, _id) && tokenOwner[_to].remove(_id)) {
success[i] = true;
tokenContract.transferFrom(address(this), _to, _id);
} else {
success[i] = false;
}
unchecked {
++i;
}
}
}
function changeSigner(address _signer) external onlyOperator {
require(_signer != address(0), "Address cannot be empty");
signer = _signer;
}
function changeOperator(address _operator) external onlyOperator {
require(_operator != address(0), "Address cannot be empty");
operator = _operator;
}
function changeTreasury(address _treasuryAddr) external onlyOperator {
require(_treasuryAddr != address(0), "Address cannot be empty");
treasuryAddress = _treasuryAddr;
}
function setPaused(bool _bool) external onlyOperator {
paused = _bool;
}
function changePriceInfo(
uint256 _ethPrice,
uint256 _erc20Price,
address _erc20Contract
) external onlyOperator {
ethPrice = _ethPrice;
erc20Price = _erc20Price;
erc20Contract = IERC20(_erc20Contract);
}
}
/****************************************
* @author: 🍖 *
* @team: Asteria *
* audited and improved by @Sheeeev66 *
* of @thecoredevs *
****************************************/
Read Contract
erc20Contract 0xa8f6c913 → address
erc20Price 0x4adccde5 → uint256
ethPrice 0xff186b2e → uint256
getHeldTokens 0x66836b7c → uint256[]
getPriceInfo 0x330227bf → uint256, uint256, address
heldBalance 0xf10c974f → uint256
isHeld 0x1c4b41bf → bool
signerNonce 0x22f0e36f → uint256
tokenContract 0x55a373d6 → address
treasuryAddress 0xc5f956af → address
Write Contract 9 functions
These functions modify contract state and require a wallet transaction to execute.
changeOperator 0x06394c9b
address _operator
changePriceInfo 0xe1ae8f05
uint256 _ethPrice
uint256 _erc20Price
address _erc20Contract
changeSigner 0xaad2b723
address _signer
changeTreasury 0xb14f2a39
address _treasuryAddr
forceReturnAllTokens 0xcc7b0bd8
address _to
uint256[] ids
returns: bool[]
forceReturnToken 0x144cb452
address _to
uint256 _id
returnToken 0x906ea24b
uint256 _id
bytes _signature
bool _isERC20
uint256 _transactionId
setPaused 0x16c38b3c
bool _bool
transferToHolder 0x1f10caa3
address _tokenContract
uint256 _id
bytes _signature
bool _isERC20
uint256 _transactionId
Recent Transactions
No transactions found for this address