Address Contract Verified
Address
0xBA627f3d081cc97ac0eDc40591eda7053AC63532
Balance
0 ETH
Nonce
1
Code Size
14834 bytes
Creator
0xf6045E92...7cb5 at tx 0xba71169b...a64673
Indexed Transactions
0
Contract Bytecode
14834 bytes
0x6080604052600436106103c35760003560e01c80638a88b8b3116101f2578063b77dc4871161010d578063d79a8ab1116100a0578063ecde3c891161006f578063ecde3c8914610c77578063f1085dfb14610c97578063f8cce6c014610cad578063ff02c51714610cc057600080fd5b8063d79a8ab114610be6578063db5eb70214610c06578063e985e9c514610c26578063ec3ccec214610c6157600080fd5b8063cff0ab96116100dc578063cff0ab9614610af3578063d076503014610b81578063d299c49b14610bb1578063d547cfb714610bd157600080fd5b8063b77dc48714610a87578063b88d4fde14610a9d578063bb0fdd8d14610abd578063c87b56dd14610ad357600080fd5b8063a1876cc411610185578063a90af91211610154578063a90af91214610a1d578063aa1b103f14610a32578063b0f7676714610a47578063b113c60814610a6757600080fd5b8063a1876cc4146109aa578063a22cb465146109bd578063a537f74d146109dd578063a5da2e60146109f257600080fd5b806396062e1f116101c157806396062e1f1461090f57806396473b061461092f5780639d5e2a24146109635780639e55dcb61461097657600080fd5b80638a88b8b3146108925780638da5cb5b146108c25780638fab5047146108e057806395d89b41146108fa57600080fd5b8063484b973c116102e257806363c97d63116102755780636f8b4a72116102445780636f8b4a72146107d157806370a08231146108325780637fb3165a146108525780638a616bc01461087257600080fd5b806363c97d631461075b578063659cdef61461077b578063693d0df21461079b5780636f26d648146107bb57600080fd5b80635ad388d4116102b15780635ad388d41461069b5780635c49d2cb146106ba5780635ecc1566146106da5780636352211e1461073b57600080fd5b8063484b973c146106255780634ab165541461064557806351312f2f146106655780635944c7531461067b57600080fd5b80632525b3d71161035a5780633423e548116103295780633423e548146105b257806335137cd0146105d257806338935c1c146105f257806342842e0e1461060557600080fd5b80632525b3d7146105135780632a55205a146105335780632ab545b51461057257806330176e131461059257600080fd5b8063095ea7b311610396578063095ea7b31461048f57806318160ddd146104af5780631b8cae7b146104d357806323b872dd146104f357600080fd5b806301ffc9a7146103c857806304634d8d146103fd57806306fdde031461041f578063081812fc14610441575b600080fd5b3480156103d457600080fd5b506103e86103e3366004612e89565b610ce8565b60405190151581526020015b60405180910390f35b34801561040957600080fd5b5061041d610418366004612ed2565b610d55565b005b34801561042b57600080fd5b50610434610d8e565b6040516103f49190612f37565b34801561044d57600080fd5b5061047761045c366004612f6a565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103f4565b34801561049b57600080fd5b5061041d6104aa366004612f83565b610e1c565b3480156104bb57600080fd5b506104c560155481565b6040519081526020016103f4565b3480156104df57600080fd5b5061041d6104ee366004612faf565b610f03565b3480156104ff57600080fd5b5061041d61050e366004612fc7565b61111c565b34801561051f57600080fd5b5061041d61052e366004613008565b6112e3565b34801561053f57600080fd5b5061055361054e366004613025565b611330565b604080516001600160a01b0390931683526020830191909152016103f4565b34801561057e57600080fd5b5061041d61058d366004612f6a565b6113de565b34801561059e57600080fd5b5061041d6105ad36600461308d565b61140e565b3480156105be57600080fd5b506103e86105cd3660046131a0565b611445565b3480156105de57600080fd5b5061041d6105ed366004613008565b61145a565b61041d610600366004613233565b6114a7565b34801561061157600080fd5b5061041d610620366004612fc7565b611691565b34801561063157600080fd5b5061041d610640366004612f83565b611789565b34801561065157600080fd5b5061041d610660366004613274565b611835565b34801561067157600080fd5b506104c5600d5481565b34801561068757600080fd5b5061041d6106963660046132df565b611988565b3480156106a757600080fd5b50600f546103e890610100900460ff1681565b3480156106c657600080fd5b50600954610477906001600160a01b031681565b3480156106e657600080fd5b5061071b6106f5366004613008565b6017602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016103f4565b34801561074757600080fd5b50610477610756366004612f6a565b6119be565b34801561076757600080fd5b5061041d61077636600461332d565b611a15565b34801561078757600080fd5b5061041d61079636600461332d565b611a5a565b3480156107a757600080fd5b5061041d6107b6366004613008565b611a98565b3480156107c757600080fd5b506104c5600e5481565b3480156107dd57600080fd5b506108136107ec366004613008565b6011602052600090815260409020546001600160801b03811690600160801b900460ff1682565b604080516001600160801b0390931683529015156020830152016103f4565b34801561083e57600080fd5b506104c561084d366004613008565b611be7565b34801561085e57600080fd5b5061041d61086d366004612f6a565b611c4a565b34801561087e57600080fd5b5061041d61088d366004612f6a565b611c7a565b34801561089e57600080fd5b506103e86108ad366004612f6a565b60136020526000908152604090205460ff1681565b3480156108ce57600080fd5b50600b546001600160a01b0316610477565b3480156108ec57600080fd5b50600f546103e89060ff1681565b34801561090657600080fd5b50610434611cb9565b34801561091b57600080fd5b5061041d61092a366004612f6a565b611cc6565b34801561093b57600080fd5b506104c57f000000000000000000000000000000000000000000000000000000000000245d81565b61041d610971366004613348565b611cf6565b34801561098257600080fd5b506104c57f0000000000000000000000000000000000000000000000000000000000001b1f81565b61041d6109b83660046133c2565b611f0c565b3480156109c957600080fd5b5061041d6109d836600461343c565b612149565b3480156109e957600080fd5b506104c56121b5565b3480156109fe57600080fd5b50600c5461071b906001600160801b0380821691600160801b90041682565b348015610a2957600080fd5b506104c5600281565b348015610a3e57600080fd5b5061041d61228b565b348015610a5357600080fd5b5061041d610a62366004612f6a565b6122c2565b348015610a7357600080fd5b50600a54610477906001600160a01b031681565b348015610a9357600080fd5b506104c561a8c081565b348015610aa957600080fd5b5061041d610ab8366004613468565b6122f2565b348015610ac957600080fd5b506104c560085481565b348015610adf57600080fd5b50610434610aee366004612f6a565b6123d3565b348015610aff57600080fd5b50601854610b40906001600160401b0380821691600160401b8104821691600160801b8204169063ffffffff600160c01b8204811691600160e01b90041685565b604080516001600160401b0396871681529486166020860152929094169183019190915263ffffffff9081166060830152909116608082015260a0016103f4565b348015610b8d57600080fd5b506103e8610b9c366004612f6a565b60146020526000908152604090205460ff1681565b348015610bbd57600080fd5b5061041d610bcc366004613233565b612407565b348015610bdd57600080fd5b50610434612591565b348015610bf257600080fd5b5061041d610c01366004613233565b61259e565b348015610c1257600080fd5b50600b54610477906001600160a01b031681565b348015610c3257600080fd5b506103e8610c41366004613506565b600560209081526000928352604080842090915290825290205460ff1681565b348015610c6d57600080fd5b506104c560105481565b348015610c8357600080fd5b5061041d610c92366004613008565b612689565b348015610ca357600080fd5b506104c560125481565b61041d610cbb366004612f6a565b6126d6565b348015610ccc57600080fd5b5061047773880644ddf208e471c6f2230d31f9027578fa6fcc81565b600063152a902d60e11b6001600160e01b031983161480610d1957506301ffc9a760e01b6001600160e01b03198316145b80610d3457506380ac58cd60e01b6001600160e01b03198316145b80610d4f5750635b5e139f60e01b6001600160e01b03198316145b92915050565b600b546001600160a01b03163314610d8057604051631f7c4bf360e01b815260040160405180910390fd5b610d8a8282612a12565b5050565b60008054610d9b9061353f565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc79061353f565b8015610e145780601f10610de957610100808354040283529160200191610e14565b820191906000526020600020905b815481529060010190602001808311610df757829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610e6557506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610ea75760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6009546001600160a01b03163314610f2e57604051631f7c4bf360e01b815260040160405180910390fd5b610f3e6040820160208301613573565b6001600160401b0316610f546020830183613573565b6001600160401b031610158015610f8357506000610f786040830160208401613573565b6001600160401b0316115b8015610fa457506000610f9c608083016060840161359c565b63ffffffff16115b8015610fc557506000610fbd60a083016080840161359c565b63ffffffff16115b610fe2576040516340636ec960e01b815260040160405180910390fd5b6040805160a0810190915280610ffb6020840184613573565b6001600160401b0316815260200182602001602081019061101c9190613573565b6001600160401b0316815260200161103a6060840160408501613573565b6001600160401b03168152602001611058608084016060850161359c565b63ffffffff16815260200161107360a084016080850161359c565b63ffffffff9081169091528151601880546020850151604086015160608701516080909701518616600160e01b026001600160e01b0397909616600160c01b0263ffffffff60c01b196001600160401b03928316600160801b02166bffffffffffffffffffffffff60801b19938316600160401b026fffffffffffffffffffffffffffffffff199095169290961691909117929092171692909217919091179290921617905550565b6000818152600260205260409020546001600160a01b038481169116146111725760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610e9e565b6001600160a01b0382166111bc5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9e565b336001600160a01b03841614806111f657506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b8061121757506000818152600460205260409020546001600160a01b031633145b6112545760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610e9e565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600b546001600160a01b0316331461130e57604051631f7c4bf360e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60008281526007602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b03169282019290925282916113a55750604080518082019091526006546001600160a01b0381168252600160a01b90046001600160601b031660208201525b6020810151600090612710906113c4906001600160601b0316876135d8565b6113ce919061360d565b91519350909150505b9250929050565b6009546001600160a01b0316331461140957604051631f7c4bf360e01b815260040160405180910390fd5b600e55565b600a546001600160a01b0316331461143957604051631f7c4bf360e01b815260040160405180910390fd5b6016610d8a828261366f565b6000611452828585612acc565b949350505050565b6009546001600160a01b0316331461148557604051631f7c4bf360e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b600f54610100900460ff166114cf5760405163951b974f60e01b815260040160405180910390fd5b6008546114dc90826135d8565b34146115035760405163b0b0ec3560e01b8152336004820152306024820152604401610e9e565b60005b8181101561167257601460008484848181106115245761152461372e565b602090810292909201358352508101919091526040016000205460ff161561155f576040516303a9a53560e61b815260040160405180910390fd5b6001601460008585858181106115775761157761372e565b90506020020135815260200190815260200160002060006101000a81548160ff021916908315150217905550600073880644ddf208e471c6f2230d31f9027578fa6fcc6001600160a01b0316636352211e8585858181106115da576115da61372e565b905060200201356040518263ffffffff1660e01b81526004016115ff91815260200190565b602060405180830381865afa15801561161c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116409190613744565b600e8054919250611661918391600061165883613761565b91905055612ae2565b5061166b81613761565b9050611506565b508181905060156000828254611688919061377a565b90915550505050565b61169c83838361111c565b6001600160a01b0382163b15806117455750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611715573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117399190613792565b6001600160e01b031916145b6117845760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610e9e565b505050565b6009546001600160a01b031633146117b457604051631f7c4bf360e01b815260040160405180910390fd5b807f0000000000000000000000000000000000000000000000000000000000001b1f1115801561180457507f000000000000000000000000000000000000000000000000000000000000245d8111155b156118225760405163a80cc22160e01b815260040160405180910390fd5b601580546001019055610d8a8282612ae2565b6009546001600160a01b0316331461186057604051631f7c4bf360e01b815260040160405180910390fd5b8281146118805760405163a121188760e01b815260040160405180910390fd5b601580548201905560005b81811015611981578282828181106118a5576118a561372e565b905060200201357f0000000000000000000000000000000000000000000000000000000000001b1f1115801561191357507f000000000000000000000000000000000000000000000000000000000000245d8383838181106119095761190961372e565b9050602002013511155b156119315760405163a80cc22160e01b815260040160405180910390fd5b6119798585838181106119465761194661372e565b905060200201602081019061195b9190613008565b84848481811061196d5761196d61372e565b90506020020135612ae2565b60010161188b565b5050505050565b600b546001600160a01b031633146119b357604051631f7c4bf360e01b815260040160405180910390fd5b611784838383612bed565b6000818152600260205260409020546001600160a01b031680611a105760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610e9e565b919050565b6009546001600160a01b03163314611a4057604051631f7c4bf360e01b815260040160405180910390fd5b600f80549115156101000261ff0019909216919091179055565b6009546001600160a01b03163314611a8557604051631f7c4bf360e01b815260040160405180910390fd5b600f805460ff1916911515919091179055565b6009546001600160a01b0316331480611abb5750600a546001600160a01b031633145b80611ad05750600b546001600160a01b031633145b611aed57604051631f7c4bf360e01b815260040160405180910390fd5b600c546001600160801b031615801590611b265750600c54611b229061a8c090600160801b90046001600160801b031661377a565b4210155b611b6257600c54604051634433b4ab60e11b81526001600160801b038083166004830152600160801b9092049091166024820152604401610e9e565b6000816001600160a01b03164760405160006040518083038185875af1925050503d8060008114611baf576040519150601f19603f3d011682016040523d82523d6000602084013e611bb4565b606091505b5050905080610d8a5760405163b0b0ec3560e01b81523060048201526001600160a01b0383166024820152604401610e9e565b60006001600160a01b038216611c2e5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610e9e565b506001600160a01b031660009081526003602052604090205490565b6009546001600160a01b03163314611c7557604051631f7c4bf360e01b815260040160405180910390fd5b601255565b600b546001600160a01b03163314611ca557604051631f7c4bf360e01b815260040160405180910390fd5b600090815260076020526040812055565b50565b60018054610d9b9061353f565b6009546001600160a01b03163314611cf157604051631f7c4bf360e01b815260040160405180910390fd5b600855565b6008543414611d205760405163b0b0ec3560e01b8152336004820152306024820152604401610e9e565b6040516bffffffffffffffffffffffff19606087901b1660208201526034810185905260009060540160408051601f1981840301815291815281516020928301206000818152601390935291205490915060ff1615611d92576040516303a9a53560e61b815260040160405180910390fd5b838114611df75760405162461bcd60e51b815260206004820152602d60248201527f546f6b656e20636f6e747261637420616e6420696420646f6e2774206d61746360448201526c341026b2b935b632903632b0b360991b6064820152608401610e9e565b611e376012548585858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061144592505050565b611e535760405162461bcd60e51b8152600401610e9e906137af565b6040516331a9108f60e11b8152600481018690526000906001600160a01b03881690636352211e90602401602060405180830381865afa158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebf9190613744565b6000838152601360205260408120805460ff191660011790556015805492935091611ee990613761565b90915550600e8054611f0391839190600061165883613761565b50505050505050565b600854611f1c9060ff86166135d8565b3414611f435760405163b0b0ec3560e01b8152336004820152306024820152604401610e9e565b6001600160a01b0385166000908152601160209081526040918290208251808401909352546001600160801b0381168352600160801b900460ff161515908201819052612086576040516bffffffffffffffffffffffff19606088901b1660208201526001600160f81b031960f886901b166034820152839060350160405160208183030381529060405280519060200120146120345760405162461bcd60e51b815260206004820152602960248201527f53656e64657220616e6420616d6f756e7420646f6e2774206d61746368204d656044820152683935b632903632b0b360b91b6064820152608401610e9e565b6120416010548484611445565b61205d5760405162461bcd60e51b8152600401610e9e906137af565b6001602082015260ff858116908516146120815761207b85856137f2565b60ff1681525b6120a8565b8460ff168160000181815161209b9190613815565b6001600160801b03169052505b6001600160a01b0386166000908152601160209081526040822083518154928501511515600160801b0270ffffffffffffffffffffffffffffffffff199093166001600160801b03909116179190911790556015805460ff8816929061210f90849061377a565b90915550600090505b8560ff16811015611f0357600e805461213991899190600061165883613761565b61214281613761565b9050612118565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6040805160a0810182526018546001600160401b038082168352600160401b820481166020840152600160801b8204169282019290925263ffffffff600160c01b8304811660608301819052600160e01b9093041660808201819052600092839190612221904261383d565b61222b919061360d565b9050600082604001516001600160401b03168261224891906135d8565b835161225d91906001600160401b031661383d565b905082602001516001600160401b0316811015612284575060208201516001600160401b03165b9392505050565b600b546001600160a01b031633146122b657604051631f7c4bf360e01b815260040160405180910390fd5b6122c06000600655565b565b6009546001600160a01b031633146122ed57604051631f7c4bf360e01b815260040160405180910390fd5b601055565b6122fd85858561111c565b6001600160a01b0384163b15806123945750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906123459033908a90899089908990600401613854565b6020604051808303816000875af1158015612364573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123889190613792565b6001600160e01b031916145b6119815760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610e9e565b606060166123e083612cb8565b6040516020016123f19291906138a8565b6040516020818303038152906040529050919050565b600c546001600160801b0316600003612433576040516318e998a560e01b815260040160405180910390fd5b60005b818110156117845760008383838181106124525761245261372e565b90506020020160208101906124679190613008565b6001600160a01b0381166000908152601760209081526040918290208251808401909352546001600160801b038082168452600160801b90910416908201819052919250901561257e57600c5460208201516000916124d1916001600160801b0390911690613815565b82516124dd919061392f565b6001600160a01b038416600081815260176020526040808220829055516001600160801b039390931693509183908381818185875af1925050503d8060008114612543576040519150601f19603f3d011682016040523d82523d6000602084013e612548565b606091505b505090508061257b5760405163b0b0ec3560e01b81523060048201526001600160a01b0385166024820152604401610e9e565b50505b50508061258a90613761565b9050612436565b60168054610d9b9061353f565b600f5460ff166125c15760405163951b974f60e01b815260040160405180910390fd5b60005b8181101561167257600073880644ddf208e471c6f2230d31f9027578fa6fcc636352211e8585858181106125fa576125fa61372e565b905060200201356040518263ffffffff1660e01b815260040161261f91815260200190565b602060405180830381865afa15801561263c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126609190613744565b90506126788185858581811061196d5761196d61372e565b5061268281613761565b90506125c4565b600a546001600160a01b031633146126b457604051631f7c4bf360e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6126df33612db8565b806000036127005760405163220328c760e11b815260040160405180910390fd5b336000908152601760209081526040918290208251808401909352546001600160801b03808216808552600160801b909204169183019190915260029061274890849061377a565b111561276757604051630c599a5960e31b815260040160405180910390fd5b600d546127957f000000000000000000000000000000000000000000000000000000000000245d600161377a565b61279f848361377a565b11156127be5760405163bdec14e360e01b815260040160405180910390fd5b6040805160a0810182526018546001600160401b038082168352600160401b820481166020840152600160801b8204169282019290925263ffffffff600160c01b8304811660608301819052600160e01b9093041660808201529042108061282e575080516001600160401b0316155b1561284c5760405163951b974f60e01b815260040160405180910390fd5b6000816080015163ffffffff16826060015163ffffffff164261286f919061383d565b612879919061360d565b9050600082604001516001600160401b03168261289691906135d8565b83516128ab91906001600160401b031661383d565b905082602001516001600160401b03168110156128d2575060208201516001600160401b03165b6128dc81876135d8565b34146129035760405163b0b0ec3560e01b8152336004820152306024820152604401610e9e565b845160208601516000916001600160801b038082168a01811692909102848a02011681612932576129326135f7565b60408051808201825289516001600160801b03908c01811682529390920483811660208085019182523360009081526017909152928320935190518516600160801b029416939093179091559091505b878110156129a25761299a3387806001019850612ae2565b600101612982565b5060158054880190557f000000000000000000000000000000000000000000000000000000000000245d851115612a0457604080518082019091526001600160801b03808416808352429091166020909201829052600160801b90910217600c555b505050600d91909155505050565b6127106001600160601b0382161115612a3d5760405162461bcd60e51b8152600401610e9e9061395e565b6001600160a01b038216612a935760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610e9e565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b600082612ad98584612dfa565b14949350505050565b6001600160a01b038216612b2c5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9e565b6000818152600260205260409020546001600160a01b031615612b825760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610e9e565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6127106001600160601b0382161115612c185760405162461bcd60e51b8152600401610e9e9061395e565b6001600160a01b038216612c6e5760405162461bcd60e51b815260206004820152601b60248201527f455243323938313a20496e76616c696420706172616d657465727300000000006044820152606401610e9e565b6040805180820182526001600160a01b0393841681526001600160601b0392831660208083019182526000968752600790529190942093519051909116600160a01b029116179055565b606081600003612cdf5750506040805180820190915260018152600360fc1b602082015290565b8160005b8115612d095780612cf381613761565b9150612d029050600a8361360d565b9150612ce3565b6000816001600160401b03811115612d2357612d23613047565b6040519080825280601f01601f191660200182016040528015612d4d576020820181803683370190505b5090505b841561145257612d6260018361383d565b9150612d6f600a866139a8565b612d7a90603061377a565b60f81b818381518110612d8f57612d8f61372e565b60200101906001600160f81b031916908160001a905350612db1600a8661360d565b9450612d51565b3332141580612dd157506000816001600160a01b03163b115b15611cb6576040516393575bef60e01b81526001600160a01b0382166004820152602401610e9e565b600081815b8451811015612e3f57612e2b82868381518110612e1e57612e1e61372e565b6020026020010151612e47565b915080612e3781613761565b915050612dff565b509392505050565b6000818310612e63576000828152602084905260409020612284565b5060009182526020526040902090565b6001600160e01b031981168114611cb657600080fd5b600060208284031215612e9b57600080fd5b813561228481612e73565b6001600160a01b0381168114611cb657600080fd5b80356001600160601b0381168114611a1057600080fd5b60008060408385031215612ee557600080fd5b8235612ef081612ea6565b9150612efe60208401612ebb565b90509250929050565b60005b83811015612f22578181015183820152602001612f0a565b83811115612f31576000848401525b50505050565b6020815260008251806020840152612f56816040850160208701612f07565b601f01601f19169190910160400192915050565b600060208284031215612f7c57600080fd5b5035919050565b60008060408385031215612f9657600080fd5b8235612fa181612ea6565b946020939093013593505050565b600060a08284031215612fc157600080fd5b50919050565b600080600060608486031215612fdc57600080fd5b8335612fe781612ea6565b92506020840135612ff781612ea6565b929592945050506040919091013590565b60006020828403121561301a57600080fd5b813561228481612ea6565b6000806040838503121561303857600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561308557613085613047565b604052919050565b600060208083850312156130a057600080fd5b82356001600160401b03808211156130b757600080fd5b818501915085601f8301126130cb57600080fd5b8135818111156130dd576130dd613047565b6130ef601f8201601f1916850161305d565b9150808252868482850101111561310557600080fd5b8084840185840137600090820190930192909252509392505050565b600082601f83011261313257600080fd5b813560206001600160401b0382111561314d5761314d613047565b8160051b61315c82820161305d565b928352848101820192828101908785111561317657600080fd5b83870192505b848310156131955782358252918301919083019061317c565b979650505050505050565b6000806000606084860312156131b557600080fd5b833592506020840135915060408401356001600160401b038111156131d957600080fd5b6131e586828701613121565b9150509250925092565b60008083601f84011261320157600080fd5b5081356001600160401b0381111561321857600080fd5b6020830191508360208260051b85010111156113d757600080fd5b6000806020838503121561324657600080fd5b82356001600160401b0381111561325c57600080fd5b613268858286016131ef565b90969095509350505050565b6000806000806040858703121561328a57600080fd5b84356001600160401b03808211156132a157600080fd5b6132ad888389016131ef565b909650945060208701359150808211156132c657600080fd5b506132d3878288016131ef565b95989497509550505050565b6000806000606084860312156132f457600080fd5b83359250602084013561330681612ea6565b915061331460408501612ebb565b90509250925092565b80358015158114611a1057600080fd5b60006020828403121561333f57600080fd5b6122848261331d565b60008060008060006080868803121561336057600080fd5b853561336b81612ea6565b9450602086013593506040860135925060608601356001600160401b0381111561339457600080fd5b6133a0888289016131ef565b969995985093965092949392505050565b803560ff81168114611a1057600080fd5b600080600080600060a086880312156133da57600080fd5b85356133e581612ea6565b94506133f3602087016133b1565b9350613401604087016133b1565b92506060860135915060808601356001600160401b0381111561342357600080fd5b61342f88828901613121565b9150509295509295909350565b6000806040838503121561344f57600080fd5b823561345a81612ea6565b9150612efe6020840161331d565b60008060008060006080868803121561348057600080fd5b853561348b81612ea6565b9450602086013561349b81612ea6565b93506040860135925060608601356001600160401b03808211156134be57600080fd5b818801915088601f8301126134d257600080fd5b8135818111156134e157600080fd5b8960208285010111156134f357600080fd5b9699959850939650602001949392505050565b6000806040838503121561351957600080fd5b823561352481612ea6565b9150602083013561353481612ea6565b809150509250929050565b600181811c9082168061355357607f821691505b602082108103612fc157634e487b7160e01b600052602260045260246000fd5b60006020828403121561358557600080fd5b81356001600160401b038116811461228457600080fd5b6000602082840312156135ae57600080fd5b813563ffffffff8116811461228457600080fd5b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156135f2576135f26135c2565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261361c5761361c6135f7565b500490565b601f82111561178457600081815260208120601f850160051c810160208610156136485750805b601f850160051c820191505b8181101561366757828155600101613654565b505050505050565b81516001600160401b0381111561368857613688613047565b61369c81613696845461353f565b84613621565b602080601f8311600181146136d157600084156136b95750858301515b600019600386901b1c1916600185901b178555613667565b600085815260208120601f198616915b82811015613700578886015182559484019460019091019084016136e1565b508582101561371e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561375657600080fd5b815161228481612ea6565b600060018201613773576137736135c2565b5060010190565b6000821982111561378d5761378d6135c2565b500190565b6000602082840312156137a457600080fd5b815161228481612e73565b60208082526023908201527f4e6f7420612076616c6964206c65616620696e20746865204d65726b6c65207460408201526272656560e81b606082015260800190565b600060ff821660ff84168082101561380c5761380c6135c2565b90039392505050565b60006001600160801b0383811690831681811015613835576138356135c2565b039392505050565b60008282101561384f5761384f6135c2565b500390565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008084546138b68161353f565b600182811680156138ce57600181146138e357613912565b60ff1984168752821515830287019450613912565b8860005260208060002060005b858110156139095781548a8201529084019082016138f0565b50505082870194505b505050508351613926818360208801612f07565b01949350505050565b60006001600160801b0380831681851681830481118215151615613955576139556135c2565b02949350505050565b6020808252602a908201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646040820152692073616c65507269636560b01b606082015260800190565b6000826139b7576139b76135f7565b50069056fea2646970667358221220bfd511e5f783d0ed97ae0564829d1a6a67dc8f6e1974f38b7dea43c25636067a64736f6c634300080f0033
Verified Source Code Full Match
Compiler: v0.8.15+commit.e14f2714
EVM: london
Optimization: Yes (200 runs)
BoredAndDangerous.sol 586 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import {ERC721} from "solmate/tokens/ERC721.sol";
import {ERC2981} from "openzeppelin-contracts/contracts/token/common/ERC2981.sol";
import {MerkleProof} from "openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol";
import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol";
interface IERC721 {
function ownerOf(uint tokenId) external view returns (address);
}
contract BoredAndDangerous is ERC721, ERC2981 {
/// @notice The original writer's room contract
address public constant WRITERS_ROOM = 0x880644ddF208E471C6f2230d31f9027578FA6FcC;
/// @notice The grace period for refund claiming
uint public constant DUTCH_AUCTION_GRACE_PERIOD = 12 hours;
/// @notice The mint cap in the dutch auction
uint public constant DUTCH_AUCTION_MINT_CAP = 2;
/// @notice The first token id that dutch auction minters will receive, inclusive
uint public immutable DUTCH_AUCTION_START_ID;
/// @notice The last token id that dutch auction minters will receive, inclusive
uint public immutable DUTCH_AUCTION_END_ID;
/// @notice The price for writelist mints
uint public writelistPrice;
/// @notice The address which can admin mint for free, set merkle roots, and set auction params
address public mintingOwner;
/// @notice The address which can update the metadata uri
address public metadataOwner;
/// @notice The address which will be returned for the ERC721 owner() standard for setting royalties
address public royaltyOwner;
/// @notice Records the price and time when the final dutch auction token sells out
struct DutchAuctionFinalization {
uint128 price;
uint128 time;
}
/// @notice The instantiation of the dutch auction finalization struct
DutchAuctionFinalization public dutchEnd;
/// @notice The token id which will be minted next in the dutch auction
uint public dutchAuctionNextId;
/// @notice The token id which will be minted next in the writelist mint
uint public writelistMintNextId;
/// @notice Records whether a whitelist allocation has been started, and how many are remaining to claim
struct Writelist {
uint128 remaining;
bool used;
}
/// @notice Whether free mints for writers' room holders are open
bool public writelistMintWritersRoomFreeOpen;
/// @notice Whether paid mints for writers' room holders are open
bool public writelistMintWritersRoomOpen;
/// @notice Construct this from (address, amount) tuple elements
bytes32 public giveawayMerkleRoot;
/// @notice Caches writelist allocations once they've been used
mapping(address => Writelist) public giveawayWritelist;
/// @notice Construct this from (address, tokenId) tuple elements
bytes32 public apeMerkleRoot;
/// @notice Maps (address, tokenId) hash to bool, true if token has minted
mapping(bytes32 => bool) public apeWritelistUsed;
/// @notice Maps tokenId to bool, true if token has minted
mapping(uint => bool) public writersroomWritelistUsed;
/// @notice Total number of tokens which have minted
uint public totalSupply = 0;
/// @notice The prefix to attach to the tokenId to get the metadata uri
string public baseTokenURI;
/// @notice Struct is packed to fit within a single 256-bit slot
struct DutchAuctionMintHistory {
uint128 amount;
uint128 price;
}
/// @notice Store the mint history for an individual address. Used to issue refunds
mapping(address => DutchAuctionMintHistory) public mintHistory;
/// @notice Struct is packed to fit within a single 256-bit slot
/// @dev uint64 has max value 1.8e19, or 18 ether
/// @dev uint32 has max value 4.2e9, which corresponds to max timestamp of year 2106
struct DutchAuctionParams {
uint64 startPrice;
uint64 endPrice;
uint64 priceIncrement;
uint32 startTime;
uint32 timeIncrement;
}
/// @notice The instantiation of dutch auction parameters
DutchAuctionParams public params;
/// @notice Emitted when a token is minted
event Mint(address indexed owner, uint indexed tokenId);
/// @notice Emitted when an accounts receives its dutch auction refund
event DutchAuctionRefund(address indexed account);
/// @notice Raised when an unauthorized user calls a gated function
error AccessControl();
/// @notice Raised when a non-EOA account calls a gated function
error OnlyEOA(address msgSender);
/// @notice Raised when a user exceeds their mint cap
error ExceededUserMintCap();
/// @notice Raised when the mint has not reached the required timestamp
error MintNotOpen();
/// @notice Raised when the user attempts to writelist mint on behalf of a token they do not own
error DoesNotOwnToken(uint tokenId);
/// @notice Raised when the user attempts to mint after the dutch auction finishes
error DutchAuctionOver();
/// @notice Raised when the admin attempts to withdraw funds before the dutch auction grace period has ended
error DutchAuctionGracePeriod(uint endPrice, uint endTime);
/// @notice Raised when a user attempts to claim their dutch auction refund before the dutch auction ends
error DutchAuctionNotOver();
/// @notice Raised when the admin attempts to mint within the dutch auction range while the auction is still ongoing
error DutchAuctionNotOverAdmin();
/// @notice Raised when the admin attempts to set dutch auction parameters that don't make sense
error DutchAuctionBadParamsAdmin();
/// @notice Raised when `sender` does not pass the proper ether amount to `recipient`
error FailedToSendEther(address sender, address recipient);
/// @notice Raised when a user tries to writelist mint twice
error WritelistUsed();
/// @notice Raised when two calldata arrays do not have the same length
error MismatchedArrays();
/// @notice Raised when the user attempts to mint zero items
error MintZero();
constructor(uint _DUTCH_AUCTION_START_ID, uint _DUTCH_AUCTION_END_ID) ERC721("Bored & Dangerous", "BOOK") {
DUTCH_AUCTION_START_ID = _DUTCH_AUCTION_START_ID;
DUTCH_AUCTION_END_ID = _DUTCH_AUCTION_END_ID;
dutchAuctionNextId = _DUTCH_AUCTION_START_ID;
writelistMintNextId = _DUTCH_AUCTION_END_ID + 1;
mintingOwner = msg.sender;
metadataOwner = msg.sender;
royaltyOwner = msg.sender;
}
/// @notice Admin mint a token
function ownerMint(address recipient, uint tokenId) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
if (DUTCH_AUCTION_START_ID <= tokenId && tokenId <= DUTCH_AUCTION_END_ID) {
revert DutchAuctionNotOverAdmin();
}
unchecked {
++totalSupply;
}
_mint(recipient, tokenId);
}
/// @notice Admin mint a batch of tokens
function ownerMintBatch(address[] calldata recipients, uint[] calldata tokenIds) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
if (recipients.length != tokenIds.length) {
revert MismatchedArrays();
}
unchecked {
totalSupply += tokenIds.length;
for (uint i = 0; i < tokenIds.length; ++i) {
if (DUTCH_AUCTION_START_ID <= tokenIds[i] && tokenIds[i] <= DUTCH_AUCTION_END_ID) {
revert DutchAuctionNotOverAdmin();
}
_mint(recipients[i], tokenIds[i]);
}
}
}
///////////////////
// DUTCH AUCTION //
///////////////////
/// @notice The current dutch auction price
/// @dev Reverts if dutch auction has not started yet
/// @dev Returns the end price even if the dutch auction has sold out
function dutchAuctionPrice() public view returns (uint) {
DutchAuctionParams memory _params = params;
uint numIncrements = (block.timestamp - _params.startTime) / _params.timeIncrement;
uint price = _params.startPrice - numIncrements * _params.priceIncrement;
if (price < _params.endPrice) {
price = _params.endPrice;
}
return price;
}
/// @notice Dutch auction with refunds
/// @param amount The number of NFTs to mint, either 1 or 2
function dutchAuctionMint(uint amount) external payable {
// Enforce EOA mints
_onlyEOA(msg.sender);
if (amount == 0) {
revert MintZero();
}
DutchAuctionMintHistory memory userMintHistory = mintHistory[msg.sender];
// Enforce per-account mint cap
if (userMintHistory.amount + amount > DUTCH_AUCTION_MINT_CAP) {
revert ExceededUserMintCap();
}
uint256 _dutchAuctionNextId = dutchAuctionNextId;
// Enforce global mint cap
if (_dutchAuctionNextId + amount > DUTCH_AUCTION_END_ID + 1) {
revert DutchAuctionOver();
}
DutchAuctionParams memory _params = params;
// Enforce timing
if (block.timestamp < _params.startTime || _params.startPrice == 0) {
revert MintNotOpen();
}
// Calculate dutch auction price
uint numIncrements = (block.timestamp - _params.startTime) / _params.timeIncrement;
uint price = _params.startPrice - numIncrements * _params.priceIncrement;
if (price < _params.endPrice) {
price = _params.endPrice;
}
// Check mint price
if (msg.value != amount * price) {
revert FailedToSendEther(msg.sender, address(this));
}
unchecked {
uint128 newPrice = (userMintHistory.amount * userMintHistory.price + uint128(amount * price)) / uint128(userMintHistory.amount + amount);
mintHistory[msg.sender] = DutchAuctionMintHistory({
amount: userMintHistory.amount + uint128(amount),
price: newPrice
});
for (uint i = 0; i < amount; ++i) {
_mint(msg.sender, _dutchAuctionNextId++);
}
totalSupply += amount;
if (_dutchAuctionNextId > DUTCH_AUCTION_END_ID) {
dutchEnd = DutchAuctionFinalization({
price: uint128(price),
time: uint128(block.timestamp)
});
}
dutchAuctionNextId = _dutchAuctionNextId;
}
}
/// @notice Provide dutch auction refunds to people who minted early
/// @dev Deliberately left unguarded so users can either claim their own, or batch refund others
function claimDutchAuctionRefund(address[] calldata accounts) external {
// Check if dutch auction over
if (dutchEnd.price == 0) {
revert DutchAuctionNotOver();
}
for (uint i = 0; i < accounts.length; ++i) {
address account = accounts[i];
DutchAuctionMintHistory memory mint = mintHistory[account];
// If an account has already been refunded, skip instead of reverting
// This prevents griefing attacks when performing batch refunds
if (mint.price > 0) {
uint refundAmount = mint.amount * (mint.price - dutchEnd.price);
delete mintHistory[account];
(bool sent,) = account.call{value: refundAmount}("");
// Revert if the address has a malicious receive function
// This is not a griefing vector because the function can be retried
// without the failing recipient
if (!sent) {
revert FailedToSendEther(address(this), account);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// WRITELIST MINTS (free writer's room, paid writer's room, paid bored/mutant ape, paid giveaway) //
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @notice Free mint from writelist ticket allocation
function writelistMintWritersRoomFree(uint[] calldata tokenIds) external {
if (!writelistMintWritersRoomFreeOpen) {
revert MintNotOpen();
}
for (uint i = 0; i < tokenIds.length; ++i) {
address tokenOwner = IERC721(WRITERS_ROOM).ownerOf(tokenIds[i]);
// This will revert is specific tokenId already minted
_mint(tokenOwner, tokenIds[i]);
}
totalSupply += tokenIds.length;
}
/// @notice Paid mint for a writer's room NFT
function writelistMintWritersRoom(uint[] calldata tokenIds) external payable {
if (!writelistMintWritersRoomOpen) {
revert MintNotOpen();
}
// Check payment
if (msg.value != tokenIds.length * writelistPrice) {
revert FailedToSendEther(msg.sender, address(this));
}
for (uint i = 0; i < tokenIds.length; ++i) {
if (writersroomWritelistUsed[tokenIds[i]]) {
revert WritelistUsed();
}
writersroomWritelistUsed[tokenIds[i]] = true;
address tokenOwner = IERC721(WRITERS_ROOM).ownerOf(tokenIds[i]);
_mint(tokenOwner, writelistMintNextId++);
}
totalSupply += tokenIds.length;
}
/// @notice Mint for a licensed bored ape or mutant ape
function writelistMintApes(address tokenContract, uint tokenId, bytes32 leaf, bytes32[] calldata proof) external payable {
// Check payment
if (msg.value != writelistPrice) {
revert FailedToSendEther(msg.sender, address(this));
}
bytes32 tokenHash = keccak256(abi.encodePacked(tokenContract, tokenId));
// Create storage element tracking user mints if this is the first mint for them
if (apeWritelistUsed[tokenHash]) {
revert WritelistUsed();
}
// Verify that (tokenContract, tokenId) correspond to Merkle leaf
require(tokenHash == leaf, "Token contract and id don't match Merkle leaf");
// Verify that (leaf, proof) matches the Merkle root
require(verify(apeMerkleRoot, leaf, proof), "Not a valid leaf in the Merkle tree");
// Get the current tokenOwner and mint to them
address tokenOwner = IERC721(tokenContract).ownerOf(tokenId);
apeWritelistUsed[tokenHash] = true;
++totalSupply;
_mint(tokenOwner, writelistMintNextId++);
}
/// @notice Mint from writelist allocation
function writelistMintGiveaway(address tokenOwner, uint8 amount, uint8 totalAllocation, bytes32 leaf, bytes32[] memory proof) external payable {
// Check payment
if (msg.value != amount * writelistPrice) {
revert FailedToSendEther(msg.sender, address(this));
}
Writelist memory writelist = giveawayWritelist[tokenOwner];
// Create storage element tracking user mints if this is the first mint for them
if (!writelist.used) {
// Verify that (tokenOwner, amount) correspond to Merkle leaf
require(keccak256(abi.encodePacked(tokenOwner, totalAllocation)) == leaf, "Sender and amount don't match Merkle leaf");
// Verify that (leaf, proof) matches the Merkle root
require(verify(giveawayMerkleRoot, leaf, proof), "Not a valid leaf in the Merkle tree");
writelist.used = true;
// Save some gas by never writing to this slot if it will be reset to zero at method end
if (amount != totalAllocation) {
writelist.remaining = totalAllocation - amount;
}
}
else {
writelist.remaining -= amount;
}
giveawayWritelist[tokenOwner] = writelist;
totalSupply += amount;
for (uint i = 0; i < amount; ++i) {
_mint(tokenOwner, writelistMintNextId++);
}
}
/// @notice Ensure the proof and leaf match the merkle root
function verify(bytes32 root, bytes32 leaf, bytes32[] memory proof) public pure returns (bool) {
return MerkleProof.verify(proof, root, leaf);
}
/////////////////////////
// ADMIN FUNCTIONALITY //
/////////////////////////
/// @notice Set metadata
function setBaseTokenURI(string memory _baseTokenURI) external {
if (msg.sender != metadataOwner) {
revert AccessControl();
}
baseTokenURI = _baseTokenURI;
}
/// @notice Set merkle root
function setGiveawayMerkleRoot(bytes32 _giveawayMerkleRoot) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
giveawayMerkleRoot = _giveawayMerkleRoot;
}
/// @notice Set merkle root
function setApeMerkleRoot(bytes32 _apeMerkleRoot) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
apeMerkleRoot = _apeMerkleRoot;
}
/// @notice Set parameters
function setDutchAuctionStruct(DutchAuctionParams calldata _params) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
if (!(_params.startPrice >= _params.endPrice && _params.endPrice > 0 && _params.startTime > 0 && _params.timeIncrement > 0)) {
revert DutchAuctionBadParamsAdmin();
}
params = DutchAuctionParams({
startPrice: _params.startPrice,
endPrice: _params.endPrice,
priceIncrement: _params.priceIncrement,
startTime: _params.startTime,
timeIncrement: _params.timeIncrement
});
}
/// @notice Set writelistMintNextId
/// @dev Should not be used, but failsafe in case the admin accidentally mints a token id in the writelist range too early
function setWritelistMintNextId(uint _writelistMintNextId) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
writelistMintNextId = _writelistMintNextId;
}
/// @notice Set writelistMintWritersRoomFreeOpen
function setWritelistMintWritersRoomFreeOpen(bool _value) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
writelistMintWritersRoomFreeOpen = _value;
}
/// @notice Set writelistMintWritersRoomOpen
function setWritelistMintWritersRoomOpen(bool _value) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
writelistMintWritersRoomOpen = _value;
}
/// @notice Set writelistPrice
function setWritelistPrice(uint _price) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
writelistPrice = _price;
}
/// @notice Claim funds
function claimFunds(address payable recipient) external {
if (!(msg.sender == mintingOwner || msg.sender == metadataOwner || msg.sender == royaltyOwner)) {
revert AccessControl();
}
// Wait for the grace period after scheduled end to allow claiming of dutch auction refunds
if (!(dutchEnd.price > 0 && block.timestamp >= dutchEnd.time + DUTCH_AUCTION_GRACE_PERIOD)) {
revert DutchAuctionGracePeriod(dutchEnd.price, dutchEnd.time);
}
(bool sent,) = recipient.call{value: address(this).balance}("");
if (!sent) {
revert FailedToSendEther(address(this), recipient);
}
}
////////////////////////////////////
// ACCESS CONTROL ADDRESS UPDATES //
////////////////////////////////////
/// @notice Update the mintingOwner
/// @dev Can also be used to revoke this power by setting to 0x0
function setMintingOwner(address _mintingOwner) external {
if (msg.sender != mintingOwner) {
revert AccessControl();
}
mintingOwner = _mintingOwner;
}
/// @notice Update the metadataOwner
/// @dev Can also be used to revoke this power by setting to 0x0
/// @dev Should only be revoked after setting an IPFS url so others can pin
function setMetadataOwner(address _metadataOwner) external {
if (msg.sender != metadataOwner) {
revert AccessControl();
}
metadataOwner = _metadataOwner;
}
/// @notice Update the royaltyOwner
/// @dev Can also be used to revoke this power by setting to 0x0
function setRoyaltyOwner(address _royaltyOwner) external {
if (msg.sender != royaltyOwner) {
revert AccessControl();
}
royaltyOwner = _royaltyOwner;
}
/// @notice The address which can set royalties
function owner() external view returns (address) {
return royaltyOwner;
}
// ROYALTY FUNCTIONALITY
/// @dev See {IERC165-supportsInterface}.
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) {
return
interfaceId == 0x2a55205a || // ERC165 Interface ID for ERC2981
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/// @dev See {ERC2981-_setDefaultRoyalty}.
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external {
if (msg.sender != royaltyOwner) {
revert AccessControl();
}
_setDefaultRoyalty(receiver, feeNumerator);
}
/// @dev See {ERC2981-_deleteDefaultRoyalty}.
function deleteDefaultRoyalty() external {
if (msg.sender != royaltyOwner) {
revert AccessControl();
}
_deleteDefaultRoyalty();
}
/// @dev See {ERC2981-_setTokenRoyalty}.
function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external {
if (msg.sender != royaltyOwner) {
revert AccessControl();
}
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
/// @dev See {ERC2981-_resetTokenRoyalty}.
function resetTokenRoyalty(uint256 tokenId) external {
if (msg.sender != royaltyOwner) {
revert AccessControl();
}
_resetTokenRoyalty(tokenId);
}
// METADATA FUNCTIONALITY
/// @notice Returns the metadata URI for a given token
function tokenURI(uint256 tokenId) public view override returns (string memory) {
return string(abi.encodePacked(baseTokenURI, Strings.toString(tokenId)));
}
// INTERNAL FUNCTIONS
/// @dev Revert if the account is a smart contract. Does not protect against calls from the constructor.
/// @param account The account to check
function _onlyEOA(address account) internal view {
if (msg.sender != tx.origin || account.code.length > 0) {
revert OnlyEOA(account);
}
}
}
ERC721.sol 231 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed spender, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE/LOGIC
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
function tokenURI(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC721 BALANCE/OWNER STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) internal _ownerOf;
mapping(address => uint256) internal _balanceOf;
function ownerOf(uint256 id) public view virtual returns (address owner) {
require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
}
function balanceOf(address owner) public view virtual returns (uint256) {
require(owner != address(0), "ZERO_ADDRESS");
return _balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
ERC721 APPROVAL STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
}
/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 id) public virtual {
address owner = _ownerOf[id];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(
address from,
address to,
uint256 id
) public virtual {
require(from == _ownerOf[id], "WRONG_FROM");
require(to != address(0), "INVALID_RECIPIENT");
require(
msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
"NOT_AUTHORIZED"
);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
unchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
function safeTransferFrom(
address from,
address to,
uint256 id
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
bytes calldata data
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(_ownerOf[id] == address(0), "ALREADY_MINTED");
// Counter overflow is incredibly unrealistic.
unchecked {
_balanceOf[to]++;
}
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint256 id) internal virtual {
address owner = _ownerOf[id];
require(owner != address(0), "NOT_MINTED");
// Ownership check above ensures no underflow.
unchecked {
_balanceOf[owner]--;
}
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MINT LOGIC
//////////////////////////////////////////////////////////////*/
function _safeMint(address to, uint256 id) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _safeMint(
address to,
uint256 id,
bytes memory data
) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
}
/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}
Strings.sol 75 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// 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 Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
IERC2981.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
ERC2981.sol 111 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}
ERC165.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
MerkleProof.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The proofs can be generated using the JavaScript library
* https://github.com/miguelmota/merkletreejs[merkletreejs].
* Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
*
* See `test/utils/cryptography/MerkleProof.test.js` for some examples.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
*/
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) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
* consuming from one or the other at each step according to the instructions given by
* `proofFlags`.
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
Read Contract
DUTCH_AUCTION_END_ID 0x96473b06 → uint256
DUTCH_AUCTION_GRACE_PERIOD 0xb77dc487 → uint256
DUTCH_AUCTION_MINT_CAP 0xa90af912 → uint256
DUTCH_AUCTION_START_ID 0x9e55dcb6 → uint256
WRITERS_ROOM 0xff02c517 → address
apeMerkleRoot 0xf1085dfb → bytes32
apeWritelistUsed 0x8a88b8b3 → bool
balanceOf 0x70a08231 → uint256
baseTokenURI 0xd547cfb7 → string
dutchAuctionNextId 0x51312f2f → uint256
dutchAuctionPrice 0xa537f74d → uint256
dutchEnd 0xa5da2e60 → uint128, uint128
getApproved 0x081812fc → address
giveawayMerkleRoot 0xec3ccec2 → bytes32
giveawayWritelist 0x6f8b4a72 → uint128, bool
isApprovedForAll 0xe985e9c5 → bool
metadataOwner 0xb113c608 → address
mintHistory 0x5ecc1566 → uint128, uint128
mintingOwner 0x5c49d2cb → address
name 0x06fdde03 → string
owner 0x8da5cb5b → address
ownerOf 0x6352211e → address
params 0xcff0ab96 → uint64, uint64, uint64, uint32, uint32
royaltyInfo 0x2a55205a → address, uint256
royaltyOwner 0xdb5eb702 → address
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
tokenURI 0xc87b56dd → string
totalSupply 0x18160ddd → uint256
verify 0x3423e548 → bool
writelistMintNextId 0x6f26d648 → uint256
writelistMintWritersRoomFreeOpen 0x8fab5047 → bool
writelistMintWritersRoomOpen 0x5ad388d4 → bool
writelistPrice 0xbb0fdd8d → uint256
writersroomWritelistUsed 0xd0765030 → bool
Write Contract 29 functions
These functions modify contract state and require a wallet transaction to execute.
approve 0x095ea7b3
address spender
uint256 id
claimDutchAuctionRefund 0xd299c49b
address[] accounts
claimFunds 0x693d0df2
address recipient
deleteDefaultRoyalty 0xaa1b103f
No parameters
dutchAuctionMint 0xf8cce6c0
uint256 amount
ownerMint 0x484b973c
address recipient
uint256 tokenId
ownerMintBatch 0x4ab16554
address[] recipients
uint256[] tokenIds
resetTokenRoyalty 0x8a616bc0
uint256 tokenId
safeTransferFrom 0x42842e0e
address from
address to
uint256 id
safeTransferFrom 0xb88d4fde
address from
address to
uint256 id
bytes data
setApeMerkleRoot 0x7fb3165a
bytes32 _apeMerkleRoot
setApprovalForAll 0xa22cb465
address operator
bool approved
setBaseTokenURI 0x30176e13
string _baseTokenURI
setDefaultRoyalty 0x04634d8d
address receiver
uint96 feeNumerator
setDutchAuctionStruct 0xcf9acb32
tuple _params
setGiveawayMerkleRoot 0xb0f76767
bytes32 _giveawayMerkleRoot
setMetadataOwner 0xecde3c89
address _metadataOwner
setMintingOwner 0x35137cd0
address _mintingOwner
setRoyaltyOwner 0x2525b3d7
address _royaltyOwner
setTokenRoyalty 0x5944c753
uint256 tokenId
address receiver
uint96 feeNumerator
setWritelistMintNextId 0x2ab545b5
uint256 _writelistMintNextId
setWritelistMintWritersRoomFreeOpen 0x659cdef6
bool _value
setWritelistMintWritersRoomOpen 0x63c97d63
bool _value
setWritelistPrice 0x96062e1f
uint256 _price
transferFrom 0x23b872dd
address from
address to
uint256 id
writelistMintApes 0x9d5e2a24
address tokenContract
uint256 tokenId
bytes32 leaf
bytes32[] proof
writelistMintGiveaway 0xa1876cc4
address tokenOwner
uint8 amount
uint8 totalAllocation
bytes32 leaf
bytes32[] proof
writelistMintWritersRoom 0x38935c1c
uint256[] tokenIds
writelistMintWritersRoomFree 0xd79a8ab1
uint256[] tokenIds
Recent Transactions
No transactions found for this address