Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xc31d52A017E523164Ba0A09ac19385c10bc2B890
Balance 0 ETH
Nonce 2
Code Size 20580 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

20580 bytes
0x60806040526004361015610015575b366142c257005b60003560e01c8063012b87291461036557806301ffc9a71461036057806304634d8d1461035b57806306fdde0314610356578063081812fc14610351578063095ea7b31461034c57806318160ddd146103475780631ee8b41b14610342578063212f69121461033d57806323b872dd146103385780632419f51b14610333578063248a9ca31461032e5780632a55205a146103295780632f2ff15d1461032457806333cfcb9f1461031f57806336568abe1461031a57806340c10f191461031557806342842e0e1461031057806342966c681461030b578063492e224b146103065780634a00cc4814610301578063572b6c05146102fc5780635944c753146102f75780636352211e146102f257806363b45e2d146102ed57806370a08231146102e85780637a70a895146102e35780637c3b1137146102de5780637da0a877146102d957806383040532146102d457806384b0196e146102cf57806391d14854146102ca578063938e3d7b146102c557806395d89b41146102c05780639fc4d68f146102bb578063a05112fc146102b6578063a217fddf146102b1578063a22cb465146102ac578063ac9650d8146102a7578063b88d4fde146102a2578063c22707ee1461029d578063c4376dd714610298578063c54c07e114610293578063c87b56dd1461028e578063ce0b601314610289578063ce80564214610284578063d37c353b1461027f578063d547741f1461027a578063e05688fe14610275578063e715032214610270578063e8a3d4851461026b578063e985e9c5146102665763ee7d2adf0361000e57612660565b612614565b612570565b612519565b612362565b612320565b612152565b61204b565b61200c565b611fed565b611daf565b611bdb565b611bb3565b611b62565b611afd565b611a15565b6119f9565b6119bc565b6118a8565b6117d5565b6116db565b611697565b61159f565b61156e565b6114cc565b6114a3565b6113ab565b6112d4565b6112b6565b611287565b6111a4565b611150565b610f94565b610e73565b610d3f565b610d1c565b610ca2565b610c4d565b610c0a565b610bc8565b610b1e565b610aef565b610ac9565b610ab7565b610a4f565b6109cc565b6109a9565b610900565b610889565b6107ad565b6106b4565b6105af565b610508565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761039b57604052565b61036a565b606081019081106001600160401b0382111761039b57604052565b602081019081106001600160401b0382111761039b57604052565b60c081019081106001600160401b0382111761039b57604052565b90601f801991011681019081106001600160401b0382111761039b57604052565b6040519061041f82610380565b565b6001600160401b03811161039b57601f01601f191660200190565b92919261044882610421565b9161045660405193846103f1565b829481845281830111610473578281602093846000960137010152565b600080fd5b9080601f83011215610473578160206104939335910161043c565b90565b602060031982011261047357600435906001600160401b0382116104735761049391600401610478565b60005b8381106104d35750506000910152565b81810151838201526020016104c3565b906020916104fc815180928185528580860191016104c0565b601f01601f1916010190565b346104735760208061052161051c36610496565b6147b9565b01519060409182519180830181845282518091528484019180868360051b8701019401926000965b8388106105565786860387f35b9091929394838061058c600193603f198b820301875285838b5163ffffffff60e01b8151168452015191818582015201906104e3565b970193019701969093929193610549565b6001600160e01b031981160361047357565b34610473576020366003190112610473576106166004356105cf8161059d565b6001600160e01b031981166301ffc9a760e01b811491908215610666575b8215610655575b8215610644575b821561061a575b505060405190151581529081906020820190565b0390f35b63152a902d60e11b1491508115610634575b503880610602565b61063e91506137e5565b3861062c565b915061064f816137e5565b916105fb565b635b5e139f60e01b811492506105f4565b6380ac58cd60e01b811492506105ed565b6001600160a01b0381160361047357565b602435906001600160601b038216820361047357565b604435906001600160601b038216820361047357565b34610473576040366003190112610473576004356106d181610677565b6106d9610688565b906106e26127ee565b6001600160601b03821661271080821161077e5750506001600160a01b038116156107615761073861075f92610728610719610412565b6001600160a01b039094168452565b6001600160601b03166020830152565b805160209091015160a01b6001600160a01b0319166001600160a01b039190911617600955565b005b604051635b6cc80560e11b815260006004820152602490fd5b0390fd5b6044925060405191636f483d0960e01b835260048301526024820152fd5b9060206104939281815201906104e3565b346104735760008060031936011261088657604051816002546107cf816118ec565b8084529060019081811690811561085e5750600114610805575b610616846107f9818803826103f1565b6040519182918261079c565b60028352602094507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b82841061084b5750505081610616936107f992820101936107e9565b805485850187015292850192810161082f565b61061696506107f99450602092508593915060ff191682840152151560051b820101936107e9565b80fd5b34610473576020366003190112610473576004356000548110806108e4575b156108d2576000908152600660209081526040918290205491516001600160a01b03909216825290f35b6040516333d1c03960e21b8152600490fd5b50600081815260046020526040902054600160e01b16156108a8565b60403660031901126104735760043561091881610677565b6024356001600160a01b038061092d83613d57565b1690813303610978575b600093838552600660205261094f8160408720613811565b16907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b81600052600760205260ff61099133604060002061277c565b5416610937576040516367d9dca160e11b8152600490fd5b346104735760003660031901126104735760206000546001549003604051908152f35b34610473576000366003190112610473576040517f000000000000000000000000dc2550635745d4400343721c934c353a69c5737c6001600160a01b03168152602090f35b906040610a3c610a2a84516060855260608501906104e3565b602085015184820360208601526104e3565b928101516001600160a01b031691015290565b3461047357602036600319011261047357610616610a77600435610a728161059d565b6148bd565b604051918291602083526020830190610a11565b606090600319011261047357600435610aa381610677565b90602435610ab081610677565b9060443590565b61075f610ac336610a8b565b91613dc6565b34610473576020366003190112610473576020610ae7600435612ef4565b604051908152f35b346104735760203660031901126104735760043560005260086020526020600160406000200154604051908152f35b3461047357604036600319011261047357600435600052600a602052604060002060405190610b4c82610380565b546001600160a01b03811680835260a09190911c602083015215610bba575b6020810151610b9e9061271090610b8d906001600160601b0316602435612a41565b92519204916001600160a01b031690565b604080516001600160a01b039290921682526020820192909252f35b50610bc3612a05565b610b6b565b346104735760403660031901126104735761075f602435600435610beb82610677565b806000526008602052610c056001604060002001546128f0565b612912565b34610473576040366003190112610473576024356001600160401b03811161047357610c3d61075f913690600401610478565b610c456127ee565b60043561340a565b3461047357604036600319011261047357602435610c6a81610677565b6001600160a01b0380610c7b613864565b1690821603610c905761075f90600435612995565b60405163334bd91960e11b8152600490fd5b3461047357604036600319011261047357600435610cbf81610677565b602435610cca61285e565b600054818101809111610d175760125410610ce85761075f9161420f565b60405162461bcd60e51b815260206004820152600760248201526621546f6b656e7360c81b6044820152606490fd5b612a2b565b61075f610d2836610a8b565b9060405192610d36846103bb565b600084526140dd565b3461047357602036600319011261047357600435610d5c81613d57565b60008281526006602052604090208054916001600160a01b03811691338085149084141715610d8a565b1590565b610e3d575b600093610d9b84613f10565b610e34575b50610daa82612762565b80546001600160801b030190554260a01b8217600360e01b17610dcc85611511565b55600160e11b811615610e01575b506000805160206150188339815191528280a461075f610dfc60015460010190565b600155565b60018401610e0e81611511565b5415610e1b575b50610dda565b83548114610e1557610e2c90611511565b553880610e15565b83905538610da0565b610e5c610d86610e5533610e5087612748565b61277c565b5460ff1690565b15610d8f57604051632ce44b5f60e11b8152600490fd5b34610473576020366003190112610473576020610e91600435613169565b6040519015158152f35b805190610eb060409283855283850190610a11565b90602080910151938181840391015283519182815281810182808560051b8401019601946000925b858410610ee9575050505050505090565b909192939495968580610f21600193601f1986820301885286838d5163ffffffff60e01b8151168452015191818582015201906104e3565b990194019401929594939190610ed8565b602080820190808352835180925260408301928160408460051b8301019501936000915b848310610f665750505050505090565b9091929394958480610f84600193603f198682030187528a51610e9b565b9801930193019194939290610f56565b346104735760008060031936011261088657604051630940198960e31b81529080826004817f000000000000000000000000dc2550635745d4400343721c934c353a69c5737c6001600160a01b03165afa91821561114b578192611127575b50815191610fff614f83565b80519280815b8681106110f257506110236110289161101e88886130eb565b612a63565b6145f0565b948193825b82811061109757505050915b83831061104e57604051806106168782610f32565b61108b6110919161107061106b6110658787612b7d565b51614640565b61478d565b61107a8289612b7d565b526110858188612b7d565b506130dd565b926130dd565b91611039565b6110af610d866110a78385612b7d565b515151614de4565b6110c2575b6110bd906130dd565b61102d565b946110ea6110bd916110d48885612b7d565b516110df828c612b7d565b52611085818b612b7d565b9590506110b4565b6110ff6110a78287612b7d565b611112575b61110d906130dd565b611005565b9061111f61110d916130dd565b919050611104565b6111449192503d8084833e61113c81836103f1565b81019061451a565b9038610ff3565b613ae4565b3461047357602036600319011261047357602060043561116f81610677565b6040519060018060a01b03807f000000000000000000000000c82bbe41f2cf04e3a8efa18f7032bdd7f6d98a81169116148152f35b34610473576060366003190112610473576004356024356111c481610677565b6111cc61069e565b6111d46127ee565b6127106001600160601b0382168181116112635750506001600160a01b038216156112435761075f9261122e61123e9261121e61120f610412565b6001600160a01b039096168652565b6001600160601b03166020850152565b600052600a602052604060002090565b613830565b604051634b4f842960e11b81526004810184905260006024820152604490fd5b60649185916040519263dfd1fc1b60e01b8452600484015260248301526044820152fd5b346104735760203660031901126104735760206001600160a01b036112ad600435613d57565b16604051908152f35b34610473576000366003190112610473576020600f54604051908152f35b34610473576020366003190112610473576004356112f181610677565b6001600160a01b0316801561132157600052600560205260206001600160401b0360406000205416604051908152f35b6040516323d3ad8160e21b8152600490fd5b9181601f84011215610473578235916001600160401b038311610473576020838186019501011161047357565b90600319604081840112610473576004356001600160401b03918282116104735760809082860301126104735760040192602435918211610473576113a791600401611333565b9091565b34610473576113b936611360565b91906113d36113cb6060840184612adf565b8101906133eb565b926001600160a01b0390911691831561147857600054916113f485846130eb565b60125410610ce857610616957fff097c7d8b1957a4ff09ef1361b5fb54dcede3941ba836d0beb9d10bec725de69261142b926139b5565b93611436818561420f565b61144d611441613864565b6001600160a01b031690565b60408051948552602085019290925292a36040516001600160a01b0390911681529081906020820190565b60405162461bcd60e51b815260206004820152600360248201526271747960e81b6044820152606490fd5b346104735760206001600160a01b0360406114c061051c36610496565b51015116604051908152f35b34610473576000366003190112610473576040517f000000000000000000000000c82bbe41f2cf04e3a8efa18f7032bdd7f6d98a816001600160a01b03168152602090f35b6000526004602052604060002090565b7f8502233096d909befbda0999bb8ea2f3a6be3c138b9fbf003752a4c8bce86f6c60005260086020527f85da32aea425a83be1133c4e958580985fa04602ddf03ad35008a70703b20eb790565b34610473576020366003190112610473576004356000526011602052602060ff604060002054166040519015158152f35b346104735760008060031936011261088657611649906115de7f5369676e6174757265416374696f6e000000000000000000000000000000000f612d00565b6116077f3100000000000000000000000000000000000000000000000000000000000001612df8565b9160405191611615836103bb565b818352604051948594600f60f81b865261163b60209360e08589015260e08801906104e3565b9086820360408801526104e3565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b82811061168057505050500390f35b835185528695509381019392810192600101611671565b3461047357604036600319011261047357602060ff6116cf6024356116bb81610677565b60043560005260088452604060002061277c565b54166040519015158152f35b34610473576116e936610496565b6116f16127ee565b80516001600160401b03811161039b57611715816117106014546118ec565b61319b565b602080601f831160011461175257508192600092611747575b5050600019600383901b1c191660019190911b17601455005b01519050388061172e565b6014600052601f198316939091907fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec926000905b8682106117bd57505083600195106117a4575b505050811b01601455005b015160001960f88460031b161c19169055388080611799565b80600185968294968601518155019501930190611786565b346104735760008060031936011261088657604051816003546117f7816118ec565b8084529060019081811690811561085e575060011461182057610616846107f9818803826103f1565b60038352602094507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8284106118665750505081610616936107f992820101936107e9565b805485850187015292850192810161184a565b9060406003198301126104735760043591602435906001600160401b038211610473576113a791600401611333565b34610473576106166118c26118bc36611879565b91613033565b6040519182916020835260208301906104e3565b634e487b7160e01b600052600060045260246000fd5b90600182811c9216801561191c575b602083101461190657565b634e487b7160e01b600052602260045260246000fd5b91607f16916118fb565b9060009291805491611937836118ec565b9182825260019384811690816000146119995750600114611959575b50505050565b90919394506000526020928360002092846000945b838610611985575050505001019038808080611953565b80548587018301529401938590820161196e565b9294505050602093945060ff191683830152151560051b01019038808080611953565b3461047357602036600319011261047357600435600052600e6020526106166119f26118c2604060002060405192838092611926565b03826103f1565b3461047357600036600319011261047357602060405160008152f35b3461047357604036600319011261047357600435611a3281610677565b6024359081151580920361047357336000526007602052611a5781604060002061277c565b60ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602080820190808352835180925260408301928160408460051b8301019501936000915b848310611acf5750505050505090565b9091929394958480611aed600193603f198682030187528a516104e3565b9801930193019194939290611abf565b34610473576020366003190112610473576001600160401b036004358181116104735736602382011215610473578060040135918211610473573660248360051b8301011161047357610616916024611b569201612b91565b60405191829182611a9b565b608036600319011261047357600435611b7a81610677565b602435611b8681610677565b606435916001600160401b03831161047357611ba961075f933690600401610478565b91604435916140dd565b3461047357610616611bc761051c36610496565b604051918291602083526020830190610e9b565b34610473576040611bf4611bee36611360565b916138bd565b825191151582526001600160a01b03166020820152f35b6001600160401b03811161039b5760051b60200190565b81601f8201121561047357803590611c3982611c0b565b92604092611c49845195866103f1565b808552602093848087019260051b8501019383851161047357858101925b858410611c78575050505050505090565b6001600160401b0384358181116104735783019184601f198489030112610473578451611ca481610380565b89840135611cb18161059d565b81528584013592831161047357611ccf888b80969581960101610478565b83820152815201930192611c67565b60031990602081830112610473576004908135916001600160401b038084116104735760408585850301126104735760405194611d1a86610380565b848301358281116104735760609086019182860301126104735760405190611d41826103a0565b83810135838111610473578585611d5a92840101610478565b825260248101359083821161047357611d798686604494840101610478565b60208401520135611d8981610677565b60408201528552602484013590811161047357611da7930101611c22565b602082015290565b3461047357611dbd36611cde565b611dcd611dc8614358565b614301565b805151611de4611ddc82614685565b541515614bbe565b611e006002611df283614640565b01546001600160a01b031690565b82516040908101516001600160a01b0393919284169190611e25908516831415614c1c565b611e388551611e3383614640565b6149ee565b6003611e4d81611e4784614640565b01614705565b805190611e6383611e5d86614640565b01614cc3565b60005b828110611fbc57505050602094858701918251519760005b898110611e8757005b80855190611e9491612b7d565b51611e9e90614a91565b8982875190611eac91612b7d565b5101518951808c81019283611ec091612b2d565b03601f1981018252611ed290826103f1565b5190206001600160e01b031991611eee91831690831614614a9f565b825182875190611efd91612b7d565b51611f0790614a91565b611f1090614885565b90611f1a916149ee565b83611f2488614640565b0182875190611f3291612b7d565b51611f3c91614b72565b82518901516001600160a01b0316908883885190611f5991612b7d565b51611f6390614a91565b918c858a5190611f7291612b7d565b51015192888d5192839216951693611f8a908261079c565b037f7f4649aa14a7e9abd7f21a02ea35b32c907d59bb701c52c0e028ddf57533c74c91a4611fb7906130dd565b611e7e565b80611fe3611fde611fd9611fd3611fe89587612b7d565b51614a91565b614885565b614d19565b6130dd565b611e66565b34610473576020366003190112610473576106166118c2600435613590565b3461047357602036600319011261047357602060043561202b8161059d565b6001600160a01b0390604090612040906148bd565b015116604051908152f35b346104735761205936611879565b9161206261285e565b61206b81612ef4565b612076848483613033565b92612090604051612086816103bb565b600081528361321a565b61209a848361340a565b6120a2613864565b906000194301438111610d17576120ff60946106169861211395604051948286936020850198893783019144602084015260018060601b03199060601b1660408301524260548301524060748201520360748101845201826103f1565b519020916000526013602052604060002090565b557f6df1d8db2a036436ffe0b2d1833f2c5f1e624818dfce2578c0faa4b83ef9998d60405180612143858261079c565b0390a26040519182918261079c565b34610473576060366003190112610473576001600160401b0360043560243582811161047357612186903690600401611333565b9091604435848111610473576121a0903690600401611333565b9390946121ab61285e565b846122b7575b50811561228a57601254926121c736828461043c565b9280850195868611610d1757600f5497600160401b89101561039b5761226a612265612277946122567f2a0365091ef1a40953c670dce28177e37520648a6fdc91506bffac0ab045570d996122438d6106169f80600161222a9201600f55612eb2565b90919082549060031b91821b91600019901b1916179055565b8c60005260106020526040600020613343565b61225f8b601255565b896130eb565b612a54565b9360405195869586613317565b0390a26040519081529081906020820190565b60405162461bcd60e51b81526020600482015260056024820152640c08185b5d60da1b6044820152606490fd5b848601604087820312610473578635918211610473576122d8918701610478565b51151580612313575b6122ec575b386121b1565b601254828101809111610d175761230e9061230836878961043c565b9061321a565b6122e6565b50602085013515156122e1565b346104735760403660031901126104735761075f60243560043561234382610677565b80600052600860205261235d6001604060002001546128f0565b612995565b346104735761237036611cde565b61237b611dc8614358565b80515161238f61238a82614d5a565b614990565b61239d8251611e3383614640565b81516040908101516001600160a01b0392906123bc9084161515614a24565b602092838501908151519560005b8781106123d357005b808461245161243f6124328a6124146124228e806124038a6123fc611fd36125149e8d51612b7d565b9a51612b7d565b510151935192839182018095612b2d565b03601f1981018352826103f1565b5190206001600160e01b03191690565b6001600160e01b03191690565b6001600160e01b031992831614614a9f565b61247361246d6114416002611df2611fd9611fd3888d51612b7d565b15614b07565b6124898451611e33611fd9611fd3868b51612b7d565b6124aa600361249789614640565b016124a3848951612b7d565b5190614b72565b83518801516001600160a01b0316907fb5a3e9571e367979a4a14de42b248d0837c26fd8e879846062abcf7cee1712736124e8611fd3858a51612b7d565b918b6124f5868b51612b7d565b5101519261250c898d51938493169616948261079c565b0390a36130dd565b6123ca565b34610473576040366003190112610473576001600160401b036004358181116104735761254a903690600401610478565b90602435908111610473576106169161256a6118c2923690600401611333565b916130f8565b34610473576000806003193601126108865760405181601454612592816118ec565b8084529060019081811690811561085e57506001146125bb57610616846107f9818803826103f1565b60148352602094507fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec5b8284106126015750505081610616936107f992820101936107e9565b80548585018701529285019281016125e5565b3461047357604036600319011261047357602060ff6116cf60043561263881610677565b6024359061264582610677565b6001600160a01b03166000908152600785526040902061277c565b346104735761266e36610496565b612679611dc8614358565b61268a61268582614eb6565b614bbe565b6126986002611df283614640565b6126b76126b26126ac6003611e4786614640565b93614640565b614d37565b8151906001600160a01b031660005b8281106126cf57005b806126e0611fd36127439387612b7d565b837f5968261591c9d57680edfe0bed3bb6a37ab7fb354578affd1e5be8ce18e6c9d361272d6020612711868b612b7d565b5101516040516001600160e01b0319909516949182918261079c565b0390a3611fe3611fde611fd9611fd38489612b7d565b6126c6565b6001600160a01b0316600090815260076020526040902090565b6001600160a01b0316600090815260056020526040902090565b9060018060a01b0316600052602052604060002090565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6600052600860205260ff906127e9907f51a495916474fe1a0c0fcfb65a8a97682b84a054118858cdd1f5dfd7fc0919eb61277c565b541690565b6127f6613864565b60008052600860205260ff61282b827f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c761277c565b5416156128355750565b60405163e2517d3f60e01b81526001600160a01b03909116600482015260006024820152604490fd5b612866613864565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66000819052600860205260ff6128bd837f51a495916474fe1a0c0fcfb65a8a97682b84a054118858cdd1f5dfd7fc0919eb61277c565b5416156128c8575050565b60405163e2517d3f60e01b81526001600160a01b039092166004830152602482015260449150fd5b6128f8613864565b9080600052600860205260ff6128bd83604060002061277c565b600090808252600860205260ff61292c846040852061277c565b541661298f578082526008602052612947836040842061277c565b805460ff191660011790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d6001600160a01b0380612984613864565b1694169280a4600190565b50905090565b600090808252600860205260ff6129af846040852061277c565b54161561298f5780825260086020526129cb836040842061277c565b805460ff191690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6001600160a01b0380612984613864565b60405190612a1282610380565b6009546001600160a01b038116835260a01c6020830152565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715610d1757565b600019810191908211610d1757565b91908203918211610d1757565b90612a7a82611c0b565b612a8760405191826103f1565b8281528092612a98601f1991611c0b565b019060005b828110612aa957505050565b806060602080938501015201612a9d565b6000198114610d175760010190565b634e487b7160e01b600052603260045260246000fd5b903590601e198136030182121561047357018035906001600160401b0382116104735760200191813603831361047357565b90821015612b28576113a79160051b810190612adf565b612ac9565b90612b40602092828151948592016104c0565b0190565b6020908161041f939594612b718760405198899585870137840191838301600081528151948592016104c0565b010380855201836103f1565b8051821015612b285760209160051b010190565b6001600160a01b03612ba1613864565b1633149160008093600014612c215750604051612bbd816103bb565b83815283368137905b612bcf81612a70565b935b818110612bdf575050505090565b80612c01612bfb85612bf5612c1c95878a612b11565b90612b44565b30612c84565b612c0b8288612b7d565b52612c168187612b7d565b50612aba565b612bd1565b36601319810194508411610d175760405190612c3c82610380565b60148252601481956020840137603482015290612bc6565b3d15612c7f573d90612c6582610421565b91612c7360405193846103f1565b82523d6000602084013e565b606090565b60008061049393602081519101845af4612c9c612c54565b9190612cc45750805115612cb257805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612cf7575b612cd5575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612ccd565b60ff8114612d3e5760ff811690601f8211612d2c5760405191612d2283610380565b8252602082015290565b604051632cd44ac360e21b8152600490fd5b50604051600b54816000612d51836118ec565b808352600193808516908115612dd75750600114612d77575b50610493925003826103f1565b600b60009081527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db994602093509091905b818310612dbf575050610493935082010138612d6a565b85548784018501529485019486945091830191612da8565b905061049394506020925060ff191682840152151560051b82010138612d6a565b60ff8114612e1a5760ff811690601f8211612d2c5760405191612d2283610380565b50604051600c54816000612e2d836118ec565b808352600193808516908115612dd75750600114612e525750610493925003826103f1565b600c60009081527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c794602093509091905b818310612e9a575050610493935082010138612d6a565b85548784018501529485019486945091830191612e83565b600f54811015612b2857600f60005260206000200190600090565b600080516020614ff88339815191528054821015612b285760005260206000200190600090565b600f54811015612f2957600f6000527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802015490565b60405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606490fd5b90929192612f6b81610421565b91612f7960405193846103f1565b82948284528282011161047357602061041f9301906104c0565b91906040838203126104735782516001600160401b03811161047357830181601f82011215610473576020918183612fcd93519101612f5e565b92015190565b926020809594612feb839594828151948592016104c0565b01918237019081520190565b15612ffe57565b60405162461bcd60e51b815260206004820152600d60248201526c496e636f7272656374206b657960981b6044820152606490fd5b92919092600052600e6020526119f2613056604060002060405192838092611926565b8051156130a4578161241461309b61308661041f9561307f866020808c99518301019101612f93565b96906130f8565b96604051928391602083019546918b88612fd3565b51902014612ff7565b60405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81d1bc81c995d99585b607a1b6044820152606490fd5b9060018201809211610d1757565b91908201809211610d1757565b909291928151916040918251956020938486890101815285885260005b8681106131255750505050505050565b815186810190848683376131498482878101868c820152038a8101845201826103f1565b5190208682870101511886828b0101528581018091111561311557612a2b565b600052600e60205261317f6040600020546118ec565b151590565b81811061318f575050565b60008155600101613184565b90601f82116131a8575050565b61041f9160146000526020600020906020601f840160051c830193106131d6575b601f0160051c0190613184565b90915081906131c9565b9190601f81116131ef57505050565b61041f926000526020600020906020601f840160051c830193106131d657601f0160051c0190613184565b9190916000526020600e81526040600020908351906001600160401b03821161039b576132518261324b85546118ec565b856131e0565b80601f831160011461328b575081929394600092613280575b50508160011b916000199060031b1c1916179055565b01519050388061326a565b90601f198316956132a185600052602060002090565b926000905b8882106132de575050836001959697106132c5575b505050811b019055565b015160001960f88460031b161c191690553880806132bb565b806001859682949686015181550195019301906132a6565b908060209392818452848401376000828201840152601f01601f1916010190565b939161049395936133359286526060602087015260608601916132f6565b9260408185039101526132f6565b91909182516001600160401b03811161039b5761336a8161336484546118ec565b846131e0565b602080601f831160011461339a5750819293946000926132805750508160011b916000199060031b1c1916179055565b90601f198316956133b085600052602060002090565b926000905b8882106133d3575050836001959697106132c557505050811b019055565b806001859682949686015181550195019301906133b5565b9190826040910312610473576020823561340481610677565b92013590565b80600052601160205260ff60406000205416613473576134587f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c928260005260106020526040600020613343565b613461816134f7565b604080519182526020820192909252a1565b60405162461bcd60e51b815260206004820152600c60248201526b2130ba31b410333937bd32b760a11b6044820152606490fd5b60405190600f548083528260209182820190600f60005283600020936000905b8282106134dd5750505061041f925003836103f1565b8554845260019586019588955093810193909101906134c7565b600f54906135036134a7565b600091825b8481106135465760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818985d18da1259608a1b6044820152606490fd5b6135508184612b7d565b5182146135655761356090612aba565b613508565b91929350508061357457505090565b9091506000198101908111610d175761358c91612b7d565b5190565b6135998161367b565b906135a3836136e0565b926135ad82613169565b156135dc575050506104936135cf916124146040519384926020840190612b2d565b600360fc1b815260010190565b906135e79291613761565b6040519060a08201604052608082019060008252905b6000190190600a9060308282060183530490816135fd57905061363f92613645610493936080601f199485810192030181526040519586936020850190612b2d565b90612b2d565b039081018352826103f1565b60609060208152600f60208201526e125b9d985b1a59081d1bdad95b9259608a1b60408201520190565b90600f54916136886134a7565b9060005b8481106136ac5760405162461bcd60e51b81528061077a60048201613651565b6136b68184612b7d565b5182106136ce57600181018091111561368c57612a2b565b935050826136db91612b7d565b519190565b90600f54916136ed6134a7565b600091825b8581106137125760405162461bcd60e51b81528061077a60048201613651565b61371c8184612b7d565b5182106137345760018101809111156136f257612a2b565b6119f294955061374991506104939392612b7d565b51815260106020526040809120905192838092611926565b919080600052601360205260406000205480156137df57600092806137c0575b5082820391808311610d175783146137aa578190068301809311610d17576104939206906130eb565b634e487b7160e01b600052601260045260246000fd5b9092506000198101908111610d17576137d890612ef4565b9138613781565b50505090565b63ffffffff60e01b16637965db0b60e01b8114908115613803575090565b6301ffc9a760e01b14919050565b80546001600160a01b0319166001600160a01b03909216919091179055565b90602060018060a01b03916138488382511685613811565b0151825490911660a09190911b6001600160a01b031916179055565b337f000000000000000000000000c82bbe41f2cf04e3a8efa18f7032bdd7f6d98a816001600160a01b031614806138b2575b156138ae576013193601368111610d17573560601c90565b3390565b506014361015613896565b91610e5561397b610d869261397561398c9561396d6138db896139a1565b6138e760208b016139a1565b906139056138fe60408d01359c6060810190612adf565b369161043c565b602081519101206040519160208301937f242b17107e6aef17754836dd680cb66bbf39e46a5f20952950acbbae68643d02855260018060801b0380921660408501521660608301528b608083015260a082015260a08152613965816103d6565b519020613c17565b92369161043c565b90613a92565b93600052600d602052604060002090565b806139945791565b5061399e81612793565b91565b356001600160801b03811681036104735790565b92916139c191846138bd565b929015613a63576139d1816139a1565b426001600160801b03909116118015613a40575b613a1157613a04604061041f920135600052600d602052604060002090565b805460ff19166001179055565b60405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606490fd5b50613a5c613a50602083016139a1565b6001600160801b031690565b42116139e5565b60405162461bcd60e51b8152602060048201526007602482015266125b9d985b1a5960ca1b6044820152606490fd5b61049391613a9f91613aa8565b90929192613b8a565b8151919060418303613ad957613ad292506020820151906060604084015193015160001a90613af0565b9192909190565b505060009160029190565b6040513d6000823e3d90fd5b91906fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411613b5e57926020929160ff608095604051948552168484015260408301526060820152600092839182805260015afa1561114b5780516001600160a01b03811615613b5557918190565b50809160019190565b50505060009160039190565b60041115613b7457565b634e487b7160e01b600052602160045260246000fd5b613b9381613b6a565b80613b9c575050565b613ba581613b6a565b60018103613bbf5760405163f645eedf60e01b8152600490fd5b613bc881613b6a565b60028103613be95760405163fce698f760e01b815260048101839052602490fd5b80613bf5600392613b6a565b14613bfd5750565b6040516335e2f38360e21b81526004810191909152602490fd5b604290613c22613c3d565b906040519161190160f01b8352600283015260228201522090565b307f000000000000000000000000c31d52a017e523164ba0a09ac19385c10bc2b8906001600160a01b03161480613d2e575b15613c98577f456a661c7c14e451543280845a80df85e137443e4ac9282e9d52c106ce8b101490565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f9d4ffaa97baca5653914910a43096d3910699e440d067aae25095cef149d7c4e60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a08152613d28816103d6565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000014614613c6f565b8060009081548110613d76575b604051636f96cda160e11b8152600490fd5b81526004906020918083526040928383205494600160e01b861615613d9d57505050613d64565b93929190935b8515613db157505050505090565b60001901808352818552838320549550613da3565b90613dd083613d57565b6001600160a01b0383811692828216849003613eff57600086815260066020526040902080549092613e116001600160a01b03881633908114908414171590565b613ed5575b8216958615613ec357613e4993613e3c92613e31858461404b565b613eb9575b50612762565b8054600019019055612762565b80546001019055600160e11b4260a01b84178117613e6686611511565b55811615613e85575b50600080516020615018833981519152600080a4565b60018401613e9281611511565b5415613e9f575b50613e6f565b6000548114613e9957613eb190611511565b553880613e99565b6000905538613e36565b604051633a954ecd60e21b8152600490fd5b613ee8610d86610e5533610e508b612748565b15613e1657604051632ce44b5f60e11b8152600490fd5b60405162a1148160e81b8152600490fd5b613f18611521565b9060009182805260205260ff6040832054161580613fb5575b80613fae575b613f3f575050565b613f4d60ff91610e50611521565b5416159081613f8f575b50613f5e57565b60405162461bcd60e51b815260206004820152600960248201526810aa2920a729a322a960b91b6044820152606490fd5b60ff9150604090613f9e611521565b8180526020522054161538613f57565b5081613f37565b506001600160a01b0381161515613f31565b613fcf611521565b60009081805260205260ff6040822054161580614044575b80614032575b613ff5575050565b604060ff91614002611521565b8180526020522054161590816140195750613f5e57565b60ff915061402990610e50611521565b54161538613f57565b506001600160a01b0382161515613fed565b5080613fe7565b614053611521565b6000805260205261406c60ff6040600020541615151590565b806140cb575b806140b9575b614080575050565b610d86610e5561409292610e50611521565b908161409f5750613f5e57565b6140b39150610e55610d8691610e50611521565b38613f57565b506001600160a01b0382161515614078565b506001600160a01b0381161515614072565b9291906140eb828286613dc6565b803b6140f75750505050565b61410093614166565b1561410e5738808080611953565b6040516368d2bf6b60e11b8152600490fd5b9081602091031261047357516104938161059d565b6001600160a01b039182168152911660208201526040810191909152608060608201819052610493929101906104e3565b9260209161418f936000604051809681958294630a85bd0160e11b9a8b85523360048601614135565b03926001600160a01b03165af1600091816141df575b506141d1576141b2612c54565b805190816141cc576040516368d2bf6b60e11b8152600490fd5b602001fd5b6001600160e01b0319161490565b61420191925060203d8111614208575b6141f981836103f1565b810190614120565b90386141a5565b503d6141ef565b9060009081549281156142b05761422581613fc7565b61422e81612762565b80546001600160401b0184020190556001600160a01b0316906001904260a01b81831460e11b17831761426086611511565b558401938160008051602061501883398151915291808587858180a4015b8581036142a157505050156142905755565b604051622e076360e81b8152600490fd5b8083918587858180a40161427e565b60405163b562e8dd60e01b8152600490fd5b600080806001600160a01b0360406142e483356001600160e01b0319166148bd565b015116368280378136915af43d82803e156142fd573d90f35b3d90fd5b1561430857565b60405162461bcd60e51b815260206004820152602260248201527f42617365526f757465723a2063616c6c6572206e6f7420617574686f72697a65604482015261321760f11b6064820152608490fd5b60ff6127e9614365613864565b6000805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c761277c565b9080601f8301121561047357815161049392602001612f5e565b91909160608184031261047357604051906143c8826103a0565b81938151916001600160401b039283811161047357826143e9918301614394565b84526020810151928311610473576144076040939284938301614394565b602085015201519161441883610677565b0152565b9190604092838183031261047357835161443581610380565b80948251936001600160401b039485811161047357816144569186016143ae565b8352602093848101519086821161047357019181601f840112156104735782519061448082611c0b565b9661448d825198896103f1565b828852868089019360051b8601019484861161047357878101935b8685106144ba57505050505050500152565b84518381116104735782019084601f198389030112610473578451906144df82610380565b8a8301516144ec8161059d565b825285830151918583116104735761450b898d80969581960101614394565b838201528152019401936144a8565b9060209081838203126104735782516001600160401b0393848211610473570181601f8201121561047357805161455081611c0b565b9461455e60405196876103f1565b818652848087019260051b8401019380851161047357858401925b85841061458a575050505050505090565b83518381116104735787916145a4848480948a010161441c565b815201930192614579565b604051906145bc826103a0565b600060408360608152606060208201520152565b604051906145dd82610380565b60606020836145ea6145af565b81520152565b906145fa82611c0b565b61460760405191826103f1565b8281528092614618601f1991611c0b565b019060005b82811061462957505050565b6020906146346145d0565b8282850101520161461d565b60206146599181604051938285809451938492016104c0565b81017f1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee0087581520301902090565b602061469e9181604051938285809451938492016104c0565b810160008051602061503883398151915281520301902090565b906040516146c5816103a0565b6040819381516146d9816119f28185611926565b835281516146ee816119f28160018601611926565b6020840152600201546001600160a01b0316910152565b90815461471181611c0b565b92604093614721855191826103f1565b828152809460208092019260005281600020906000935b85851061474757505050505050565b600284600192845161475881610380565b865460e01b6001600160e01b0319168152855161477b816119f281898c01611926565b83820152815201930194019391614738565b9060405161479a81610380565b60206147b4600383956147ac816146b8565b855201614705565b910152565b6147c16145d0565b506147cb81614685565b54600090156147e1575061106b61049391614640565b80614800926040518094819263611383f760e11b83526004830161079c565b03817f000000000000000000000000dc2550635745d4400343721c934c353a69c5737c6001600160a01b03165afa91821561114b57819261484057505090565b909291503d8084833e61485381836103f1565b810190602081830312614881578051906001600160401b03821161487d576104939394500161441c565b8480fd5b8380fd5b63ffffffff60e01b166000527f1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee00876602052604060002090565b6148c56145af565b506148d76148d282614885565b6146b8565b604081015190916001600160a01b0391600091908316156148f85750505090565b81929350602460405180958193631097b48960e11b835263ffffffff60e01b1660048301527f000000000000000000000000dc2550635745d4400343721c934c353a69c5737c165afa91821561114b57819261495357505090565b909291503d8084833e61496681836103f1565b810190602081830312614881578051906001600160401b03821161487d57610493939450016143ae565b1561499757565b60405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152683c9032bc34b9ba399760b91b6064820152608490fd5b600261041f926149ff815184613343565b614a10602082015160018501613343565b604001516001600160a01b03169101613811565b15614a2b57565b60405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e53746174653a20616464696e6720657874656e73696f6e604482015277103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760411b6064820152608490fd5b516001600160e01b03191690565b15614aa657565b60405162461bcd60e51b815260206004820152603360248201527f457874656e73696f6e53746174653a20666e2073656c6563746f7220616e642060448201527239b4b3b730ba3ab9329036b4b9b6b0ba31b41760691b6064820152608490fd5b15614b0e57565b60405162461bcd60e51b815260206004820152603660248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152753c9032bc34b9ba39903337b910333ab731ba34b7b71760511b6064820152608490fd5b908154600160401b81101561039b5760018101808455811015612b2857602060019161041f946000528160002090831b0192805160e01c63ffffffff1985541617845501519101613343565b15614bc557565b60405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a20657874656e73696f6e20646f6573206e60448201526837ba1032bc34b9ba1760b91b6064820152608490fd5b15614c2357565b60405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a2072652d616464696e672073616d6520656044820152683c3a32b739b4b7b71760b91b6064820152608490fd5b614c8481546118ec565b9081614c8e575050565b81601f60009311600114614ca0575055565b908083918252614cbf601f60208420940160051c840160018501613184565b5555565b805460009182815581614cd557505050565b6001600160ff1b0382168203610d175782526020822091600191821b8301925b838110614d025750505050565b808260029255614d13848201614c7a565b01614cf5565b6002600091614d2781614c7a565b614d3360018201614c7a565b0155565b600361041f91611e5d81614d19565b9190614d555761041f91613343565b6118d6565b614d6381614685565b54614dde57600080516020614ff88339815191528054600160401b81101561039b5760018101808355811015612b285781614dac84602093614dc1956000528460002001613343565b549281604051938285809451938492016104c0565b810160008051602061503883398151915281520301902055600190565b50600090565b6020614dfd9181604051938285809451938492016104c0565b810160008051602061503883398151915281520301902054151590565b600080516020614ff883398151915280548015614ea0576000190190614e3f82612ecd565b614d5557614e4d81546118ec565b9081614e5857505055565b601f8211600114614e6b57600091505555565b614e8d614e9d92826000526001601f6020600020920160051c82019101613184565b6000908082528160208120915555565b55565b634e487b7160e01b600052603160045260246000fd5b6040516020818351614ecb81838588016104c0565b60008051602061503883398151915290820190815203019020548015614f7c576000199181830191808311610d1757600080516020614ff883398151915254938401938411610d17578383614f339460009603614f39575b505050614f2e614e1a565b614685565b55600190565b614f2e614f6191614f6d614f4f614f7395612ecd565b5091614f686040518096818096611926565b03846103f1565b612ecd565b90614d46565b55388080614f23565b5050600090565b600080516020614ff8833981519152908154614f9e81611c0b565b92604093614fae855191826103f1565b828152809460208092019260005281600020906000935b858510614fd457505050505050565b60018481928451614fe9816119f2818a611926565b815201930194019391614fc556fe1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee00873ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee00874a164736f6c6343000814000a

