Address: 0x6e9c5390A2D61dBbbaB6CAd685aA61cc666AC59A
Balance (XRP): 0 XRP
Bytecode: 0x60806040526004361015610013575b611806565b61001e60003561024c565b8062fdd58e1461024757806301ffc9a71461024257806304634d8d1461023d57806306fdde03146102385780630b5ee006146102335780630bb310de1461022e5780630e89341c1461022957806318160ddd1461022457806320ec271b1461021f578063248a9ca31461021a5780632693ebf2146102155780632a55205a146102105780632eb2c2d61461020b5780632f2ff15d1461020657806336568abe146102015780634e1273f4146101fc5780635944c753146101f75780636c0360eb146101f2578063731133e9146101ed5780637e518ec8146101e85780638ff83ac1146101e35780639010d07c146101de57806391d14854146101d9578063938e3d7b146101d45780639d043a66146101cf578063a217fddf146101ca578063a22cb465146101c5578063b390c0ab146101c0578063b48ab8b6146101bb578063ca15c873146101b6578063d547741f146101b1578063e8a3d485146101ac578063e985e9c5146101a7578063ed4c2ac7146101a25763f242432a0361000e576117cc565b611728565b6116f2565b61168f565b61164b565b611616565b6115df565b61151b565b6114e7565b611460565b6113ed565b611325565b6112ef565b6112b9565b611238565b61113b565b611104565b610ff3565b610faf565b610f3b565b610dc7565b610d93565b610d28565b610bcb565b610b37565b610ab1565b610a14565b6108e5565b610875565b610823565b6107d1565b6106bf565b610465565b6103c7565b61031a565b60e01c90565b60405190565b600080fd5b600080fd5b600080fd5b60018060a01b031690565b61027b90610267565b90565b61028781610272565b0361028e57565b600080fd5b905035906102a08261027e565b565b90565b6102ae816102a2565b036102b557565b600080fd5b905035906102c7826102a5565b565b91906040838203126102f257806102e66102ef9260008601610293565b936020016102ba565b90565b61025d565b610300906102a2565b9052565b9190610318906000602085019401906102f7565b565b3461034b576103476103366103303660046102c9565b90611810565b61033e610252565b91829182610304565b0390f35b610258565b63ffffffff60e01b1690565b61036581610350565b0361036c57565b600080fd5b9050359061037e8261035c565b565b9060208282031261039a5761039791600001610371565b90565b61025d565b151590565b6103ad9061039f565b9052565b91906103c5906000602085019401906103a4565b565b346103f7576103f36103e26103dd366004610380565b611839565b6103ea610252565b918291826103b1565b0390f35b610258565b6bffffffffffffffffffffffff1690565b610416816103fc565b0361041d57565b600080fd5b9050359061042f8261040d565b565b919060408382031261045a578061044e6104579260008601610293565b93602001610422565b90565b61025d565b60000190565b346104945761047e610478366004610431565b906118db565b610486610252565b806104908161045f565b0390f35b610258565b60009103126104a457565b61025d565b634e487b7160e01b600052600060045260246000fd5b634e487b7160e01b600052602260045260246000fd5b90600160028304921680156104f5575b60208310146104f057565b6104bf565b91607f16916104e5565b60209181520190565b600052602060002090565b906000929180549061052e610527836104d5565b80946104ff565b91600181169081600014610587575060011461054a575b505050565b6105579192939450610508565b916000925b81841061056f5750500190388080610545565b6001816020929593955484860152019101929061055c565b92949550505060ff1916825215156020020190388080610545565b906105ac91610513565b90565b601f801991011690565b634e487b7160e01b600052604160045260246000fd5b906105d9906105af565b810190811067ffffffffffffffff8211176105f357604052565b6105b9565b9061061861061192610608610252565b938480926105a2565b03836105cf565b565b9060001061062e5761062b906105f8565b90565b6104a9565b610640600860009061061a565b90565b5190565b60209181520190565b60005b838110610664575050906000910152565b806020918301518185015201610653565b61069461069d6020936106a29361068b81610643565b93848093610647565b95869101610650565b6105af565b0190565b6106bc9160208201916000818403910152610675565b90565b346106ef576106cf366004610499565b6106eb6106da610633565b6106e2610252565b918291826106a6565b0390f35b610258565b600080fd5b600080fd5b9061071161070a610252565b92836105cf565b565b67ffffffffffffffff81116107315761072d6020916105af565b0190565b6105b9565b90826000939282370152565b9092919261075761075282610713565b6106fe565b938185526020850190828401116107735761077192610736565b565b6106f9565b9080601f830112156107965781602061079393359101610742565b90565b6106f4565b906020828203126107cc57600082013567ffffffffffffffff81116107c7576107c49201610778565b90565b610262565b61025d565b346107ff576107e96107e436600461079b565b611b1c565b6107f1610252565b806107fb8161045f565b0390f35b610258565b9060208282031261081e5761081b91600001610293565b90565b61025d565b346108515761083b610836366004610804565b611bf9565b610843610252565b8061084d8161045f565b0390f35b610258565b906020828203126108705761086d916000016102ba565b90565b61025d565b346108a5576108a161089061088b366004610856565b611d23565b610898610252565b918291826106a6565b0390f35b610258565b1c90565b90565b6108c19060086108c693026108aa565b6108ae565b90565b906108d491546108b1565b90565b6108e26000806108c9565b90565b34610915576108f5366004610499565b6109116109006108d7565b610908610252565b91829182610304565b0390f35b610258565b67ffffffffffffffff81116109325760208091020190565b6105b9565b600080fd5b9092919261095161094c8261091a565b6106fe565b938185526020808601920283019281841161098e57915b8383106109755750505050565b6020809161098384866102ba565b815201920191610968565b610937565b9080601f830112156109b1578160206109ae9335910161093c565b90565b6106f4565b919091604081840312610a0f57600081013567ffffffffffffffff8111610a0a57836109e3918301610993565b92602082013567ffffffffffffffff8111610a0557610a029201610993565b90565b610262565b610262565b61025d565b34610a4357610a2d610a273660046109b6565b90611d6d565b610a35610252565b80610a3f8161045f565b0390f35b610258565b90565b610a5481610a48565b03610a5b57565b600080fd5b90503590610a6d82610a4b565b565b90602082820312610a8957610a8691600001610a60565b90565b61025d565b610a9790610a48565b9052565b9190610aaf90600060208501940190610a8e565b565b34610ae157610add610acc610ac7366004610a6f565b611dcf565b610ad4610252565b91829182610a9b565b0390f35b610258565b90565b610afd610af8610b02926102a2565b610ae6565b6102a2565b90565b90610b0f90610ae9565b600052602052604060002090565b610b3490610b2f600191600092610b05565b6108c9565b90565b34610b6757610b63610b52610b4d366004610856565b610b1d565b610b5a610252565b91829182610304565b0390f35b610258565b9190604083820312610b955780610b89610b9292600086016102ba565b936020016102ba565b90565b61025d565b610ba390610272565b9052565b916020610bc9929493610bc260408201966000830190610b9a565b01906102f7565b565b34610bfd57610be4610bde366004610b6c565b90611fc1565b90610bf9610bf0610252565b92839283610ba7565b0390f35b610258565b600080fd5b909182601f83011215610c415781359167ffffffffffffffff8311610c3c576020019260208302840111610c3757565b610937565b610c02565b6106f4565b909182601f83011215610c805781359167ffffffffffffffff8311610c7b576020019260018302840111610c7657565b610937565b610c02565b6106f4565b9160a083830312610d2357610c9d8260008501610293565b92610cab8360208301610293565b92604082013567ffffffffffffffff8111610d1e5781610ccc918401610c07565b929093606082013567ffffffffffffffff8111610d195783610cef918401610c07565b929093608082013567ffffffffffffffff8111610d1457610d109201610c46565b9091565b610262565b610262565b610262565b61025d565b34610d6057610d4a610d3b366004610c85565b9695909594919493929361209c565b610d52610252565b80610d5c8161045f565b0390f35b610258565b9190604083820312610d8e5780610d82610d8b9260008601610a60565b93602001610293565b90565b61025d565b34610dc257610dac610da6366004610d65565b90612338565b610db4610252565b80610dbe8161045f565b0390f35b610258565b34610df657610de0610dda366004610d65565b906123ee565b610de8610252565b80610df28161045f565b0390f35b610258565b909182601f83011215610e355781359167ffffffffffffffff8311610e30576020019260208302840111610e2b57565b610937565b610c02565b6106f4565b9091604082840312610e9557600082013567ffffffffffffffff8111610e905783610e66918401610dfb565b929093602082013567ffffffffffffffff8111610e8b57610e879201610c07565b9091565b610262565b610262565b61025d565b5190565b60209181520190565b60200190565b610eb6906102a2565b9052565b90610ec781602093610ead565b0190565b60200190565b90610eee610ee8610ee184610e9a565b8093610e9e565b92610ea7565b9060005b818110610eff5750505090565b909192610f18610f126001928651610eba565b94610ecb565b9101919091610ef2565b610f389160208201916000818403910152610ed1565b90565b34610f6f57610f6b610f5a610f51366004610e3a565b92919091612422565b610f62610252565b91829182610f22565b0390f35b610258565b9091606082840312610faa57610fa7610f9084600085016102ba565b93610f9e8160208601610293565b93604001610422565b90565b61025d565b34610fde57610fc8610fc2366004610f74565b916124bf565b610fd0610252565b80610fda8161045f565b0390f35b610258565b610ff0600960009061061a565b90565b3461102357611003366004610499565b61101f61100e610fe3565b611016610252565b918291826106a6565b0390f35b610258565b67ffffffffffffffff8111611046576110426020916105af565b0190565b6105b9565b9092919261106061105b82611028565b6106fe565b9381855260208501908284011161107c5761107a92610736565b565b6106f9565b9080601f8301121561109f5781602061109c9335910161104b565b90565b6106f4565b906080828203126110ff576110bc8160008401610293565b926110ca82602085016102ba565b926110d883604083016102ba565b92606082013567ffffffffffffffff81116110fa576110f79201611081565b90565b610262565b61025d565b34611136576111206111173660046110a4565b9291909161251e565b611128610252565b806111328161045f565b0390f35b610258565b346111695761115361114e36600461079b565b612554565b61115b610252565b806111658161045f565b0390f35b610258565b919061010083820312611233576111888160008501610293565b92602081013567ffffffffffffffff811161122e57826111a9918301610778565b92604082013567ffffffffffffffff811161122957836111ca918401610778565b92606083013567ffffffffffffffff811161122457816111eb918501610778565b926111f98260808301610293565b9261122161120a8460a08501610422565b936112188160c08601610293565b9360e001610a60565b90565b610262565b610262565b610262565b61025d565b346112705761125a61124b36600461116e565b969590959491949392936125cb565b611262610252565b8061126c8161045f565b0390f35b610258565b919060408382031261129e578061129261129b9260008601610a60565b936020016102ba565b90565b61025d565b91906112b790600060208501940190610b9a565b565b346112ea576112e66112d56112cf366004611275565b90612691565b6112dd610252565b918291826112a3565b0390f35b610258565b346113205761131c61130b611305366004610d65565b906126e9565b611313610252565b918291826103b1565b0390f35b610258565b346113535761133d61133836600461079b565b61273c565b611345610252565b8061134f8161045f565b0390f35b610258565b600080fd5b908160c091031261136b5790565b611358565b908160e091031261137e5790565b611358565b916060838303126113e85761139b8260008501610293565b92602081013567ffffffffffffffff81116113e357836113bc91830161135d565b92604082013567ffffffffffffffff81116113de576113db9201611370565b90565b610262565b610262565b61025d565b3461141e5761141a611409611403366004611383565b91612a9a565b611411610252565b91829182610a9b565b0390f35b610258565b90565b60001b90565b61144061143b61144592611423565b611426565b610a48565b90565b611452600061142c565b90565b61145d611448565b90565b3461149057611470366004610499565b61148c61147b611455565b611483610252565b91829182610a9b565b0390f35b610258565b61149e8161039f565b036114a557565b600080fd5b905035906114b782611495565b565b91906040838203126114e257806114d66114df9260008601610293565b936020016114aa565b90565b61025d565b34611516576115006114fa3660046114b9565b90612b3b565b611508610252565b806115128161045f565b0390f35b610258565b3461154a5761153461152e366004610b6c565b90612b8b565b61153c610252565b806115468161045f565b0390f35b610258565b906080828203126115da576115678160008401610293565b92602083013567ffffffffffffffff81116115d55782611588918501610993565b92604081013567ffffffffffffffff81116115d057836115a9918301610993565b92606082013567ffffffffffffffff81116115cb576115c89201611081565b90565b610262565b610262565b610262565b61025d565b34611611576115fb6115f236600461154f565b92919091612bc8565b611603610252565b8061160d8161045f565b0390f35b610258565b346116465761164261163161162c366004610a6f565b612bd6565b611639610252565b91829182610304565b0390f35b610258565b3461167a5761166461165e366004610d65565b90612c26565b61166c610252565b806116768161045f565b0390f35b610258565b61168c600a60009061061a565b90565b346116bf5761169f366004610499565b6116bb6116aa61167f565b6116b2610252565b918291826106a6565b0390f35b610258565b91906040838203126116ed57806116e16116ea9260008601610293565b93602001610293565b90565b61025d565b346117235761171f61170e6117083660046116c4565b90612c32565b611716610252565b918291826103b1565b0390f35b610258565b346117565761174061173b366004610a6f565b612cc1565b611748610252565b806117528161045f565b0390f35b610258565b91909160a0818403126117c7576117758360008301610293565b926117838160208401610293565b9261179182604085016102ba565b9261179f83606083016102ba565b92608082013567ffffffffffffffff81116117c2576117be9201610c46565b9091565b610262565b61025d565b34611801576117eb6117df36600461175b565b94939093929192612ccc565b6117f3610252565b806117fd8161045f565b0390f35b610258565b600080fd5b600090565b61181861180b565b50679a31110384e0b0c960205260145260005260406000205490565b600090565b611841611834565b5063c79b8b5f60e01b61185c61185683610350565b91610350565b148015611880575b908115611870575b5090565b61187a9150612e9b565b3861186c565b5061188a81612e9b565b611864565b7f6db4061a20ca83a3be756ee172bd37a029093ac5afe4ce968c6d5435b43cb01190565b906118cd916118c86118c361188f565b612edf565b6118cf565b565b906118d9916130f9565b565b906118e5916118b3565b565b7fe02a0315b383857ac496e9d2b2546a699afaeb4e5e83a1fdef64376d0b74e5a590565b6119249061191f61191a6118e7565b612edf565b611b0f565b565b601f602091010490565b1b90565b9190600861195091029161194a60001984611930565b92611930565b9181191691161790565b90565b919061197361196e61197b93610ae9565b61195a565b908354611934565b9055565b6119919161198b61180b565b9161195d565b565b5b81811061199f575050565b806119ad600060019361197f565b01611994565b9190601f81116119c3575b505050565b6119cf6119f493610508565b9060206119db84611926565b830193106119fc575b6119ed90611926565b0190611993565b3880806119be565b91506119ed819290506119e4565b90611a1b90600019906008026108aa565b191690565b81611a2a91611a0a565b906002021790565b90611a3c81610643565b9067ffffffffffffffff8211611afe57611a6082611a5a85546104d5565b856119b3565b602090601f8311600114611a9557918091611a8493600092611a89575b5050611a20565b90555b565b90915001513880611a7d565b601f19831691611aa485610508565b9260005b818110611ae657509160029391856001969410611acc575b50505002019055611a87565b611adc910151601f841690611a0a565b9055388080611ac0565b91936020600181928787015181550195019201611aa8565b6105b9565b90611b0d91611a32565b565b611b1a906008611b03565b565b611b259061190b565b565b7f70649ec320b507febad3e8ef750e5f580b9ae32f9f50d4c7b121332c8197153090565b611b6490611b5f611b5a611b27565b612edf565b611be4565b565b611b7a611b75611b7f92610267565b610ae6565b610267565b90565b611b8b90611b66565b90565b611b9790611b82565b90565b90611bab60018060a01b0391611426565b9181191691161790565b611bbe90611b82565b90565b90565b90611bd9611bd4611be092611bb5565b611bc1565b8254611b9a565b9055565b611bf0611bf791611b8e565b6006611bc4565b565b611c0290611b4b565b565b606090565b905090565b9060009291805490611c29611c22836104d5565b8094611c09565b91600181169081600014611c7d5750600114611c45575b505050565b611c529192939450610508565b6000905b838210611c695750500190388080611c40565b600181602092548486015201910190611c56565b92949550505060ff19168252801515020190388080611c40565b611cbc611cb392602092611caa81610643565b94858093611c09565b93849101610650565b0190565b60007f2e6a736f6e000000000000000000000000000000000000000000000000000000910152565b611cf460058092611c09565b611cfd81611cc0565b0190565b91611d12611d1d93611d1893611c0e565b90611c97565b611ce8565b90565b90565b611d6a90611d2f611c04565b50611d65611d3e600992613173565b91611d56611d4a610252565b93849260208401611d01565b602082018103825203826105cf565b611d20565b90565b611d7a91339190916132c1565b565b600090565b611d8a90610a48565b90565b90611d9790611d81565b600052602052604060002090565b60001c90565b90565b611dba611dbf91611da5565b611dab565b90565b611dcc9054611dae565b90565b6001611de8611dee92611de0611d7c565b506004611d8d565b01611dc2565b90565b600090565b90611e0090610ae9565b600052602052604060002090565b60018060a01b031690565b611e25611e2a91611da5565b611e0e565b90565b611e379054611e19565b90565b90611e4490610272565b9052565b60a01c90565b6bffffffffffffffffffffffff1690565b611e6b611e7091611e48565b611e4e565b90565b611e7d9054611e5f565b90565b90611e8a906103fc565b9052565b611e9860406106fe565b90565b90611ed2611ec96000611eac611e8e565b94611ec3611ebb838301611e2d565b838801611e3a565b01611e73565b60208401611e80565b565b611edd90611e9b565b90565b611eea9051610272565b90565b611f01611efc611f0692611423565b610ae6565b610267565b90565b611f1290611eed565b90565b611f1f90516103fc565b90565b611f36611f31611f3b926103fc565b610ae6565b6102a2565b90565b634e487b7160e01b600052601160045260246000fd5b611f63611f69919392936102a2565b926102a2565b91611f758382026102a2565b928184041490151715611f8457565b611f3e565b634e487b7160e01b600052601260045260246000fd5b611fab611fb1916102a2565b916102a2565b908115611fbc570490565b611f89565b611fe4611fe991939293611fd3611df1565b50611fdc61180b565b506003611df6565b611ed4565b91611ff660008401611ee0565b61201161200b6120066000611f09565b610272565b91610272565b1461205e575b600061205361203d61205a9361203761203260208901611f15565b611f22565b90611f54565b61204d6120486133cc565b611f22565b90611f9f565b9301611ee0565b9190565b915061205a600061205361203d6120756002611ed4565b959350505050612017565b61208b91369161093c565b90565b61209991369161104b565b90565b9693969590949192956120ad6133e3565b6122e6575b8287036122d85760601b679a31110384e0b0c9179460601b679a31110384e0b0c91791856020528560601c958360601c9384156122ca578733036122ae575b8860051b805b61224e57505050828660207f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb604051604081528b8d8160051b948286936040860152838d6060870137836060018286015260608486010190815201376080339380010190a46121646133f1565b612231575b50813b61217a575b50505050505050565b602080809786946000528060c06040519b8c9a63bc197c818c5233868d015260408c015260a060608c01528a8360051b998a9586948593015260e08d01378160c00160808c015260e0828c010192835284830137818060e0010160a08a01520101838152013780010161010401601c60405101600080515af115612222575b63bc197c8160e01b9051036122145738808080808080612171565b639c05499b6000526004601cfd5b3d156121f9573d6000823e3d90fd5b612248908690849086908a8c919287948b966133ff565b38612169565b60209003808b01358360205281880135600052604060002080548083116122a0578290039055826020526040600020908154908101908110612292578291556120f7565b6301336cea6000526004601cfd5b63f4d678b86000526004601cfd5b336000526034600c20546120f157634b6e7f186000526004601cfd5b63ea553b346000526004601cfd5b633b800a466000526004601cfd5b61230984886123038b87906122fd88948c96612080565b50612080565b5061208e565b506120b2565b9061232a9161232561232082611dcf565b612edf565b61232c565b565b9061233691613449565b565b906123429161230f565b565b60207f20726f6c657320666f722073656c660000000000000000000000000000000000917f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201520152565b61239f602f604092610647565b6123a881612344565b0190565b6123c29060208101906000818303910152612392565b90565b156123cc57565b6123d4610252565b62461bcd60e51b8152806123ea600482016123ac565b0390fd5b9061241b916124168261241061240a612405613473565b610272565b91610272565b146123c5565b613480565b565b606090565b9392919061242e61241d565b5082036124855760405193828552602085019260051b808481016040525b6124565750505050565b602090038082013560601b679a31110384e0b0c91760205280830135600052806040600020548186015261244c565b633b800a466000526004601cfd5b906124ae92916124a96124a461188f565b612edf565b6124b0565b565b916124bd9291909161352e565b565b906124ca9291612493565b565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a690565b9061250c9392916125076125026124cc565b612edf565b61250e565b565b9161251c93919091926135b1565b565b9061252a9392916124f0565b565b6125459061254061253b6118e7565b612edf565b612547565b565b612552906009611b03565b565b61255d9061252c565b565b60ff1690565b61257161257691611da5565b61255f565b90565b6125839054612565565b90565b9061259260ff91611426565b9181191691161790565b6125a59061039f565b90565b90565b906125c06125bb6125c79261259c565b6125a8565b8254612586565b9055565b959694939294336126046125fe7f000000000000000000000000024b9949fed1c8dd7154de653456d64aa1093384610272565b91610272565b14158015612666575b6126495761263b9761262e966126299489949091929394613607565b6130f9565b6126366124cc565b613449565b6126476001600b6125ab565b565b600063f92ee8a960e01b8152806126626004820161045f565b0390fd5b50612671600b612579565b61260d565b9061268090611d81565b600052602052604060002090565b90565b906126b16126ac6126b6936126a4611df1565b506005612676565b61268e565b6136a0565b90565b6126c290611b66565b90565b6126ce906126b9565b90565b906126db906126c5565b600052602052604060002090565b61271191600061270661270c936126fe611834565b506004611d8d565b016126d1565b612579565b90565b61272d906127286127236118e7565b612edf565b61272f565b565b61273a90600a611b03565b565b61274590612714565b565b60018060a01b031690565b61275e61276391611da5565b612747565b90565b6127709054612752565b90565b61277c906126b9565b90565b60e01b90565b9050519061279282610a4b565b565b906020828203126127ae576127ab91600001612785565b90565b61025d565b506127c2906020810190610293565b90565b6127ce90610272565b9052565b506127e1906020810190610371565b90565b6127ed90610350565b9052565b50612800906020810190610a60565b90565b61280c90610a48565b9052565b600080fd5b600080fd5b600080fd5b903560016020038236030381121561286057016020813591019167ffffffffffffffff821161285b57600182023603831361285657565b612815565b612810565b61281a565b60209181520190565b9190612888816128818161288d95612865565b8095610736565b6105af565b0190565b90356001604003823603038112156128a7570190565b61281a565b90356001602003823603038112156128ed57016020813591019167ffffffffffffffff82116128e85760018202360383136128e357565b612815565b612810565b61281a565b919061290c8161290581612911956104ff565b8095610736565b6105af565b0190565b67ffffffffffffffff1690565b61292b81612915565b0361293257565b600080fd5b9050359061294482612922565b565b50612955906020810190612937565b90565b61296190612915565b9052565b906129a390602061299b6129916040840161298360008801886128ac565b9086830360008801526128f2565b9482810190612946565b910190612958565b90565b612a5091612a42612a3760c083016129ce6129c460008701876127b3565b60008601906127c5565b6129e86129de60208701876127d2565b60208601906127e4565b612a026129f860408701876127f1565b6040860190612803565b612a1c612a1260608701876127f1565b6060860190612803565b612a29608086018661281f565b90858303608087015261286e565b9260a0810190612891565b9060a0818403910152612965565b90565b939290612a7f604091612a8794612a72606089019260008a0190610b9a565b87820360208901526129a6565b940190610a8e565b565b612a91610252565b3d6000823e3d90fd5b9150602090612aa7611d7c565b50612aba612ab56006612766565b612773565b612ae6633808a90b949294612af1612ad26007611dc2565b612ada610252565b9788968795869561277f565b855260048501612a53565b03915afa908115612b3657600091612b08575b5090565b612b29915060203d8111612b2f575b612b2181836105cf565b810190612794565b38612b04565b503d612b17565b612a89565b901515679a31110384e0b0c96020523360145281600052806034600c205560005260601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a3565b612b9891339190916136d9565b565b90612bb6939291612bb1612bac6124cc565b612edf565b612bb8565b565b91612bc6939190919261372b565b565b90612bd4939291612b9a565b565b612bf5612bf0612bfa92612be861180b565b506005612676565b61268e565b613814565b90565b90612c1891612c13612c0e82611dcf565b612edf565b612c1a565b565b90612c2491613480565b565b90612c3091612bfd565b565b612c3a611834565b50679a31110384e0b0c96020526014526000526034600c205490565b612c6f90612c6a612c65611b27565b612edf565b612cb4565b565b90612c7e60001991611426565b9181191691161790565b612c9190611da5565b90565b90612ca9612ca4612cb092611d81565b612c88565b8254612c71565b9055565b612cbf906007612c94565b565b612cca90612c56565b565b94909194612cd86133e3565b612e76575b60601b679a31110384e0b0c9179160601b679a31110384e0b0c917918060205260601c928260601c928315612e6857843303612e4c575b8660005260406000208054808411612e3e5783900390556020526040600020805490828201918210612e305755806020528284337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a4612d766133f1565b612e0b575b823b612d8a575b505050505050565b602094829160405197889663f23a6e618852338989015260408801526060870152608086015260a0808601528160c086015260e085013760c401906000601c8401915af115612dfc575b63f23a6e6160e01b905103612dee57388080808080612d82565b639c05499b6000526004601cfd5b3d15612dd4573d6000823e3d90fd5b612e1486613834565b50612e1e81613834565b50612e2a85839061208e565b50612d7b565b6301336cea6000526004601cfd5b63f4d678b86000526004601cfd5b336000526034600c2054612d1457634b6e7f186000526004601cfd5b63ea553b346000526004601cfd5b612e7f86613834565b50612e8984613834565b50612e9585839061208e565b50612cdd565b612ea3611834565b50612ead81613854565b8015612ed0575b908115612ec0575b5090565b612eca91506138fa565b38612ebc565b50612eda81613894565b612eb4565b612ef190612eeb613473565b906139f1565b565b60207f2073616c65507269636500000000000000000000000000000000000000000000917f455243323938313a20726f79616c7479206665652077696c6c2065786365656460008201520152565b612f4e602a604092610647565b612f5781612ef3565b0190565b612f719060208101906000818303910152612f41565b90565b15612f7b57565b612f83610252565b62461bcd60e51b815280612f9960048201612f5b565b0390fd5b60007f455243323938313a20696e76616c696420726563656976657200000000000000910152565b612fd26019602092610647565b612fdb81612f9d565b0190565b612ff59060208101906000818303910152612fc5565b90565b15612fff57565b613007610252565b62461bcd60e51b81528061301d60048201612fdf565b0390fd5b61302b60406106fe565b90565b90565b9061304661304161304d926126c5565b61302e565b8254611b9a565b9055565b60a01b90565b906130716bffffffffffffffffffffffff60a01b91613051565b9181191691161790565b61308f61308a613094926103fc565b610ae6565b6103fc565b90565b90565b906130af6130aa6130b69261307b565b613097565b8254613057565b9055565b906130e5602060006130eb946130dd8282016130d7848801611ee0565b90613031565b019201611f15565b9061309a565b565b906130f7916130ba565b565b9061316a613171926131258361311e6131186131136133cc565b6103fc565b916103fc565b1115612f74565b61314b8161314461313e6131396000611f09565b610272565b91610272565b1415612ff8565b91613161613157613021565b9360008501611e3a565b60208301611e80565b60026130ed565b565b9061317c611c04565b506080604051019160208301604052600083528290600a6000198092955b01948181066030018653049384156131b95790600a919080929161319a565b93505082602091039203918252565b6131dc6131d76131e192611423565b610ae6565b6102a2565b90565b60016131f091016102a2565b90565b634e487b7160e01b600052603260045260246000fd5b9061321382610e9a565b811015613224576020809102010190565b6131f3565b61323390516102a2565b90565b61324261324791611da5565b6108ae565b90565b6132549054613236565b90565b61326661326c919392936102a2565b926102a2565b820391821161327757565b611f3e565b9061329161328c61329892610ae9565b61195a565b8254612c71565b9055565b6132ab6132b1919392936102a2565b926102a2565b82018092116132bc57565b611f3e565b6132d19093929193848391613a8a565b6132da83610e9a565b926132e560006131c8565b926132f060006131c8565b935b846133056132ff886102a2565b916102a2565b10156133825761337661337c9161335d613328613323888a90613209565b613229565b613357613348600161334261333d8d8c613209565b613229565b90610b05565b916133528361324a565b613257565b9061327c565b61337061336b878990613209565b613229565b9061329c565b946131e4565b936132f2565b915093506133a6925061339f915061339a600061324a565b613257565b600061327c565b565b600090565b90565b6133c46133bf6133c9926133ad565b610ae6565b6103fc565b90565b6133d46133a8565b506133e06127106133b0565b90565b6133eb611834565b50600090565b6133f9611834565b50600090565b5050949293909361340e6133f1565b61341b575b505050505050565b6134316134379361343d97969092939596612080565b50612080565b5061208e565b50388080808080613413565b9061346b6134666134709361345f818590613aa5565b6005612676565b61268e565b613b8c565b50565b61347b611df1565b503390565b906134a261349d6134a793613496818590613bc7565b6005612676565b61268e565b613c61565b50565b60007f455243323938313a20496e76616c696420706172616d65746572730000000000910152565b6134df601b602092610647565b6134e8816134aa565b0190565b61350290602081019060008183039101526134d2565b90565b1561350c57565b613514610252565b62461bcd60e51b81528061352a600482016134ec565b0390fd5b6135aa906135a36135af949361355e8561355761355161354c6133cc565b6103fc565b916103fc565b1115612f74565b6135848161357d6135776135726000611f09565b610272565b91610272565b1415613505565b9361359a613590613021565b9560008701611e3a565b60208501611e80565b6003611df6565b6130ed565b565b6135ff91926135cb613605956135f0939086849192613c9c565b6135e86135e1826135dc600061324a565b61329c565b600061327c565b926001610b05565b916135fa8361324a565b61329c565b9061327c565b565b919261362661366b969461361f61362d946008611b03565b6009611b03565b600a611b03565b61363f613638611448565b8290613449565b61365161364a61188f565b8290613449565b61366361365c6118e7565b8290613449565b919091613d9d565b565b90565b61367c61368191611da5565b610ae9565b90565b61369861369361369d926102a2565b610ae6565b610267565b90565b6136cc6136c76136d6936136c260006136d1956136bb611df1565b500161366d565b613e18565b613670565b613684565b6126b9565b90565b613714613729936136ef61372393858391613e3a565b61370c61370582613700600061324a565b613257565b600061327c565b926001610b05565b9161371e8361324a565b613257565b9061327c565b565b9261373c9194939085849192613e55565b61374583610e9a565b9161375060006131c8565b9061375b60006131c8565b915b8261377061376a876102a2565b916102a2565b10156137ee576137966137e89161379061378b878790613209565b613229565b9061329c565b926137e36137ad6137a8878490613209565b613229565b6137dd6137ce60016137c86137c38d8890613209565b613229565b90610b05565b916137d88361324a565b61329c565b9061327c565b6131e4565b9161375d565b91509350613812925061380b9150613806600061324a565b61329c565b600061327c565b565b61382c60006138319261382561180b565b500161366d565b613f98565b90565b9061383d61241d565b506040519160408301604052600183526020830152565b61385c611834565b50633e85e62f60e01b61387761387183610350565b91610350565b14908115613884575b5090565b61388e9150613fb0565b38613880565b61389c611834565b506138a681613fd7565b80156138eb575b80156138d0575b9081156138c0575b5090565b6138ca9150614017565b386138bc565b5060006138e56138df83610350565b91610350565b146138b4565b506138f581614017565b6138ad565b613902611834565b5061390c81614017565b908115613918575b5090565b6139229150614057565b38613914565b90565b61393f61393a61394492613928565b610ae6565b6102a2565b90565b60007f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000910152565b61397b60178092611c09565b61398481613947565b0190565b60007f206973206d697373696e6720726f6c6520000000000000000000000000000000910152565b6139bc60118092611c09565b6139c581613988565b0190565b6139e36139ee93926139dd6139e89361396f565b90611c97565b6139b0565b90611c97565b90565b90613a06613a008383906126e9565b1561039f565b613a0e575050565b613a8691613a64613a3d613a2d613a27613a69956140e5565b93613670565b613a37602061392b565b906142fe565b91613a55613a49610252565b938492602084016139c9565b602082018103825203826105cf565b611d20565b613a71610252565b91829162461bcd60e51b8352600483016106a6565b0390fd5b9091613aa392613a9a6000611f09565b92909192614479565b565b613ab9613ab38284906126e9565b1561039f565b613ac2575b5050565b613ae56001613ae06000613ad860048690611d8d565b0185906126d1565b6125ab565b90613aee613473565b90613b2b613b25613b1f7f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d95611d81565b926126c5565b926126c5565b92613b34610252565b80613b3e8161045f565b0390a43880613abe565b613b5190611b66565b90565b613b68613b63613b6d92610267565b610ae6565b6102a2565b90565b613b84613b7f613b89926102a2565b611426565b610a48565b90565b90613bbf613bb9613bb4613baf6000613bc496613ba7611834565b500194613b48565b613b54565b613b70565b9161366d565b614669565b90565b613bd28183906126e9565b613bdb575b5050565b613bfe6000613bf96000613bf160048690611d8d565b0185906126d1565b6125ab565b90613c07613473565b90613c44613c3e613c387ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b95611d81565b926126c5565b926126c5565b92613c4d610252565b80613c578161045f565b0390a43880613bd7565b90613c94613c8e613c89613c846000613c9996613c7c611834565b500194613b48565b613b54565b613b70565b9161366d565b614729565b90565b91929092613ca86133e3565b613d84575b8260601b8015613d7657679a31110384e0b0c960205283601452846000526040600020805490838201918210613d6857558160205260601c6000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62604083a4613d156133f1565b613d4f575b613d2383614833565b613d2e575b50505050565b613d4693613d3c6000611f09565b9390919293614840565b38808080613d28565b613d5884613834565b50613d6281613834565b50613d1a565b6301336cea6000526004601cfd5b63ea553b346000526004601cfd5b613d8d84613834565b50613d9781613834565b50613cad565b90613db3613db89392613dae611b27565b613449565b6148d9565b565b5490565b600052602060002090565b613dd281613dba565b821015613ded57613de4600191613dbe565b91020190600090565b6131f3565b613e02906008613e0793026108aa565b611dab565b90565b90613e159154613df2565b90565b613e37916000613e3192613e2a611d7c565b5001613dc9565b90613e0a565b90565b9091613e5392613e4a6000611f09565b929091926148f9565b565b91929092613e616133e3565b613f93575b8051845103613f85578260601b8015613f775780679a31110384e0b0c917602052845160051b805b613f4057506000604051604081527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb81885160051b602001604082019081818c60045afa503d60400160208301523d01865160051b60200181818960045afa503d01039360601c933392a4613f016133f1565b613f3b575b613f0f83614833565b613f1a575b50505050565b613f3293613f286000611f09565b93909192936149fd565b38808080613f14565b613f06565b8083015190808701516000526040600020918254908101908110613f6957602092550380613e8e565b6301336cea6000526004601cfd5b63ea553b346000526004601cfd5b633b800a466000526004601cfd5b613e66565b6000613fad91613fa661180b565b5001613dba565b90565b613fb8611834565b5060e01c630e89341c8114906301ffc9a763d9b67a2682149114171790565b613fdf611834565b5080613ffa613ff463152a902d60e11b610350565b91610350565b14908115614007575b5090565b6140119150614ab4565b38614003565b61401f611834565b508061403a614034635a05180f60e01b610350565b91610350565b14908115614047575b5090565b6140519150614ada565b38614043565b61405f611834565b508061407a614074634e821d3360e11b610350565b91610350565b14908115614087575b5090565b6140919150613894565b38614083565b90565b60ff1690565b6140b46140af6140b992614097565b610ae6565b61409a565b90565b6140c660146140a0565b90565b6140dd6140d86140e29261409a565b610ae6565b6102a2565b90565b6141026140fd614118926140f7611c04565b50613b48565b613b54565b61411261410d6140bc565b6140c9565b906142fe565b90565b90565b61413261412d6141379261411b565b610ae6565b6102a2565b90565b9061414c61414783611028565b6106fe565b918252565b369037565b9061417b6141638361413a565b926020806141718693611028565b9201910390614151565b565b600360fc1b90565b5190565b9061419382614185565b8110156141a557600160209102010190565b6131f3565b600f60fb1b90565b90565b6141c96141c46141ce926141b2565b610ae6565b6102a2565b90565b6141da906102a2565b600081146141e9576001900390565b611f3e565b6f181899199a1a9b1b9c1cb0b131b232b360811b90565b61420d6141ee565b90565b90565b61422761422261422c92614210565b610ae6565b6102a2565b90565b60f81b90565b90565b61424c61424761425192614235565b610ae6565b61409a565b90565b6142739061426d6142676142789461409a565b916102a2565b906108aa565b6102a2565b90565b60007f537472696e67733a20686578206c656e67746820696e73756666696369656e74910152565b6142af60208092610647565b6142b88161427b565b0190565b6142d290602081019060008183039101526142a3565b90565b156142dc57565b6142e4610252565b62461bcd60e51b8152806142fa600482016142bc565b0390fd5b9190614308611c04565b506143a261439261433e6143396143296002614324879161411e565b611f54565b614333600261411e565b9061329c565b614156565b9261434761417d565b6143608561435a60009360001a936131c8565b90614189565b536143696141aa565b6143828561437c60019360001a936141b5565b90614189565b5361438d600261411e565b611f54565b61439c60016141b5565b9061329c565b925b836143b86143b260016141b5565b916102a2565b111561441f576143c6614205565b816143d1600f614213565b1691601083101561441a576143ed61440e92614414941a61422f565b6143fd8591889060001a92614189565b536144086004614238565b90614254565b936141d1565b926143a4565b6131f3565b6144479293506144429061443c61443660006131c8565b916102a2565b146142d5565b611d20565b90565b9061445c61445783610713565b6106fe565b918252565b61446b600061444a565b90565b614476614461565b90565b919392906144856133e3565b6145b1575b81518551036145a35760601b9182679a31110384e0b0c9176020528060601b83811490151715614581575b50835160051b805b61454b57507f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6000939460405192839160408352805160051b60200180916040850192839160045afa503d60400160208401523d019081815160051b602001809260045afa503d01039260601c923392a46145366133f1565b61453d575b565b61454561446e565b5061453b565b80820151908086015160005260406000208054928381116145735760209303905503806144bd565b63f4d678b86000526004601cfd5b6000526034600c20541561459557386144b5565b634b6e7f186000526004601cfd5b633b800a466000526004601cfd5b6145b961446e565b5061448a565b90565b600052602060002090565b5490565b6145da816145cd565b8210156145f5576145ec6001916145c2565b91020190600090565b6131f3565b919061461061460b61461893611d81565b612c88565b908354611934565b9055565b908154916801000000000000000083101561464c578261464491600161464a950181556145d1565b906145fa565b565b6105b9565b9061465b90611d81565b600052602052604060002090565b614671611834565b50614686614680828490614b1a565b1561039f565b6000146146c9576146bf6146c4926146aa6146a3600085016145bf565b829061461c565b60016146b860008501613dba565b9301614651565b61327c565b600190565b5050600090565b634e487b7160e01b600052603160045260246000fd5b6146f8916146f2611d7c565b916145fa565b565b614703816145cd565b801561472457600190039061472161471b83836145d1565b906146e6565b55565b6146d0565b614731611834565b50614748614743600183018490614651565b61324a565b908161475d61475760006131c8565b916102a2565b141560001461482b576147dd9260016147d89284614786600096614780856141b5565b90613257565b6147a3614794888501613dba565b61479d866141b5565b90613257565b806147b66147b0846102a2565b916102a2565b036147e2575b5050506147d26147cd8683016145bf565b6146fa565b01614651565b61197f565b600190565b614823926148156148016147fb61481e948c8901613dc9565b90613e0a565b9361480f85918c8901613dc9565b906145fa565b91858501614651565b61327c565b3880806147bc565b505050600090565b61483b611834565b503b90565b919360209360405195869463f23a6e618652338787015260601b60601c60408601526060850152608084015260a08084015280518091818060c08701526148c5575b505060c401906000601c8401915af1156148b6575b63f23a6e6160e01b9051036148a857565b639c05499b6000526004601cfd5b3d15614897573d6000823e3d90fd5b818660e08701920160045afa508038614882565b906148f06148e96148f793611b8e565b6006611bc4565b6007612c94565b565b909291926149056133e3565b6149db575b60601b9081679a31110384e0b0c917602052818160601b148160601b1517156149b9575b50826000526040600020908154918284116149ab57836000930390558260205260601c337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62604084a461497f6133f1565b614988575b5050565b61499461499a92613834565b50613834565b506149a361446e565b503880614984565b63f4d678b86000526004601cfd5b6000526034600c2054156149cd573861492e565b634b6e7f186000526004601cfd5b6149e484613834565b506149ee83613834565b506149f761446e565b5061490a565b919360209360405195869463bc197c818652338787015260601b60601c604086015260a06060860152805160051b8601809160c0870192839160045afa503d60a001908160808701523d019182815160051b8801809260045afa503d0160a08501523d01908181518601809260045afa50601c8301903d0103906000601c8401915af115614aa5575b63bc197c8160e01b905103614a9757565b639c05499b6000526004601cfd5b3d15614a86573d6000823e3d90fd5b614abc611834565b50614ad6614ad06301ffc9a760e01b610350565b91610350565b1490565b614ae2611834565b5080614afd614af7637965db0b60e01b610350565b91610350565b14908115614b0a575b5090565b614b149150613fd7565b38614b06565b614b38916001614b3392614b2c611834565b5001614651565b61324a565b614b4b614b4560006131c8565b916102a2565b14159056fea26469706673582212201008807002fe6072ba72743479d7976a506937a4e756aa0aef6ad714bef8804e64736f6c634300081b0033
AccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../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 => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ 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 override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @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 override 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 override 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 override 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 `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @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 Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
AccessControlEnumerable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerable.sol"; import "./AccessControl.sol"; import "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } }
IAccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @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. * * _Available since v3.1._ */ 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 `account`. */ function renounceRole(bytes32 role, address account) external; }
IAccessControlEnumerable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
Ownable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
IERC1967.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
IERC2981.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981 is IERC165 { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo( uint256 tokenId, uint256 salePrice ) external view returns (address receiver, uint256 royaltyAmount); }
draft-IERC1822.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
Proxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ 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 This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
IBeacon.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
UpgradeableBeacon.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol) pragma solidity ^0.8.0; import "./IBeacon.sol"; import "../../access/Ownable.sol"; import "../../utils/Address.sol"; /** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their * implementation contract, which is where they will delegate all function calls. * * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. */ contract UpgradeableBeacon is IBeacon, Ownable { address private _implementation; /** * @dev Emitted when the implementation returned by the beacon is changed. */ event Upgraded(address indexed implementation); /** * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the * beacon. */ constructor(address implementation_) { _setImplementation(implementation_); } /** * @dev Returns the current implementation address. */ function implementation() public view virtual override returns (address) { return _implementation; } /** * @dev Upgrades the beacon to a new implementation. * * Emits an {Upgraded} event. * * Requirements: * * - msg.sender must be the owner of the contract. * - `newImplementation` must be a contract. */ function upgradeTo(address newImplementation) public virtual onlyOwner { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation contract address for this beacon * * Requirements: * * - `newImplementation` must be a contract. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); _implementation = newImplementation; } }
ERC2981.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol) pragma solidity ^0.8.0; import "../../interfaces/IERC2981.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. * * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. * * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the * fee is specified in basis points by default. * * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. * * _Available since v4.5._ */ abstract contract ERC2981 is IERC2981, ERC165 { struct RoyaltyInfo { address receiver; uint96 royaltyFraction; } RoyaltyInfo private _defaultRoyaltyInfo; mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); } /** * @inheritdoc IERC2981 */ function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) { RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; if (royalty.receiver == address(0)) { royalty = _defaultRoyaltyInfo; } uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); return (royalty.receiver, royaltyAmount); } /** * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an * override. */ function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /** * @dev Sets the royalty information that all ids in this contract will default to. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: invalid receiver"); _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Removes default royalty information. */ function _deleteDefaultRoyalty() internal virtual { delete _defaultRoyaltyInfo; } /** * @dev Sets the royalty information for a specific token id, overriding the global default. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: Invalid parameters"); _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Resets royalty information for the token id back to the global default. */ function _resetTokenRoyalty(uint256 tokenId) internal virtual { delete _tokenRoyaltyInfo[tokenId]; } }
Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
Create2.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol) pragma solidity ^0.8.0; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. */ library Create2 { /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { require(address(this).balance >= amount, "Create2: insufficient balance"); require(bytecode.length != 0, "Create2: bytecode length is zero"); /// @solidity memory-safe-assembly assembly { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) } require(addr != address(0), "Create2: Failed on deploy"); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |-------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0xFF | FF | // |-------------------|---------------------------------------------------------------------------| // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff mstore8(start, 0xff) addr := keccak256(start, 85) } } }
StorageSlot.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @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(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ 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 } } }
Strings.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(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) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
Math.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // 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. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
SignedMath.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @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); } } }
EnumerableSet.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev 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 (bytes32) { 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 (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, 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(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @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(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, 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(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(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(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @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(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, 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(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev 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(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, 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(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
Attestation.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { LibBytes } from "../../../utils/LibBytes.sol"; import { ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX } from "./ISignalsImplicitMode.sol"; using LibBytes for bytes; /// @notice Attestation for a specific session /// @param approvedSigner Address of the approved signer /// @param identityType Identity type /// @param issuerHash Hash of the issuer /// @param audienceHash Hash of the audience /// @param applicationData Unspecified application data /// @param authData Auth data struct Attestation { address approvedSigner; bytes4 identityType; bytes32 issuerHash; bytes32 audienceHash; bytes applicationData; AuthData authData; } /// @notice Auth data for an attestation /// @param redirectUrl Authorization redirect URL /// @param issuedAt Timestamp of the attestation issuance struct AuthData { string redirectUrl; uint64 issuedAt; } /// @title LibAttestation /// @author Michael Standen /// @notice Library for attestation management library LibAttestation { /// @notice Hashes an attestation function toHash( Attestation memory attestation ) internal pure returns (bytes32) { return keccak256(toPacked(attestation)); } /// @notice Decodes an attestation from a packed bytes array /// @param encoded The packed bytes array /// @param pointer The pointer to the start of the attestation /// @return attestation The decoded attestation /// @return newPointer The new pointer to the end of the attestation function fromPacked( bytes calldata encoded, uint256 pointer ) internal pure returns (Attestation memory attestation, uint256 newPointer) { newPointer = pointer; (attestation.approvedSigner, newPointer) = encoded.readAddress(newPointer); (attestation.identityType, newPointer) = encoded.readBytes4(newPointer); (attestation.issuerHash, newPointer) = encoded.readBytes32(newPointer); (attestation.audienceHash, newPointer) = encoded.readBytes32(newPointer); // Application data (arbitrary bytes) uint256 dataSize; (dataSize, newPointer) = encoded.readUint24(newPointer); attestation.applicationData = encoded[newPointer:newPointer + dataSize]; newPointer += dataSize; // Auth data (attestation.authData, newPointer) = fromPackedAuthData(encoded, newPointer); return (attestation, newPointer); } /// @notice Decodes the auth data from a packed bytes /// @param encoded The packed bytes containing the auth data /// @param pointer The pointer to the start of the auth data within the encoded data /// @return authData The decoded auth data /// @return newPointer The pointer to the end of the auth data within the encoded data function fromPackedAuthData( bytes calldata encoded, uint256 pointer ) internal pure returns (AuthData memory authData, uint256 newPointer) { uint24 redirectUrlLength; (redirectUrlLength, pointer) = encoded.readUint24(pointer); authData.redirectUrl = string(encoded[pointer:pointer + redirectUrlLength]); pointer += redirectUrlLength; (authData.issuedAt, pointer) = encoded.readUint64(pointer); return (authData, pointer); } /// @notice Encodes an attestation into a packed bytes array /// @param attestation The attestation to encode /// @return encoded The packed bytes array function toPacked( Attestation memory attestation ) internal pure returns (bytes memory encoded) { return abi.encodePacked( attestation.approvedSigner, attestation.identityType, attestation.issuerHash, attestation.audienceHash, uint24(attestation.applicationData.length), attestation.applicationData, toPackAuthData(attestation.authData) ); } /// @notice Encodes the auth data into a packed bytes array /// @param authData The auth data to encode /// @return encoded The packed bytes array function toPackAuthData( AuthData memory authData ) internal pure returns (bytes memory encoded) { return abi.encodePacked(uint24(bytes(authData.redirectUrl).length), bytes(authData.redirectUrl), authData.issuedAt); } /// @notice Generates the implicit request magic return value /// @param attestation The attestation /// @param wallet The wallet /// @return magic The expected implicit request magic function generateImplicitRequestMagic(Attestation memory attestation, address wallet) internal pure returns (bytes32) { return keccak256( abi.encodePacked(ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX, wallet, attestation.audienceHash, attestation.issuerHash) ); } }
ISignalsImplicitMode.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { Payload } from "../../../modules/Payload.sol"; import { Attestation } from "./Attestation.sol"; /// @dev Magic prefix for the implicit request bytes32 constant ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX = keccak256(abi.encodePacked("acceptImplicitRequest")); /// @title ISignalsImplicitMode /// @author Agustin Aguilar, Michael Standen /// @notice Interface for the contracts that support implicit mode validation interface ISignalsImplicitMode { /// @notice Determines if an implicit request is valid /// @param wallet The wallet's address /// @param attestation The attestation data /// @param call The call to validate /// @return magic The hash of the implicit request if valid function acceptImplicitRequest( address wallet, Attestation calldata attestation, Payload.Call calldata call ) external view returns (bytes32 magic); }
Payload.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { LibBytes } from "../utils/LibBytes.sol"; using LibBytes for bytes; /// @title Payload /// @author Agustin Aguilar, Michael Standen, William Hua /// @notice Library for encoding and decoding payloads library Payload { /// @notice Error thrown when the kind is invalid error InvalidKind(uint8 kind); /// @dev keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") bytes32 private constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev keccak256("Sequence Wallet") bytes32 private constant EIP712_DOMAIN_NAME_SEQUENCE = 0x4aa45ca7ad825ceb1bf35643f0a58c295239df563b1b565c2485f96477c56318; /// @dev keccak256("3") bytes32 private constant EIP712_DOMAIN_VERSION_SEQUENCE = 0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de; function domainSeparator(bool _noChainId, address _wallet) internal view returns (bytes32 _domainSeparator) { return keccak256( abi.encode( EIP712_DOMAIN_TYPEHASH, EIP712_DOMAIN_NAME_SEQUENCE, EIP712_DOMAIN_VERSION_SEQUENCE, _noChainId ? uint256(0) : uint256(block.chainid), _wallet ) ); } /// @dev keccak256("Call(address to,uint256 value,bytes data,uint256 gasLimit,bool delegateCall,bool onlyFallback,uint256 behaviorOnError)") bytes32 private constant CALL_TYPEHASH = 0x0603985259a953da1f65a522f589c17bd1d0117ec1d3abb7c0788aef251ef437; /// @dev keccak256("Calls(Call[] calls,uint256 space,uint256 nonce,address[] wallets)Call(address to,uint256 value,bytes data,uint256 gasLimit,bool delegateCall,bool onlyFallback,uint256 behaviorOnError)") bytes32 private constant CALLS_TYPEHASH = 0x11e1e4079a79a66e4ade50033cfe2678cdd5341d2dfe5ef9513edb1a0be147a2; /// @dev keccak256("Message(bytes message,address[] wallets)") bytes32 private constant MESSAGE_TYPEHASH = 0xe19a3b94fc3c7ece3f890d98a99bc422615537a08dea0603fa8425867d87d466; /// @dev keccak256("ConfigUpdate(bytes32 imageHash,address[] wallets)") bytes32 private constant CONFIG_UPDATE_TYPEHASH = 0x11fdeb7e8373a1aa96bfac8d0ea91526b2c5d15e5cee20e0543e780258f3e8e4; /// @notice Kind of transaction uint8 public constant KIND_TRANSACTIONS = 0x00; /// @notice Kind of digest uint8 public constant KIND_MESSAGE = 0x01; /// @notice Kind of config update uint8 public constant KIND_CONFIG_UPDATE = 0x02; /// @notice Kind of message uint8 public constant KIND_DIGEST = 0x03; /// @notice Behavior on error: ignore error uint8 public constant BEHAVIOR_IGNORE_ERROR = 0x00; /// @notice Behavior on error: revert on error uint8 public constant BEHAVIOR_REVERT_ON_ERROR = 0x01; /// @notice Behavior on error: abort on error uint8 public constant BEHAVIOR_ABORT_ON_ERROR = 0x02; /// @notice Payload call information /// @param to Address of the target contract /// @param value Value to send with the call /// @param data Data to send with the call /// @param gasLimit Gas limit for the call /// @param delegateCall If the call is a delegate call /// @param onlyFallback If the call should only be executed in an error scenario /// @param behaviorOnError Behavior on error struct Call { address to; uint256 value; bytes data; uint256 gasLimit; bool delegateCall; bool onlyFallback; uint256 behaviorOnError; } /// @notice Decoded payload /// @param kind Kind of payload /// @param noChainId If the chain ID should be omitted /// @param calls Array of calls (transaction kind) /// @param space Nonce space for the calls (transaction kind) /// @param nonce Nonce value for the calls (transaction kind) /// @param message Message to validate (message kind) /// @param imageHash Image hash to update to (config update kind) /// @param digest Digest to validate (digest kind) /// @param parentWallets Parent wallets struct Decoded { uint8 kind; bool noChainId; // Transaction kind Call[] calls; uint256 space; uint256 nonce; // Message kind // TODO: Maybe native 721 ? bytes message; // Config update kind bytes32 imageHash; // Digest kind for 1271 bytes32 digest; // Parent wallets address[] parentWallets; } function fromMessage( bytes memory message ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_MESSAGE; _decoded.message = message; } function fromConfigUpdate( bytes32 imageHash ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_CONFIG_UPDATE; _decoded.imageHash = imageHash; } function fromDigest( bytes32 digest ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_DIGEST; _decoded.digest = digest; } function fromPackedCalls( bytes calldata packed ) internal view returns (Decoded memory _decoded) { _decoded.kind = KIND_TRANSACTIONS; // Read the global flag (uint256 globalFlag, uint256 pointer) = packed.readFirstUint8(); // First bit determines if space is zero or not if (globalFlag & 0x01 == 0x01) { _decoded.space = 0; } else { (_decoded.space, pointer) = packed.readUint160(pointer); } // Next 3 bits determine the size of the nonce uint256 nonceSize = (globalFlag >> 1) & 0x07; if (nonceSize > 0) { // Read the nonce (_decoded.nonce, pointer) = packed.readUintX(pointer, nonceSize); } uint256 numCalls; // Bit 5 determines if the batch contains a single call if (globalFlag & 0x10 == 0x10) { numCalls = 1; } else { // Bit 6 determines if the number of calls uses 1 byte or 2 bytes if (globalFlag & 0x20 == 0x20) { (numCalls, pointer) = packed.readUint16(pointer); } else { (numCalls, pointer) = packed.readUint8(pointer); } } // Read the calls _decoded.calls = new Call[](numCalls); for (uint256 i = 0; i < numCalls; i++) { uint8 flags; (flags, pointer) = packed.readUint8(pointer); // First bit determines if this is a call to self // or a call to another address if (flags & 0x01 == 0x01) { // Call to self _decoded.calls[i].to = address(this); } else { // Call to another address (_decoded.calls[i].to, pointer) = packed.readAddress(pointer); } // Second bit determines if the call has value or not if (flags & 0x02 == 0x02) { (_decoded.calls[i].value, pointer) = packed.readUint256(pointer); } // Third bit determines if the call has data or not if (flags & 0x04 == 0x04) { // 3 bytes determine the size of the calldata uint256 calldataSize; (calldataSize, pointer) = packed.readUint24(pointer); _decoded.calls[i].data = packed[pointer:pointer + calldataSize]; pointer += calldataSize; } // Fourth bit determines if the call has a gas limit or not if (flags & 0x08 == 0x08) { (_decoded.calls[i].gasLimit, pointer) = packed.readUint256(pointer); } // Fifth bit determines if the call is a delegate call or not _decoded.calls[i].delegateCall = (flags & 0x10 == 0x10); // Sixth bit determines if the call is fallback only _decoded.calls[i].onlyFallback = (flags & 0x20 == 0x20); // Last 2 bits are directly mapped to the behavior on error _decoded.calls[i].behaviorOnError = (flags & 0xC0) >> 6; } } function hashCall( Call memory c ) internal pure returns (bytes32) { return keccak256( abi.encode( CALL_TYPEHASH, c.to, c.value, keccak256(c.data), c.gasLimit, c.delegateCall, c.onlyFallback, c.behaviorOnError ) ); } function hashCalls( Call[] memory calls ) internal pure returns (bytes32) { // In EIP712, an array is often hashed as the keccak256 of the concatenated // hashes of each item. So we hash each Call, pack them, and hash again. bytes32[] memory callHashes = new bytes32[](calls.length); for (uint256 i = 0; i < calls.length; i++) { callHashes[i] = hashCall(calls[i]); } return keccak256(abi.encodePacked(callHashes)); } function toEIP712( Decoded memory _decoded ) internal pure returns (bytes32) { bytes32 walletsHash = keccak256(abi.encodePacked(_decoded.parentWallets)); if (_decoded.kind == KIND_TRANSACTIONS) { bytes32 callsHash = hashCalls(_decoded.calls); // The top-level struct for Calls might be something like: // Calls(bytes32 callsHash,uint256 space,uint256 nonce,bytes32 walletsHash) return keccak256(abi.encode(CALLS_TYPEHASH, callsHash, _decoded.space, _decoded.nonce, walletsHash)); } else if (_decoded.kind == KIND_MESSAGE) { // If you define your top-level as: Message(bytes32 messageHash,bytes32 walletsHash) return keccak256(abi.encode(MESSAGE_TYPEHASH, keccak256(_decoded.message), walletsHash)); } else if (_decoded.kind == KIND_CONFIG_UPDATE) { // Top-level: ConfigUpdate(bytes32 imageHash,bytes32 walletsHash) return keccak256(abi.encode(CONFIG_UPDATE_TYPEHASH, _decoded.imageHash, walletsHash)); } else if (_decoded.kind == KIND_DIGEST) { // Top-level: Use MESSAGE_TYPEHASH but assume the digest is already the hashed message return keccak256(abi.encode(MESSAGE_TYPEHASH, _decoded.digest, walletsHash)); } else { // Unknown kind revert InvalidKind(_decoded.kind); } } function hash( Decoded memory _decoded ) internal view returns (bytes32) { bytes32 domain = domainSeparator(_decoded.noChainId, address(this)); bytes32 structHash = toEIP712(_decoded); return keccak256(abi.encodePacked("\x19\x01", domain, structHash)); } function hashFor(Decoded memory _decoded, address _wallet) internal view returns (bytes32) { bytes32 domain = domainSeparator(_decoded.noChainId, _wallet); bytes32 structHash = toEIP712(_decoded); return keccak256(abi.encodePacked("\x19\x01", domain, structHash)); } }
LibBytes.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; /// @title Library for reading data from bytes arrays /// @author Agustin Aguilar (aa@horizon.io), Michael Standen (mstan@horizon.io) /// @notice This library contains functions for reading data from bytes arrays. /// @dev These functions do not check if the input index is within the bounds of the data array. /// @dev Reading out of bounds may return dirty values. library LibBytes { function readFirstUint8( bytes calldata _data ) internal pure returns (uint8 a, uint256 newPointer) { assembly { let word := calldataload(_data.offset) a := shr(248, word) newPointer := 1 } } function readUint8(bytes calldata _data, uint256 _index) internal pure returns (uint8 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(248, word) newPointer := add(_index, 1) } } function readUint16(bytes calldata _data, uint256 _index) internal pure returns (uint16 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(240, word) newPointer := add(_index, 2) } } function readUint24(bytes calldata _data, uint256 _index) internal pure returns (uint24 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(232, word) newPointer := add(_index, 3) } } function readUint64(bytes calldata _data, uint256 _index) internal pure returns (uint64 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(192, word) newPointer := add(_index, 8) } } function readUint160(bytes calldata _data, uint256 _index) internal pure returns (uint160 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(96, word) newPointer := add(_index, 20) } } function readUint256(bytes calldata _data, uint256 _index) internal pure returns (uint256 a, uint256 newPointer) { assembly { a := calldataload(add(_index, _data.offset)) newPointer := add(_index, 32) } } function readUintX( bytes calldata _data, uint256 _index, uint256 _length ) internal pure returns (uint256 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) let shift := sub(256, mul(_length, 8)) a := and(shr(shift, word), sub(shl(mul(8, _length), 1), 1)) newPointer := add(_index, _length) } } function readBytes4(bytes calldata _data, uint256 _pointer) internal pure returns (bytes4 a, uint256 newPointer) { assembly { let word := calldataload(add(_pointer, _data.offset)) a := and(word, 0xffffffff00000000000000000000000000000000000000000000000000000000) newPointer := add(_pointer, 4) } } function readBytes32(bytes calldata _data, uint256 _pointer) internal pure returns (bytes32 a, uint256 newPointer) { assembly { a := calldataload(add(_pointer, _data.offset)) newPointer := add(_pointer, 32) } } function readAddress(bytes calldata _data, uint256 _index) internal pure returns (address a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := and(shr(96, word), 0xffffffffffffffffffffffffffffffffffffffff) newPointer := add(_index, 20) } } /// @dev ERC-2098 Compact Signature function readRSVCompact( bytes calldata _data, uint256 _index ) internal pure returns (bytes32 r, bytes32 s, uint8 v, uint256 newPointer) { uint256 yParityAndS; assembly { r := calldataload(add(_index, _data.offset)) yParityAndS := calldataload(add(_index, add(_data.offset, 32))) newPointer := add(_index, 64) } uint256 yParity = uint256(yParityAndS >> 255); s = bytes32(uint256(yParityAndS) & ((1 << 255) - 1)); v = uint8(yParity) + 27; } }
SignalsImplicitMode.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import { IImplicitProjectValidation } from "../registry/IImplicitProjectValidation.sol"; import { ERC165, IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; import { Attestation } from "sequence-v3/src/extensions/sessions/implicit/Attestation.sol"; import { ISignalsImplicitMode } from "sequence-v3/src/extensions/sessions/implicit/ISignalsImplicitMode.sol"; import { Payload } from "sequence-v3/src/modules/Payload.sol"; /// @title SignalsImplicitMode /// @author Michael Standen /// @notice Base contract for implicit mode validation by project abstract contract SignalsImplicitMode is ISignalsImplicitMode, ERC165 { IImplicitProjectValidation internal _validator; bytes32 internal _projectId; /// @notice Initialize implicit mode validation /// @param validator The IImplicitProjectValidation address /// @param projectId The project id function _initializeSignalsImplicitMode(address validator, bytes32 projectId) internal { _validator = IImplicitProjectValidation(validator); _projectId = projectId; } /// @inheritdoc ISignalsImplicitMode function acceptImplicitRequest( address wallet, Attestation calldata attestation, Payload.Call calldata call ) external view returns (bytes32) { _validateImplicitRequest(wallet, attestation, call); return _validator.validateAttestation(wallet, attestation, _projectId); } /// @notice Validates an implicit request /// @dev Optional hook for additional validation of the implicit requests /// @param wallet The wallet's address /// @param attestation The attestation data /// @param call The call to validate function _validateImplicitRequest( address wallet, Attestation calldata attestation, Payload.Call calldata call ) internal view virtual { } /// @inheritdoc IERC165 function supportsInterface( bytes4 interfaceId ) public view virtual override returns (bool) { return interfaceId == type(ISignalsImplicitMode).interfaceId || super.supportsInterface(interfaceId); } }
IImplicitProjectValidation.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import { Attestation } from "sequence-v3/src/extensions/sessions/implicit/Attestation.sol"; /// @title IImplicitProjectValidation /// @author Michael Standen /// @notice Interface for contracts supporting validation of implicit sessions for projects interface IImplicitProjectValidation { /// @notice Invalid redirect url error error InvalidRedirectUrl(); /// @notice Check if a project has a code /// @param wallet The wallet address /// @param attestation The attestation /// @param projectId The project id /// @return magic The attestation magic bytes for the wallet address function validateAttestation( address wallet, Attestation calldata attestation, bytes32 projectId ) external view returns (bytes32); }
ERC1155.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC1155 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol) /// /// @dev Note: /// - The ERC1155 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - The transfer functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC1155 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The lengths of the input arrays are not the same. error ArrayLengthsMismatch(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Only the token owner or an approved account can manage the tokens. error NotOwnerNorApproved(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC1155Receiver interface. error TransferToNonERC1155ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` of token `id` is transferred /// from `from` to `to` by `operator`. event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); /// @dev Emitted when `amounts` of token `ids` are transferred /// from `from` to `to` by `operator`. event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id` /// is updated to `value`. This event is not used in the base contract. /// You may need to emit this event depending on your URI logic. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata event URI(string value, uint256 indexed id); /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`. uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE = 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62; /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`. uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE = 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `ownerSlotSeed` of a given owner is given by. /// ``` /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)) /// ``` /// /// The balance slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, id) /// let balanceSlot := keccak256(0x00, 0x40) /// ``` /// /// The operator approval slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, operator) /// let operatorApprovalSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the URI for token `id`. /// /// You can either return the same templated URI for all token IDs, /// (e.g. "https://example.com/api/{id}.json"), /// or return a unique URI for each `id`. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata function uri(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of `id` owned by `owner`. function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, id) result := sload(keccak256(0x00, 0x40)) } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, operator) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits a {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, caller()) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-line log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Received}, which is called upon a batch transfer. /// /// Emits a {TransferSingle} event. function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155Received} check if `to` is a smart contract. if extcodesize(to) { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) mstore(add(m, 0xc0), data.length) calldatacopy(add(m, 0xe0), data.offset, data.length) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - `ids` and `amounts` must have the same length. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, amounts.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, ids.length) } i {} { i := sub(i, 0x20) let amount := calldataload(add(amounts.offset, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, calldataload(add(ids.offset, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := shl(5, ids.length) mstore(add(m, 0x40), ids.length) calldatacopy(add(m, 0x60), ids.offset, n) // Copy the `amounts`. mstore(add(m, 0x20), add(0x60, n)) let o := add(add(m, n), 0x60) mstore(o, ids.length) calldatacopy(add(o, 0x20), amounts.offset, n) // Do the emit. log4(m, add(add(n, n), 0x80), _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to) } } if (_useAfterTokenTransfer()) { _afterTokenTransferCalldata(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155BatchReceived} check if `to` is a smart contract. if extcodesize(to) { mstore(0x00, to) // Cache `to` to prevent stack too deep. let m := mload(0x40) // Prepare the calldata. // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := shl(5, ids.length) mstore(add(m, 0xc0), ids.length) calldatacopy(add(m, 0xe0), ids.offset, n) // Copy the `amounts`. mstore(add(m, 0x80), add(0xc0, n)) let o := add(add(m, n), 0xe0) mstore(o, ids.length) calldatacopy(add(o, 0x20), amounts.offset, n) // Copy the `data`. mstore(add(m, 0xa0), add(add(0xe0, n), n)) o := add(add(o, n), 0x20) mstore(o, data.length) calldatacopy(add(o, 0x20), data.offset, data.length) let nAll := add(0x104, add(data.length, add(n, n))) // Revert if the call reverts. if iszero(call(gas(), mload(0x00), 0, add(mload(0x40), 0x1c), nAll, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Returns the amounts of `ids` for `owners. /// /// Requirements: /// - `owners` and `ids` must have the same length. function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, owners.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } balances := mload(0x40) mstore(balances, ids.length) let o := add(balances, 0x20) let i := shl(5, ids.length) mstore(0x40, add(i, o)) // Loop through all the `ids` and load the balances. for {} i {} { i := sub(i, 0x20) let owner := calldataload(add(owners.offset, i)) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))) mstore(0x00, calldataload(add(ids.offset, i))) mstore(add(o, i), sload(keccak256(0x00, 0x40))) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` of `id` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Received}, which is called upon a batch transfer. /// /// Emits a {TransferSingle} event. function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Increase and store the updated balance of `to`. { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, to) mstore(0x00, id) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data); } /// @dev Mints `amounts` of `ids` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Loop through all the `ids` and update the balances. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Increase and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), from, id, amount)`. function _burn(address from, uint256 id, uint256 amount) internal virtual { _burn(address(0), from, id, amount); } /// @dev Destroys `amount` of `id` from `from`. /// /// Requirements: /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferSingle} event. function _burn(address by, address from, uint256 id, uint256 amount) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), _single(id), _single(amount), ""); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Decrease and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), _single(id), _single(amount), ""); } } /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`. function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { _batchBurn(address(0), from, ids, amounts); } /// @dev Destroys `amounts` of `ids` from `from`. /// /// Requirements: /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferBatch} event. function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), ids, amounts, ""); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Decrease and store the updated balance of `from`. { mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), ids, amounts, ""); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, by) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) let m := shr(96, not(0)) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`. function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) internal virtual { _safeTransfer(address(0), from, to, id, amount, data); } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Received}, which is called upon a batch transfer. /// /// Emits a {TransferSingle} event. function _safeTransfer( address by, address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) // forgefmt: disable-next-line log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data); } /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`. function _safeBatchTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _safeBatchTransfer(address(0), from, to, ids, amounts, data); } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _safeBatchTransfer( address by, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_) mstore(0x20, fromSlotSeed) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override this function to return true if `_beforeTokenTransfer` is used. /// This is to help the compiler avoid producing dead bytecode. function _useBeforeTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called before any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /// @dev Override this function to return true if `_afterTokenTransfer` is used. /// This is to help the compiler avoid producing dead bytecode. function _useAfterTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called after any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _afterTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for calling the `_afterTokenTransfer` hook. /// This is to help the compiler avoid producing dead bytecode. function _afterTokenTransferCalldata( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) private { if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155Received( address from, address to, uint256 id, uint256 amount, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) let n := mload(data) mstore(add(m, 0xc0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155BatchReceived( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0xc0) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. let s := add(0xa0, returndatasize()) mstore(add(m, 0x80), s) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) // Copy the `data`. mstore(add(m, 0xa0), add(s, returndatasize())) o := add(o, returndatasize()) n := add(0x20, mload(data)) pop(staticcall(gas(), 4, data, n, o, n)) n := sub(add(o, returndatasize()), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Returns `x` in an array with a single element. function _single(uint256 x) private pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x40, add(result, 0x40)) mstore(result, 1) mstore(add(result, 0x20), x) } } }
LibBytes.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for byte related operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) library LibBytes { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct BytesStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the bytes. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the bytes storage `$` to `s`. function set(BytesStorage storage $, bytes memory s) internal { /// @solidity memory-safe-assembly assembly { let n := mload(s) let packed := or(0xff, shl(8, n)) for { let i := 0 } 1 {} { if iszero(gt(n, 0xfe)) { i := 0x1f packed := or(n, shl(8, mload(add(s, i)))) if iszero(gt(n, i)) { break } } let o := add(s, 0x20) mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), mload(add(o, i))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to `s`. function setCalldata(BytesStorage storage $, bytes calldata s) internal { /// @solidity memory-safe-assembly assembly { let packed := or(0xff, shl(8, s.length)) for { let i := 0 } 1 {} { if iszero(gt(s.length, 0xfe)) { i := 0x1f packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) if iszero(gt(s.length, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) i := add(i, 0x20) if iszero(lt(i, s.length)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to the empty bytes. function clear(BytesStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty bytes "". function isEmpty(BytesStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(BytesStorage storage $) internal view returns (uint256 result) { result = uint256($._spacer); /// @solidity memory-safe-assembly assembly { let n := and(0xff, result) result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) } } /// @dev Returns the value stored in `$`. function get(BytesStorage storage $) internal view returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) let packed := sload($.slot) let n := shr(8, packed) for { let i := 0 } 1 {} { if iszero(eq(or(packed, 0xff), packed)) { mstore(o, packed) n := and(0xff, packed) i := 0x1f if iszero(gt(n, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { mstore(add(o, i), sload(add(p, shr(5, i)))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } mstore(result, n) // Store the length of the memory. mstore(add(o, n), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. } } /// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0. function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) { /// @solidity memory-safe-assembly assembly { for { let packed := sload($.slot) } 1 {} { if iszero(eq(or(packed, 0xff), packed)) { if iszero(gt(i, 0x1e)) { result := byte(i, packed) break } if iszero(gt(i, and(0xff, packed))) { mstore(0x00, $.slot) let j := sub(i, 0x1f) result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j)))) } break } if iszero(gt(i, shr(8, packed))) { mstore(0x00, $.slot) result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i)))) } break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTES OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(bytes memory subject, bytes memory needle, bytes memory replacement) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let needleLen := mload(needle) let replacementLen := mload(replacement) let d := sub(result, subject) // Memory difference. let i := add(subject, 0x20) // Subject bytes pointer. mstore(0x00, add(i, mload(subject))) // End of subject. if iszero(gt(needleLen, mload(subject))) { let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, needleLen), h)) { mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let j := 0 } 1 {} { mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) j := add(j, 0x20) if iszero(lt(j, replacementLen)) { break } } d := sub(add(d, replacementLen), needleLen) if needleLen { i := add(i, needleLen) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } } let end := mload(0x00) let n := add(sub(d, add(result, 0x20)), end) // Copy the rest of the bytes one word at a time. for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } let o := add(i, d) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := not(0) // Initialize to `NOT_FOUND`. for { let subjectLen := mload(subject) } 1 {} { if iszero(mload(needle)) { result := from if iszero(gt(from, subjectLen)) { break } result := subjectLen break } let needleLen := mload(needle) let subjectStart := add(subject, 0x20) subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) let m := shl(3, sub(0x20, and(needleLen, 0x1f))) let s := mload(add(needle, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } if iszero(lt(needleLen, 0x20)) { for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, needleLen), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return indexOf(subject, needle, 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let needleLen := mload(needle) if gt(needleLen, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), needleLen) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if eq(keccak256(subject, needleLen), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return lastIndexOf(subject, needle, type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { return indexOf(subject, needle) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `needle`. function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) // Just using keccak256 directly is actually cheaper. let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) result := lt(gt(n, mload(subject)), t) } } /// @dev Returns whether `subject` ends with `needle`. function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) let notInRange := gt(n, mload(subject)) // `subject + 0x20 + max(subject.length - needle.length, 0)`. let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) // Just using keccak256 directly is actually cheaper. result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) } } /// @dev Returns `subject` repeated `times`. function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(or(iszero(times), iszero(l))) { result := mload(0x40) subject := add(subject, 0x20) let o := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let j := 0 } 1 {} { mstore(add(o, j), mload(add(subject, j))) j := add(j, 0x20) if iszero(lt(j, l)) { break } } o := add(o, l) times := sub(times, 1) if iszero(times) { break } } mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, sub(o, add(result, 0x20))) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(gt(l, end)) { end := l } if iszero(gt(l, start)) { start := l } if lt(start, end) { result := mload(0x40) let n := sub(end, start) let i := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let j := and(add(n, 0x1f), w) } 1 {} { mstore(add(result, j), mload(add(i, j))) j := add(j, w) // `sub(j, 0x20)`. if iszero(j) { break } } let o := add(add(result, 0x20), n) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { result = slice(subject, start, type(uint256).max); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start, uint256 end) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, end), sub(end, start)) } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, subject.length), sub(subject.length, start)) } } /// @dev Reduces the size of `subject` to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := subject mstore(mul(lt(n, mload(result)), result), n) } } /// @dev Returns a copy of `subject`, with the length reduced to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.offset := subject.offset result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) } } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let searchLen := mload(needle) if iszero(gt(searchLen, mload(subject))) { result := mload(0x40) let i := add(subject, 0x20) let o := add(result, 0x20) let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, searchLen), h)) { i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. o := add(o, 0x20) i := add(i, searchLen) // Advance `i` by `searchLen`. if searchLen { if iszero(lt(i, subjectSearchEnd)) { break } continue } } i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(o, 0x20)) } } } /// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes. function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) for { let prevIndex := 0 } 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let l := sub(index, prevIndex) mstore(element, l) // Store the length of the element. // Copy the `subject` one word at a time, backwards. for { let o := and(add(l, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. // Allocate memory for the length and the bytes, rounded up to a multiple of 32. mstore(0x40, add(element, and(add(l, 0x3f), w))) mstore(indexPtr, element) // Store the `element` into the array. } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated bytes of `a` and `b`. /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let w := not(0x1f) let aLen := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLen, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLen := mload(b) let output := add(result, aLen) // Copy `b` one word at a time, backwards. for { let o := and(add(bLen, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLen := add(aLen, bLen) let last := add(add(result, 0x20), totalLen) mstore(last, 0) // Zeroize the slot after the bytes. mstore(result, totalLen) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) let bLen := mload(b) let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f)) if n { for { let i := 0x20 } 1 {} { let x := mload(add(a, i)) let y := mload(add(b, i)) if iszero(or(xor(x, y), eq(i, n))) { i := add(i, 0x20) continue } result := sub(gt(x, y), lt(x, y)) break } } // forgefmt: disable-next-item if iszero(result) { let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201 let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0))) let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0))) result := sub(gt(x, y), lt(x, y)) if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) } } } } /// @dev Directly returns `a` without copying. function directReturn(bytes memory a) internal pure { /// @solidity memory-safe-assembly assembly { // Assumes that the bytes does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the bytes is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the bytes. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } /// @dev Directly returns `a` with minimal copying. function directReturn(bytes[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) // `a.length`. let o := add(a, 0x20) // Start of elements in `a`. let u := a // Highest memory slot. let w := not(0x1f) for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. let s := mload(c) // `a[i]`. let l := mload(s) // `a[i].length`. let r := and(l, 0x1f) // `a[i].length % 32`. let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. // If `s` comes before `o`, or `s` is not zero right padded. if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { let m := mload(0x40) mstore(m, l) // Copy `a[i].length`. for {} 1 {} { mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. z := add(z, w) // `sub(z, 0x20)`. if iszero(z) { break } } let e := add(add(m, 0x20), l) mstore(e, 0) // Zeroize the slot after the copied bytes. mstore(0x40, add(e, 0x20)) // Allocate memory. s := m } mstore(c, sub(s, o)) // Convert to calldata offset. let t := add(l, add(s, 0x20)) if iszero(lt(t, u)) { u := t } } let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. mstore(retStart, 0x20) // Store the return offset. return(retStart, add(0x40, sub(u, retStart))) // End the transaction. } } /// @dev Returns the word at `offset`, without any bounds checks. function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(add(add(a, 0x20), offset)) } } /// @dev Returns the word at `offset`, without any bounds checks. function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := calldataload(add(a.offset, offset)) } } /// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks. function staticStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { let l := sub(a.length, 0x20) result.offset := add(a.offset, offset) result.length := sub(a.length, offset) if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) } } } /// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks. function dynamicStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { let l := sub(a.length, 0x20) let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. result.offset := add(a.offset, s) result.length := sub(a.length, s) if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) } } } /// @dev Returns bytes in calldata. Performs bounds checks. function bytesInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { let l := sub(a.length, 0x20) let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. result.offset := add(add(a.offset, s), 0x20) result.length := calldataload(add(a.offset, s)) // forgefmt: disable-next-item if or(shr(64, or(result.length, or(s, or(l, a.offset)))), or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) } } } /// @dev Returns empty calldata bytes. For silencing the compiler. function emptyCalldata() internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.length := 0 } } }
LibString.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {LibBytes} from "./LibBytes.sol"; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated string storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native string storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct StringStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /// @dev The input string must be a 7-bit ASCII. error StringNot7BitASCII(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; /// @dev Lookup for '0123456789'. uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; /// @dev Lookup for '0123456789abcdefABCDEF'. uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; /// @dev Lookup for '01234567'. uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; /// @dev Lookup for ' \t\n\r\x0b\x0c'. uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRING STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the string storage `$` to `s`. function set(StringStorage storage $, string memory s) internal { LibBytes.set(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to `s`. function setCalldata(StringStorage storage $, string calldata s) internal { LibBytes.setCalldata(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to the empty string. function clear(StringStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty string "". function isEmpty(StringStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(StringStorage storage $) internal view returns (uint256) { return LibBytes.length(bytesStorage($)); } /// @dev Returns the value stored in `$`. function get(StringStorage storage $) internal view returns (string memory) { return string(LibBytes.get(bytesStorage($))); } /// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0. function uint8At(StringStorage storage $, uint256 i) internal view returns (uint8) { return LibBytes.uint8At(bytesStorage($), i); } /// @dev Helper to cast `$` to a `BytesStorage`. function bytesStorage(StringStorage storage $) internal pure returns (LibBytes.BytesStorage storage casted) { /// @solidity memory-safe-assembly assembly { casted.slot := $.slot } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly 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. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end of the memory to calculate the length later. let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 1)`. // Store the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(result, add(48, mod(temp, 10))) temp := div(temp, 10) // Keep dividing `temp` until zero. if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. mstore(result, n) // Store the length. } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory result) { if (value >= 0) return toString(uint256(value)); unchecked { result = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let n := mload(result) // Load the string length. mstore(result, 0x2d) // Store the '-' character. result := sub(result, 1) // Move back the string pointer by a byte. mstore(result, add(n, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2 + 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 byteCount) internal pure returns (string memory result) { result = toHexStringNoPrefix(value, byteCount); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 byteCount) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f))) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(result, add(byteCount, byteCount)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(result, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := add(mload(result), 2) // Compute the length. mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := mload(result) // Get the length. result := add(result, o) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory result) { result = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(result, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Allocate memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(result, 0x80)) mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. result := add(result, 2) mstore(result, 40) // Store the length. let o := add(result, 0x20) mstore(add(o, 40), 0) // Zeroize the slot after the string. value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory result) { result = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(raw) result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(result, add(n, n)) // Store the length of the output. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let o := add(result, 0x20) let end := add(raw, n) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 let mask := shl(7, div(not(0), 255)) let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /// @dev Returns if this string is a 7-bit ASCII string, /// AND all characters are in the `allowed` lookup. /// Note: If `s` is empty, returns true regardless of `allowed`. function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if mload(s) { let allowed_ := shr(128, shl(128, allowed)) let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := and(result, shr(byte(0, mload(o)), allowed_)) o := add(o, 1) if iszero(and(result, lt(o, end))) { break } } } } } /// @dev Converts the bytes in the 7-bit ASCII string `s` to /// an allowed lookup for use in `is7BitASCII(s, allowed)`. /// To save runtime gas, you can cache the result in an immutable variable. function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := or(result, shl(byte(0, mload(o)), 1)) o := add(o, 1) if iszero(lt(o, end)) { break } } if shr(128, result) { mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(string memory subject, string memory needle, string memory replacement) internal pure returns (string memory) { return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement))); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.contains(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` starts with `needle`. function startsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.startsWith(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` ends with `needle`. function endsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.endsWith(bytes(subject), bytes(needle)); } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory) { return string(LibBytes.repeat(bytes(subject), times)); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, end)); } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, type(uint256).max)); } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory) { return LibBytes.indicesOf(bytes(subject), bytes(needle)); } /// @dev Returns an arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter)); /// @solidity memory-safe-assembly assembly { result := a } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory) { return string(LibBytes.concat(bytes(a), bytes(b))); } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(subject) if n { result := mload(0x40) let o := add(result, 0x20) let d := sub(subject, result) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) for { let end := add(o, n) } 1 {} { let b := byte(0, mload(add(d, o))) mstore8(o, xor(and(shr(b, flags), 0x20), b)) o := add(o, 1) if eq(o, end) { break } } mstore(result, n) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) // Store the length. let o := add(result, 0x20) mstore(o, s) // Store the bytes of the string. mstore(add(o, n), 0) // Zeroize the slot after the string. mstore(0x40, add(result, 0x40)) // Allocate memory. } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let end := add(s, mload(s)) let o := add(result, 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(o, c) o := add(o, 1) continue } let t := shr(248, mload(c)) mstore(o, mload(and(t, 0x1f))) o := add(o, shr(5, t)) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(o, c) o := add(o, 1) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), c) o := add(o, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(o, mload(0x19)) // "\\u00XX". o := add(o, 6) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), mload(add(c, 8))) o := add(o, 2) } if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Encodes `s` so that it can be safely used in a URI, /// just like `encodeURIComponent` in JavaScript. /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent /// See: https://datatracker.ietf.org/doc/html/rfc2396 /// See: https://datatracker.ietf.org/doc/html/rfc3986 function encodeURIComponent(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Store "0123456789ABCDEF" in scratch space. // Uppercased to be consistent with JavaScript's implementation. mstore(0x0f, 0x30313233343536373839414243444546) let o := add(result, 0x20) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // If not in `[0-9A-Z-a-z-_.!~*'()]`. if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { mstore8(o, 0x25) // '%'. mstore8(add(o, 1), mload(and(shr(4, c), 15))) mstore8(add(o, 2), mload(and(c, 15))) o := add(o, 3) continue } mstore8(o, c) o := add(o, 1) } mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. function cmp(string memory a, string memory b) internal pure returns (int256) { return LibBytes.cmp(bytes(a), bytes(b)); } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(result, 0) // Zeroize the length slot. mstore(add(result, 0x1f), packed) // Store the length and bytes. mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( or( // Load the length and the bytes of `a` and `b`. shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), // `totalLen != 0 && totalLen < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLen, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { resultA := mload(0x40) // Grab the free memory pointer. resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { /// @solidity memory-safe-assembly assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
SequenceProxyFactory.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { ITransparentUpgradeableBeaconProxy, TransparentUpgradeableBeaconProxy } from "./TransparentUpgradeableBeaconProxy.sol"; import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol"; import { UpgradeableBeacon } from "openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol"; import { Create2 } from "openzeppelin-contracts/contracts/utils/Create2.sol"; /** * An proxy factory that deploys upgradeable beacon proxies. * @dev The factory owner is able to upgrade the beacon implementation. * @dev Proxy deployers are able to override the beacon reference with their own. */ abstract contract SequenceProxyFactory is Ownable { UpgradeableBeacon public beacon; /** * Initialize a Sequence Proxy Factory. * @param implementation The initial beacon implementation. * @param factoryOwner The owner of the factory. */ function _initialize(address implementation, address factoryOwner) internal { beacon = new UpgradeableBeacon(implementation); Ownable._transferOwnership(factoryOwner); } /** * Deploys and initializes a new proxy instance. * @param _salt The deployment salt. * @param _proxyOwner The owner of the proxy. * @param _data The initialization data. * @return proxyAddress The address of the deployed proxy. */ function _createProxy( bytes32 _salt, address _proxyOwner, bytes memory _data ) internal returns (address proxyAddress) { bytes32 saltedHash = keccak256(abi.encodePacked(_salt, _proxyOwner, address(beacon), _data)); bytes memory bytecode = type(TransparentUpgradeableBeaconProxy).creationCode; proxyAddress = Create2.deploy(0, saltedHash, bytecode); ITransparentUpgradeableBeaconProxy(payable(proxyAddress)).initialize(_proxyOwner, address(beacon), _data); } /** * Computes the address of a proxy instance. * @param _salt The deployment salt. * @param _proxyOwner The owner of the proxy. * @return proxy The expected address of the deployed proxy. */ function _computeProxyAddress( bytes32 _salt, address _proxyOwner, bytes memory _data ) internal view returns (address) { bytes32 saltedHash = keccak256(abi.encodePacked(_salt, _proxyOwner, address(beacon), _data)); bytes32 bytecodeHash = keccak256(type(TransparentUpgradeableBeaconProxy).creationCode); return Create2.computeAddress(saltedHash, bytecodeHash); } /** * Upgrades the beacon implementation. * @param implementation The new beacon implementation. */ function upgradeBeacon( address implementation ) public onlyOwner { beacon.upgradeTo(implementation); } }
TransparentUpgradeableBeaconProxy.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { BeaconProxy, Proxy } from "./openzeppelin/BeaconProxy.sol"; import { ERC1967Proxy, TransparentUpgradeableProxy } from "./openzeppelin/TransparentUpgradeableProxy.sol"; interface ITransparentUpgradeableBeaconProxy { function initialize(address admin, address beacon, bytes memory data) external; } error InvalidInitialization(); /** * @dev As the underlying proxy implementation (TransparentUpgradeableProxy) allows the admin to call the implementation, * care must be taken to avoid proxy selector collisions. Implementation selectors must not conflict with the proxy selectors. * See https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing]. * The proxy selectors are: * - 0xcf7a1d77: initialize * - 0x3659cfe6: upgradeTo (from TransparentUpgradeableProxy) * - 0x4f1ef286: upgradeToAndCall (from TransparentUpgradeableProxy) * - 0x8f283970: changeAdmin (from TransparentUpgradeableProxy) * - 0xf851a440: admin (from TransparentUpgradeableProxy) * - 0x5c60da1b: implementation (from TransparentUpgradeableProxy) */ contract TransparentUpgradeableBeaconProxy is TransparentUpgradeableProxy, BeaconProxy { /** * Decode the initialization data from the msg.data and call the initialize function. */ function _dispatchInitialize() private returns (bytes memory) { _requireZeroValue(); (address admin, address beacon, bytes memory data) = abi.decode(msg.data[4:], (address, address, bytes)); initialize(admin, beacon, data); return ""; } function initialize(address admin, address beacon, bytes memory data) internal { if (_admin() != address(0)) { // Redundant call. This function can only be called when the admin is not set. revert InvalidInitialization(); } _changeAdmin(admin); _upgradeBeaconToAndCall(beacon, data, false); } /** * @dev If the admin is not set, the fallback function is used to initialize the proxy. * @dev If the admin is set, the fallback function is used to delegatecall the implementation. */ function _fallback() internal override(TransparentUpgradeableProxy, Proxy) { if (_getAdmin() == address(0)) { bytes memory ret; bytes4 selector = msg.sig; if (selector == ITransparentUpgradeableBeaconProxy.initialize.selector) { ret = _dispatchInitialize(); // solhint-disable-next-line no-inline-assembly assembly { return(add(ret, 0x20), mload(ret)) } } // When the admin is not set, the fallback function is used to initialize the proxy. revert InvalidInitialization(); } TransparentUpgradeableProxy._fallback(); } /** * Returns the current implementation address. * @dev This is the implementation address set by the admin, or the beacon implementation. */ function _implementation() internal view override(ERC1967Proxy, BeaconProxy) returns (address) { address implementation = ERC1967Proxy._implementation(); if (implementation != address(0)) { return implementation; } return BeaconProxy._implementation(); } }
BeaconProxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol) // Note: This implementation is an exact copy with the constructor removed, and pragma and imports updated. pragma solidity ^0.8.19; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; import "openzeppelin-contracts/contracts/proxy/Proxy.sol"; import "openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. * * _Available since v3.4._ */ contract BeaconProxy is Proxy, ERC1967Upgrade { /** * @dev Returns the current beacon address. */ function _beacon() internal view virtual returns (address) { return _getBeacon(); } /** * @dev Returns the current implementation address of the associated beacon. */ function _implementation() internal view virtual override returns (address) { return IBeacon(_getBeacon()).implementation(); } /** * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. * * Requirements: * * - `beacon` must be a contract. * - The implementation returned by `beacon` must be a contract. */ function _setBeacon(address beacon, bytes memory data) internal virtual { _upgradeBeaconToAndCall(beacon, data, false); } }
ERC1967Proxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol) // Note: This implementation is an exact copy with the constructor removed, and pragma and imports updated. pragma solidity ^0.8.19; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; import "openzeppelin-contracts/contracts/proxy/Proxy.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
TransparentUpgradeableProxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/transparent/TransparentUpgradeableProxy.sol) /// @notice This implementation is a copy of OpenZeppelin's with the following changes: /// - Pragma updated /// - Imports updated /// - Constructor removed /// - Allows admin to call implementation pragma solidity ^0.8.19; import "./ERC1967Proxy.sol"; /** * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} * does not implement this interface directly, and some of its functions are implemented by an internal dispatch * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not * include them in the ABI so this interface must be used to interact with it. */ interface ITransparentUpgradeableProxy is IERC1967 { function admin() external view returns (address); function implementation() external view returns (address); function changeAdmin( address ) external; function upgradeTo( address ) external; function upgradeToAndCall(address, bytes memory) external payable; } /** * @dev This contract implements a proxy that is upgradeable by an admin. * * Unlike the original OpenZeppelin implementation, this contract does not prevent the admin from calling the implementation. * This potentially exposes the admin to a proxy selector attack. See * https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing]. * When using this contract, you must ensure that the implementation function selectors do not clash with the proxy selectors. * The proxy selectors are: * - 0x3659cfe6: upgradeTo * - 0x4f1ef286: upgradeToAndCall * - 0x8f283970: changeAdmin * - 0xf851a440: admin * - 0x5c60da1b: implementation * * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not * inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the * implementation. * * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler * will not check that there are no selector conflicts, due to the note above. A selector clash between any new function * and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could * render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. * * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the * implementation provides a function with the same selector. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } } /** * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior */ function _fallback() internal virtual override { if (msg.sender == _getAdmin()) { bytes memory ret; bytes4 selector = msg.sig; if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) { ret = _dispatchUpgradeTo(); } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) { ret = _dispatchUpgradeToAndCall(); } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) { ret = _dispatchChangeAdmin(); } else if (selector == ITransparentUpgradeableProxy.admin.selector) { ret = _dispatchAdmin(); } else if (selector == ITransparentUpgradeableProxy.implementation.selector) { ret = _dispatchImplementation(); } else { // Call implementation return super._fallback(); } assembly { return(add(ret, 0x20), mload(ret)) } } else { super._fallback(); } } /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function _dispatchAdmin() private returns (bytes memory) { _requireZeroValue(); address admin = _getAdmin(); return abi.encode(admin); } /** * @dev Returns the current implementation. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function _dispatchImplementation() private returns (bytes memory) { _requireZeroValue(); address implementation = _implementation(); return abi.encode(implementation); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _dispatchChangeAdmin() private returns (bytes memory) { _requireZeroValue(); address newAdmin = abi.decode(msg.data[4:], (address)); _changeAdmin(newAdmin); return ""; } /** * @dev Upgrade the implementation of the proxy. */ function _dispatchUpgradeTo() private returns (bytes memory) { _requireZeroValue(); address newImplementation = abi.decode(msg.data[4:], (address)); _upgradeToAndCall(newImplementation, bytes(""), false); return ""; } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. */ function _dispatchUpgradeToAndCall() private returns (bytes memory) { (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); _upgradeToAndCall(newImplementation, data, true); return ""; } /** * @dev Returns the current admin. * * CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead. */ function _admin() internal view virtual returns (address) { return _getAdmin(); } /** * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to * emulate some proxy functions being non-payable while still allowing value to pass through. */ function _requireZeroValue() internal { require(msg.value == 0); } }
ERC1155BaseToken.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { ERC2981Controlled } from "../common/ERC2981Controlled.sol"; import { SignalsImplicitModeControlled } from "../common/SignalsImplicitModeControlled.sol"; import { ERC1155, ERC1155Supply } from "./extensions/supply/ERC1155Supply.sol"; import { LibString } from "solady/utils/LibString.sol"; error InvalidInitialization(); /** * A standard base implementation of ERC-1155 for use in Sequence library contracts. */ abstract contract ERC1155BaseToken is ERC1155Supply, ERC2981Controlled, SignalsImplicitModeControlled { bytes32 internal constant METADATA_ADMIN_ROLE = keccak256("METADATA_ADMIN_ROLE"); string public name; string public baseURI; string public contractURI; /** * Deploy contract. */ constructor() { } /** * Initialize the contract. * @param owner Owner address. * @param tokenName Token name. * @param tokenBaseURI Base URI for token metadata. * @param tokenContractURI Contract URI for token metadata. * @param implicitModeValidator Implicit session validator address. * @param implicitModeProjectId Implicit session project id. * @dev This should be called immediately after deployment. */ function _initialize( address owner, string memory tokenName, string memory tokenBaseURI, string memory tokenContractURI, address implicitModeValidator, bytes32 implicitModeProjectId ) internal { name = tokenName; baseURI = tokenBaseURI; contractURI = tokenContractURI; _grantRole(DEFAULT_ADMIN_ROLE, owner); _grantRole(ROYALTY_ADMIN_ROLE, owner); _grantRole(METADATA_ADMIN_ROLE, owner); _initializeImplicitMode(owner, implicitModeValidator, implicitModeProjectId); } // // Metadata // /// @inheritdoc ERC1155 function uri( uint256 _id ) public view virtual override returns (string memory) { return string(abi.encodePacked(baseURI, LibString.toString(_id), ".json")); } /** * Update the base URI of token's URI. * @param tokenBaseURI New base URI of token's URI */ function setBaseMetadataURI( string memory tokenBaseURI ) external onlyRole(METADATA_ADMIN_ROLE) { baseURI = tokenBaseURI; } /** * Update the name of the contract. * @param tokenName New contract name */ function setContractName( string memory tokenName ) external onlyRole(METADATA_ADMIN_ROLE) { name = tokenName; } /** * Update the contract URI of token's URI. * @param tokenContractURI New contract URI of token's URI * @notice Refer to https://docs.opensea.io/docs/contract-level-metadata */ function setContractURI( string memory tokenContractURI ) external onlyRole(METADATA_ADMIN_ROLE) { contractURI = tokenContractURI; } // // Burn // /** * Allows the owner of the token to burn their tokens. * @param tokenId Id of token to burn * @param amount Amount of tokens to burn */ function burn(uint256 tokenId, uint256 amount) public virtual { _burn(msg.sender, tokenId, amount); } /** * Burn tokens of given token id for each (tokenIds[i], amounts[i]) pair. * @param tokenIds Array of token ids to burn * @param amounts Array of the amount to be burned */ function batchBurn(uint256[] memory tokenIds, uint256[] memory amounts) public virtual { super._batchBurn(msg.sender, tokenIds, amounts); } // // Views // /** * Check interface support. * @param interfaceId Interface id * @return True if supported */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155Supply, ERC2981Controlled, SignalsImplicitModeControlled) returns (bool) { return ERC1155Supply.supportsInterface(interfaceId) || ERC2981Controlled.supportsInterface(interfaceId) || SignalsImplicitModeControlled.supportsInterface(interfaceId); } }
ERC1155Supply.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { IERC1155Supply, IERC1155SupplyFunctions } from "./IERC1155Supply.sol"; import { ERC1155 } from "solady/tokens/ERC1155.sol"; /** * An ERC-1155 extension that tracks token supply. */ abstract contract ERC1155Supply is ERC1155, IERC1155Supply { // Current supply uint256 public totalSupply; mapping(uint256 => uint256) public tokenSupply; /** * Mint _amount of tokens of a given id * @param _to The address to mint tokens to * @param _id Token id to mint * @param _amount The amount to be minted * @param _data Data to pass if receiver is contract */ function _mint(address _to, uint256 _id, uint256 _amount, bytes memory _data) internal virtual override { super._mint(_to, _id, _amount, _data); totalSupply += _amount; tokenSupply[_id] += _amount; } /** * Mint tokens for each ids in _ids * @param _to The address to mint tokens to * @param _ids Array of ids to mint * @param _amounts Array of amount of tokens to mint per id * @param _data Data to pass if receiver is contract */ function _batchMint( address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data ) internal virtual override { super._batchMint(_to, _ids, _amounts, _data); uint256 nMint = _ids.length; uint256 totalAmount = 0; for (uint256 i = 0; i < nMint; i++) { totalAmount += _amounts[i]; tokenSupply[_ids[i]] += _amounts[i]; } totalSupply += totalAmount; } /** * Burn _amount of tokens of a given token id * @param _from The address to burn tokens from * @param _id Token id to burn * @param _amount The amount to be burned */ function _burn(address _from, uint256 _id, uint256 _amount) internal virtual override { super._burn(_from, _id, _amount); totalSupply -= _amount; tokenSupply[_id] -= _amount; } /** * Burn tokens of given token id for each (_ids[i], _amounts[i]) pair * @param _from The address to burn tokens from * @param _ids Array of token ids to burn * @param _amounts Array of the amount to be burned */ function _batchBurn(address _from, uint256[] memory _ids, uint256[] memory _amounts) internal virtual override { super._batchBurn(_from, _ids, _amounts); uint256 nBurn = _ids.length; uint256 totalAmount = 0; for (uint256 i = 0; i < nBurn; i++) { tokenSupply[_ids[i]] -= _amounts[i]; totalAmount += _amounts[i]; } totalSupply -= totalAmount; } // // Views // /** * Check interface support. * @param interfaceId Interface id * @return True if supported */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155) returns (bool) { return type(IERC1155SupplyFunctions).interfaceId == interfaceId || super.supportsInterface(interfaceId); } }
IERC1155Supply.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; interface IERC1155SupplyFunctions { /** * Returns the total supply of ERC1155 tokens. */ function totalSupply() external returns (uint256); /** * Returns the total supply of a given ERC1155 token. * @param tokenId The ERC1155 token id. */ function tokenSupply( uint256 tokenId ) external returns (uint256); } interface IERC1155SupplySignals { /** * Invalid array input length. */ error InvalidArrayLength(); } interface IERC1155Supply is IERC1155SupplySignals { }
ERC1155Items.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { ERC1155BaseToken, ERC2981Controlled } from "../../ERC1155BaseToken.sol"; import { IERC1155Items, IERC1155ItemsFunctions } from "./IERC1155Items.sol"; /** * An implementation of ERC-1155 capable of minting when role provided. */ contract ERC1155Items is ERC1155BaseToken, IERC1155Items { bytes32 internal constant MINTER_ROLE = keccak256("MINTER_ROLE"); address private immutable initializer; bool private initialized; constructor() { initializer = msg.sender; } /** * Initialize the contract. * @param owner Owner address * @param tokenName Token name * @param tokenBaseURI Base URI for token metadata * @param tokenContractURI Contract URI for token metadata * @param royaltyReceiver Address of who should be sent the royalty payment * @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) * @param implicitModeValidator The implicit mode validator address * @param implicitModeProjectId The implicit mode project id * @dev This should be called immediately after deployment. */ function initialize( address owner, string memory tokenName, string memory tokenBaseURI, string memory tokenContractURI, address royaltyReceiver, uint96 royaltyFeeNumerator, address implicitModeValidator, bytes32 implicitModeProjectId ) public virtual { if (msg.sender != initializer || initialized) { revert InvalidInitialization(); } ERC1155BaseToken._initialize( owner, tokenName, tokenBaseURI, tokenContractURI, implicitModeValidator, implicitModeProjectId ); _setDefaultRoyalty(royaltyReceiver, royaltyFeeNumerator); _grantRole(MINTER_ROLE, owner); initialized = true; } // // Minting // /** * Mint tokens. * @param to Address to mint tokens to. * @param tokenId Token ID to mint. * @param amount Amount of tokens to mint. * @param data Data to pass if receiver is contract. */ function mint(address to, uint256 tokenId, uint256 amount, bytes memory data) external onlyRole(MINTER_ROLE) { _mint(to, tokenId, amount, data); } /** * Mint tokens. * @param to Address to mint tokens to. * @param tokenIds Token IDs to mint. * @param amounts Amounts of tokens to mint. * @param data Data to pass if receiver is contract. */ function batchMint( address to, uint256[] memory tokenIds, uint256[] memory amounts, bytes memory data ) external onlyRole(MINTER_ROLE) { _batchMint(to, tokenIds, amounts, data); } // // Views // /** * Check interface support. * @param interfaceId Interface id * @return True if supported */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155BaseToken) returns (bool) { return type(IERC1155ItemsFunctions).interfaceId == interfaceId || ERC1155BaseToken.supportsInterface(interfaceId) || super.supportsInterface(interfaceId); } }
ERC1155ItemsFactory.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { SequenceProxyFactory } from "../../../../proxies/SequenceProxyFactory.sol"; import { ERC1155Items } from "./ERC1155Items.sol"; import { IERC1155ItemsFactory, IERC1155ItemsFactoryFunctions } from "./IERC1155ItemsFactory.sol"; /** * Deployer of ERC-1155 Items proxies. */ contract ERC1155ItemsFactory is IERC1155ItemsFactory, SequenceProxyFactory { /** * Creates an ERC-1155 Items Factory. * @param factoryOwner The owner of the ERC-1155 Items Factory */ constructor( address factoryOwner ) { ERC1155Items impl = new ERC1155Items(); SequenceProxyFactory._initialize(address(impl), factoryOwner); } /// @inheritdoc IERC1155ItemsFactoryFunctions function deploy( address proxyOwner, address tokenOwner, string memory name, string memory baseURI, string memory contractURI, address royaltyReceiver, uint96 royaltyFeeNumerator, address implicitModeValidator, bytes32 implicitModeProjectId ) external returns (address proxyAddr) { bytes32 salt = keccak256( abi.encode( tokenOwner, name, baseURI, contractURI, royaltyReceiver, royaltyFeeNumerator, implicitModeValidator, implicitModeProjectId ) ); proxyAddr = _createProxy(salt, proxyOwner, ""); ERC1155Items(proxyAddr).initialize( tokenOwner, name, baseURI, contractURI, royaltyReceiver, royaltyFeeNumerator, implicitModeValidator, implicitModeProjectId ); emit ERC1155ItemsDeployed(proxyAddr); return proxyAddr; } /// @inheritdoc IERC1155ItemsFactoryFunctions function determineAddress( address proxyOwner, address tokenOwner, string memory name, string memory baseURI, string memory contractURI, address royaltyReceiver, uint96 royaltyFeeNumerator, address implicitModeValidator, bytes32 implicitModeProjectId ) external view returns (address proxyAddr) { bytes32 salt = keccak256( abi.encode( tokenOwner, name, baseURI, contractURI, royaltyReceiver, royaltyFeeNumerator, implicitModeValidator, implicitModeProjectId ) ); return _computeProxyAddress(salt, proxyOwner, ""); } }
IERC1155Items.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; interface IERC1155ItemsFunctions { /** * Mint tokens. * @param to Address to mint tokens to. * @param tokenId Token ID to mint. * @param amount Amount of tokens to mint. * @param data Data to pass if receiver is contract. */ function mint(address to, uint256 tokenId, uint256 amount, bytes memory data) external; /** * Mint tokens. * @param to Address to mint tokens to. * @param tokenIds Token IDs to mint. * @param amounts Amounts of tokens to mint. * @param data Data to pass if receiver is contract. */ function batchMint(address to, uint256[] memory tokenIds, uint256[] memory amounts, bytes memory data) external; } interface IERC1155ItemsSignals { /** * Invalid initialization error. */ error InvalidInitialization(); } interface IERC1155Items is IERC1155ItemsFunctions, IERC1155ItemsSignals { }
IERC1155ItemsFactory.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; interface IERC1155ItemsFactoryFunctions { /** * Creates an ERC-1155 Items proxy. * @param proxyOwner The owner of the ERC-1155 Items proxy * @param tokenOwner The owner of the ERC-1155 Items implementation * @param name The name of the ERC-1155 Items proxy * @param baseURI The base URI of the ERC-1155 Items proxy * @param contractURI The contract URI of the ERC-1155 Items proxy * @param royaltyReceiver Address of who should be sent the royalty payment * @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) * @param implicitModeValidator The implicit mode validator address * @param implicitModeProjectId The implicit mode project id * @return proxyAddr The address of the ERC-1155 Items Proxy */ function deploy( address proxyOwner, address tokenOwner, string memory name, string memory baseURI, string memory contractURI, address royaltyReceiver, uint96 royaltyFeeNumerator, address implicitModeValidator, bytes32 implicitModeProjectId ) external returns (address proxyAddr); /** * Computes the address of a proxy instance. * @param proxyOwner The owner of the ERC-1155 Items proxy * @param tokenOwner The owner of the ERC-1155 Items implementation * @param name The name of the ERC-1155 Items proxy * @param baseURI The base URI of the ERC-1155 Items proxy * @param contractURI The contract URI of the ERC-1155 Items proxy * @param royaltyReceiver Address of who should be sent the royalty payment * @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) * @param implicitModeValidator The implicit mode validator address * @param implicitModeProjectId The implicit mode project id * @return proxyAddr The address of the ERC-1155 Items Proxy */ function determineAddress( address proxyOwner, address tokenOwner, string memory name, string memory baseURI, string memory contractURI, address royaltyReceiver, uint96 royaltyFeeNumerator, address implicitModeValidator, bytes32 implicitModeProjectId ) external returns (address proxyAddr); } interface IERC1155ItemsFactorySignals { /** * Event emitted when a new ERC-1155 Items proxy contract is deployed. * @param proxyAddr The address of the deployed proxy. */ event ERC1155ItemsDeployed(address proxyAddr); } interface IERC1155ItemsFactory is IERC1155ItemsFactoryFunctions, IERC1155ItemsFactorySignals { }
ERC2981Controlled.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { IERC2981Controlled } from "./IERC2981Controlled.sol"; import { AccessControlEnumerable } from "openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol"; import { ERC2981 } from "openzeppelin-contracts/contracts/token/common/ERC2981.sol"; /** * An implementation of ERC-2981 that allows updates by roles. */ abstract contract ERC2981Controlled is ERC2981, AccessControlEnumerable, IERC2981Controlled { bytes32 internal constant ROYALTY_ADMIN_ROLE = keccak256("ROYALTY_ADMIN_ROLE"); // // Royalty // /** * Sets the royalty information that all ids in this contract will default to. * @param receiver Address of who should be sent the royalty payment * @param feeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyRole(ROYALTY_ADMIN_ROLE) { _setDefaultRoyalty(receiver, feeNumerator); } /** * Sets the royalty information that a given token id in this contract will use. * @param tokenId The token id to set the royalty information for * @param receiver Address of who should be sent the royalty payment * @param feeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) * @notice This overrides the default royalty information for this token id */ function setTokenRoyalty( uint256 tokenId, address receiver, uint96 feeNumerator ) external onlyRole(ROYALTY_ADMIN_ROLE) { _setTokenRoyalty(tokenId, receiver, feeNumerator); } // // Views // /** * Check interface support. * @param interfaceId Interface id * @return True if supported */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC2981, AccessControlEnumerable) returns (bool) { return ERC2981.supportsInterface(interfaceId) || AccessControlEnumerable.supportsInterface(interfaceId) || type(IERC2981Controlled).interfaceId == interfaceId || super.supportsInterface(interfaceId); } }
IERC2981Controlled.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; interface IERC2981ControlledFunctions { /** * Sets the royalty information that all ids in this contract will default to. * @param receiver Address of who should be sent the royalty payment * @param feeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external; /** * Sets the royalty information that a given token id in this contract will use. * @param tokenId The token id to set the royalty information for * @param receiver Address of who should be sent the royalty payment * @param feeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500) * @notice This overrides the default royalty information for this token id */ function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external; } interface IERC2981Controlled is IERC2981ControlledFunctions { }
SignalsImplicitModeControlled.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.19; import { AccessControlEnumerable } from "openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol"; import { IERC165, IImplicitProjectValidation, SignalsImplicitMode } from "signals-implicit-mode/src/helper/SignalsImplicitMode.sol"; /** * An abstract contract that allows implicit session access for a given project. */ abstract contract SignalsImplicitModeControlled is AccessControlEnumerable, SignalsImplicitMode { bytes32 internal constant _IMPLICIT_MODE_ADMIN_ROLE = keccak256("IMPLICIT_MODE_ADMIN_ROLE"); function _initializeImplicitMode(address owner, address validator, bytes32 projectId) internal { _grantRole(_IMPLICIT_MODE_ADMIN_ROLE, owner); _initializeSignalsImplicitMode(validator, projectId); } /** * Updates the validator for implicit mode validation. * @param validator The validator address. * @notice Only callable by an address with the project admin role. */ function setImplicitModeValidator( address validator ) external onlyRole(_IMPLICIT_MODE_ADMIN_ROLE) { _validator = IImplicitProjectValidation(validator); } /** * Updates the settings for implicit mode validation. * @param projectId The project id. * @notice Only callable by an address with the project admin role. */ function setImplicitModeProjectId( bytes32 projectId ) external onlyRole(_IMPLICIT_MODE_ADMIN_ROLE) { _projectId = projectId; } /// @inheritdoc IERC165 function supportsInterface( bytes4 interfaceId ) public view virtual override(AccessControlEnumerable, SignalsImplicitMode) returns (bool) { return AccessControlEnumerable.supportsInterface(interfaceId) || SignalsImplicitMode.supportsInterface(interfaceId); } }
Gas Token: