Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xBDA937F5C5f4eFB2261b6FcD25A71A1C350FdF20
Balance 0 ETH
Nonce 1
Code Size 23081 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

23081 bytes
0x6080604052600436106103765760003560e01c80637a0839bb116101d1578063b88d4fde11610102578063e86b8d71116100a0578063f0ba84401161006f578063f0ba844014610af2578063f2fde38b14610b7b578063fae6595a14610b9b578063ff6a29a314610bbb57600080fd5b8063e86b8d7114610a7c578063e985e9c514610a9c578063ec3ea81514610abc578063ed9152c814610ad257600080fd5b8063d1a12d6a116100dc578063d1a12d6a146109f9578063dc84355414610a0f578063dd0b281e14610a3c578063e1452a6f14610a5c57600080fd5b8063b88d4fde14610999578063c87b56dd146109b9578063cd7c0326146109d957600080fd5b8063a046d5101161016f578063a87430ba11610149578063a87430ba146108dd578063a9922b6214610930578063affed0e014610963578063b40e0e931461097957600080fd5b8063a046d5101461087d578063a22cb4651461089d578063a35d521a146108bd57600080fd5b80638592ffd5116101ab5780638592ffd5146107e957806387bfa1d7146108165780638da5cb5b1461084a57806395d89b411461086857600080fd5b80637a0839bb146107865780638197a838146107b3578063824e39fb146107c957600080fd5b80632d0335ab116102ab5780636352211e1161024957806370a082311161022357806370a082311461071e578063715018a61461073e57806373593edd146107535780637636d3e41461076657600080fd5b80636352211e1461064e57806365c138501461066e5780636c728d9e146106fe57600080fd5b806342842e0e1161028557806342842e0e146105b55780634378a6e3146105d55780635225a135146106025780635d818d9e1461061757600080fd5b80632d0335ab146105575780633408e4701461058d5780633ccfd60b146105a057600080fd5b80630c53c51c1161031857806320379ee5116102f257806320379ee5146104d55780632342592f146104ea57806323b872dd1461050a578063242a00871461052a57600080fd5b80630c53c51c146104825780630f7e5970146104955780631fa2c0a3146104c257600080fd5b806307ab1beb1161035457806307ab1beb146103f557806307cfce4114610417578063081812fc1461042a578063095ea7b31461046257600080fd5b806301ffc9a71461037b57806303403abb146103b057806306fdde03146103d3575b600080fd5b34801561038757600080fd5b5061039b610396366004614e06565b610bef565b60405190151581526020015b60405180910390f35b3480156103bc57600080fd5b506103c5610c41565b6040519081526020016103a7565b3480156103df57600080fd5b506103e8610d8c565b6040516103a791906153b2565b34801561040157600080fd5b50610415610410366004614d8c565b610e1e565b005b610415610425366004614fac565b610eed565b34801561043657600080fd5b5061044a6104453660046150e5565b61117f565b6040516001600160a01b0390911681526020016103a7565b34801561046e57600080fd5b5061041561047d366004614d60565b611214565b6103e8610490366004614ced565b61133c565b3480156104a157600080fd5b506103e8604051806040016040528060018152602001603160f81b81525081565b6104156104d036600461514d565b611516565b3480156104e157600080fd5b506008546103c5565b3480156104f657600080fd5b50610415610505366004614d8c565b6116c9565b34801561051657600080fd5b50610415610525366004614c0c565b611785565b34801561053657600080fd5b5061054a6105453660046150e5565b6117bd565b6040516103a79190615330565b34801561056357600080fd5b506103c5610572366004614bb6565b6001600160a01b031660009081526009602052604090205490565b34801561059957600080fd5b50466103c5565b3480156105ac57600080fd5b5061041561182e565b3480156105c157600080fd5b506104156105d0366004614c0c565b6118e1565b3480156105e157600080fd5b506105f56105f03660046150e5565b6118fc565b6040516103a791906152fc565b34801561060e57600080fd5b50610415611965565b34801561062357600080fd5b5061062c611aac565b60408051941515855260208501939093529183015260608201526080016103a7565b34801561065a57600080fd5b5061044a6106693660046150e5565b611b60565b34801561067a57600080fd5b506106c76106893660046150e5565b60196020526000908152604090205460ff808216916101008104909116906201000081046001600160601b031690600160701b900463ffffffff1684565b6040516103a79493929190931515845291151560208401526001600160601b0316604083015263ffffffff16606082015260800190565b34801561070a57600080fd5b5061054a6107193660046150e5565b611bd7565b34801561072a57600080fd5b506103c5610739366004614bb6565b611c16565b34801561074a57600080fd5b50610415611c9d565b6104156107613660046150fe565b611cf2565b34801561077257600080fd5b50610415610781366004615007565b611cff565b34801561079257600080fd5b506107a66107a1366004614ee5565b611f4e565b6040516103a7919061536a565b3480156107bf57600080fd5b506103c5601c5481565b3480156107d557600080fd5b5061054a6107e43660046150e5565b611f70565b3480156107f557600080fd5b506108096108043660046150e5565b611f9f565b6040516103a7919061558c565b34801561082257600080fd5b506103c57f000000000000000000000000000000000000000000000000000000000001518081565b34801561085657600080fd5b506000546001600160a01b031661044a565b34801561087457600080fd5b506103e8612104565b34801561088957600080fd5b50610415610898366004614d8c565b612113565b3480156108a957600080fd5b506104156108b8366004614cb8565b6121cf565b3480156108c957600080fd5b506104156108d8366004614eca565b6122d1565b3480156108e957600080fd5b506109166108f8366004614bb6565b601a6020526000908152604090205460ff8082169161010090041682565b6040805160ff9384168152929091166020830152016103a7565b34801561093c57600080fd5b5061095061094b3660046150e5565b612433565b60405161ffff90911681526020016103a7565b34801561096f57600080fd5b506103c5601d5481565b34801561098557600080fd5b506104156109943660046150fe565b612440565b3480156109a557600080fd5b506104156109b4366004614c4d565b612510565b3480156109c557600080fd5b506103e86109d43660046150e5565b61254f565b3480156109e557600080fd5b50600a5461044a906001600160a01b031681565b348015610a0557600080fd5b506103c560175481565b348015610a1b57600080fd5b50610a2f610a2a3660046150e5565b61260b565b6040516103a7919061533e565b348015610a4857600080fd5b50610415610a57366004614bb6565b61265f565b348015610a6857600080fd5b5061054a610a773660046150e5565b61277b565b348015610a8857600080fd5b50610415610a97366004614d8c565b6127aa565b348015610aa857600080fd5b5061039b610ab7366004614bd3565b612866565b348015610ac857600080fd5b506103c5600d5481565b348015610ade57600080fd5b50601b5461044a906001600160a01b031681565b348015610afe57600080fd5b50610b48610b0d3660046150e5565b6018602052600090815260409020805460029091015460ff8083169261ffff6101008204169263010000009091049091169063ffffffff1684565b60408051941515855261ffff909316602085015260ff9091169183019190915263ffffffff1660608201526080016103a7565b348015610b8757600080fd5b50610415610b96366004614bb6565b612949565b348015610ba757600080fd5b50610415610bb6366004614fac565b612a03565b348015610bc757600080fd5b5061044a7f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e181565b60006001600160e01b031982166380ac58cd60e01b1480610c2057506001600160e01b03198216635b5e139f60e01b145b80610c3b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006002600c541415610c6f5760405162461bcd60e51b8152600401610c6690615555565b60405180910390fd5b6002600c55601b546001600160a01b03163314610cc75760405162461bcd60e51b815260206004820152601660248201527526bab9ba103132903a34329030bab1ba34b7b732b2b960511b6044820152606401610c66565b6000806000610cd4611aac565b50925092509250828015610ce85750816002145b610d045760405162461bcd60e51b8152600401610c6690615478565b60008111610d455760405162461bcd60e51b815260206004820152600e60248201526d4e6f206d6f7265205072696d657360901b6044820152606401610c66565b601654600090610d5790600190615849565b90506000610d66601583612afb565b9050610d73601583612b95565b610d7d3382612bdb565b6001600c559695505050505050565b606060018054610d9b906158a3565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc7906158a3565b8015610e145780601f10610de957610100808354040283529160200191610e14565b820191906000526020600020905b815481529060010190602001808311610df757829003601f168201915b5050505050905090565b336001600160a01b037f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e11614610e665760405162461bcd60e51b8152600401610c66906153c5565b60125415610e865760405162461bcd60e51b8152600401610c6690615528565b610ec4838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250612cf8915050565b80518051601191610eda91839160200190614782565b5060208201518160010155905050505050565b6002600c541415610f105760405162461bcd60e51b8152600401610c6690615555565b6002600c556000610f2085612e10565b90506000610f2d85612e10565b8251909150610f755760405162461bcd60e51b8152602060048201526014602482015273135d5cdd081bdddb88199a5c9cdd081a5b9c1d5d60621b6044820152606401610c66565b608081015151610fba5760405162461bcd60e51b815260206004820152601060248201526f4d7573742062652072656e7461626c6560801b6044820152606401610c66565b8060800151604001516001600160601b031634101561100f5760405162461bcd60e51b81526020600482015260116024820152704d7573742070617920737475642066656560781b6044820152606401610c66565b60208101516001600160a01b03166108fc600a61102d346009615807565b61103791906157f3565b6040518115909202916000818181858888f1935050505015801561105f573d6000803e3d6000fd5b5080608001516060015163ffffffff1642106110b65760405162461bcd60e51b815260206004820152601660248201527552656e74616c2070617373656420646561646c696e6560501b6044820152606401610c66565b80608001516020015115611166576000805b600681101561111657818061110257508761ffff1683608001516080015182600681106110f7576110f7615959565b602002015161ffff16145b91508061110e816158de565b9150506110c8565b50806111645760405162461bcd60e51b815260206004820152601a60248201527f4d7573742062652077686974656c697374656420737569746f720000000000006044820152606401610c66565b505b61117282828686612fd2565b50506001600c5550505050565b6000818152600360205260408120546001600160a01b03166111f85760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c66565b506000908152600560205260409020546001600160a01b031690565b600061121f82611b60565b9050806001600160a01b0316836001600160a01b0316141561128d5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610c66565b806001600160a01b031661129f6133a1565b6001600160a01b031614806112bb57506112bb81610ab76133a1565b61132d5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610c66565b61133783836133b0565b505050565b60408051606081810183526001600160a01b0388166000818152600960209081529085902054845283015291810186905261137a878287878761341e565b6113d05760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610c66565b6001600160a01b03871660009081526009602052604081208054600192906113f99084906157b6565b90915550506040517f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b9061143290899033908a90615293565b60405180910390a1600080306001600160a01b0316888a60405160200161145a929190615261565b60408051601f198184030181529082905261147491615245565b6000604051808303816000865af19150503d80600081146114b1576040519150601f19603f3d011682016040523d82523d6000602084013e6114b6565b606091505b5091509150816115085760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610c66565b925050505b95945050505050565b6002600c5414156115395760405162461bcd60e51b8152600401610c6690615555565b6002600c556000808061154a611aac565b5092509250925082801561155e5750600282105b61157a5760405162461bcd60e51b8152600401610c6690615478565b868110156115ca5760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f756768205072696d657320617661696c61626c6500000000006044820152606401610c66565b601487111561161b5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74206d696e74203e3230205072696d6573206174206f6e636500006044820152606401610c66565b600082156116315767010a741a4627800061163a565b66b1a2bc2ec500005b90506116468189615807565b3410156116865760405162461bcd60e51b815260206004820152600e60248201526d52657175697265732076616c756560901b6044820152606401610c66565b611693838989898961350e565b60005b888110156116b9576116a7846136d6565b806116b1816158de565b915050611696565b50506001600c5550505050505050565b336001600160a01b037f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e116146117115760405162461bcd60e51b8152600401610c66906153c5565b601654156117315760405162461bcd60e51b8152600401610c6690615528565b61176f838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250612cf8915050565b80518051601591610eda91839160200190614782565b6117966117906133a1565b826137ae565b6117b25760405162461bcd60e51b8152600401610c66906154d7565b61133783838361387d565b6117c56147cd565b600082815260186020526040808220815180830192839052926001909101916002918390855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116117eb575094979650505050505050565b6118366133a1565b6001600160a01b03166118516000546001600160a01b031690565b6001600160a01b0316146118775760405162461bcd60e51b8152600401610c66906154a2565b6002600c54141561189a5760405162461bcd60e51b8152600401610c6690615555565b6002600c55600080546040516001600160a01b03909116914780156108fc02929091818181858888f193505050501580156118d9573d6000803e3d6000fd5b506001600c55565b61133783838360405180602001604052806000815250612510565b6119046147eb565b6000828152600e6020526040812054905b60178160ff16101561195e57600160ff821683901c811614838260ff166017811061194257611942615959565b9115156020909202015280611956816158f9565b915050611915565b5050919050565b61196d6133a1565b6001600160a01b03166119886000546001600160a01b031690565b6001600160a01b0316146119ae5760405162461bcd60e51b8152600401610c66906154a2565b6002600c5414156119d15760405162461bcd60e51b8152600401610c6690615555565b6002600c55600080806119e2611aac565b5092509250925082611a065760405162461bcd60e51b8152600401610c6690615478565b6202a300601c54611a1791906157b6565b4211611a655760405162461bcd60e51b815260206004820152601c60248201527f4d757374207761697420666f722073616c6520746f20656c61707365000000006044820152606401610c66565b600060148210611a76576014611a78565b815b905060005b81811015611aa057611a8e846136d6565b80611a98816158de565b915050611a7d565b50506001600c55505050565b6000806000806000601c5490508060001415611ad657600080600080945094509450945050611b5a565b60125415611b0757611c20601c54611aee91906157b6565b9150814211600060116001015494509450945050611b5a565b60145415611b3857611c20601c54611b1f91906157b6565b9150814211600160136001015494509450945050611b5a565b61a8c0601c54611b4891906157b6565b60165442821096506002955093509150505b90919293565b6000818152600360205260408120546001600160a01b031680610c3b5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610c66565b611bdf6147cd565b8115611c1157611bf2600f836002613a28565b90508160021415611c1157600081815b61ffff90921660209290920201525b919050565b60006001600160a01b038216611c815760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610c66565b506001600160a01b031660009081526004602052604090205490565b611ca56133a1565b6001600160a01b0316611cc06000546001600160a01b031690565b6001600160a01b031614611ce65760405162461bcd60e51b8152600401610c66906154a2565b611cf06000613b56565b565b6113376001848484611516565b611d0c8461ffff16611b60565b6001600160a01b0316336001600160a01b031614611d625760405162461bcd60e51b815260206004820152601360248201527226bab9ba1037bbb71039b0b4b2103a37b5b2b760691b6044820152606401610c66565b611d6a61480a565b81518015611e0b5760068110611db25760405162461bcd60e51b815260206004820152600d60248201526c4d6178203620737569746f727360981b6044820152606401610c66565b60005b81811015611e0957838181518110611dcf57611dcf615959565b6020026020010151838260068110611de957611de9615959565b61ffff909216602092909202015280611e01816158de565b915050611db5565b505b6040518060a001604052806001151581526020016000831115158152602001866001600160601b031681526020018563ffffffff16815260200183815250601960008861ffff16815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a8154816001600160601b0302191690836001600160601b03160217905550606082015181600001600e6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600101906006611f0b929190614828565b505060405161ffff881681527f1e8109f6f067c9591f7a38bcb3b3688cdc1b164ea7c3daba0ac8eeb5fea0919691506020015b60405180910390a1505050505050565b6060611f5e838360000151613ba6565b9050611f6981613e26565b9392505050565b611f786147cd565b8115611c1157611f8b600f836006613a28565b90508160041415611c115760008181611c02565b611fa76148b9565b614000821115611fec5760405162461bcd60e51b815260206004820152601060248201526f4e756d62657220746f6f206c6172676560801b6044820152606401610c66565b6000828152601860209081526040808320815160a081018352815460ff80821615158352610100820461ffff16958301959095526301000000900490931683830152815180830192839052909160608401919060018401906002908288855b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161204b575050509284525050506002919091015463ffffffff1660209182015260408051808201825283815281516060810190925283830151939450929183019181906120cd9061ffff16611f70565b81526020016120e3856020015161ffff16611bd7565b81526020016120f9856020015161ffff1661277b565b905290529392505050565b606060028054610d9b906158a3565b336001600160a01b037f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e1161461215b5760405162461bcd60e51b8152600401610c66906153c5565b6010541561217b5760405162461bcd60e51b8152600401610c6690615528565b6121b9838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250612cf8915050565b80518051600f91610eda91839160200190614782565b6121d76133a1565b6001600160a01b0316826001600160a01b031614156122385760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610c66565b80600660006122456133a1565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff1916921515929092179091556122896133a1565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516122c5911515815260200190565b60405180910390a35050565b6122de8161ffff16611b60565b6001600160a01b0316336001600160a01b0316146123345760405162461bcd60e51b815260206004820152601360248201527226bab9ba1037bbb71039b0b4b2103a37b5b2b760691b6044820152606401610c66565b61233c61480a565b6040805160a08101825260008082526020808301828152838501838152606085018481526080860188815261ffff8a1686526019909452959093208451815492519451965163ffffffff16600160701b0263ffffffff60701b196001600160601b039890981662010000029790971662010000600160901b03199515156101000261ff00199215159290921661ffff199094169390931717939093161793909317815591519091906123f49060018301906006614828565b505060405161ffff841681527f396f7dc4f260ae4695269b875731b4d5f1ad68f054148f2f494970c5b9b8b4da91506020015b60405180910390a15050565b6000610c3b600f83612afb565b604080516020810185905290810183905260009060600160405160208183030381529060405280519060200120905061247c82600d5483613f39565b6124bf5760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21036b2b935b63290383937b7b360611b6044820152606401610c66565b6000848152600e602090815260409182902085905581518681529081018590527f8d713df5173641079700714d0f246546c554a22ba03e8c018c8c558563b93232910160405180910390a150505050565b61252161251b6133a1565b836137ae565b61253d5760405162461bcd60e51b8152600401610c66906154d7565b61254984848484613fe8565b50505050565b6060600061255c83611f9f565b90506000612569846118fc565b905060006125778584611f4e565b60405163255c8cc760e01b81529091507340614f51a985302d7060966a072b7e846a21e4e69063255c8cc7906125b790889087908690889060040161561c565b60006040518083038186803b1580156125cf57600080fd5b505af41580156125e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261150d9190810190614e5d565b61261361480a565b600082815260196020908152604091829020825160c08101938490526001909101805461ffff1682529092909160069190839060029086018084116117eb575094979650505050505050565b336001600160a01b037f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e116146126a75760405162461bcd60e51b8152600401610c66906153c5565b601054158015906126b9575060125415155b80156126c6575060145415155b80156126d3575060165415155b6127115760405162461bcd60e51b815260206004820152600f60248201526e139bdd081a5b9a5d1a585b1a5e9959608a1b6044820152606401610c66565b42601c55601b80546001600160a01b0383166001600160a01b031990911617905561274e6127476000546001600160a01b031690565b6000612bdb565b506040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c890600090a150565b6127836147cd565b8115611c1157612796600f836004613a28565b90508160031415611c115760008181611c02565b336001600160a01b037f000000000000000000000000ff62c2edae704b956a64d445485f6e709142f4e116146127f25760405162461bcd60e51b8152600401610c66906153c5565b601454156128125760405162461bcd60e51b8152600401610c6690615528565b612850838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250612cf8915050565b80518051601391610eda91839160200190614782565b600a546000906001600160a01b03168015801590612908575060405163c455279160e01b81526001600160a01b038581166004830152808516919083169063c45527919060240160206040518083038186803b1580156128c557600080fd5b505afa1580156128d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fd9190614e40565b6001600160a01b0316145b15612917576001915050610c3b565b6001600160a01b0380851660009081526006602090815260408083209387168352929052205460ff165b949350505050565b6129516133a1565b6001600160a01b031661296c6000546001600160a01b031690565b6001600160a01b0316146129925760405162461bcd60e51b8152600401610c66906154a2565b6001600160a01b0381166129f75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c66565b612a0081613b56565b50565b6002600c541415612a265760405162461bcd60e51b8152600401610c6690615555565b6002600c556000612a3685612e10565b90506000612a4385612e10565b82519091508015612a52575080515b6111665760405162461bcd60e51b815260206004820152601c60248201527f42726565646572206d757374206f776e20696e70757420746f6b656e000000006044820152606401610c66565b600033301415612af557600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b03169150612af89050565b50335b90565b600082600101548210612b405760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610c66565b6000612b4d6010846157f3565b90506000612b5c601085615919565b9050612b69816010615807565b856000018381548110612b7e57612b7e615959565b9060005260206000200154901c9250505092915050565b6000612bb260018460010154612bab9190615849565b8490612afb565b9050612bbf83838361401b565b600183018054906000612bd18361588c565b9190505550505050565b6000612be56147cd565b612bf28361ffff16612433565b6040805160a081018252600180825261ffff8781166020808501918252848601848152606086018981524263ffffffff1660808801529784166000818152601890935296909120855181549351925162ffffff1990941690151562ffff0019161761010092909416919091029290921763ff0000001916630100000060ff909216919091021781559351929550909291612c90918301906002614828565b50608091909101516002909101805463ffffffff191663ffffffff909216919091179055612cbe84836140b7565b6040518281527f6c685112450c2165ecbd4d3be7e8fb204a0d220e3fa51953f6fcedf5037ed3059060200160405180910390a15092915050565b60408051808201909152606081526000602082015282516000612d1c6010856157f3565b9050612d298160016157b6565b8214612d6c5760405162461bcd60e51b8152602060048201526012602482015271092dcecc2d8d2c840c2e4e440d8cadccee8d60731b6044820152606401610c66565b6000612d79601086615919565b90506000612d88826010615807565b878481518110612d9a57612d9a615959565b6020026020010151901c905080600014612df65760405162461bcd60e51b815260206004820152601760248201527f496e76616c69642075696e74323536207061636b696e670000000000000000006044820152606401610c66565b505060408051808201909152948552505050602082015290565b612e186148de565b6000612e278361ffff16611b60565b6040805160a080820183526001600160a01b038416338114835260208084019190915261ffff80891684860181905260009081526018835285902085519384018652805460ff808216151586526101008204909316938501939093526301000000909204168285015283518085019094529394509092606080850193908301906001830160028282826020028201916000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612eba575050509284525050506002919091015463ffffffff90811660209283015291835261ffff87166000908152601982526040808220815160a081018352815460ff808216151583526101008204161515828701526201000081046001600160601b031682850152600160701b90049095166060860152815160c08101928390529590930194608085019290916001850191600691908390855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612f8857505050929093525050509152509392505050565b6000836040015161ffff16856040015161ffff16612ff09190615807565b90506140008111156130375760405162461bcd60e51b815260206004820152601060248201526f4e756d62657220746f6f206c6172676560801b6044820152606401610c66565b8061305d61ffff82166000908152600360205260409020546001600160a01b0316151590565b156130a15760405162461bcd60e51b8152602060048201526014602482015273273ab6b132b91030b63932b0b23c903a30b5b2b760611b6044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000001518086606001516080015163ffffffff166130db91906157b6565b4211801561312157507f000000000000000000000000000000000000000000000000000000000001518085606001516080015163ffffffff1661311e91906157b6565b42115b61316d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f7420627265656420736f20717569636b6c790000000000000000006044820152606401610c66565b846040015161ffff16866040015161ffff1614801561318f5750606086015151155b156131dc5760405162461bcd60e51b815260206004820152601c60248201527f436f6d706f73697465732063616e6e6f742073656c662d6272656564000000006044820152606401610c66565b60408087015161ffff9081166000908152601860209081528382206002908101805463ffffffff421663ffffffff1991821681179092558b8701519095168452858420909101805490941617909255825160a0810184528181529182015260608088015183015190890151830151919283019161325991906157ce565b60ff90811682526040805180820182528a82015161ffff90811682528a8301518116602080840191909152808601929092524263ffffffff169483019490945285841660009081526018825282902085518154928701519387015162ffffff1990931690151562ffff0019161761010093909516929092029390931763ff00000019166301000000939092169290920217815560608201516133019060018301906002614828565b50608091909101516002909101805463ffffffff191663ffffffff9092169190911790556133333361ffff83166140b7565b8315613348576133488161ffff168585612440565b61335286866140d5565b60408087015186820151825161ffff808616825292831660208201529116918101919091527f30be847db9d81ac3b6da70a088210302e2688f8a3be64693715f10f36526941e90606001611f3e565b60006133ab612a9e565b905090565b600081815260056020526040902080546001600160a01b0319166001600160a01b03841690811790915581906133e582611b60565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006001600160a01b0386166134845760405162461bcd60e51b815260206004820152602560248201527f4e61746976654d6574615472616e73616374696f6e3a20494e56414c49445f5360448201526424a3a722a960d91b6064820152608401610c66565b60016134976134928761419f565b61421c565b6040805160008152602081018083529290925260ff851690820152606081018690526080810185905260a0016020604051602081039080840390855afa1580156134e5573d6000803e3d6000fd5b505050602060405103516001600160a01b0316866001600160a01b031614905095945050505050565b62015180601c5461351f91906157b6565b4210156136cf576040516001600160601b03193360601b16602082015260348101849052605481018390526000906074016040516020818303038152906040528051906020012090506135758260175483613f39565b6135b85760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21036b2b935b63290383937b7b360611b6044820152606401610c66565b60008587156135de57336000908152601a6020526040902054610100900460ff166135f2565b336000908152601a602052604090205460ff165b6135fc91906157ce565b90508661366757848160ff1611156136465760405162461bcd60e51b815260206004820152600d60248201526c0457863656564696e672063617609c1b6044820152606401610c66565b336000908152601a60205260409020805460ff191660ff83161790556136cc565b838160ff1611156136aa5760405162461bcd60e51b815260206004820152600d60248201526c0457863656564696e672063617609c1b6044820152606401610c66565b336000908152601a60205260409020805461ff00191661010060ff8416021790555b50505b5050505050565b60006136e061424c565b9050600082613728576012546000906136f99084615919565b9050613706601182612afb565b9150613713601182612b95565b61372284601160010154614347565b506137a4565b826001141561376a576014546000906137419084615919565b905061374e601382612afb565b915061375b601382612b95565b61372284601360010154614347565b60405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818985d18da1259608a1b6044820152606401610c66565b6125493382612bdb565b6000818152600360205260408120546001600160a01b03166138275760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c66565b600061383283611b60565b9050806001600160a01b0316846001600160a01b0316148061386d5750836001600160a01b03166138628461117f565b6001600160a01b0316145b8061294157506129418185612866565b826001600160a01b031661389082611b60565b6001600160a01b0316146138f85760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610c66565b6001600160a01b03821661395a5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610c66565b61396583838361438a565b6139706000826133b0565b6001600160a01b0383166000908152600460205260408120805460019290613999908490615849565b90915550506001600160a01b03821660009081526004602052604081208054600192906139c79084906157b6565b909155505060008181526003602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b613a306147cd565b6000613a3c8585612afb565b90508261ffff168161ffff1610158015613a565750600084115b15613ad157806000613a69600187615849565b90506000613a778685615826565b90505b8061ffff168361ffff1610613acd57613a938883612afb565b92508061ffff168361ffff161415613ab15761ffff83168552613acd565b81613abb57613acd565b81613ac58161588c565b925050613a7a565b5050505b806000613adf8660016157b6565b90506000613aed8685615790565b90505b8061ffff168361ffff1611613b4b5787600101548210613b0f57613b4b565b613b2582613b1c816158de565b93508990612afb565b92508061ffff168361ffff161415613b465761ffff83166020860152613b4b565b613af0565b505050509392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b805160609015613bff5760408051600180825281830190925290602080830190803683370190505090508281600081518110613be457613be4615959565b602002602001019061ffff16908161ffff1681525050610c3b565b60608201518051600091613ce091906018908490815b6020908102919091015161ffff9081168352828201939093526040918201600020825160a081018452815460ff808216151583526101008204909616938201939093526301000000909204909316818301528151808301909252919060608301906001830160028282826020028201916000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411613c89575050509284525050506002919091015463ffffffff16602090910152613ba6565b8051606085015160208101519293509091600091613d05919060189084906001613c15565b8051909150613d1481846157b6565b6001600160401b03811115613d2b57613d2b61596f565b604051908082528060200260200182016040528015613d54578160200160208202803683370190505b50945060005b83811015613db357848181518110613d7457613d74615959565b6020026020010151868281518110613d8e57613d8e615959565b61ffff9092166020928302919091019091015280613dab816158de565b915050613d5a565b5060005b81811015613e1b57828181518110613dd157613dd1615959565b6020026020010151868286613de691906157b6565b81518110613df657613df6615959565b61ffff9092166020928302919091019091015280613e13816158de565b915050613db7565b505050505092915050565b805160609060015b81811015613f31576000848281518110613e4a57613e4a615959565b602002602001015190506000600183613e639190615849565b90505b60008112158015613e9757508161ffff16868281518110613e8957613e89615959565b602002602001015161ffff16115b15613ef057858181518110613eae57613eae615959565b602002602001015186826001613ec491906157b6565b81518110613ed457613ed4615959565b61ffff9092166020928302919091019091015260001901613e66565b81868260010181518110613f0657613f06615959565b602002602001019061ffff16908161ffff168152505050508080613f29906158de565b915050613e2e565b509192915050565b600081815b8551811015613fdd576000868281518110613f5b57613f5b615959565b60200260200101519050808311613f9d576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250613fca565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b5080613fd5816158de565b915050613f3e565b509092149392505050565b613ff384848461387d565b613fff84848484614446565b6125495760405162461bcd60e51b8152600401610c66906153ef565b60006140286010846157f3565b90506000614037601085615919565b90506000614046826010615807565b61ffff901b19905060008187600001858154811061406657614066615959565b90600052602060002001541690508260106140819190615807565b8561ffff16901b91508181178760000185815481106140a2576140a2615959565b60009182526020909120015550505050505050565b6140d182826040518060200160405280600081525061455a565b5050565b60608201515180156140e957506060810151515b156140f2575050565b6060820151511561412c57805161411b5760405162461bcd60e51b8152600401610c6690615441565b6140d1816040015161ffff1661458d565b606081015151156141665781516141555760405162461bcd60e51b8152600401610c6690615441565b6140d1826040015161ffff1661458d565b81518015614172575080515b61418e5760405162461bcd60e51b8152600401610c6690615441565b61411b826040015161ffff1661458d565b60006040518060800160405280604381526020016159b160439139805160209182012083518483015160408087015180519086012090516141ff950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061422760085490565b60405161190160f01b60208201526022810191909152604281018390526062016141ff565b601d80546000918261425d836158de565b90915550506040516001600160601b03193360601b166020820152439042906034016040516020818303038152906040528051906020012060001c6142a291906157f3565b6040516001600160601b03194160601b166020820152459042906034016040516020818303038152906040528051906020012060001c6142e291906157f3565b6142ec44426157b6565b6142f691906157b6565b61430091906157b6565b61430a91906157b6565b61431491906157b6565b601d546040805160208101939093528201526060016040516020818303038152906040528051906020012060001c905090565b806140d15742601c557fa3cfaded1a887a6b8bc79d67e12e00966d9805697c70933c8a9eff74e667eb2e61437c8360016157b6565b604051908152602001612427565b61439261480a565b6040805160a0810182526000808252602080830182815283850183815260608501848152608086018881528986526019909452959093208451815492519451965163ffffffff16600160701b0263ffffffff60701b196001600160601b039890981662010000029790971662010000600160901b03199515156101000261ff00199215159290921661ffff199094169390931717939093161793909317815591519091906136cc9060018301906006614828565b60006001600160a01b0384163b1561454f57836001600160a01b031663150b7a0261446f6133a1565b8786866040518563ffffffff1660e01b815260040161449194939291906152bf565b602060405180830381600087803b1580156144ab57600080fd5b505af19250505080156144db575060408051601f3d908101601f191682019092526144d891810190614e23565b60015b614535573d808015614509576040519150601f19603f3d011682016040523d82523d6000602084013e61450e565b606091505b50805161452d5760405162461bcd60e51b8152600401610c66906153ef565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612941565b506001949350505050565b6145648383614634565b6145716000848484614446565b6113375760405162461bcd60e51b8152600401610c66906153ef565b600061459882611b60565b90506145a68160008461438a565b6145b16000836133b0565b6001600160a01b03811660009081526004602052604081208054600192906145da908490615849565b909155505060008281526003602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03821661468a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610c66565b6000818152600360205260409020546001600160a01b0316156146ef5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610c66565b6146fb6000838361438a565b6001600160a01b03821660009081526004602052604081208054600192906147249084906157b6565b909155505060008181526003602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b8280548282559060005260206000209081019282156147bd579160200282015b828111156147bd5782518255916020019190600101906147a2565b506147c9929150614914565b5090565b60405180604001604052806002906020820280368337509192915050565b604051806102e001604052806017906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b6001830191839082156147bd5791602002820160005b8382111561487e57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261483e565b80156148ac5782816101000a81549061ffff021916905560020160208160010104928301926001030261487e565b50506147c9929150614914565b60405180604001604052806148cc614929565b81526020016148d961495f565b905290565b6040805160a0810182526000808252602082018190529181019190915260608101614907614929565b81526020016148d961498c565b5b808211156147c95760008155600101614915565b6040805160a08101825260008082526020820181905291810191909152606081016149526147cd565b8152600060209091015290565b60405180606001604052806149726147cd565b815260200161497f6147cd565b81526020016148d96147cd565b6040805160a0810182526000808252602082018190529181018290526060810191909152608081016148d961480a565b600082601f8301126149cd57600080fd5b813560206149e26149dd83615746565b615716565b80838252828201915082860187848660051b8901011115614a0257600080fd5b60005b85811015614a2157813584529284019290840190600101614a05565b5090979650505050505050565b600082601f830112614a3f57600080fd5b604051604081018181106001600160401b0382111715614a6157614a6161596f565b8060405250808385604086011115614a7857600080fd5b60005b6002811015614aa257614a8d82614b7f565b83526020928301929190910190600101614a7b565b509195945050505050565b80358015158114611c1157600080fd5b600082601f830112614ace57600080fd5b8135614adc6149dd82615769565b818152846020838601011115614af157600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614b2057600080fd5b604051606081018181106001600160401b0382111715614b4257614b4261596f565b604052905080614b528484614a2e565b8152614b618460408501614a2e565b6020820152614b738460808501614a2e565b60408201525092915050565b803561ffff81168114611c1157600080fd5b803563ffffffff81168114611c1157600080fd5b803560ff81168114611c1157600080fd5b600060208284031215614bc857600080fd5b8135611f6981615985565b60008060408385031215614be657600080fd5b8235614bf181615985565b91506020830135614c0181615985565b809150509250929050565b600080600060608486031215614c2157600080fd5b8335614c2c81615985565b92506020840135614c3c81615985565b929592945050506040919091013590565b60008060008060808587031215614c6357600080fd5b8435614c6e81615985565b93506020850135614c7e81615985565b92506040850135915060608501356001600160401b03811115614ca057600080fd5b614cac87828801614abd565b91505092959194509250565b60008060408385031215614ccb57600080fd5b8235614cd681615985565b9150614ce460208401614aad565b90509250929050565b600080600080600060a08688031215614d0557600080fd5b8535614d1081615985565b945060208601356001600160401b03811115614d2b57600080fd5b614d3788828901614abd565b9450506040860135925060608601359150614d5460808701614ba5565b90509295509295909350565b60008060408385031215614d7357600080fd5b8235614d7e81615985565b946020939093013593505050565b600080600060408486031215614da157600080fd5b83356001600160401b0380821115614db857600080fd5b818601915086601f830112614dcc57600080fd5b813581811115614ddb57600080fd5b8760208260051b8501011115614df057600080fd5b6020928301989097509590910135949350505050565b600060208284031215614e1857600080fd5b8135611f698161599a565b600060208284031215614e3557600080fd5b8151611f698161599a565b600060208284031215614e5257600080fd5b8151611f6981615985565b600060208284031215614e6f57600080fd5b81516001600160401b03811115614e8557600080fd5b8201601f81018413614e9657600080fd5b8051614ea46149dd82615769565b818152856020838501011115614eb957600080fd5b61150d826020830160208601615860565b600060208284031215614edc57600080fd5b611f6982614b7f565b6000808284036101a0811215614efa57600080fd5b614f0384614b7f565b9250601f1901610180811215614f1857600080fd5b614f206156cc565b60c0821215614f2e57600080fd5b614f366156f4565b9150614f4460208601614aad565b8252614f5260408601614b7f565b6020830152614f6360608601614ba5565b6040830152614f758660808701614a2e565b6060830152614f8660c08601614b91565b6080830152818152614f9b8660e08701614b0e565b602082015280925050509250929050565b60008060008060808587031215614fc257600080fd5b614fcb85614b7f565b9350614fd960208601614b7f565b92506040850135915060608501356001600160401b03811115614ffb57600080fd5b614cac878288016149bc565b6000806000806080858703121561501d57600080fd5b61502685614b7f565b93506020808601356001600160601b038116811461504357600080fd5b935061505160408701614b91565b925060608601356001600160401b0381111561506c57600080fd5b8601601f8101881361507d57600080fd5b803561508b6149dd82615746565b8082825284820191508484018b868560051b87010111156150ab57600080fd5b600094505b838510156150d5576150c181614b7f565b8352600194909401939185019185016150b0565b50979a9699509497505050505050565b6000602082840312156150f757600080fd5b5035919050565b60008060006060848603121561511357600080fd5b833592506020840135915060408401356001600160401b0381111561513757600080fd5b615143868287016149bc565b9150509250925092565b6000806000806080858703121561516357600080fd5b84359350602085013592506040850135915060608501356001600160401b03811115614ffb57600080fd5b8060005b60178110156125495781511515845260209384019390910190600101615192565b8060005b600281101561254957815161ffff168452602093840193909101906001016151b7565b600081518084526020808501945080840160005b8381101561520e57815161ffff16875295820195908201906001016151ee565b509495945050505050565b60008151808452615231816020860160208601615860565b601f01601f19169290920160200192915050565b60008251615257818460208701615860565b9190910192915050565b60008351615273818460208801615860565b60609390931b6001600160601b0319169190920190815260140192915050565b6001600160a01b0384811682528316602082015260606040820181905260009061150d90830184615219565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906152f290830184615219565b9695505050505050565b6102e08101818360005b60178110156153275781511515835260209283019290910190600101615306565b50505092915050565b60408101610c3b82846151b3565b60c08101818360005b600681101561532757815161ffff16835260209283019290910190600101615347565b6020808252825182820181905260009190848201906040850190845b818110156153a657835161ffff1683529284019291840191600101615386565b50909695505050505050565b602081526000611f696020830184615219565b60208082526010908201526f27b7363c9034b734ba34b0b634bd32b960811b604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526018908201527f42726565646572206d757374206f776e206275726e696e670000000000000000604082015260600190565b60208082526010908201526f4261746368206e6f742061637469766560801b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b602080825260139082015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600061018082019050825180511515835261ffff602082015116602084015260ff604082015116604084015260608101516155ca60608501826151b3565b5063ffffffff60808201511660a08401525060208301516155ef60c0840182516151b3565b60208101516156026101008501826151b3565b50604001516156156101408401826151b3565b5092915050565b60006104a0868352855180511515602085015261ffff602082015116604085015260ff6040820151166060850152606081015161565c60808601826151b3565b5063ffffffff60808201511660c085015250602086015161568160e0850182516151b3565b60208101516156946101208601826151b3565b50604001516156a76101608501826151b3565b50806101a08401526156bb818401866151da565b91505061150d6101c083018461518e565b604080519081016001600160401b03811182821017156156ee576156ee61596f565b60405290565b60405160a081016001600160401b03811182821017156156ee576156ee61596f565b604051601f8201601f191681016001600160401b038111828210171561573e5761573e61596f565b604052919050565b60006001600160401b0382111561575f5761575f61596f565b5060051b60200190565b60006001600160401b038211156157825761578261596f565b50601f01601f191660200190565b600061ffff8083168185168083038211156157ad576157ad61592d565b01949350505050565b600082198211156157c9576157c961592d565b500190565b600060ff821660ff84168060ff038211156157eb576157eb61592d565b019392505050565b60008261580257615802615943565b500490565b60008160001904831182151516156158215761582161592d565b500290565b600061ffff838116908316818110156158415761584161592d565b039392505050565b60008282101561585b5761585b61592d565b500390565b60005b8381101561587b578181015183820152602001615863565b838111156125495750506000910152565b60008161589b5761589b61592d565b506000190190565b600181811c908216806158b757607f821691505b602082108114156158d857634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156158f2576158f261592d565b5060010190565b600060ff821660ff8114156159105761591061592d565b60010192915050565b60008261592857615928615943565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114612a0057600080fd5b6001600160e01b031981168114612a0057600080fdfe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529a26469706673582212204441b21cbfe6a1dd26971eed92a336b3877f15f6861293a2babc875af44889be64736f6c63430008070033

