Address Contract Verified
Address
0x2844c02b1232A541Dab625F4c8b17347cb3c184a
Balance
0 ETH
Nonce
1
Code Size
8843 bytes
Creator
0xe850CFE5...8fF9 at tx 0x67bd821e...998339
Indexed Transactions
0
Contract Bytecode
8843 bytes
0x60806040526004361061018b5760003560e01c806382afd23b116100d6578063c87b56dd1161007f578063dbf03d7f11610059578063dbf03d7f1461049e578063f2fde38b146104b1578063f56116fc146104d157600080fd5b8063c87b56dd1461043d578063d179e3d01461045d578063d55f92731461047d57600080fd5b806395d89b41116100b057806395d89b41146103f55780639c8c4b3d1461040a578063bb7866931461042a57600080fd5b806382afd23b14610359578063881d8a40146103795780638da5cb5b146103d757600080fd5b80635c975abb11610138578063715018a611610112578063715018a614610304578063754ecc26146103195780637663f8221461033957600080fd5b80635c975abb1461027f5780636352211e1461029e57806370a08231146102d657600080fd5b806336566f061161016957806336566f061461022857806351cff8d91461023f57806355f804b31461025f57600080fd5b806301ffc9a71461019057806306fdde03146101c55780631e6c3850146101e7575b600080fd5b34801561019c57600080fd5b506101b06101ab366004611d9c565b6104f1565b60405190151581526020015b60405180910390f35b3480156101d157600080fd5b506101da61058e565b6040516101bc9190611e16565b3480156101f357600080fd5b5060085461020f90600160401b900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101bc565b34801561023457600080fd5b5061023d610620565b005b34801561024b57600080fd5b5061023d61025a366004611e3e565b61064c565b34801561026b57600080fd5b5061023d61027a366004611e9d565b610712565b34801561028b57600080fd5b50600554600160a01b900460ff166101b0565b3480156102aa57600080fd5b506102be6102b9366004611edf565b610727565b6040516001600160a01b0390911681526020016101bc565b3480156102e257600080fd5b506102f66102f1366004611e3e565b61078c565b6040519081526020016101bc565b34801561031057600080fd5b5061023d610826565b34801561032557600080fd5b5061023d610334366004611ef8565b610838565b34801561034557600080fd5b506101b0610354366004611f1a565b610937565b34801561036557600080fd5b506101b0610374366004611edf565b61096a565b34801561038557600080fd5b50610399610394366004611edf565b6109b0565b60408051825167ffffffffffffffff1681526020808401516001600160c01b031690820152918101516001600160a01b0316908201526060016101bc565b3480156103e357600080fd5b506005546001600160a01b03166102be565b34801561040157600080fd5b506101da610a91565b34801561041657600080fd5b506102f6610425366004611f1a565b610aa0565b6102f6610438366004611f53565b610aad565b34801561044957600080fd5b506101da610458366004611edf565b610c88565b34801561046957600080fd5b5061023d610478366004611edf565b610d98565b34801561048957600080fd5b5060085461020f9067ffffffffffffffff1681565b6102f66104ac366004611f53565b610f16565b3480156104bd57600080fd5b5061023d6104cc366004611e3e565b6110e0565b3480156104dd57600080fd5b506009546102be906001600160a01b031681565b60006001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000148061055457506001600160e01b031982167fc28b40ff00000000000000000000000000000000000000000000000000000000145b8061058857507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b60606001805461059d90611fa8565b80601f01602080910402602001604051908101604052809291908181526020018280546105c990611fa8565b80156106165780601f106105eb57610100808354040283529160200191610616565b820191906000526020600020905b8154815290600101906020018083116105f957829003601f168201915b5050505050905090565b610628611170565b600554600160a01b900460ff1615610644576106426111ca565b565b61064261121f565b610654611170565b6001600160a01b0381166106d55760405162461bcd60e51b815260206004820152602760248201527f77697468647261773a20616464726573732063616e2774206265207a65726f2060448201527f616464726573730000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b60405130906001600160a01b03831690823180156108fc02916000818181858888f1935050505015801561070d573d6000803e3d6000fd5b505050565b61071a611170565b600a61070d828483612046565b6000818152600360205260408120546001600160a01b0316806105885760405162461bcd60e51b815260206004820152601c60248201527f6f776e65724f663a20746f6b656e20646f65736e27742065786973740000000060448201526064016106cc565b60006001600160a01b03821661080a5760405162461bcd60e51b815260206004820152602c60248201527f62616c616e63654f663a2061646472657373207a65726f206973206e6f74206160448201527f2076616c6964206f776e6572000000000000000000000000000000000000000060648201526084016106cc565b506001600160a01b031660009081526004602052604090205490565b61082e611170565b6106426000611262565b6000828152600360205260409020546001600160a01b031661089c5760405162461bcd60e51b815260206004820152601860248201527f726566726573683a20746f6b656e206e6f7420666f756e64000000000000000060448201526064016106cc565b600082815260076020526040902060018101546001600160a01b031633146109065760405162461bcd60e51b815260206004820152601260248201527f726566726573683a206e6f74206f776e6572000000000000000000000000000060448201526064016106cc565b610910824261211d565b81546001600160c01b0391909116600160401b0267ffffffffffffffff9091161790555050565b60008061094484846112b4565b6000818152600360205260409020549091506001600160a01b031615155b949350505050565b6000818152600360205260408120546001600160a01b031615158015610588575050600090815260076020526040902054600160401b90046001600160c01b0316421090565b60408051606081018252600080825260208201819052918101919091526109d5611327565b6000828152600360205260409020546001600160a01b0316610a395760405162461bcd60e51b815260206004820152601660248201527f6c696e6b733a20746f6b656e206e6f7420666f756e640000000000000000000060448201526064016106cc565b506000908152600760209081526040918290208251606081018452815467ffffffffffffffff81168252600160401b90046001600160c01b031692810192909252600101546001600160a01b03169181019190915290565b60606002805461059d90611fa8565b60008061096284846112b4565b6009546040516370a0823160e01b81526001600160a01b03808616600483015260009286928492909116906370a0823190602401602060405180830381865afa158015610afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b229190612130565b11610b6f5760405162461bcd60e51b815260206004820152601560248201527f6f6e6c79537065637472653a206e656564204e4654000000000000000000000060448201526064016106cc565b610b77611327565b6000610b84868686611381565b6000818152600760205260408120600880549394509092909190610bb19067ffffffffffffffff16612149565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825467ffffffffffffffff1916178255600854610bfa91600160401b909104164261211d565b815467ffffffffffffffff16600160401b6001600160c01b0392909216919091021781556001810180546001600160a01b0319166001600160a01b0389169081179091556040805191825233602083015281018390527f5467f48b622cc93f455af2c7710a7b6844111e9e211ca8ff2479064f1c76de3e906060015b60405180910390a15095945050505050565b60606000600a8054610c9990611fa8565b905011610ce85760405162461bcd60e51b815260206004820152601b60248201527f746f6b656e5552493a20626173655552492069736e277420736574000000000060448201526064016106cc565b6000828152600360205260409020546001600160a01b0316610d4c5760405162461bcd60e51b815260206004820152601d60248201527f746f6b656e5552493a20746f6b656e20646f65736e277420657869737400000060448201526064016106cc565b600082815260076020526040902054600a90610d719067ffffffffffffffff1661148a565b604051602001610d82929190612170565b6040516020818303038152906040529050919050565b6000818152600360205260409020546001600160a01b0316610dfc5760405162461bcd60e51b815260206004820152601860248201527f756e65717569703a20746f6b656e206e6f7420666f756e64000000000000000060448201526064016106cc565b600081815260076020526040902033610e1483610727565b6001600160a01b03161480610e35575060018101546001600160a01b031633145b610e815760405162461bcd60e51b815260206004820181905260248201527f756e65717569703a206d75737420626520686f6c646572206f72206f776e657260448201526064016106cc565b600882901c60009081526020819052604090208054600160ff85161b19169055610eaa8261152a565b6001810154604080516001600160a01b0390921682523360208301527fc05298d0898fd7f4c335551a22839534908c4c7f89f20d35dcd1d4dcba52ea25910160405180910390a150600090815260076020526040812090815560010180546001600160a01b0319169055565b6009546040516370a0823160e01b81523360048201819052600092909183916001600160a01b0316906370a0823190602401602060405180830381865afa158015610f65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f899190612130565b11610fd65760405162461bcd60e51b815260206004820152601560248201527f6f6e6c79537065637472653a206e656564204e4654000000000000000000000060448201526064016106cc565b610fde611327565b6000610feb8686866115bd565b60008181526007602052604081206008805493945090929091906110189067ffffffffffffffff16612149565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825467ffffffffffffffff191617825560085461106191600160401b909104164261211d565b81546001600160c01b0391909116600160401b0267ffffffffffffffff9091161781556001810180546001600160a01b03191633908117909155604080519182526001600160a01b038916602083015281018390527f5467f48b622cc93f455af2c7710a7b6844111e9e211ca8ff2479064f1c76de3e90606001610c76565b6110e8611170565b6001600160a01b0381166111645760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106cc565b61116d81611262565b50565b6005546001600160a01b031633146106425760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106cc565b6111d261169c565b6005805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b611227611327565b6005805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586112023390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000807f93c86b6f16d05688c27172668c232ca3b501d3313ded3f32c0f132d7a22e0b1b8484604051602001611306939291909283526001600160a01b03918216602084015216604082015260600190565b604051602081830303815290604052805190602001209050610962816116f5565b600554600160a01b900460ff16156106425760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016106cc565b60006001600160a01b03841633036113db5760405162461bcd60e51b815260206004820152601b60248201527f5f74616b653a2063616e27742074616b652066726f6d2073656c66000000000060448201526064016106cc565b60006113e93386868661175e565b600881901c600090815260208190526040902054909150600160ff83161b16156114555760405162461bcd60e51b815260206004820152601660248201527f5f74616b653a20696420616c726561647920757365640000000000000000000060448201526064016106cc565b611460853383611829565b50600881901c60009081526020819052604090208054600160ff84161b17905590505b9392505050565b606060006114978361191a565b600101905060008167ffffffffffffffff8111156114b7576114b7611fe2565b6040519080825280601f01601f1916602001820160405280156114e1576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85049450846114eb57509392505050565b600061153582610727565b6001600160a01b038116600090815260046020526040812080549293506001929091906115639084906121f7565b909155505060008281526003602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60006001600160a01b03841633036116175760405162461bcd60e51b815260206004820152601b60248201527f5f676976653a2063616e277420676976652066726f6d2073656c66000000000060448201526064016106cc565b60006116253386868661175e565b600881901c600090815260208190526040902054909150600160ff83161b16156116915760405162461bcd60e51b815260206004820152601660248201527f5f676976653a20696420616c726561647920757365640000000000000000000060448201526064016106cc565b611460338683611829565b600554600160a01b900460ff166106425760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016106cc565b60006105886117026119fc565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008061176b86866112b4565b90506117ae858286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b2392505050565b6118205760405162461bcd60e51b815260206004820152602660248201527f5f73616665436865636b41677265656d656e743a20696e76616c69642073696760448201527f6e6174757265000000000000000000000000000000000000000000000000000060648201526084016106cc565b95945050505050565b6000818152600360205260408120546001600160a01b03161561188e5760405162461bcd60e51b815260206004820152601560248201527f5f6d696e743a20746f6b656e496420657869737473000000000000000000000060448201526064016106cc565b6001600160a01b03831660009081526004602052604081208054600192906118b790849061211d565b909155505060008281526003602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a45092915050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611963577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef8100000000831061198f576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106119ad57662386f26fc10000830492506010015b6305f5e10083106119c5576305f5e100830492506008015b61271083106119d957612710830492506004015b606483106119eb576064830492506002015b600a83106105885760010192915050565b6000306001600160a01b037f0000000000000000000000002844c02b1232a541dab625f4c8b17347cb3c184a16148015611a5557507f000000000000000000000000000000000000000000000000000000000000000146145b15611a7f57507f7d55aefd139ee693ea340b5991653249f3949bbffc8d32734e72047ac90e304590565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff344e774553d5793c418bc8b0494585d4e3cdc0aea30186d4c71f17ac3e9c2ef828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611b328585611c93565b90925090506000816004811115611b4b57611b4b61220a565b148015611b695750856001600160a01b0316826001600160a01b0316145b15611b7957600192505050611483565b600080876001600160a01b0316631626ba7e60e01b8888604051602401611ba1929190612220565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051611bf49190612239565b600060405180830381855afa9150503d8060008114611c2f576040519150601f19603f3d011682016040523d82523d6000602084013e611c34565b606091505b5091509150818015611c47575080516020145b8015611c87575080517f1626ba7e0000000000000000000000000000000000000000000000000000000090611c859083016020908101908401612130565b145b98975050505050505050565b6000808251604103611cc95760208301516040840151606085015160001a611cbd87828585611cd8565b94509450505050611cd1565b506000905060025b9250929050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611d0f5750600090506003611d93565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611d63573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611d8c57600060019250925050611d93565b9150600090505b94509492505050565b600060208284031215611dae57600080fd5b81356001600160e01b03198116811461148357600080fd5b60005b83811015611de1578181015183820152602001611dc9565b50506000910152565b60008151808452611e02816020860160208601611dc6565b601f01601f19169290920160200192915050565b6020815260006114836020830184611dea565b6001600160a01b038116811461116d57600080fd5b600060208284031215611e5057600080fd5b813561148381611e29565b60008083601f840112611e6d57600080fd5b50813567ffffffffffffffff811115611e8557600080fd5b602083019150836020828501011115611cd157600080fd5b60008060208385031215611eb057600080fd5b823567ffffffffffffffff811115611ec757600080fd5b611ed385828601611e5b565b90969095509350505050565b600060208284031215611ef157600080fd5b5035919050565b60008060408385031215611f0b57600080fd5b50508035926020909101359150565b60008060408385031215611f2d57600080fd5b8235611f3881611e29565b91506020830135611f4881611e29565b809150509250929050565b600080600060408486031215611f6857600080fd5b8335611f7381611e29565b9250602084013567ffffffffffffffff811115611f8f57600080fd5b611f9b86828701611e5b565b9497909650939450505050565b600181811c90821680611fbc57607f821691505b602082108103611fdc57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b601f82111561070d57600081815260208120601f850160051c8101602086101561201f5750805b601f850160051c820191505b8181101561203e5782815560010161202b565b505050505050565b67ffffffffffffffff83111561205e5761205e611fe2565b6120728361206c8354611fa8565b83611ff8565b6000601f8411600181146120a6576000851561208e5750838201355b600019600387901b1c1916600186901b178355612100565b600083815260209020601f19861690835b828110156120d757868501358255602094850194600190920191016120b7565b50868210156120f45760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561058857610588612107565b60006020828403121561214257600080fd5b5051919050565b600067ffffffffffffffff80831681810361216657612166612107565b6001019392505050565b600080845461217e81611fa8565b6001828116801561219657600181146121ab576121da565b60ff19841687528215158302870194506121da565b8860005260208060002060005b858110156121d15781548a8201529084019082016121b8565b50505082870194505b5050505083516121ee818360208801611dc6565b01949350505050565b8181038181111561058857610588612107565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006109626040830184611dea565b6000825161224b818460208701611dc6565b919091019291505056fea26469706673582212204aa4bfd98bb843f688c86af426ba340ebfc33fe27e9e88aa43e514c8e063600e64736f6c63430008110033
Verified Source Code Full Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (1000 runs)
ERC721Metadata.sol 9 lines
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.6;
interface IERC721Metadata {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
EIP712.sol 104 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/
abstract contract EIP712 {
/* solhint-disable var-name-mixedcase */
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
Strings.sol 70 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
ERC4973O.sol 115 lines
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.8;
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol';
import {BitMaps} from '@openzeppelin/contracts/utils/structs/BitMaps.sol';
import {ERC165} from './ERC165.sol';
import {IERC721Metadata} from './interfaces/ERC721Metadata.sol';
import {IERC4973} from './interfaces/ERC4973.sol';
bytes32 constant AGREEMENT_HASH = keccak256('Agreement(address active,address passive)');
/// @notice Modified version of the reference implementation of EIP-4973 tokens.
/// @author Felix Nordén
/// Heavy inspiration taken from the reference implementation (https://github.com/rugpullindex/ERC4973/blob/master/src/ERC4973.sol)
abstract contract ERC4973O is EIP712, ERC165, IERC721Metadata, IERC4973 {
using BitMaps for BitMaps.BitMap;
BitMaps.BitMap internal _usedHashes;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
constructor(string memory name_, string memory symbol_, string memory version) EIP712(name_, version) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC721Metadata).interfaceId || interfaceId == type(IERC4973).interfaceId || super.supportsInterface(interfaceId);
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function unequip(uint256 tokenId) public virtual override {
require(msg.sender == ownerOf(tokenId), 'unequip: sender must be owner');
_usedHashes.unset(tokenId);
_burn(tokenId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), 'balanceOf: address zero is not a valid owner');
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ownerOf: token doesn't exist");
return owner;
}
function _give(address to, bytes calldata signature) internal virtual returns (uint256) {
require(msg.sender != to, "_give: can't give from self");
uint256 tokenId = _safeCheckAgreement(msg.sender, to, signature);
require(!_usedHashes.get(tokenId), '_give: id already used');
_mint(msg.sender, to, tokenId);
_usedHashes.set(tokenId);
return tokenId;
}
function _take(address from, bytes calldata signature) internal virtual returns (uint256) {
require(msg.sender != from, "_take: can't take from self");
uint256 tokenId = _safeCheckAgreement(msg.sender, from, signature);
require(!_usedHashes.get(tokenId), '_take: id already used');
_mint(from, msg.sender, tokenId);
_usedHashes.set(tokenId);
return tokenId;
}
function _safeCheckAgreement(address active, address passive, bytes calldata signature) internal virtual returns (uint256) {
bytes32 hash = _getHash(active, passive);
require(SignatureChecker.isValidSignatureNow(passive, hash, signature), '_safeCheckAgreement: invalid signature');
uint256 tokenId = uint256(hash);
return tokenId;
}
function _getHash(address active, address passive) internal view returns (bytes32) {
bytes32 structHash = keccak256(abi.encode(AGREEMENT_HASH, active, passive));
return _hashTypedDataV4(structHash);
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _mint(address from, address to, uint256 tokenId) internal virtual returns (uint256) {
require(!_exists(tokenId), '_mint: tokenId exists');
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return tokenId;
}
function _burn(uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
}
SpectreTether.sol 129 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {IERC4973} from './interfaces/ERC4973.sol';
import {ERC4973O} from './ERC4973O.sol';
import {ITether, Link} from './interfaces/Tether.sol';
import {BitMaps} from '@openzeppelin/contracts/utils/structs/BitMaps.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';
import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
contract SpectreTether is ITether, ERC4973O, Ownable, Pausable, ReentrancyGuard {
using BitMaps for BitMaps.BitMap;
using ECDSA for bytes32;
using Strings for uint64;
mapping(uint256 => Link) private _links;
uint64 public tokenIndex;
uint64 public validityPeriod;
address public passContract;
string private _baseURI;
constructor(
string memory name_,
string memory symbol_,
string memory version_,
address passContract_,
uint64 validityPeriod_
) ERC4973O(name_, symbol_, version_) {
passContract = passContract_;
validityPeriod = validityPeriod_;
}
modifier onlySpectre(address holder) {
require(IERC721(passContract).balanceOf(holder) > 0, "onlySpectre: need NFT");
_;
}
function take(address from, bytes calldata signature) external payable onlySpectre(from) whenNotPaused returns (uint256) {
uint256 tokenId = _take(from, signature);
Link storage link = _links[tokenId];
link.tokenIndex = ++tokenIndex;
link.expiration = uint192(block.timestamp + validityPeriod);
link.holder = from;
emit Tether(from, msg.sender, tokenId);
return tokenId;
}
function give(address to, bytes calldata signature) external payable onlySpectre(msg.sender) whenNotPaused returns (uint256) {
uint256 tokenId = _give(to, signature);
Link storage link = _links[tokenId];
link.tokenIndex = ++tokenIndex;
link.expiration = uint192(block.timestamp + validityPeriod);
link.holder = msg.sender;
emit Tether(msg.sender, to, tokenId);
return tokenId;
}
function unequip(uint256 tokenId) public override(ERC4973O, IERC4973) {
require(_exists(tokenId), 'unequip: token not found');
Link storage link = _links[tokenId];
require(ownerOf(tokenId) == msg.sender || link.holder == msg.sender, 'unequip: must be holder or owner');
_usedHashes.unset(tokenId);
_burn(tokenId);
emit Untether(link.holder, msg.sender);
delete _links[tokenId];
}
function refresh(uint256 tokenId, uint256 validityPeriod_) external {
require(_exists(tokenId), "refresh: token not found");
Link storage link = _links[tokenId];
require(msg.sender == link.holder, "refresh: not owner");
link.expiration = uint192(block.timestamp + validityPeriod_);
}
function isActive (uint256 tokenId) external view returns (bool) {
return _exists(tokenId) && block.timestamp < _links[tokenId].expiration ;
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(bytes(_baseURI).length > 0, "tokenURI: baseURI isn't set");
require(_exists(tokenId), "tokenURI: token doesn't exist");
return string.concat(_baseURI, _links[tokenId].tokenIndex.toString());
}
function exists(address active, address passive) external view returns (bool) {
uint256 tokenId = uint256(_getHash(active, passive));
return _exists(tokenId);
}
function tokenId(address active, address passive) external view returns (uint256) {
uint256 tokenId = uint256(_getHash(active, passive));
return tokenId;
}
function links(uint256 tokenId) external whenNotPaused view returns (Link memory) {
require(_exists(tokenId), "links: token not found");
return _links[tokenId];
}
function withdraw(address payable to) external onlyOwner {
require(to != address(0), "withdraw: address can't be zero address");
address contractAddress = address(this);
to.transfer(contractAddress.balance);
}
function setBaseURI(string calldata baseURI) external onlyOwner {
_baseURI = baseURI;
}
function togglePaused() external onlyOwner {
if (paused()) {
_unpause();
} else {
_pause();
}
}
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
Math.sol 345 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
ERC165.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./interfaces/ERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
Tether.sol 33 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {IERC4973} from './ERC4973.sol';
import {BitMaps} from '@openzeppelin/contracts/utils/structs/BitMaps.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';
import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
struct Link {
uint64 tokenIndex;
uint192 expiration;
address holder;
}
interface ITether is IERC4973 {
event Tether(address holder, address operator, uint256 tokenId);
event Untether(address holder, address operator);
function refresh(uint256 tokenId, uint256 validityPeriod_) external;
function isActive (uint256 tokenId) external view returns (bool);
function exists(address active, address passive) external view returns (bool);
function tokenId(address active, address passive) external view returns (uint256);
function links(uint256 tokenId) external view returns (Link memory);
}
ERC4973.sol 44 lines
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.6;
/** @title Account-bound tokens
* @dev See https://eips.ethereum.org/EIPS/eip-4973
* Note: the ERC-165 identifier for this interface is 0x5164cf47
*/
interface IERC4973 {
/// @dev This emits when ownership of any ABT changes by any mechanism.
/// This event emits when ABTs are given or equipped and unequipped
/// (`to` == 0).
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
/// @notice Count all ABTs assigned to an owner
/// @dev ABTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param owner An address for whom to query the balance
/// @return The number of ABTs owned by `address owner`, possibly zero
function balanceOf(address owner) external view returns (uint256);
/// @notice Find the address bound to an ERC4973 account-bound token
/// @dev ABTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param tokenId The identifier for an ABT.
/// @return The address of the owner bound to the ABT.
function ownerOf(uint256 tokenId) external view returns (address);
/// @notice Removes the `uint256 tokenId` from an account. At any time, an
/// ABT receiver must be able to disassociate themselves from an ABT
/// publicly through calling this function. After successfully executing this
/// function, given the parameters for calling `function give` or
/// `function take` a token must be re-equipable.
/// @dev Must emit a `event Transfer` with the `address to` field pointing to
/// the zero address.
/// @param tokenId The identifier for an ABT.
function unequip(uint256 tokenId) external;
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Pausable.sol 105 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
ReentrancyGuard.sol 69 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
IERC721.sol 145 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.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);
}
SignatureChecker.sol 42 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../Address.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
if (error == ECDSA.RecoverError.NoError && recovered == signer) {
return true;
}
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length == 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
BitMaps.sol 55 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
* Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
*/
library BitMaps {
struct BitMap {
mapping(uint256 => uint256) _data;
}
/**
* @dev Returns whether the bit at `index` is set.
*/
function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
return bitmap._data[bucket] & mask != 0;
}
/**
* @dev Sets the bit at `index` to the boolean `value`.
*/
function setTo(
BitMap storage bitmap,
uint256 index,
bool value
) internal {
if (value) {
set(bitmap, index);
} else {
unset(bitmap, index);
}
}
/**
* @dev Sets the bit at `index`.
*/
function set(BitMap storage bitmap, uint256 index) internal {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
bitmap._data[bucket] |= mask;
}
/**
* @dev Unsets the bit at `index`.
*/
function unset(BitMap storage bitmap, uint256 index) internal {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
bitmap._data[bucket] &= ~mask;
}
}
IERC1271.sol 19 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
ECDSA.sol 213 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.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 `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_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);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
ERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
Read Contract
balanceOf 0x70a08231 → uint256
exists 0x7663f822 → bool
isActive 0x82afd23b → bool
links 0x881d8a40 → tuple
name 0x06fdde03 → string
owner 0x8da5cb5b → address
ownerOf 0x6352211e → address
passContract 0xf56116fc → address
paused 0x5c975abb → bool
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
tokenId 0x9c8c4b3d → uint256
tokenIndex 0xd55f9273 → uint64
tokenURI 0xc87b56dd → string
validityPeriod 0x1e6c3850 → uint64
Write Contract 9 functions
These functions modify contract state and require a wallet transaction to execute.
give 0xdbf03d7f
address to
bytes signature
returns: uint256
refresh 0x754ecc26
uint256 tokenId
uint256 validityPeriod_
renounceOwnership 0x715018a6
No parameters
setBaseURI 0x55f804b3
string baseURI
take 0xbb786693
address from
bytes signature
returns: uint256
togglePaused 0x36566f06
No parameters
transferOwnership 0xf2fde38b
address newOwner
unequip 0xd179e3d0
uint256 tokenId
withdraw 0x51cff8d9
address to
Recent Transactions
No transactions found for this address