Verified Source Code Partial Match

Compiler: v0.8.20+commit.a1b79de6 EVM: paris Optimization: Yes (20 runs)
Petopia.sol 276 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "erc721a/contracts/extensions/ERC721ABurnable.sol";
import "lib/dynamic-contracts/src/presets/BaseRouter.sol";
import "./SignatureAction.sol";
import "./DelayedReveal.sol";
import "./LazyMint.sol";

contract Petopia is
ERC721ABurnable,
AccessControl,
ERC2771Context,
ERC2981,
Multicall,
BaseRouter,
SignatureAction,
DelayedReveal,
LazyMint
{
    bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 private constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");

    mapping(uint256 => bytes32) private tokenIdOffset;
    /// @notice Emitted when tokens are claimed via `claimWithSignature`.
    event TokensClaimed(
        address indexed claimer,
        address indexed receiver,
        uint256 startTokenId,
        uint256 quantityClaimed
    );

    /*///////////////////////////////////////////////////////////////
                    Constructor and Initializer logic
    //////////////////////////////////////////////////////////////*/

    constructor(
        address _defaultAdmin,
        string memory _name,
        string memory _symbol,
        string memory _contractURI,
        address _royaltyRecipient,
        uint16 _royaltyBps,
        Extension[] memory _extensions,
        address _trustedForwarders
    )
    BaseRouter(_extensions)
    ERC2771Context(_trustedForwarders)
    ERC721A(_name, _symbol)
    {
        _baseContractURI = _contractURI;
        _setupRoles(_defaultAdmin);
        _setDefaultRoyalty(_royaltyRecipient, _royaltyBps);
    }

    function _setupRoles(address _defaultAdmin) internal {
        _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE);
        _setRoleAdmin(MINTER_ROLE, DEFAULT_ADMIN_ROLE);
        _setRoleAdmin(TRANSFER_ROLE, DEFAULT_ADMIN_ROLE);

        _grantRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
        _grantRole(MINTER_ROLE, _defaultAdmin);
        _grantRole(TRANSFER_ROLE, address(0));
    }

    function mint(address to, uint quantity) external onlyRole(MINTER_ROLE) {
        uint256 tokenIdToMint = _nextTokenId();
        if (tokenIdToMint + quantity > nextTokenIdToLazyMint) {
            revert("!Tokens");
        }
        _mint(to, quantity);
    }

    /*///////////////////////////////////////////////////////////////
              Internal functions
    //////////////////////////////////////////////////////////////*/

    function _beforeTokenTransfers(
        address from,
        address to,
        uint startTokenId,
        uint quantity
    ) internal virtual override {
        super._beforeTokenTransfers(from, to, startTokenId, quantity);

        // if transfer is restricted on the contract, we still want to allow burning and minting
        if (!hasRole(TRANSFER_ROLE, address(0)) && from != address(0) && to != address(0)) {
            if (!hasRole(TRANSFER_ROLE, from) && !hasRole(TRANSFER_ROLE, to)) {
                revert("!TRANSFER");
            }
        }
    }

    function _canSetExtension() internal view virtual override returns (bool) {
        return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    function _isAuthorizedSigner(address _signer) internal view override returns (bool) {
        return hasRole(MINTER_ROLE, _signer);
    }

    /*///////////////////////////////////////////////////////////////
                   Lazy minting + delayed-reveal logic
   //////////////////////////////////////////////////////////////*

   /**
    *  @dev Lets an account with `MINTER_ROLE` lazy mint 'n' NFTs.
     *       The URIs for each token is the provided `_baseURIForTokens` + `{tokenId}`.
     */
    function lazyMint(
        uint256 _amount,
        string calldata _baseURIForTokens,
        bytes calldata _data
    ) external onlyRole(MINTER_ROLE) returns (uint256 batchId) {
        if (_data.length > 0) {
            (bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
            if (encryptedURI.length != 0 && provenanceHash != "") {
                _setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
            }
        }

        return _lazyMint(_amount, _baseURIForTokens, _data);
    }

    function claimWithSignature(GenericRequest calldata _req, bytes calldata _signature)
    external
    returns (address signer)
    {
        (
            address to,
            uint256 quantity
        ) = abi.decode(_req.data, (address, uint256));

        if (quantity == 0) {
            revert("qty");
        }

        uint256 tokenIdToMint = _nextTokenId();
        if (tokenIdToMint + quantity > nextTokenIdToLazyMint) {
            revert("!Tokens");
        }
        // Verify and process payload.
        signer = _processRequest(_req, _signature);

        // Mint tokens.
        _mint(to, quantity);

        emit TokensClaimed(_msgSender(), to, tokenIdToMint, quantity);
    }

    /// @dev Lets an account with `MINTER_ROLE` reveal the URI for a batch of 'delayed-reveal' NFTs.
    function reveal(uint256 _index, bytes calldata _key)
    external
    onlyRole(MINTER_ROLE)
    returns (string memory revealedURI)
    {
        uint256 batchId = getBatchIdAtIndex(_index);
        revealedURI = getRevealURI(batchId, _key);

        _setEncryptedData(batchId, "");
        _setBaseURI(batchId, revealedURI);

        _scrambleOffset(batchId, _key);

        emit TokenURIRevealed(_index, revealedURI);
    }
    /*///////////////////////////////////////////////////////////////
                  Metadata, EIP 165 / 721 / 2981 / 2771 logic
    //////////////////////////////////////////////////////////////*/
    /// @dev Returns the URI for a given tokenId.
    function tokenURI(uint256 _tokenId) public view virtual override(ERC721A, IERC721A) returns (string memory) {
        (uint256 batchId,uint256 index) = _getBatchId(_tokenId);
        string memory batchUri = _getBaseURI(_tokenId);

        if (isEncryptedBatch(batchId)) {
            return string(abi.encodePacked(batchUri, "0"));
        } else {
            uint256 fairMetadataId = _getFairMetadataId(_tokenId, batchId, index);
            return string(abi.encodePacked(batchUri, _toString(fairMetadataId)));
        }
    }

    /// @dev Returns the fair metadata ID for a given tokenId.
    function _getFairMetadataId(
        uint256 _tokenId,
        uint256 _batchId,
        uint256 _indexOfBatchId
    ) private view returns (uint256 fairMetadataId) {
        bytes32 bytesRandom = tokenIdOffset[_batchId];
        if (bytesRandom == bytes32(0)) {
            return _tokenId;
        }

        uint256 randomness = uint256(bytesRandom);
        uint256 prevBatchId;
        if (_indexOfBatchId > 0) {
            prevBatchId = getBatchIdAtIndex(_indexOfBatchId - 1);
        }

        uint256 batchSize = _batchId - prevBatchId;
        uint256 offset = randomness % batchSize;
        fairMetadataId = prevBatchId + (_tokenId + offset) % batchSize;
    }

    string private _baseContractURI;

    function contractURI() public view returns (string memory) {
        return _baseContractURI;
    }

    function setContractURI(string memory _uri) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _baseContractURI = _uri;
    }

    function setBaseURI(uint256 _batchId, string memory _baseURI) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _setBaseURI(_batchId, _baseURI);
    }

    function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(AccessControl, ERC721A, IERC721A, ERC2981)
    returns (bool)
    {
        return ERC721A.supportsInterface(interfaceId) || AccessControl.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId);
    }

    /// @dev Scrambles tokenId offset for a given batchId.
    function _scrambleOffset(uint256 _batchId, bytes calldata _seed) private {
        tokenIdOffset[_batchId] = keccak256(abi.encodePacked(_seed, block.prevrandao, _msgSender(), block.timestamp, blockhash(block.number - 1)));
    }

    function setDefaultRoyalty(address receiver, uint96 feeNumerator)
    external
    onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _setDefaultRoyalty(receiver, feeNumerator);
    }

    function setTokenRoyalty(
        uint tokenId,
        address receiver,
        uint96 feeNumerator
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _setTokenRoyalty(tokenId, receiver, feeNumerator);
    }

    function _msgSender()
    internal
    view
    virtual
    override(Context, ERC2771Context)
    returns (address sender)
    {
        return ERC2771Context._msgSender();
    }

    function _msgData()
    internal
    view
    virtual
    override(Context, ERC2771Context)
    returns (bytes calldata)
    {
        return ERC2771Context._msgData();
    }

    function _contextSuffixLength() internal view virtual override(ERC2771Context, Context) returns (uint) {
        return ERC2771Context._contextSuffixLength();
    }
}
LazyMint.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/ILazyMint.sol";
import "./BatchMintMetadata.sol";