Verified Source Code Partial Match

Compiler: v0.8.7+commit.e28d00a7 EVM: london Optimization: Yes (200 runs)
Primes.sol 2740 lines
pragma solidity ^0.8.7;

/**
 * @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);
}

/**
 * @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`, 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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * 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 Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @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 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);

    /**
     * @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;
}

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

/*
 * @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;
    }
}

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

/**
 * @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;
    }
}

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC165, IERC165)
        returns (bool)
    {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return
            bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        override
        returns (bool)
    {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @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.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId)
        internal
        view
        virtual
        returns (bool)
    {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner ||
            getApproved(tokenId) == spender ||
            isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (
                bytes4 retval
            ) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

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() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        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 {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract Initializable {
    bool inited = false;

    modifier initializer() {
        require(!inited, "already inited");
        _;
        inited = true;
    }
}

contract EIP712Base is Initializable {
    struct EIP712Domain {
        string name;
        string version;
        address verifyingContract;
        bytes32 salt;
    }

    string public constant ERC712_VERSION = "1";

    bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
        keccak256(
            bytes("EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)")
        );
    bytes32 internal domainSeperator;

    // supposed to be called once while initializing.
    // one of the contracts that inherits this contract follows proxy pattern
    // so it is not possible to do this in a constructor
    function _initializeEIP712(string memory name) internal initializer {
        _setDomainSeperator(name);
    }

    function _setDomainSeperator(string memory name) internal {
        domainSeperator = keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(name)),
                keccak256(bytes(ERC712_VERSION)),
                address(this),
                bytes32(getChainId())
            )
        );
    }

    function getDomainSeperator() public view returns (bytes32) {
        return domainSeperator;
    }

    function getChainId() public view returns (uint256) {
        uint256 id;
        assembly {
            id := chainid()
        }
        return id;
    }

    /**
     * Accept message hash and returns hash message in EIP712 compatible form
     * So that it can be used to recover signer from signature signed using EIP712 formatted data
     * https://eips.ethereum.org/EIPS/eip-712
     * "\\x19" makes the encoding deterministic
     * "\\x01" is the version byte to make it compatible to EIP-191
     */
    function toTypedMessageHash(bytes32 messageHash) internal view returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash));
    }
}

