Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x3FeD135c3d8fFe36ce0CB835cef57C4566F25852
Balance 0 ETH
Nonce 1
Code Size 7246 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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