/**
 *  The `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs
 *  at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually
 *  minting a non-zero balance of NFTs of those tokenIds.
 */

abstract contract LazyMint is ILazyMint, BatchMintMetadata {
    /// @notice The tokenId assigned to the next new NFT to be lazy minted.
    uint256 internal nextTokenIdToLazyMint;

    /**
     *  @notice                  Lets an authorized address lazy mint a given amount of NFTs.
     *
     *  @param _amount           The number of NFTs to lazy mint.
     *  @param _baseURIForTokens The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each
     *                           of those NFTs is `${baseURIForTokens}/${tokenId}`.
     *  @param _data             Additional bytes data to be used at the discretion of the consumer of the contract.
     *  @return batchId          A unique integer identifier for the batch of NFTs lazy minted together.
     */
    function _lazyMint(
        uint256 _amount,
        string calldata _baseURIForTokens,
        bytes calldata _data
    ) internal returns (uint256 batchId) {

        if (_amount == 0) {
            revert("0 amt");
        }

        uint256 startId = nextTokenIdToLazyMint;

        (nextTokenIdToLazyMint, batchId) = _batchMintMetadata(startId, _amount, _baseURIForTokens);

        emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _data);

        return batchId;
    }
}
DelayedReveal.sol 81 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/IDelayedReveal.sol";