contract NativeMetaTransaction is EIP712Base {
    bytes32 private constant META_TRANSACTION_TYPEHASH =
        keccak256(bytes("MetaTransaction(uint256 nonce,address from,bytes functionSignature)"));
    event MetaTransactionExecuted(
        address userAddress,
        address payable relayerAddress,
        bytes functionSignature
    );
    mapping(address => uint256) nonces;

    /*
     * Meta transaction structure.
     * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas
     * He should call the desired function directly in that case.
     */
    struct MetaTransaction {
        uint256 nonce;
        address from;
        bytes functionSignature;
    }

    function executeMetaTransaction(
        address userAddress,
        bytes memory functionSignature,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) public payable returns (bytes memory) {
        MetaTransaction memory metaTx = MetaTransaction({
            nonce: nonces[userAddress],
            from: userAddress,
            functionSignature: functionSignature
        });

        require(verify(userAddress, metaTx, sigR, sigS, sigV), "Signer and signature do not match");

        // increase nonce for user (to avoid re-use)
        nonces[userAddress] += 1;

        emit MetaTransactionExecuted(userAddress, payable(msg.sender), functionSignature);

        // Append userAddress and relayer address at the end to extract it from calling context
        (bool success, bytes memory returnData) = address(this).call(
            abi.encodePacked(functionSignature, userAddress)
        );
        require(success, "Function call not successful");

        return returnData;
    }

    function hashMetaTransaction(MetaTransaction memory metaTx) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    META_TRANSACTION_TYPEHASH,
                    metaTx.nonce,
                    metaTx.from,
                    keccak256(metaTx.functionSignature)
                )
            );
    }

    function getNonce(address user) public view returns (uint256 nonce) {
        nonce = nonces[user];
    }

    function verify(
        address signer,
        MetaTransaction memory metaTx,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) internal view returns (bool) {
        require(signer != address(0), "NativeMetaTransaction: INVALID_SIGNER");
        return
            signer == ecrecover(toTypedMessageHash(hashMetaTransaction(metaTx)), sigV, sigR, sigS);
    }
}