abstract contract DelayedReveal is IDelayedReveal {
    /// @dev Mapping from tokenId of a batch of tokens => to delayed reveal data.
    mapping(uint256 => bytes) public encryptedData;

    /// @dev Sets the delayed reveal data for a batchId.
    function _setEncryptedData(uint256 _batchId, bytes memory _encryptedData) internal {
        encryptedData[_batchId] = _encryptedData;
    }

    function getRevealURI(uint256 _batchId, bytes calldata _key) public view returns (string memory revealedURI) {
        bytes memory data = encryptedData[_batchId];
        if (data.length == 0) {
            revert("Nothing to reveal");
        }

        (bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(data, (bytes, bytes32));

        revealedURI = string(encryptDecrypt(encryptedURI, _key));

        require(keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) == provenanceHash, "Incorrect key");
    }

    /**
     *  @notice         Encrypt/decrypt data on chain.
     *  @dev            Encrypt/decrypt given `data` with `key`. Uses inline assembly.
     *                  See: https://ethereum.stackexchange.com/questions/69825/decrypt-message-on-chain
     *
     *  @param data     Bytes of data to encrypt/decrypt.
     *  @param key      Secure key used by caller for encryption/decryption.
     *
     *  @return result  Output after encryption/decryption of given data.
     */
    function encryptDecrypt(bytes memory data, bytes calldata key) public pure override returns (bytes memory result) {
        // Store data length on stack for later use
        uint256 length = data.length;

        // solhint-disable-next-line no-inline-assembly
        assembly {
        // Set result to free memory pointer
            result := mload(0x40)
        // Increase free memory pointer by lenght + 32
            mstore(0x40, add(add(result, length), 32))
        // Set result length
            mstore(result, length)
        }

        // Iterate over the data stepping by 32 bytes
        for (uint256 i = 0; i < length; i += 32) {
            // Generate hash of the key and offset
            bytes32 hash = keccak256(abi.encodePacked(key, i));

            bytes32 chunk;
            // solhint-disable-next-line no-inline-assembly
            assembly {
            // Read 32-bytes data chunk
                chunk := mload(add(data, add(i, 32)))
            }
            // XOR the chunk with hash
            chunk ^= hash;
            // solhint-disable-next-line no-inline-assembly
            assembly {
            // Write 32-byte encrypted chunk
                mstore(add(result, add(i, 32)), chunk)
            }
        }
    }

    /**
     *  @notice         Returns whether the relvant batch of NFTs is subject to a delayed reveal.
     *  @dev            Returns `true` if `_batchId`'s base URI is encrypted.
     *  @param _batchId ID of a batch of NFTs.
     */
    function isEncryptedBatch(uint256 _batchId) public view returns (bool) {
        return encryptedData[_batchId].length > 0;
    }
}
SignatureAction.sol 69 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./interfaces/ISignatureAction.sol";