abstract contract ContextMixin {
    function msgSender() internal view returns (address payable sender) {
        if (msg.sender == address(this)) {
            bytes memory array = msg.data;
            uint256 index = msg.data.length;
            assembly {
                // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
            }
        } else {
            sender = payable(msg.sender);
        }
        return sender;
    }
}

contract OwnableDelegateProxy {}

contract ProxyRegistry {
    mapping(address => OwnableDelegateProxy) public proxies;
}

abstract contract ERC721Tradable is ContextMixin, Ownable, ERC721, NativeMetaTransaction {
    address public proxyRegistryAddress;
    uint256 private _currentTokenId = 0;

    constructor(
        string memory _name,
        string memory _symbol,
        address _proxyRegistryAddress
    ) ERC721(_name, _symbol) Ownable() {
        proxyRegistryAddress = _proxyRegistryAddress;
        _initializeEIP712(_name);
    }

    /**
     * Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings.
     */
    function isApprovedForAll(address owner, address operator) public view override returns (bool) {
        // Whitelist OpenSea proxy contract for easy trading.
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (
            proxyRegistryAddress != address(0) && address(proxyRegistry.proxies(owner)) == operator
        ) {
            return true;
        }

        return super.isApprovedForAll(owner, operator);
    }

    /**
     * This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
     */
    function _msgSender() internal view override returns (address sender) {
        return ContextMixin.msgSender();
    }
}

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 make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