abstract contract SignatureAction is EIP712, ISignatureAction {
    using ECDSA for bytes32;

    bytes32 private constant TYPEHASH =
    keccak256("GenericRequest(uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid,bytes data)");

    /// @dev Mapping from a signed request UID => whether the request is processed.
    mapping(bytes32 => bool) private executed;

    constructor()
    EIP712("SignatureAction", "1")
    {}
    /// @dev Verifies that a request is signed by an authorized account.
    function verify(GenericRequest calldata _req, bytes calldata _signature)
    public
    view
    override
    returns (bool success, address signer)
    {
        signer = _recoverAddress(_req, _signature);
        success = !executed[_req.uid] && _isAuthorizedSigner(signer);
    }

    /// @dev Returns whether a given address is authorized to sign requests.
    function _isAuthorizedSigner(address _signer) internal view virtual returns (bool);

    /// @dev Verifies a request and marks the request as processed.
    function _processRequest(GenericRequest calldata _req, bytes calldata _signature)
    internal
    returns (address signer)
    {
        bool success;
        (success, signer) = verify(_req, _signature);

        if (!success) {
            revert("Invalid");
        }

        if (_req.validityStartTimestamp > block.timestamp || block.timestamp > _req.validityEndTimestamp) {
            revert("expired");
        }

        executed[_req.uid] = true;
    }

    /// @dev Returns the address of the signer of the request.
    function _recoverAddress(GenericRequest calldata _req, bytes calldata _signature) internal view returns (address) {
        return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
    }

    /// @dev Encodes a request for recovery of the signer in `recoverAddress`.
    function _encodeRequest(GenericRequest calldata _req) internal pure returns (bytes memory) {
        return
            abi.encode(
            TYPEHASH,
            _req.validityStartTimestamp,
            _req.validityEndTimestamp,
            _req.uid,
            keccak256(_req.data)
        );
    }
}
ERC721A.sol 1091 lines
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import './IERC721A.sol';

/**
 * @dev Interface of ERC721 token receiver.
 */