library Packed16BitArray {
    using Packed16BitArray for Packed16BitArray.PackedArray;

    struct PackedArray {
        uint256[] array;
        uint256 length;
    }

    // Verifies that the higher level count is correct, and that the last uint256 is left packed with 0's
    function initStruct(uint256[] memory _arr, uint256 _len)
        internal
        pure
        returns (PackedArray memory)
    {
        uint256 actualLength = _arr.length;
        uint256 len0 = _len / 16;
        require(actualLength == len0 + 1, "Invalid arr length");

        uint256 len1 = _len % 16;
        uint256 leftPacked = uint256(_arr[len0] >> (len1 * 16));
        require(leftPacked == 0, "Invalid uint256 packing");

        return PackedArray(_arr, _len);
    }

    function getValue(PackedArray storage ref, uint256 _index) internal view returns (uint16) {
        require(_index < ref.length, "Invalid index");
        uint256 aid = _index / 16;
        uint256 iid = _index % 16;
        return uint16(ref.array[aid] >> (iid * 16));
    }

    function biDirectionalSearch(
        PackedArray storage ref,
        uint256 _startIndex,
        uint16 _delta
    ) internal view returns (uint16[2] memory hits) {
        uint16 startVal = ref.getValue(_startIndex);

        // Search down
        if (startVal >= _delta && _startIndex > 0) {
            uint16 tempVal = startVal;
            uint256 tempIdx = _startIndex - 1;
            uint16 target = startVal - _delta;

            while (tempVal >= target) {
                tempVal = ref.getValue(tempIdx);
                if (tempVal == target) {
                    hits[0] = tempVal;
                    break;
                }
                if (tempIdx == 0) {
                    break;
                } else {
                    tempIdx--;
                }
            }
        }
        {
            // Search up
            uint16 tempVal = startVal;
            uint256 tempIdx = _startIndex + 1;
            uint16 target = startVal + _delta;

            while (tempVal <= target) {
                if (tempIdx >= ref.length) break;
                tempVal = ref.getValue(tempIdx++);
                if (tempVal == target) {
                    hits[1] = tempVal;
                    break;
                }
            }
        }
    }

    function setValue(
        PackedArray storage ref,
        uint256 _index,
        uint16 _value
    ) internal {
        uint256 aid = _index / 16;
        uint256 iid = _index % 16;

        // 1. Do an && between old value and a mask
        uint256 mask = uint256(~(uint256(65535) << (iid * 16)));
        uint256 masked = ref.array[aid] & mask;
        // 2. Do an |= between (1) and positioned _value
        mask = uint256(_value) << (iid * 16);
        ref.array[aid] = masked | mask;
    }

    function extractIndex(PackedArray storage ref, uint256 _index) internal {
        // Get value at the end
        uint16 endValue = ref.getValue(ref.length - 1);
        ref.setValue(_index, endValue);
        // TODO - could get rid of this and rely on length if need to reduce gas
        // ref.setValue(ref.length - 1, 0);
        ref.length--;
    }
}

library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        // Check if the computed hash (root) is equal to the provided root
        return computedHash == root;
    }
}

/// @title MathBlocks, Primes
/********************************************
 * MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM *
 * MMMMMMMMMMMMNmdddddddddddddddddmNMMMMMMM *
 * MMMMMMMMMmhyssooooooooooooooooosyhNMMMMM *
 * MMMMMMMmyso+/::::::::::::::::::/osyMMMMM *
 * MMMMMMhys+::/+++++++++++++++++/:+syNMMMM *
 * MMMMNyso/:/+/::::+/:::/+:::::::+oshMMMMM *
 * MMMMmys/-//:/++:/+://-++-+oooossydMMMMMM *
 * MMMMNyso+//+s+/:+/:+/:+/:+syddmNMMMMMMMM *
 * MMMMMNdyyyyso/:++:/+:/+/:+syNMMMMMMMMMMM *
 * MMMMMMMMMhso/:/+/:++:/++-+symMMMMMMMMMMM *
 * MMMMMMMMdys+:/++:/++:/++:/+syNMMMMMMMMMM *
 * MMMMMMMNys+:/++/:+s+:/+++:/oydMMMMMMMMMM *
 * MMMMMMMmys+:/+/:/oso/:///:/sydMMMMMMMMMM *
 * MMMMMMMMhso+///+osyso+///osyhMMMMMMMMMMM *
 * MMMMMMMMMmhyssyyhmMdhyssyydNMMMMMMMMMMMM *
 * MMMMMMMMMMMMMNMMMMMMMMMNMMMMMMMMMMMMMMMM *
 *******************************************/