interface ERC721A__IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC721A
 *
 * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
 * Non-Fungible Token Standard, including the Metadata extension.
 * Optimized for lower gas during batch mints.
 *
 * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
 * starting from `_startTokenId()`.
 *
 * Assumptions:
 *
 * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is IERC721A {
    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
    struct TokenApprovalRef {
        address value;
    }

    // =============================================================
    //                           CONSTANTS
    // =============================================================

    // Mask of an entry in packed address data.
    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;

    // The bit position of `numberMinted` in packed address data.
    uint256 private constant _BITPOS_NUMBER_MINTED = 64;

    // The bit position of `numberBurned` in packed address data.
    uint256 private constant _BITPOS_NUMBER_BURNED = 128;

    // The bit position of `aux` in packed address data.
    uint256 private constant _BITPOS_AUX = 192;

    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;

    // The bit position of `startTimestamp` in packed ownership.
    uint256 private constant _BITPOS_START_TIMESTAMP = 160;

    // The bit mask of the `burned` bit in packed ownership.
    uint256 private constant _BITMASK_BURNED = 1 << 224;

    // The bit position of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;

    // The bit mask of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;

    // The bit position of `extraData` in packed ownership.
    uint256 private constant _BITPOS_EXTRA_DATA = 232;

    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    // The maximum `quantity` that can be minted with {_mintERC2309}.
    // This limit is to prevent overflows on the address data entries.
    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
    // is required to cause an overflow, which is unrealistic.
    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;

    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // =============================================================
    //                            STORAGE
    // =============================================================

    // The next token ID to be minted.
    uint256 private _currentIndex;

    // The number of tokens burned.
    uint256 private _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned.
    // See {_packedOwnershipOf} implementation for details.
    //
    // Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `startTimestamp`
    // - [224]      `burned`
    // - [225]      `nextInitialized`
    // - [232..255] `extraData`
    mapping(uint256 => uint256) private _packedOwnerships;

    // Mapping owner address to address data.
    //
    // Bits Layout:
    // - [0..63]    `balance`
    // - [64..127]  `numberMinted`
    // - [128..191] `numberBurned`
    // - [192..255] `aux`
    mapping(address => uint256) private _packedAddressData;

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

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

    // =============================================================
    //                          CONSTRUCTOR
    // =============================================================

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    // =============================================================
    //                   TOKEN COUNTING OPERATIONS
    // =============================================================

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Returns the next token ID to be minted.
     */
    function _nextTokenId() internal view virtual returns (uint256) {
        return _currentIndex;
    }

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than `_currentIndex - _startTokenId()` times.
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view virtual returns (uint256) {
        // Counter underflow is impossible as `_currentIndex` does not decrement,
        // and it is initialized to `_startTokenId()`.
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev Returns the total number of tokens burned.
     */
    function _totalBurned() internal view virtual returns (uint256) {
        return _burnCounter;
    }

    // =============================================================
    //                    ADDRESS DATA OPERATIONS
    // =============================================================

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
    }

    /**
     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal virtual {
        uint256 packed = _packedAddressData[owner];
        uint256 auxCasted;
        // Cast `aux` with assembly to avoid redundant masking.
        assembly {
            auxCasted := aux
        }
        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
        _packedAddressData[owner] = packed;
    }

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        // The interface IDs are constants representing the first 4 bytes
        // of the XOR of all function selectors in the interface.
        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
        return
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
    }

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @dev Returns the token collection name.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
    }

    /**
     * @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, it can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return '';
    }

    // =============================================================
    //                     OWNERSHIPS OPERATIONS
    // =============================================================

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        return address(uint160(_packedOwnershipOf(tokenId)));
    }

    /**
     * @dev Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around over time.
     */
    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnershipOf(tokenId));
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct at `index`.
     */
    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnerships[index]);
    }

    /**
     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
     */
    function _initializeOwnershipAt(uint256 index) internal virtual {
        if (_packedOwnerships[index] == 0) {
            _packedOwnerships[index] = _packedOwnershipOf(index);
        }
    }

    /**
     * Returns the packed ownership data of `tokenId`.
     */
    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr)
                if (curr < _currentIndex) {
                    uint256 packed = _packedOwnerships[curr];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // Invariant:
                        // There will always be an initialized ownership slot
                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                        // before an unintialized ownership slot
                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                        // Hence, `curr` will not underflow.
                        //
                        // We can directly compare the packed value.
                        // If the address is zero, packed will be zero.
                        while (packed == 0) {
                            packed = _packedOwnerships[--curr];
                        }
                        return packed;
                    }
                }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
     */
    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
        ownership.addr = address(uint160(packed));
        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
        ownership.burned = packed & _BITMASK_BURNED != 0;
        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
    }

    /**
     * @dev Packs ownership data into a single uint256.
     */
    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
        }
    }

    /**
     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
     */
    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
        // For branchless setting of the `nextInitialized` flag.
        assembly {
            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
        }
    }

    // =============================================================
    //                      APPROVAL OPERATIONS
    // =============================================================

    /**
     * @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) public payable virtual override {
        address owner = ownerOf(tokenId);

        if (_msgSenderERC721A() != owner)
            if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                revert ApprovalCallerNotOwnerNorApproved();
            }

        _tokenApprovals[tokenId].value = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId].value;
    }

    /**
     * @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) public virtual override {
        _operatorApprovals[_msgSenderERC721A()][operator] = approved;
        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
    }

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @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. See {_mint}.
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex && // If within bounds,
            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
    }

    /**
     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
     */
    function _isSenderApprovedOrOwner(
        address approvedAddress,
        address owner,
        address msgSender
    ) private pure returns (bool result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
            msgSender := and(msgSender, _BITMASK_ADDRESS)
            // `msgSender == owner || msgSender == approvedAddress`.
            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
        }
    }

    /**
     * @dev Returns the storage slot and value for the approved address of `tokenId`.
     */
    function _getApprovedSlotAndAddress(uint256 tokenId)
        private
        view
        returns (uint256 approvedAddressSlot, address approvedAddress)
    {
        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
        assembly {
            approvedAddressSlot := tokenApproval.slot
            approvedAddress := sload(approvedAddressSlot)
        }
    }

    // =============================================================
    //                      TRANSFER OPERATIONS
    // =============================================================

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * 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
    ) public payable virtual override {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        // The nested ifs save around 20+ gas over a compound boolean condition.
        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();

        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // We can directly increment and decrement the balances.
            --_packedAddressData[from]; // Updates: `balance -= 1`.
            ++_packedAddressData[to]; // Updates: `balance += 1`.

            // Updates:
            // - `address` to the next owner.
            // - `startTimestamp` to the timestamp of transfering.
            // - `burned` to `false`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                to,
                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @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 memory _data
    ) public payable virtual override {
        transferFrom(from, to, tokenId);
        if (to.code.length != 0)
            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                revert TransferToNonERC721ReceiverImplementer();
            }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token IDs
     * are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token IDs
     * have been transferred. This includes minting.
     * And also called after one token has been burned.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * `from` - Previous owner of the given token ID.
     * `to` - Target address that will receive the token.
     * `tokenId` - Token ID to be transferred.
     * `_data` - Optional data to send along with the call.
     *
     * Returns whether the call correctly returned the expected magic value.
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
            bytes4 retval
        ) {
            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    // =============================================================
    //                        MINT OPERATIONS
    // =============================================================

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _mint(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // `balance` and `numberMinted` have a maximum limit of 2**64.
        // `tokenId` has a maximum limit of 2**256.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            uint256 toMasked;
            uint256 end = startTokenId + quantity;

            // Use assembly to loop and emit the `Transfer` event for gas savings.
            // The duplicated `log4` removes an extra check and reduces stack juggling.
            // The assembly, together with the surrounding Solidity code, have been
            // delicately arranged to nudge the compiler into producing optimized opcodes.
            assembly {
                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                toMasked := and(to, _BITMASK_ADDRESS)
                // Emit the `Transfer` event.
                log4(
                    0, // Start of data (0, since no data).
                    0, // End of data (0, since no data).
                    _TRANSFER_EVENT_SIGNATURE, // Signature.
                    0, // `address(0)`.
                    toMasked, // `to`.
                    startTokenId // `tokenId`.
                )

                // The `iszero(eq(,))` check ensures that large values of `quantity`
                // that overflows uint256 will make the loop run out of gas.
                // The compiler will optimize the `iszero` away for performance.
                for {
                    let tokenId := add(startTokenId, 1)
                } iszero(eq(tokenId, end)) {
                    tokenId := add(tokenId, 1)
                } {
                    // Emit the `Transfer` event. Similar to above.
                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                }
            }
            if (toMasked == 0) revert MintToZeroAddress();

            _currentIndex = end;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * This function is intended for efficient minting only during contract creation.
     *
     * It emits only one {ConsecutiveTransfer} as defined in
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
     * instead of a sequence of {Transfer} event(s).
     *
     * Calling this function outside of contract creation WILL make your contract
     * non-compliant with the ERC721 standard.
     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
     * {ConsecutiveTransfer} event is only permissible during contract creation.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {ConsecutiveTransfer} event.
     */
    function _mintERC2309(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();
        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);

            _currentIndex = startTokenId + quantity;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * See {_mint}.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        _mint(to, quantity);

        unchecked {
            if (to.code.length != 0) {
                uint256 end = _currentIndex;
                uint256 index = end - quantity;
                do {
                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (index < end);
                // Reentrancy protection.
                if (_currentIndex != end) revert();
            }
        }
    }

    /**
     * @dev Equivalent to `_safeMint(to, quantity, '')`.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, '');
    }

    // =============================================================
    //                        BURN OPERATIONS
    // =============================================================

    /**
     * @dev Equivalent to `_burn(tokenId, false)`.
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

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

        address from = address(uint160(prevOwnershipPacked));

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        if (approvalCheck) {
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // Updates:
            // - `balance -= 1`.
            // - `numberBurned += 1`.
            //
            // We can directly decrement the balance, and increment the number burned.
            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;

            // Updates:
            // - `address` to the last owner.
            // - `startTimestamp` to the timestamp of burning.
            // - `burned` to `true`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                from,
                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    // =============================================================
    //                     EXTRA DATA OPERATIONS
    // =============================================================

    /**
     * @dev Directly sets the extra data for the ownership data `index`.
     */
    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
        uint256 packed = _packedOwnerships[index];
        if (packed == 0) revert OwnershipNotInitializedForExtraData();
        uint256 extraDataCasted;
        // Cast `extraData` with assembly to avoid redundant masking.
        assembly {
            extraDataCasted := extraData
        }
        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
        _packedOwnerships[index] = packed;
    }

    /**
     * @dev Called during each token transfer to set the 24bit `extraData` field.
     * Intended to be overridden by the cosumer contract.
     *
     * `previousExtraData` - the value of `extraData` before transfer.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _extraData(
        address from,
        address to,
        uint24 previousExtraData
    ) internal view virtual returns (uint24) {}

    /**
     * @dev Returns the next extra data for the packed ownership data.
     * The returned result is shifted into position.
     */
    function _nextExtraData(
        address from,
        address to,
        uint256 prevOwnershipPacked
    ) private view returns (uint256) {
        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
    }

    // =============================================================
    //                       OTHER OPERATIONS
    // =============================================================

    /**
     * @dev Returns the message sender (defaults to `msg.sender`).
     *
     * If you are writing GSN compatible contracts, you need to override this function.
     */
    function _msgSenderERC721A() internal view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @dev Converts a uint256 to its ASCII string decimal representation.
     */
    function _toString(uint256 value) internal pure virtual returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 1)
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }
}
IERC721A.sol 282 lines
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC721Receiver interface.
     */
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

    /**
     * @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,
        bytes calldata data
    ) external payable;

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @dev Transfers `tokenId` 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 payable;

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

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom}
     * for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

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

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}
BatchMintMetadata.sol 126 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 *  @title   Batch-mint Metadata
 *  @notice  The `BatchMintMetadata` is a contract extension for any base NFT contract. It lets the smart contract
 *           using this extension set metadata for `n` number of NFTs all at once. This is enabled by storing a single
 *           base URI for a batch of `n` NFTs, where the metadata for each NFT in a relevant batch is `baseURI/tokenId`.
 */

contract BatchMintMetadata {
    /// @dev Largest tokenId of each batch of tokens with the same baseURI + 1 {ex: batchId 100 at position 0 includes tokens 0-99}
    uint256[] private batchIds;

    /// @dev Mapping from id of a batch of tokens => to base URI for the respective batch of tokens.
    mapping(uint256 => string) private baseURI;

    /// @dev Mapping from id of a batch of tokens => to whether the base URI for the respective batch of tokens is frozen.
    mapping(uint256 => bool) public batchFrozen;

    /// @dev This event emits when the metadata of all tokens are frozen.
    /// While not currently supported by marketplaces, this event allows
    /// future indexing if desired.
    event MetadataFrozen();

    // @dev This event emits when the metadata of a range of tokens is updated.
    /// So that the third-party platforms such as NFT market could
    /// timely update the images and related attributes of the NFTs.
    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);

    /**
     *  @notice         Returns the count of batches of NFTs.
     *  @dev            Each batch of tokens has an in ID and an associated `baseURI`.
     *                  See {batchIds}.
     */
    function getBaseURICount() public view returns (uint256) {
        return batchIds.length;
    }

    /**
     *  @notice         Returns the ID for the batch of tokens at the given index.
     *  @dev            See {getBaseURICount}.
     *  @param _index   Index of the desired batch in batchIds array.
     */
    function getBatchIdAtIndex(uint256 _index) public view returns (uint256) {
        if (_index >= getBaseURICount()) {
            revert("Invalid index");
        }
        return batchIds[_index];
    }

    /// @dev Returns the id for the batch of tokens the given tokenId belongs to.
    function _getBatchId(uint256 _tokenId) internal view returns (uint256 batchId, uint256 index) {
        uint256 numOfTokenBatches = getBaseURICount();
        uint256[] memory indices = batchIds;

        for (uint256 i = 0; i < numOfTokenBatches; i += 1) {
            if (_tokenId < indices[i]) {
                index = i;
                batchId = indices[i];

                return (batchId, index);
            }
        }

        revert("Invalid tokenId");
    }

    /// @dev Returns the baseURI for a token. The intended metadata URI for the token is baseURI + tokenId.
    function _getBaseURI(uint256 _tokenId) internal view returns (string memory) {
        uint256 numOfTokenBatches = getBaseURICount();
        uint256[] memory indices = batchIds;

        for (uint256 i = 0; i < numOfTokenBatches; i += 1) {
            if (_tokenId < indices[i]) {
                return baseURI[indices[i]];
            }
        }
        revert("Invalid tokenId");
    }

    /// @dev returns the starting tokenId of a given batchId.
    function _getBatchStartId(uint256 _batchID) internal view returns (uint256) {
        uint256 numOfTokenBatches = getBaseURICount();
        uint256[] memory indices = batchIds;

        for (uint256 i = 0; i < numOfTokenBatches; i++) {
            if (_batchID == indices[i]) {
                if (i > 0) {
                    return indices[i - 1];
                }
                return 0;
            }
        }
        revert("Invalid batchId");
    }

    /// @dev Sets the base URI for the batch of tokens with the given batchId.
    function _setBaseURI(uint256 _batchId, string memory _baseURI) internal {
        require(!batchFrozen[_batchId], "Batch frozen");
        baseURI[_batchId] = _baseURI;
        emit BatchMetadataUpdate(_getBatchStartId(_batchId), _batchId);
    }

    /// @dev Freezes the base URI for the batch of tokens with the given batchId.
    function _freezeBaseURI(uint256 _batchId) internal {
        string memory baseURIForBatch = baseURI[_batchId];
        require(bytes(baseURIForBatch).length > 0, "Invalid batch");
        batchFrozen[_batchId] = true;
        emit MetadataFrozen();
    }

    /// @dev Mints a batch of tokenIds and associates a common baseURI to all those Ids.
    function _batchMintMetadata(
        uint256 _startId,
        uint256 _amountToMint,
        string memory _baseURIForTokens
    ) internal returns (uint256 nextTokenIdToMint, uint256 batchId) {
        batchId = _startId + _amountToMint;
        nextTokenIdToMint = batchId;

        batchIds.push(batchId);

        baseURI[batchId] = _baseURIForTokens;
    }
}
ILazyMint.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ILazyMint {
    event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI);
}
IDelayedReveal.sol 10 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IDelayedReveal {
    event TokenURIRevealed(uint256 indexed index, string revealedURI);

    function reveal(uint256 identifier, bytes calldata key) external returns (string memory revealedURI);

    function encryptDecrypt(bytes memory data, bytes calldata key) external pure returns (bytes memory result);
}
Address.sol 159 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
Strings.sol 94 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        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_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        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);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}
ISignatureAction.sol 36 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ISignatureAction {
    /**
     *  @notice The payload that must be signed by an authorized wallet.
     *
     *  @param validityStartTimestamp The UNIX timestamp at and after which a signature is valid.
     *  @param validityEndTimestamp The UNIX timestamp at and after which a signature is invalid/expired.
     *  @param uid A unique non-repeatable ID for the payload.
     *  @param data Arbitrary bytes data to be used at the discretion of the contract.
     */
    struct GenericRequest {
        uint128 validityStartTimestamp;
        uint128 validityEndTimestamp;
        bytes32 uid;
        bytes data;
    }

    /// @notice Emitted when a payload is verified and executed.
    event RequestExecuted(address indexed user, address indexed signer, GenericRequest _req);

    /**
     *  @notice Verfies that a payload is signed by an authorized wallet.
     *
     *  @param req The payload signed by the authorized wallet.
     *  @param signature The signature produced by the authorized wallet signing the given payload.
     *
     *  @return success Whether the payload is signed by the authorized wallet.
     *  @return signer The address of the signer.
     */
    function verify(GenericRequest calldata req, bytes calldata signature)
    external
    view
    returns (bool success, address signer);
}
Router.sol 46 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

import "../interfaces/IRouter.sol";

abstract contract Router is IRouter {

    fallback() external payable virtual {
    /// @dev delegate calls the appropriate implementation smart contract for a given function.
        address implementation = getImplementationForFunction(msg.sig);
        _delegate(implementation);
    }

    receive() external payable virtual {}

    /// @dev delegateCalls an `implementation` smart contract.
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /// @dev Unimplemented. Returns the implementation contract address for a given function signature.
    function getImplementationForFunction(bytes4 _functionSelector) public view virtual returns (address);
}
Multicall.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Multicall.sol)

pragma solidity ^0.8.20;

import {Address} from "./Address.sol";
import {Context} from "./Context.sol";

/**
 * @dev Provides a function to batch together multiple calls in a single external call.
 *
 * Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
 * careful about sending transactions invoking {multicall}. For example, a relay address that filters function
 * selectors won't filter calls nested within a {multicall} operation.
 *
 * NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
 * If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
 * to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
 * {_msgSender} are not propagated to subcalls.
 */
abstract contract Multicall is Context {
    /**
     * @dev Receives and executes a batch of function calls on this contract.
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
        bytes memory context = msg.sender == _msgSender()
            ? new bytes(0)
            : msg.data[msg.data.length - _contextSuffixLength():];

        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
        }
        return results;
    }
}
Math.sol 415 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}
StorageSlot.sol 135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}
ShortStrings.sol 123 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}
IERC2981.sol 23 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../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.
 */
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);
}
IERC5267.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}
AccessControl.sol 209 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

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

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
ERC2981.sol 137 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/common/ERC2981.sol)

pragma solidity ^0.8.20;

import {IERC2981} from "../../interfaces/IERC2981.sol";
import {IERC165, ERC165} from "../../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.
 */
abstract contract ERC2981 is IERC2981, ERC165 {
    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyFraction;
    }

    RoyaltyInfo private _defaultRoyaltyInfo;
    mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo;

    /**
     * @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1).
     */
    error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator);

    /**
     * @dev The default royalty receiver is invalid.
     */
    error ERC2981InvalidDefaultRoyaltyReceiver(address receiver);

    /**
     * @dev The royalty set for an specific `tokenId` is invalid (eg. (numerator / denominator) >= 1).
     */
    error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator);

    /**
     * @dev The royalty receiver for `tokenId` is invalid.
     */
    error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver);

    /**
     * @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 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 {
        uint256 denominator = _feeDenominator();
        if (feeNumerator > denominator) {
            // Royalty fee will exceed the sale price
            revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator);
        }
        if (receiver == address(0)) {
            revert ERC2981InvalidDefaultRoyaltyReceiver(address(0));
        }

        _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 {
        uint256 denominator = _feeDenominator();
        if (feeNumerator > denominator) {
            // Royalty fee will exceed the sale price
            revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator);
        }
        if (receiver == address(0)) {
            revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0));
        }

        _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];
    }
}
ERC721ABurnable.sol 26 lines
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import './IERC721ABurnable.sol';
import '../ERC721A.sol';

/**
 * @title ERC721ABurnable.
 *
 * @dev ERC721A token that can be irreversibly burned (destroyed).
 */
abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
    /**
     * @dev Burns `tokenId`. See {ERC721A-_burn}.
     *
     * Requirements:
     *
     * - The caller must own `tokenId` or be an approved operator.
     */
    function burn(uint256 tokenId) public virtual override {
        _burn(tokenId, true);
    }
}
IRouter.sol 11 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

interface IRouter {
    fallback() external payable;
    receive() external payable;

    function getImplementationForFunction(bytes4 _functionSelector) external view returns (address);
}
BaseRouter.sol 154 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

// Interface
import "../interfaces/IBaseRouter.sol";

// Core
import "../core/Router.sol";

// Utils
import "./utils/StringSet.sol";
import "./utils/DefaultExtensionSet.sol";
import "./utils/ExtensionState.sol";

abstract contract BaseRouter is IBaseRouter, Router, ExtensionState {
    using StringSet for StringSet.Set;

    /*///////////////////////////////////////////////////////////////
                            State variables
    //////////////////////////////////////////////////////////////*/

    /// @notice The DefaultExtensionSet that stores default extensions of the router.
    address public immutable defaultExtensionSet;

    /*///////////////////////////////////////////////////////////////
                                Constructor
    //////////////////////////////////////////////////////////////*/

    constructor(Extension[] memory _extensions) {

        DefaultExtensionSet map = new DefaultExtensionSet();
        defaultExtensionSet = address(map);

        uint256 len = _extensions.length;

        for (uint256 i = 0; i < len; i += 1) {
            map.setExtension(_extensions[i]);
        }
    }

    /*///////////////////////////////////////////////////////////////
                        External functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Adds a new extension to the router.
    function addExtension(Extension memory _extension) external {
        require(_canSetExtension(), "BaseRouter: caller not authorized.");

        _addExtension(_extension);
    }

    /// @dev Updates an existing extension in the router, or overrides a default extension.
    function updateExtension(Extension memory _extension) external {
        require(_canSetExtension(), "BaseRouter: caller not authorized.");

        _updateExtension(_extension);
    }

    /// @dev Removes an existing extension from the router.
    function removeExtension(string memory _extensionName) external {
        require(_canSetExtension(), "BaseRouter: caller not authorized.");

        _removeExtension(_extensionName);
    }

    /*///////////////////////////////////////////////////////////////
                            View functions
    //////////////////////////////////////////////////////////////*/

    /**
     *  @notice Returns all extensions stored. Override default lugins stored in router are
     *          given precedence over default extensions in DefaultExtensionSet.
     */
    function getAllExtensions() external view returns (Extension[] memory allExtensions) {
        Extension[] memory defaultExtensions = IDefaultExtensionSet(defaultExtensionSet).getAllExtensions();
        uint256 defaultExtensionsLen = defaultExtensions.length;

        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
        string[] memory names = data.extensionNames.values();
        uint256 namesLen = names.length;

        uint256 overrides = 0;
        for (uint256 i = 0; i < defaultExtensionsLen; i += 1) {
            if (data.extensionNames.contains(defaultExtensions[i].metadata.name)) {
                overrides += 1;
            }
        }

        uint256 total = (namesLen + defaultExtensionsLen) - overrides;

        allExtensions = new Extension[](total);
        uint256 idx = 0;

        for (uint256 i = 0; i < defaultExtensionsLen; i += 1) {
            string memory name = defaultExtensions[i].metadata.name;
            if (!data.extensionNames.contains(name)) {
                allExtensions[idx] = defaultExtensions[i];
                idx += 1;
            }
        }

        for (uint256 i = 0; i < namesLen; i += 1) {
            allExtensions[idx] = data.extensions[names[i]];
            idx += 1;
        }
    }

    /// @dev Returns the extension metadata and functions for a given extension.
    function getExtension(string memory _extensionName) public view returns (Extension memory) {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
        bool isLocalExtension = data.extensionNames.contains(_extensionName);

        return isLocalExtension ? data.extensions[_extensionName] : IDefaultExtensionSet(defaultExtensionSet).getExtension(_extensionName);
    }

    /// @dev Returns the extension's implementation smart contract address.
    function getExtensionImplementation(string memory _extensionName) external view returns (address) {
        return getExtension(_extensionName).metadata.implementation;
    }

    /// @dev Returns all functions that belong to the given extension contract.
    function getAllFunctionsOfExtension(string memory _extensionName) external view returns (ExtensionFunction[] memory) {
        return getExtension(_extensionName).functions;
    }

    /// @dev Returns the extension metadata for a given function.
    function getExtensionForFunction(bytes4 _functionSelector) public view returns (ExtensionMetadata memory) {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
        ExtensionMetadata memory metadata = data.extensionMetadata[_functionSelector];

        bool isLocalExtension = metadata.implementation != address(0);

        return isLocalExtension ? metadata : IDefaultExtensionSet(defaultExtensionSet).getExtensionForFunction(_functionSelector);
    }

    /// @dev Returns the extension implementation address stored in router, for the given function.
    function getImplementationForFunction(bytes4 _functionSelector)
        public
        view
        override
        returns (address extensionAddress)
    {
        return getExtensionForFunction(_functionSelector).implementation;
    }

    /*///////////////////////////////////////////////////////////////
                        Internal functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Returns whether a extension can be set in the given execution context.
    function _canSetExtension() internal view virtual returns (bool);
}
IAccessControl.sol 98 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
ERC2771Context.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Context variant with ERC2771 support.
 *
 * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll
 * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC2771
 * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected
 * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive`
 * function only accessible if `msg.data.length == 0`.
 *
 * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption.
 * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender}
 * recovery.
 */
abstract contract ERC2771Context is Context {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

    /**
     * @dev Initializes the contract with a trusted forwarder, which will be able to
     * invoke functions on this contract on behalf of other accounts.
     *
     * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}.
     */
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder_) {
        _trustedForwarder = trustedForwarder_;
    }

    /**
     * @dev Returns the address of the trusted forwarder.
     */
    function trustedForwarder() public view virtual returns (address) {
        return _trustedForwarder;
    }

    /**
     * @dev Indicates whether any particular address is the trusted forwarder.
     */
    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return forwarder == trustedForwarder();
    }

    /**
     * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgSender() internal view virtual override returns (address) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
        } else {
            return super._msgSender();
        }
    }

    /**
     * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgData() internal view virtual override returns (bytes calldata) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return msg.data[:calldataLength - contextSuffixLength];
        } else {
            return super._msgData();
        }
    }

    /**
     * @dev ERC-2771 specifies the context as being a single address (20 bytes).
     */
    function _contextSuffixLength() internal view virtual override returns (uint256) {
        return 20;
    }
}
SignedMath.sol 43 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}
IERC721ABurnable.sol 21 lines
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../IERC721A.sol';

/**
 * @dev Interface of ERC721ABurnable.
 */
interface IERC721ABurnable is IERC721A {
    /**
     * @dev Burns `tokenId`. See {ERC721A-_burn}.
     *
     * Requirements:
     *
     * - The caller must own `tokenId` or be an approved operator.
     */
    function burn(uint256 tokenId) external;
}
IExtension.sol 63 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

interface IExtension {
    /*///////////////////////////////////////////////////////////////
                                Structs
    //////////////////////////////////////////////////////////////*/

    /**
     *  @notice A extension's metadata.
     *
     *  @param name             The unique name of the extension.
     *  @param metadataURI      The URI where the metadata for the extension lives.
     *  @param implementation   The implementation smart contract address of the extension.
     */
    struct ExtensionMetadata {
        string name;
        string metadataURI;
        address implementation;
    }

    /**
     *  @notice An interface to describe a extension's function.
     *
     *  @param functionSelector    The 4 byte selector of the function.
     *  @param functionSignature   Function signature as a string. E.g. "transfer(address,address,uint256)"
     */
    struct ExtensionFunction {
        bytes4 functionSelector;
        string functionSignature;
    }

    /**
     *  @notice An interface to describe an extension.
     *
     *  @param metadata     The extension's metadata; it's name, metadata URI and implementation contract address.
     *  @param functions    The functions that belong to the extension.
     */
    struct Extension {
        ExtensionMetadata metadata;
        ExtensionFunction[] functions;
    }

    /*///////////////////////////////////////////////////////////////
                                Events
    //////////////////////////////////////////////////////////////*/

    /// @dev Emitted when a extension is added; emitted for each function of the extension.
    event ExtensionAdded(address indexed extensionAddress, bytes4 indexed functionSelector, string functionSignature);

    /// @dev Emitted when extension is updated; emitted for each function of the extension.
    event ExtensionUpdated(
        address indexed oldExtensionAddress,
        address indexed newExtensionAddress,
        bytes4 indexed functionSelector,
        string functionSignature
    );

    /// @dev Emitted when a extension is removed; emitted for each function of the extension.
    event ExtensionRemoved(address indexed extensionAddress, bytes4 indexed functionSelector, string functionSignature);
}
ECDSA.sol 174 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}
IBaseRouter.sol 21 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