struct CoreData {
    bool isPrime;
    uint16 primeIndex;
    uint8 primeFactorCount;
    uint16[2] parents;
    uint32 lastBred;
}

struct RentalData {
    bool isRentable;
    bool whitelistOnly;
    uint96 studFee;
    uint32 deadline;
    uint16[6] suitors;
}

struct PrimeData {
    uint16[2] sexyPrimes;
    uint16[2] twins;
    uint16[2] cousins;
}

struct NumberData {
    CoreData core;
    PrimeData prime;
}

struct Activity {
    uint8 tranche0;
    uint8 tranche1;
}

enum Attribute {
    TAXICAB_NUMBER,
    PERFECT_NUMBER,
    EULERS_LUCKY_NUMBER,
    UNIQUE_PRIME,
    FRIENDLY_NUMBER,
    COLOSSALLY_ABUNDANT_NUMBER,
    FIBONACCI_NUMBER,
    REPDIGIT_NUMBER,
    WEIRD_NUMBER,
    TRIANGULAR_NUMBER,
    SOPHIE_GERMAIN_PRIME,
    STRONG_PRIME,
    FRUGAL_NUMBER,
    SQUARE_NUMBER,
    EMIRP,
    MAGIC_NUMBER,
    LUCKY_NUMBER,
    GOOD_PRIME,
    HAPPY_NUMBER,
    UNTOUCHABLE_NUMBER,
    SEMIPERFECT_NUMBER,
    HARSHAD_NUMBER,
    EVIL_NUMBER
}