import "./IDefaultExtensionSet.sol";

interface IBaseRouter is IDefaultExtensionSet {
    /*///////////////////////////////////////////////////////////////
                        External functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Adds a new extension to the router.
    function addExtension(Extension memory extension) external;

    /// @dev Updates an existing extension in the router, or overrides a default extension.
    function updateExtension(Extension memory extension) external;

    /// @dev Removes an existing extension from the router.
    function removeExtension(string memory extensionName) external;
}
EIP712.sol 160 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}
StringSet.sol 172 lines
// SPDX-License-Identifier: Apache 2.0
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

library StringSet {
    struct Set {
        // Storage of set values
        string[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(string => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, string memory value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, string memory value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                string memory lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, string memory value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (string memory) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (string[] memory) {
        return set._values;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Set storage set, string memory value) internal returns (bool) {
        return _add(set, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Set storage set, string memory value) internal returns (bool) {
        return _remove(set, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Set storage set, string memory value) internal view returns (bool) {
        return _contains(set, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Set storage set) internal view returns (uint256) {
        return _length(set);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Set storage set, uint256 index) internal view returns (string memory) {
        return _at(set, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Set storage set) internal view returns (string[] memory) {
        return _values(set);
    }
}
ERC165.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./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);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @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);
}
ExtensionState.sol 134 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

// Interface
import "../../interfaces/IExtension.sol";

// Extensions
import "./StringSet.sol";

library ExtensionStateStorage {
    bytes32 public constant EXTENSION_STATE_STORAGE_POSITION = keccak256("extension.state.storage");

    struct Data {
        /// @dev Set of names of all extensions stored.
        StringSet.Set extensionNames;
        /// @dev Mapping from extension name => `Extension` i.e. extension metadata and functions.
        mapping(string => IExtension.Extension) extensions;
        /// @dev Mapping from function selector => extension metadata of the extension the function belongs to.
        mapping(bytes4 => IExtension.ExtensionMetadata) extensionMetadata;
    }

    function extensionStateStorage() internal pure returns (Data storage extensionStateData) {
        bytes32 position = EXTENSION_STATE_STORAGE_POSITION;
        assembly {
            extensionStateData.slot := position
        }
    }
}

contract ExtensionState is IExtension {
    using StringSet for StringSet.Set;

    /*///////////////////////////////////////////////////////////////
                        Internal functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Stores a new extension in the contract.
    function _addExtension(Extension memory _extension) internal {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();

        string memory name = _extension.metadata.name;

        require(data.extensionNames.add(name), "ExtensionState: extension already exists.");
        data.extensions[name].metadata = _extension.metadata;

        require(_extension.metadata.implementation != address(0), "ExtensionState: adding extension without implementation.");

        uint256 len = _extension.functions.length;
        for (uint256 i = 0; i < len; i += 1) {
            require(
                _extension.functions[i].functionSelector ==
                    bytes4(keccak256(abi.encodePacked(_extension.functions[i].functionSignature))),
                "ExtensionState: fn selector and signature mismatch."
            );
            require(
                data.extensionMetadata[_extension.functions[i].functionSelector].implementation == address(0),
                "ExtensionState: extension already exists for function."
            );

            data.extensionMetadata[_extension.functions[i].functionSelector] = _extension.metadata;
            data.extensions[name].functions.push(_extension.functions[i]);

            emit ExtensionAdded(
                _extension.metadata.implementation,
                _extension.functions[i].functionSelector,
                _extension.functions[i].functionSignature
            );
        }
    }

    /// @dev Updates / overrides an existing extension in the contract.
    function _updateExtension(Extension memory _extension) internal {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();

        string memory name = _extension.metadata.name;
        require(data.extensionNames.contains(name), "ExtensionState: extension does not exist.");

        address oldImplementation = data.extensions[name].metadata.implementation;
        require(_extension.metadata.implementation != oldImplementation, "ExtensionState: re-adding same extension.");

        data.extensions[name].metadata = _extension.metadata;

        ExtensionFunction[] memory oldFunctions = data.extensions[name].functions;
        uint256 oldFunctionsLen = oldFunctions.length;

        delete data.extensions[name].functions;

        for (uint256 i = 0; i < oldFunctionsLen; i += 1) {
            delete data.extensionMetadata[oldFunctions[i].functionSelector];
        }

        uint256 len = _extension.functions.length;
        for (uint256 i = 0; i < len; i += 1) {
            require(
                _extension.functions[i].functionSelector ==
                    bytes4(keccak256(abi.encodePacked(_extension.functions[i].functionSignature))),
                "ExtensionState: fn selector and signature mismatch."
            );

            data.extensionMetadata[_extension.functions[i].functionSelector] = _extension.metadata;
            data.extensions[name].functions.push(_extension.functions[i]);

            emit ExtensionUpdated(
                oldImplementation,
                _extension.metadata.implementation,
                _extension.functions[i].functionSelector,
                _extension.functions[i].functionSignature
            );
        }
    }

    /// @dev Removes an existing extension from the contract.
    function _removeExtension(string memory _extensionName) internal {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();

        require(data.extensionNames.remove(_extensionName), "ExtensionState: extension does not exist.");

        address implementation = data.extensions[_extensionName].metadata.implementation;
        ExtensionFunction[] memory extensionFunctions = data.extensions[_extensionName].functions;
        delete data.extensions[_extensionName];

        uint256 len = extensionFunctions.length;
        for (uint256 i = 0; i < len; i += 1) {
            emit ExtensionRemoved(
                implementation,
                extensionFunctions[i].functionSelector,
                extensionFunctions[i].functionSignature
            );
            delete data.extensionMetadata[extensionFunctions[i].functionSelector];
        }
    }
}
IDefaultExtensionSet.sol 27 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

import "./IExtension.sol";

interface IDefaultExtensionSet is IExtension {
    /*///////////////////////////////////////////////////////////////
                            View functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Returns all extensions stored.
    function getAllExtensions() external view returns (Extension[] memory);

    /// @dev Returns all functions that belong to the given extension contract.
    function getAllFunctionsOfExtension(string memory extensionName) external view returns (ExtensionFunction[] memory);

    /// @dev Returns the extension metadata for a given function.
    function getExtensionForFunction(bytes4 functionSelector) external view returns (ExtensionMetadata memory);

    /// @dev Returns the extension's implementation smart contract address.
    function getExtensionImplementation(string memory extensionName) external view returns (address);

    /// @dev Returns the extension metadata and functions for a given extension.
    function getExtension(string memory extensionName) external view returns (Extension memory);
}
MessageHashUtils.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

import {Strings} from "../Strings.sol";

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}
DefaultExtensionSet.sol 82 lines
// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)

pragma solidity ^0.8.0;

// Interface
import "../../interfaces/IDefaultExtensionSet.sol";

// Extensions
import "./ExtensionState.sol";

contract DefaultExtensionSet is IDefaultExtensionSet, ExtensionState {
    using StringSet for StringSet.Set;

    /*///////////////////////////////////////////////////////////////
                            State variables
    //////////////////////////////////////////////////////////////*/

    /// @notice The deployer of DefaultExtensionSet.
    address private deployer;

    /*///////////////////////////////////////////////////////////////
                            Constructor
    //////////////////////////////////////////////////////////////*/

    constructor() {
        deployer = msg.sender;
    }

    /*///////////////////////////////////////////////////////////////
                            External functions
    //////////////////////////////////////////////////////////////*/

    /// @notice Stores a extension in the DefaultExtensionSet.
    function setExtension(Extension memory _extension) external {
        require(msg.sender == deployer, "DefaultExtensionSet: unauthorized caller.");
        _addExtension(_extension);
    }

    /*///////////////////////////////////////////////////////////////
                            View functions
    //////////////////////////////////////////////////////////////*/

    /// @notice Returns all extensions stored.
    function getAllExtensions() external view returns (Extension[] memory allExtensions) {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();

        string[] memory names = data.extensionNames.values();
        uint256 len = names.length;

        allExtensions = new Extension[](len);

        for (uint256 i = 0; i < len; i += 1) {
            allExtensions[i] = data.extensions[names[i]];
        }
    }

    /// @notice Returns the extension metadata and functions for a given extension.
    function getExtension(string memory _extensionName) public view returns (Extension memory) {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
        require(data.extensionNames.contains(_extensionName), "DefaultExtensionSet: extension does not exist.");
        return data.extensions[_extensionName];
    }

    /// @notice Returns the extension's implementation smart contract address.
    function getExtensionImplementation(string memory _extensionName) external view returns (address) {
        return getExtension(_extensionName).metadata.implementation;
    }

    /// @notice Returns all functions that belong to the given extension contract.
    function getAllFunctionsOfExtension(string memory _extensionName) external view returns (ExtensionFunction[] memory) {
        return getExtension(_extensionName).functions;
    }

    /// @notice Returns the extension metadata for a given function.
    function getExtensionForFunction(bytes4 _functionSelector) external view returns (ExtensionMetadata memory) {
        ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
        ExtensionMetadata memory metadata = data.extensionMetadata[_functionSelector];
        require(metadata.implementation != address(0), "DefaultExtensionSet: no extension for function.");
        return metadata;
    }
}

Read Contract

DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
balanceOf 0x70a08231 → uint256
batchFrozen 0x83040532 → bool
contractURI 0xe8a3d485 → string
defaultExtensionSet 0x1ee8b41b → address
eip712Domain 0x84b0196e → bytes1, string, string, uint256, address, bytes32, uint256[]
encryptDecrypt 0xe7150322 → bytes
encryptedData 0xa05112fc → bytes
getAllExtensions 0x4a00cc48 → tuple[]
getAllFunctionsOfExtension 0x012b8729 → tuple[]
getApproved 0x081812fc → address
getBaseURICount 0x63b45e2d → uint256
getBatchIdAtIndex 0x2419f51b → uint256
getExtension 0xc22707ee → tuple
getExtensionForFunction 0x212f6912 → tuple
getExtensionImplementation 0x7c3b1137 → address
getImplementationForFunction 0xce0b6013 → address
getRevealURI 0x9fc4d68f → string
getRoleAdmin 0x248a9ca3 → bytes32
hasRole 0x91d14854 → bool
isApprovedForAll 0xe985e9c5 → bool
isEncryptedBatch 0x492e224b → bool
isTrustedForwarder 0x572b6c05 → bool
name 0x06fdde03 → string
ownerOf 0x6352211e → address
royaltyInfo 0x2a55205a → address, uint256
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
tokenURI 0xc87b56dd → string
totalSupply 0x18160ddd → uint256
trustedForwarder 0x7da0a877 → address
verify 0x90267fbf → bool, address

Write Contract 21 functions

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

addExtension 0xfa0d3bb8
tuple _extension
approve 0x095ea7b3
address to
uint256 tokenId
burn 0x42966c68
uint256 tokenId
claimWithSignature 0x51511639
tuple _req
bytes _signature
returns: address
grantRole 0x2f2ff15d
bytes32 role
address account
lazyMint 0xd37c353b
uint256 _amount
string _baseURIForTokens
bytes _data
returns: uint256
mint 0x40c10f19
address to
uint256 quantity
multicall 0xac9650d8
bytes[] data
returns: bytes[]
removeExtension 0xee7d2adf
string _extensionName
renounceRole 0x36568abe
bytes32 role
address callerConfirmation
reveal 0xce805642
uint256 _index
bytes _key
returns: string
revokeRole 0xd547741f
bytes32 role
address account
safeTransferFrom 0x42842e0e
address from
address to
uint256 tokenId
safeTransferFrom 0xb88d4fde
address from
address to
uint256 tokenId
bytes _data
setApprovalForAll 0xa22cb465
address operator
bool approved
setBaseURI 0x33cfcb9f
uint256 _batchId
string _baseURI
setContractURI 0x938e3d7b
string _uri
setDefaultRoyalty 0x04634d8d
address receiver
uint96 feeNumerator
setTokenRoyalty 0x5944c753
uint256 tokenId
address receiver
uint96 feeNumerator
transferFrom 0x23b872dd
address from
address to
uint256 tokenId
updateExtension 0x7ac9ab4a
tuple _extension

Recent Transactions

No transactions found for this address