contract TokenAttributes {
    bytes32 public attributesRootHash;
    mapping(uint256 => uint256) internal packedTokenAttrs;

    event RevealedAttributes(uint256 tokenId, uint256 attributes);

    constructor(bytes32 _attributesRootHash) {
        attributesRootHash = _attributesRootHash;
    }

    /***************************************
                    ATTRIBUTES
    ****************************************/

    function revealAttributes(
        uint256 _tokenId,
        uint256 _attributes,
        bytes32[] memory _merkleProof
    ) public {
        bytes32 leaf = keccak256(abi.encodePacked(_tokenId, _attributes));
        require(MerkleProof.verify(_merkleProof, attributesRootHash, leaf), "Invalid merkle proof");
        packedTokenAttrs[_tokenId] = _attributes;
        emit RevealedAttributes(_tokenId, _attributes);
    }

    function getAttributes(uint256 _tokenId) public view returns (bool[23] memory attributes) {
        uint256 packed = packedTokenAttrs[_tokenId];
        for (uint8 i = 0; i < 23; i++) {
            attributes[i] = _getAttr(packed, i);
        }
        return attributes;
    }

    function _getAttr(uint256 _packed, uint256 _attribute) internal pure returns (bool attribute) {
        uint256 flag = (_packed >> _attribute) & uint256(1);
        attribute = f...

// [truncated — 103247 bytes total]

Read Contract

BREEDING_COOLDOWN 0x87bfa1d7 → uint256
ERC712_VERSION 0x0f7e5970 → string
attributesRootHash 0xec3ea815 → bytes32
auctionHouse 0xed9152c8 → address
balanceOf 0x70a08231 → uint256
batchCheck 0x5d818d9e → bool, uint256, uint256, uint256
batchStartTime 0x8197a838 → uint256
cousins 0xe1452a6f → uint16[2]
data 0xf0ba8440 → bool, uint16, uint8, uint32
fetchPrime 0xa9922b62 → uint16
getApproved 0x081812fc → address
getAttributes 0x4378a6e3 → bool[23]
getChainId 0x3408e470 → uint256
getDomainSeperator 0x20379ee5 → bytes32
getNonce 0x2d0335ab → uint256
getNumberData 0x8592ffd5 → tuple
getParents 0x242a0087 → uint16[2]
getPrimeFactors 0x630de1fb → uint16[]
getSuitors 0xdc843554 → uint16[6]
isApprovedForAll 0xe985e9c5 → bool
name 0x06fdde03 → string
nonce 0xaffed0e0 → uint256
owner 0x8da5cb5b → address
ownerOf 0x6352211e → address
proxyRegistryAddress 0xcd7c0326 → address
rental 0x65c13850 → bool, bool, uint96, uint32
setupAddr 0xff6a29a3 → address
sexyPrimes 0x824e39fb → uint16[2]
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
tokenURI 0xc87b56dd → string
twins 0x6c728d9e → uint16[2]
users 0xa87430ba → uint8, uint8
whitelistRootHash 0xd1a12d6a → bytes32

Write Contract 23 functions

These functions modify contract state and require a wallet transaction to execute.

approve 0x095ea7b3
address to
uint256 tokenId
breedPrimes 0xfae6595a
uint16 _parent1
uint16 _parent2
uint256 _attributes
bytes32[] _merkleProof
crossBreed 0x07cfce41
uint16 _parent1
uint16 _parent2
uint256 _attributes
bytes32[] _merkleProof
executeMetaTransaction 0x0c53c51c
address userAddress
bytes functionSignature
bytes32 sigR
bytes32 sigS
uint8 sigV
returns: bytes
getNextPrime 0x03403abb
No parameters
returns: uint256
initBatch0 0x07ab1beb
uint256[] _data
uint256 _length
initBatch1 0xe86b8d71
uint256[] _data
uint256 _length
initBatch2 0x2342592f
uint256[] _data
uint256 _length
initPrimes 0xa046d510
uint256[] _data
uint256 _length
list 0x7636d3e4
uint16 _tokenId
uint96 _fee
uint32 _deadline
uint16[] _suitors
mintRandomPrime 0x73593edd
uint256 _batch0Cap
uint256 _batch1Cap
bytes32[] _merkleProof
mintRandomPrimes 0x1fa2c0a3
uint256 _count
uint256 _batch0Cap
uint256 _batch1Cap
bytes32[] _merkleProof
renounceOwnership 0x715018a6
No parameters
rescueSale 0x5225a135
No parameters
revealAttributes 0xb40e0e93
uint256 _tokenId
uint256 _attributes
bytes32[] _merkleProof
safeTransferFrom 0x42842e0e
address from
address to
uint256 tokenId
safeTransferFrom 0xb88d4fde
address from
address to
uint256 tokenId
bytes _data
setApprovalForAll 0xa22cb465
address operator
bool approved
start 0xdd0b281e
address _auctionHouse
transferFrom 0x23b872dd
address from
address to
uint256 tokenId
transferOwnership 0xf2fde38b
address newOwner
unlist 0xa35d521a
uint16 _tokenId
withdraw 0x3ccfd60b
No parameters

Recent Transactions

No transactions found for this address