Address Contract Verified
Address
0x77f48CCB3EDE5bF4aBFB8eeFe61739ED01C240ce
Balance
0 ETH
Nonce
3
Code Size
11484 bytes
Creator
0x928640eA...F07C at tx 0xfdca0cc5...2d5510
Indexed Transactions
0
Contract Bytecode
11484 bytes
0x6080604052600436101562000014575b600080fd5b60003560e01c806304789c98146200010f5780630eb92516146200010457806314afd79e14620000f95780634b42e8d514620000ee57806351710e4514620000e357806366a2489f14620000d85780636d43542114620000cd5780637b37e56114620000c2578063906c87cc14620000b7578063dca0938314620000ac5763e89fad5814620000a257600080fd5b6200000f62000d34565b506200000f62000a6c565b506200000f62000a1e565b506200000f6200095d565b506200000f62000835565b506200000f62000797565b506200000f620005ef565b506200000f62000556565b506200000f6200050b565b506200000f62000463565b506200000f62000222565b600435906001600160a01b03821682036200000f57565b606435906001600160a01b03821682036200000f57565b602435906001600160a01b03821682036200000f57565b919082519283825260005b8481106200018c575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016200016a565b91959492620001d3918352620001c460209760a08986015260a08501906200015f565b9083820360408501526200015f565b818103606083015285808551928381520194019060005b8181106200020d575050506200020a93945060808184039101526200015f565b90565b825186529487019491870191600101620001ea565b50346200000f576020806003193601126200000f57620002416200011a565b906200024d826200157b565b60009160018060a01b0381168352828252604080842092815192608051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f87527f0aa333075d560d6d2e102e9d7afe8a8ba8b4a3ec41e19473caad880f9eb5fbe683527fe6bbd6277e1bf288eed5e8d1780f9a50b239e86b153736bceebccf4ea79d90b384524660605260805260a0862093835285606052608052620002f76002850162001409565b93620003066003820162001409565b90600581019684518094808a54928381520199835280832092905b8282106200035f575050505060046200034f9162000348856200035b98999a0386620003b2565b0162001409565b925195869586620001a1565b0390f35b83548b52998a01996001938401939091019062000321565b50634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff8111620003a357604052565b620003ad62000377565b604052565b90601f8019910116810190811067ffffffffffffffff821117620003a357604052565b604051906020820182811067ffffffffffffffff821117620003a357604052565b81601f820112156200000f5780359067ffffffffffffffff821162000453575b6040519262000430601f8401601f191660200185620003b2565b828452602083830101116200000f57816000926020809301838601378301015290565b6200045d62000377565b62000416565b50346200000f5760a03660031901126200000f5767ffffffffffffffff6004358181116200000f576200049b903690600401620003f6565b906024358181116200000f57620004b7903690600401620003f6565b916044359182116200000f576200035b92620004dc620004f1933690600401620003f6565b620004e662000131565b9160843593620010d9565b6040516001600160a01b0390911681529081906020820190565b50346200000f5760203660031901126200000f5760206200052b6200011a565b62000536816200157b565b60018060a01b038091166000526000825260406000205416604051908152f35b50346200000f5760203660031901126200000f576040516001600160f81b031960208083019182526bffffffffffffffffffffffff193060601b16602184015260043560358401527fac00cb7082c31222a6e9858037310d59564fa6ef5b4ae03d11cc79ad4c7a2ee860558085019190915283529190620005d9607583620003b2565b905190206040516001600160a01b039091168152f35b50346200000f5760203660031901126200000f576200060d6200011a565b62000618816200157b565b620006596200064d60016200063f8460018060a01b03166000526000602052604060002090565b01546001600160a01b031690565b6001600160a01b031690565b33036200072e576200072b600091827f11a3cf439fb225bfe74225716b6774765670ec1060e3796802e62139d69974da8180a2620006c06001620006af8360018060a01b03166000526000602052604060002090565b0180546001600160a01b0319169055565b6001600160a01b03818116600081815260208190526040902054339216907fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8680a46001600160a01b0316600090815260208190526040902080546001600160a01b03191633179055565b80f35b6040516388c3a11560e01b81526001600160a01b03919091166004820152602490fd5b6020908160408183019282815285518094520193019160005b82811062000779575050505090565b83516001600160a01b0316855293810193928101926001016200076a565b50346200000f576020806003193601126200000f57620007b66200011a565b90620007c2826200157b565b60018060a01b0391826000911681528082526007604082200192604051908193808654938481520195845280842093915b8383106200081b576200035b866200080e818a0382620003b2565b6040519182918262000751565b8454811687529581019560019485019490920191620007f3565b50346200000f5760403660031901126200000f57620008536200011a565b6200085d62000148565b906200086981620014b9565b6001600160a01b03828116908115620009435750620008a46200064d60016200063f8560018060a01b03166000526000602052604060002090565b81146200091957620008f76200091793926001927f11a3cf439fb225bfe74225716b6774765670ec1060e3796802e62139d69974da600080a26001600160a01b0316600090815260208190526040902090565b0180546001600160a01b0319166001600160a01b03909216919091179055565b005b506040516365e0406560e11b81526001600160a01b03918216600482015291166024820152604490fd5b60405163a388d26360e01b81529083166004820152602490fd5b50346200000f5760203660031901126200000f576200097b6200011a565b6200098681620014b9565b6001600160a01b03818116600081815260208190526040812060010154909392161562000a065750620009f4600191837f11a3cf439fb225bfe74225716b6774765670ec1060e3796802e62139d69974da8180a26001600160a01b0316600090815260208190526040902090565b0180546001600160a01b031916905580f35b602490604051906335809b0b60e11b82526004820152fd5b50346200000f5760203660031901126200000f57602062000a3e6200011a565b62000a49816200157b565b60018060a01b038091166000526000825260016040600020015416604051908152f35b50346200000f5760603660031901126200000f5762000a8a6200011a565b62000a9462000148565b6044359182151583036200000f5762000aad8162001503565b6001600160a01b03811660009081526020819052604090209262000ad3818486620015b0565b6001600160a01b03828116803b156200000f5760405163f460590b60e01b81526001600160a01b03861660048201528315156024820152906000908290604490829084905af1801562000d24575b62000d06575b5062000b8e62000b7f856006880162000b688662000b5784849060018060a01b0316600052602052604060002090565b9060ff801983541691151516179055565b9060018060a01b0316600052602052604060002090565b805461ff001916610100179055565b811562000bfc575062000bf79062000bcb8460077fb658b57f3a8d73a4f3bb96789edcebed831f44d5cc4a513d4416c6bb25ea0e8b9701620013cd565b604080516001600160a01b03948516815294909316602085015215159183019190915281906060820190565b0390a1005b838116946007019060005b82548082101562000cd457878362000c3962000c24858862001332565b905460039190911b1c6001600160a01b031690565b161462000c4a575060010162000c07565b7fb658b57f3a8d73a4f3bb96789edcebed831f44d5cc4a513d4416c6bb25ea0e8b975062000cce925062000bf794939162000ca462000c9c62000c2462000c9562000cc89562001361565b8662001332565b918462001332565b90919082549060031b9160018060a01b039283811b93849216901b16911916179055565b62001387565b62000bcb565b505050507fb658b57f3a8d73a4f3bb96789edcebed831f44d5cc4a513d4416c6bb25ea0e8b935062000bf79062000bcb565b8062000d1662000d1d926200038e565b8062001326565b3862000b27565b62000d2e62000e83565b62000b21565b50346200000f5760403660031901126200000f5762000d526200011a565b602490813567ffffffffffffffff8082116200000f57366023830112156200000f5781600401359081116200000f57368482840101116200000f5762000d988362001503565b60009260018060a01b03168352602093838552600360408520019262000dcb8362000dc4865462000e90565b8662000ee6565b8495601f841160011462000e0d57509484958394959362000dff575b5050508160011b916000199060031b1c191617905580f35b010135905038808062000de7565b91601f1984169662000e2486600052602060002090565b9387905b89821062000e685750508460019697981062000e4b575b50505050811b01905580f35b60001960f88660031b161c19920101351690553880808062000e3f565b80600184978683959689010135815501960192019062000e28565b506040513d6000823e3d90fd5b90600182811c9216801562000ec2575b602083101462000eac57565b634e487b7160e01b600052602260045260246000fd5b91607f169162000ea0565b81811062000ed9575050565b6000815560010162000ecd565b9190601f811162000ef657505050565b62000f25926000526020600020906020601f840160051c8301931062000f27575b601f0160051c019062000ecd565b565b909150819062000f17565b919091825167ffffffffffffffff81116200100f575b62000f608162000f59845462000e90565b8462000ee6565b602080601f831160011462000f9f57508192939460009262000f93575b50508160011b916000199060031b1c1916179055565b01519050388062000f7d565b90601f1983169562000fb685600052602060002090565b926000905b88821062000ff65750508360019596971062000fdc575b505050811b019055565b015160001960f88460031b161c1916905538808062000fd2565b8060018596829496860151815501950193019062000fbb565b6200101962000377565b62000f48565b80549160019283835580841062001064575b50906000526020908160002060005b8481106200104f575050505050565b825160ff168282015591830191840162001040565b6200107e9083600052846020600020918201910162000ecd565b3862001031565b95949390608093620010b6620010d494620010c59360018060a01b03168a5260a060208b015260a08a01906200015f565b9088820360408a01526200015f565b9086820360608801526200015f565b930152565b9294936001600160a01b0380871694909390919085156200131457338260601c0362001302576040516001600160f81b0319602082019081526bffffffffffffffffffffffff193060601b166021830152603582018490527fac00cb7082c31222a6e9858037310d59564fa6ef5b4ae03d11cc79ad4c7a2ee8605580840191909152825262001184916200064d919062001175607582620003b2565b5190206001600160a01b031690565b97883b620012e257827f106160dca18b77e6926325d074dd8328fbec25f496d6fd313ef44f3e581e2afe949262001275620012839362001230620012118e60009c9b99604051806115ca8082019082821067ffffffffffffffff831117620012d2575b620016dd833903908ff515620012ae576001600160a01b0316600090815260208190526040902090565b80546001600160a01b0319166001600160a01b03909316929092178255565b6200123f866002830162000f32565b6200124e876003830162000f32565b6200125d836004830162000f32565b600562001269620003d5565b6003815291016200101f565b6040519485948c8662001085565b0390a184167fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8280a4565b620012b862000e83565b6001600160a01b0316600090815260208190526040902090565b620012dc62000377565b620011e7565b6040516283438560e01b81526001600160a01b038a166004820152602490fd5b6040516332db94d160e21b8152600490fd5b60405163267eaa8160e21b8152600490fd5b60009103126200000f57565b80548210156200134b5760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b6000198101919082116200137157565b634e487b7160e01b600052601160045260246000fd5b80548015620013b7576000190190620013a1828262001332565b81549060018060a01b039060031b1b1916905555565b634e487b7160e01b600052603160045260246000fd5b9062000ca462000f259280549068010000000000000000821015620013f9575b60018201815562001332565b6200140362000377565b620013ed565b90604051918260008254926200141f8462000e90565b9081845260019485811690816000146200149457506001146200144d575b505062000f2592500383620003b2565b9093915060005260209081600020936000915b8183106200147b57505062000f25935082010138806200143d565b8554888401850152948501948794509183019162001460565b91505062000f2594506020925060ff191682840152151560051b82010138806200143d565b620014c4816200157b565b6001600160a01b039081166000818152602081905260409020549091163303620014eb5750565b6024906040519063d4ed9a1760e01b82526004820152fd5b6200150e816200157b565b60018060a01b03809116908160005260006020526040600020906040600020541633141590816200155b575b50620015435750565b60249060405190636e1f2bef60e01b82526004820152fd5b33600090815260069091016020526040902060ff9150541615386200153a565b6001600160a01b0390811660009081526020819052604090205416156200159e57565b604051631634d3c960e31b8152600490fd5b9080926000146200168257506001600160a01b038216156200167057600601620015f7620015f083839060018060a01b0316600052602052604060002090565b5460ff1690565b6200164f576001600160a01b03821660009081526020919091526040902062001624905460081c60ff1690565b6200162c5750565b604051634e8336ad60e11b81526001600160a01b03919091166004820152602490fd5b6040516327ec359360e21b81526001600160a01b0383166004820152602490fd5b6040516367db084560e11b8152600490fd5b6001600160a01b0316600090815260069190910160205260409020620016b190620016ad90620015f0565b1590565b620016b95750565b604051630de0cce560e41b81526001600160a01b03919091166004820152602490fdfe610160604052346200029f5762000015620002fa565b6020815191012060a0526200002962000322565b6020815191012060c0526040516020810181620000f3620000e6620000bd620000a1620000866200006e87600d906c08a92a06e626488dedac2d2dc5609b1b81520190565b6b1cdd1c9a5b99c81b985b594b60a21b8152600c0190565b6e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b8152600f0190565b6f1d5a5b9d0c8d4d8818da185a5b92590b60821b815260100190565b7f6164647265737320766572696679696e67436f6e747261637400000000000000815260190190565b602960f81b815260010190565b039162000109601f1993848101835282620002d6565b51902060e052604051620001ce602082019282620001c1620000e6620001a86200018a6200016c6200014e8a600c906b0a6d2cedccac89ee4c8cae4560a31b81520190565b711859191c995cdcc8199d5b199a5b1b195c8b60721b815260120190565b711d5a5b9d0d8d08195e1c1a5c985d1a5bdb8b60721b815260120190565b71189e5d195ccccc881bdc99195c92185cda0b60721b815260120190565b6c189e5d195cc818dbdb9d195e1d609a1b8152600d0190565b03908101835282620002d6565b519020610100908152610120468152336080526200021c60e0519060a0519160c0516040519360805192600052602052604052466060523060805260a0600020926040526000606052608052565b610140908152604051917f98a7ac23945182ac62b68fbe5ba35cc0bf5c4c34b3a410ce94a4c2270282d6b5600080a16112849384620003468539608051848181610a6e01528181610b680152610d5d015260a05184610fe6015260c0518461100a015260e05184610fc301525183610e7201525182610f7001525181610f970152f35b600080fd5b604081019081106001600160401b03821117620002c057604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b03821190821017620002c057604052565b604051906200030982620002a4565b600a8252695369676e65645a6f6e6560b01b6020830152565b604051906200033182620002a4565b60058252640312e302e360dc1b602083015256fe6080604052600436101561001e575b610016610991565b602081519101f35b60003560e01c806301e4d72a146100aa5780630be2ebbe146100a157806317b1f942146100985780632e778efc1461008f57806369c56dc914610086578063c3b1e7051461007d5763d61d79d20361000e576100786106c5565b61000e565b5061007861069b565b50610078610677565b506100786104b0565b50610078610270565b5061007861023b565b346100c9576100b8366100ce565b5062f26b9560e11b60805260206080f35b600080fd5b600319906020818301126100c957600435916001600160401b0383116100c95782610140920301126100c95760040190565b50634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761013257604052565b61013a610100565b604052565b60e081019081106001600160401b0382111761013257604052565b90601f801991011681019081106001600160401b0382111761013257604052565b6040516d086dedce6d2c8cae4c2e8d2dedc560931b60208201527f52656365697665644974656d5b5d20636f6e73696465726174696f6e00000000602e820152602960f81b604a820152602b8152606081018181106001600160401b038211176101e6575b60405290565b6101ee610100565b6101e0565b60005b8381106102065750506000910152565b81810151838201526020016101f6565b9060209161022f815180928185528580860191016101f3565b601f01601f1916010190565b50346100c95760003660031901126100c95761026c61025861017b565b604051918291602083526020830190610216565b0390f35b50346100c95761027f366100ce565b610287611045565b61029460a08201826106e2565b8235929160c435607d1960248201350161041757604481013560f81c6104055760a181013560f81c6103f3576059013560c01c924284106103dc579061033a6103166103489561034294886102f5886102ed8189610714565b9a9098610725565b9390926103018361105f565b908360a435602401356103b6575b5050610e51565b61031e610f6b565b61190160f01b6000526002526022526042600020906000602252565b9236916107d7565b90610ee5565b61037561037161036a8360018060a01b03166000526000602052604060002090565b5460ff1690565b1590565b61038b57604051630bd8fca160e11b8152602090f35b6040516317c3008960e01b81526001600160a01b039190911660048201526024810191909152604490fd5b6103d06103ca8360806103d5950190610778565b90611110565b611096565b388361030f565b50505063165460716000526020526040526044601cfd5b8463267879996000526020526024601cfd5b8463641157746000526020526024601cfd5b8463d232fd2c6000526020526024601cfd5b61043b60409283835283830190610216565b906020908181840391015283519182815281810182808560051b8401019601946000925b858410610470575050505050505090565b90919293949596858061049f600193601f1986820301885286838d518051845201519181858201520190610216565b99019401940192959493919061045f565b50346100c9576000806003193601126105605760408051916104d183610117565b60018352805b602080821015610504578351602092916104f082610117565b8482526060818301528287010152016104d7565b8461054861026c8660076105178561084b565b515261053a610524610d36565b9086989493989592955195869460208601610887565b03601f19810183528261015a565b60206105538661084b565b5101525192839283610429565b80fd5b6040516c0a4cac6cad2eccac892e8cada5609b1b60208201526e1d5a5b9d0e081a5d195b551e5c194b608a1b602d8201526d1859191c995cdcc81d1bdad95b8b60921b603c820152721d5a5b9d0c8d4d881a59195b9d1a599a595c8b606a1b604a8201526e1d5a5b9d0c8d4d88185b5bdd5b9d0b608a1b605d820152701859191c995cdcc81c9958da5c1a595b9d607a1b606c820152602960f81b607d820152605e8152608081018181106001600160401b038211176101e65760405290565b61062b61017b565b610633610563565b610671602060405180938261065181840197888151938492016101f3565b8201610665825180938680850191016101f3565b0103808452018261015a565b51902090565b50346100c95760003660031901126100c9576020610693610623565b604051908152f35b50346100c95760003660031901126100c95760206106b7610563565b818151910120604051908152f35b50346100c95760003660031901126100c95761026c610258610563565b903590601e19813603018212156100c957018035906001600160401b0382116100c9576020019181360383136100c957565b90605d116100c957601d0190604090565b9092919283605d116100c95783116100c957605d0191605c190190565b919091826004116100c95782116100c9576004916003190190565b919091826024116100c95782116100c9576024916023190190565b903590601e19813603018212156100c957018035906001600160401b0382116100c9576020019160a08202360383136100c957565b6020906001600160401b0381116107ca575b601f01601f19160190565b6107d2610100565b6107bf565b9291926107e3826107ad565b916107f1604051938461015a565b8294818452818301116100c9578281602093846000960137010152565b6020906001600160401b038111610827575b60051b0190565b61082f610100565b610820565b50634e487b7160e01b600052603260045260246000fd5b602090805115610859570190565b610861610834565b0190565b602091815181101561087a575b60051b010190565b610882610834565b610872565b909493919481526108a46020956080878401526080830190610216565b818103604083015285808551928381520194019060005b8181106108db575050506108d89394506060818403910152610216565b90565b8251865294870194918701916001016108bb565b908160209103126100c957356001600160e01b0319811681036100c95790565b6020908160408183019282815285518094520193019160005b828110610936575050505090565b83516001600160a01b031685529381019392810192600101610928565b6001600160a01b038116036100c957565b908160209103126100c957356108d881610953565b908160209103126100c9573580151581036100c95790565b6060906000356001600160e01b03191663f460590b60e01b81036109f457506109f26109d76109cb6109c33636610742565b810190610964565b6001600160a01b031690565b6109ec6109e4363661075d565b810190610979565b90610a6b565b565b6329e12e0360e21b8103610a225750905061053a6108d8610a13610b4c565b6040519283916020830161090f565b6301ffc9a760e01b14610a3157565b905061053a6108d8610a56610a51610a493636610742565b8101906108ef565b610c52565b60408051911515602083015290928391820190565b907f00000000000000000000000000000000000000000000000000000000000000003303610b315715610ae6576001600160a01b031660008181526020818152604091829020805460ff1916600117905590519182527f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2491a1565b6001600160a01b031660008181526020818152604091829020805460ff1916905590519182527f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b91a1565b636d5769be6000526004601cfd5b506040513d6000823e3d90fd5b6040516366a2489f60e01b8152306004820152600080826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610c45575b8192610ba557505090565b9091503d8083833e610bb7818361015a565b81016020918281830312610c3d578051906001600160401b038211610c41570181601f82011215610c3d57805190610bee8261080e565b94610bfc604051968761015a565b828652848087019360051b83010193841161056057508301905b828210610c24575050505090565b8380918351610c3281610953565b815201910190610c16565b8380fd5b8480fd5b610c4d610b3f565b610b9a565b63ffffffff60e01b16630b9de3bf60e21b8114908115610c85575b8115610c77575090565b6301ffc9a760e01b14919050565b630e08a82560e21b81149150610c6d565b81601f820112156100c9578051610cac816107ad565b92610cba604051948561015a565b818452602082840101116100c9576108d891602080850191016101f3565b81601f820112156100c957805191610cef8361080e565b92610cfd604051948561015a565b808452602092838086019260051b8201019283116100c9578301905b828210610d27575050505090565b81518152908301908301610d19565b610d3e610f6b565b604051628f139360e31b815230600482015290919060009081816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610e44575b80928192828092610da3575b505090919293565b9350935050503d8082843e610db8818461015a565b820160a083820312610e40576020830151906001600160401b0391828111610c3d5781610de6918601610c96565b916040850151818111610c415782610dff918701610c96565b946060810151828111610e3c5783610e18918301610cd8565b9460808201519283116105605750610e31929101610c96565b909291903880610d9b565b8580fd5b5080fd5b610e4c610b3f565b610d8f565b9392610e6091929336916107d7565b602081519101206040519260208401947f0000000000000000000000000000000000000000000000000000000000000000865260018060a01b031660408501526001600160401b038093166060850152608084015260a083015260a0825260c082019082821090821117610ed8575b60405251902090565b610ee0610100565b610ecf565b9190916000926000918280528151601f19830192835182604103946001861115610f13575b50505050505050565b90919293949596975060408301948551966060850151891a90610f51575b8452815260208760808360015afa50525252519038808080808080610f0a565b506001600160ff1b038716865260ff87901c601b01610f31565b6000467f000000000000000000000000000000000000000000000000000000000000000003610fb957507f000000000000000000000000000000000000000000000000000000000000000090565b60405190608051907f000000000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006020527f0000000000000000000000000000000000000000000000000000000000000000604052466060523060805260a081209260405260605260805290565b60206004350361105157565b6346d5d8956000526004601cfd5b604560c435013560601c9190604435831515848214151661107e575050565b83631bcf9bb76000526020526040526060526064601cfd5b60c43560a201358091036110a8575050565b6359cb96d160005260205260a435608401356040526060526064601cfd5b9160a0918110156110d657020190565b6110de610834565b020190565b805160208092019160005b8281106110fc575050505090565b8351855293810193928101926001016110ee565b9061111a8161080e565b91611128604051938461015a565b818352601f1991826111398261080e565b0136602086013760005b8181106111a95750505061067161119d9161115c610623565b9360405161117e816111726020820180956110e3565b0384810183528261015a565b5190206040805160208101968752908101919091529283906060820190565b0390810183528261015a565b806111bf6111ba60019385876110c6565b6111d0565b6111c98288610865565b5201611143565b6111d8610563565b602081519101209080359060068210156100c9576020810135906111fb82610953565b606060808201359161120c83610953565b6040519460208601968752604086015260018060a01b038094168286015260408101356080860152013560a08401521660c082015260c081526106718161013f56fea2646970667358221220021581f3f24b29ee89b9bf9c0ca61aa5f8a85650b06533d4fdcf5745a8b9828364736f6c63430008110033a2646970667358221220673d02a1aebe6b5a5b25d608ec382b42bfeb749ee00637cb1ca3ada848e5fe5c64736f6c63430008110033
Verified Source Code Full Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (200 runs)
SignedZoneV16.sol 779 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {ZoneParameters, Schema, ReceivedItem} from "../lib/ConsiderationStructs.sol";
import {ZoneInterfaceV16} from "../interfaces/ZoneInterfaceV16.sol";
import {SignedZoneEventsAndErrors} from "./interfaces/SignedZoneEventsAndErrors.sol";
import {SIP5Interface} from "./interfaces/SIP5Interface.sol";
import {SignedZoneControllerInterface} from "./interfaces/SignedZoneControllerInterface.sol";
import "./lib/SignedZoneConstants.sol";
/**
* @title SignedZoneV16
* @author ryanio, BCLeFevre
* @custom:modifiedby Tony Snark
* @notice SignedZoneV16 is an implementation of SIP-7 that requires orders
* to be signed by an approved signer.
* https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
*
* Modification:
* Removes support for SIP7 sub-standard 1.
* Adds support for SIP7 sub-standard 3.
*/
contract SignedZoneV16 is SignedZoneEventsAndErrors, ZoneInterfaceV16, SIP5Interface {
/// @dev The zone's controller that is set during deployment.
address private immutable _controller;
/// @dev The authorized signers, and if they are active
mapping(address => bool) private _signers;
/// @dev The EIP-712 digest parameters.
bytes32 internal immutable _NAME_HASH = keccak256(bytes("SignedZone"));
bytes32 internal immutable _VERSION_HASH = keccak256(bytes("1.0.0"));
// prettier-ignore
bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH = keccak256(
abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"uint256 chainId,",
"address verifyingContract",
")"
)
);
// prettier-ignore
bytes32 internal immutable _SIGNED_ORDER_TYPEHASH = keccak256(
abi.encodePacked(
"SignedOrder(",
"address fulfiller,",
"uint64 expiration,",
"bytes32 orderHash,",
"bytes context",
")"
)
);
bytes public constant CONSIDERATION_BYTES =
// prettier-ignore
abi.encodePacked(
"Consideration(",
"ReceivedItem[] consideration",
")"
);
bytes public constant RECEIVED_ITEM_BYTES =
// prettier-ignore
abi.encodePacked(
"ReceivedItem(",
"uint8 itemType,",
"address token,",
"uint256 identifier,",
"uint256 amount,",
"address recipient",
")"
);
bytes32 public constant RECEIVED_ITEM_HASHTYPE = keccak256(RECEIVED_ITEM_BYTES);
bytes32 public constant CONSIDERATION_HASHTYPE =
keccak256(abi.encodePacked(CONSIDERATION_BYTES, RECEIVED_ITEM_BYTES));
uint256 internal immutable _CHAIN_ID = block.chainid;
bytes32 internal immutable _DOMAIN_SEPARATOR;
/**
* @notice Constructor to deploy the contract.
*/
constructor() {
// Set the deployer as the controller.
_controller = msg.sender;
// Derive and set the domain separator.
_DOMAIN_SEPARATOR = _deriveDomainSeparator();
// Emit an event to signal a SIP-5 contract has been deployed.
emit SeaportCompatibleContractDeployed();
}
/**
* @dev Authorizes an order before any token fulfillments from any order have been executed by Seaport.
*
* @return authorizedOrderMagicValue The magic value that indicates a valid
* order.
*/
function authorizeOrder(
ZoneParameters calldata
) public view virtual override returns (bytes4 authorizedOrderMagicValue) {
return this.authorizeOrder.selector;
}
/**
* @notice Check if a given order including extraData is currently valid.
*
* @dev This function is called by Seaport whenever any extraData is
* provided by the caller.
*
* @return validOrderMagicValue A magic value indicating if the order is
* currently valid.
*/
function validateOrder(
ZoneParameters calldata zoneParameters
) public view virtual override returns (bytes4 validOrderMagicValue) {
// Check Zone parameters validity.
_assertValidZoneParameters();
// Put the extraData and orderHash on the stack for cheaper access.
bytes calldata extraData = zoneParameters.extraData;
bytes32 orderHash = zoneParameters.orderHash;
uint256 considerationLength;
// Declare a variable to hold the expiration.
uint64 expiration;
// Validate the extraData.
assembly {
// Get the length of the extraData.
let extraDataPtr := add(0x24, calldataload(Zone_extraData_cdPtr))
let extraDataLength := calldataload(extraDataPtr)
if iszero(eq(extraDataLength, InvalidExtraDataLength_epected_length)) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidExtraDataLength_error_selector)
mstore(InvalidExtraDataLength_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "InvalidExtraDataLength(bytes32)", orderHash)
// )
revert(0x1c, InvalidExtraDataLength_error_length)
}
// extraData bytes 0-1: SIP-6 version byte (MUST be 0x00)
let versionByte := shr(248, calldataload(add(extraDataPtr, 0x20)))
if iszero(eq(versionByte, 0x00)) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidSIP6Version_error_selector)
mstore(InvalidSIP6Version_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "InvalidSIP6Version(bytes32)", orderHash)
// )
revert(0x1c, InvalidSIP6Version_error_length)
}
// extraData bytes 93-94: Substandard #1 (MUST be 0x00)
let subStandardVersionByte := shr(
248,
calldataload(add(extraDataPtr, ExtraData_substandard_version_byte_offset))
)
if iszero(eq(subStandardVersionByte, 0x00)) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidSubstandardVersion_error_selector)
mstore(InvalidSubstandardVersion_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "InvalidSubstandardVersion(bytes32)", orderHash)
// )
revert(0x1c, InvalidSubstandardVersion_error_length)
}
// extraData bytes 21-29: expiration timestamp (uint64)
expiration := shr(192, calldataload(add(extraDataPtr, ExtraData_expiration_offset)))
// Revert if expired.
if lt(expiration, timestamp()) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, SignatureExpired_error_selector)
mstore(SignatureExpired_error_expiration_ptr, expiration)
mstore(SignatureExpired_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "SignatureExpired(uint256, bytes32)", expiration orderHash)
// )
revert(0x1c, SignatureExpired_error_length)
}
// // Get the length of the consideration array.
considerationLength := calldataload(add(0x24, calldataload(Zone_consideration_head_cdPtr)))
}
// extraData bytes 29-93: signature
// (strictly requires 64 byte compact sig, EIP-2098)
bytes calldata signature = extraData[29:93];
// extraData bytes 93-end: context (optional, variable length)
bytes calldata context = extraData[93:];
// Check the validity of the Substandard #1 extraData and get the
// expected fulfiller address.
address expectedFulfiller = _getExpectedFulfiller(orderHash);
// Check the validity of the Substandard #1 extraData and get the
// expected fulfiller address.
if (considerationLength > 0) {
_assertValidSubstandard(_deriveConsiderationHash(zoneParameters.consideration), orderHash);
}
// Derive the signedOrder hash.
bytes32 signedOrderHash = _deriveSignedOrderHash(
expectedFulfiller,
expiration,
orderHash,
context
);
// Derive the EIP-712 digest using the domain separator and signedOrder
// hash.
bytes32 digest = _deriveEIP712Digest(_domainSeparator(), signedOrderHash);
// Recover the signer address from the digest and signature.
address recoveredSigner = _recoverSigner(digest, signature);
// Revert if the signer is not active.
if (!_signers[recoveredSigner]) {
revert SignerNotActive(recoveredSigner, orderHash);
}
// Return the selector of validateOrder as the magic value.
validOrderMagicValue = ZoneInterfaceV16.validateOrder.selector;
}
/**
* @dev Returns Seaport metadata for this contract, returning the
* contract name and supported schemas.
*
* @return name The contract name
* @return schemas The supported SIPs
*/
function getSeaportMetadata()
external
view
override(SIP5Interface, ZoneInterfaceV16)
returns (string memory name, Schema[] memory schemas)
{
// Return the supported SIPs.
schemas = new Schema[](1);
schemas[0].id = 7;
// Get the SIP-7 information.
(
bytes32 domainSeparator,
string memory zoneName,
string memory apiEndpoint,
uint256[] memory substandards,
string memory documentationURI
) = _sip7Information();
// Return the zone name.
name = zoneName;
// Encode the SIP-7 information.
schemas[0].metadata = abi.encode(domainSeparator, apiEndpoint, substandards, documentationURI);
}
/**
* @notice The fallback function is used as a dispatcher for the
* `updateSigner`, `getActiveSigners` and `supportsInterface`
* functions.
*/
// prettier-ignore
fallback(bytes calldata) external payable returns (bytes memory output) {
// Get the function selector.
bytes4 selector = msg.sig;
if (selector == 0xf460590b) {
// updateSigner(address,bool)
// Get the signer, and active status.
address signer = abi.decode(msg.data[4:], (address));
bool active = abi.decode(msg.data[36:], (bool));
// Call to update the signer.
_updateSigner(signer, active);
} else if (selector == 0xa784b80c) {
// getActiveSigners()
// Call the internal function to get the active signers.
return abi.encode(_getActiveSigners());
} else if (selector == 0x01ffc9a7) {
// supportsInterface(bytes4)
// Get the interface ID.
bytes4 interfaceId = abi.decode(msg.data[4:], (bytes4));
// Call the internal function to determine if the interface is
// supported.
return abi.encode(_supportsInterface(interfaceId));
}
}
/**
* @notice Add or remove a signer to the zone.
* Only the controller can call this function.
*
* @param signer The signer address to add or remove.
*/
function _updateSigner(address signer, bool active) internal {
// Only the controller can call this function.
_assertCallerIsController();
// Add or remove the signer.
active ? _addSigner(signer) : _removeSigner(signer);
}
/**
* @notice Add a new signer to the zone.
* Only the controller or an active signer can call this function.
*
* @param signer The new signer address to add.
*/
function _addSigner(address signer) internal {
// Set the signer info.
_signers[signer] = true;
// Emit an event that the signer was added.
emit SignerAdded(signer);
}
/**
* @notice Remove an active signer from the zone.
* Only the controller or an active signer can call this function.
*
* @param signer The signer address to remove.
*/
function _removeSigner(address signer) internal {
// Set the signer's active status to false.
_signers[signer] = false;
// Emit an event that the signer was removed.
emit SignerRemoved(signer);
}
/**
* @notice Returns the active signers for the zone.
*
* @return signers The active signers.
*/
function _getActiveSigners() internal view returns (address[] memory signers) {
// Return the active signers for the zone by calling the controller.
signers = SignedZoneControllerInterface(_controller).getActiveSigners(address(this));
}
/**
* @notice Returns whether the interface is supported.
*
* @param interfaceId The interface id to check against.
*/
function _supportsInterface(bytes4 interfaceId) internal pure returns (bool supportsInterface) {
// Determine if the interface is supported.
supportsInterface =
interfaceId == type(SIP5Interface).interfaceId || // SIP-5
interfaceId == type(ZoneInterfaceV16).interfaceId || // ZoneInterface
interfaceId == 0x01ffc9a7; // ERC-165
}
/**
* @notice Internal call to return the signing information, substandards,
* and documentation about the zone.
*
* @return domainSeparator The domain separator used for signing.
* @return zoneName The zone name.
* @return apiEndpoint The API endpoint for the zone.
* @return substandards The substandards supported by the zone.
* @return documentationURI The documentation URI for the zone.
*/
function _sip7Information()
internal
view
returns (
bytes32 domainSeparator,
string memory zoneName,
string memory apiEndpoint,
uint256[] memory substandards,
string memory documentationURI
)
{
// Return the SIP-7 information.
domainSeparator = _domainSeparator();
// Get the SIP-7 information from the controller.
(, zoneName, apiEndpoint, substandards, documentationURI) = SignedZoneControllerInterface(
_controller
).getAdditionalZoneInformation(address(this));
}
/**
* @dev Derive the signedOrder hash from the orderHash and expiration.
*
* @param fulfiller The expected fulfiller address.
* @param expiration The signature expiration timestamp.
* @param orderHash The order hash.
* @param context The optional variable-length context.
*
* @return signedOrderHash The signedOrder hash.
*
*/
function _deriveSignedOrderHash(
address fulfiller,
uint64 expiration,
bytes32 orderHash,
bytes calldata context
) internal view returns (bytes32 signedOrderHash) {
// Derive the signed order hash.
signedOrderHash = keccak256(
abi.encode(_SIGNED_ORDER_TYPEHASH, fulfiller, expiration, orderHash, keccak256(context))
);
}
/**
* @dev Internal view function to return the signer of a signature.
*
* @param digest The digest to verify the signature against.
* @param signature A signature from the signer indicating that the order
* has been approved.
*
* @return recoveredSigner The recovered signer.
*/
function _recoverSigner(
bytes32 digest,
bytes memory signature
) internal view returns (address recoveredSigner) {
// Utilize assembly to perform optimized signature verification check.
assembly {
// Ensure that first word of scratch space is empty.
mstore(0, 0)
// Declare value for v signature parameter.
let v
// Get the length of the signature.
let signatureLength := mload(signature)
// Get the pointer to the value preceding the signature length.
// This will be used for temporary memory overrides - either the
// signature head for isValidSignature or the digest for ecrecover.
let wordBeforeSignaturePtr := sub(signature, OneWord)
// Cache the current value behind the signature to restore it later.
let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)
// Declare lenDiff + recoveredSigner scope to manage stack pressure.
{
// Take the difference between the max ECDSA signature length
// and the actual signature length. Overflow desired for any
// values > 65. If the diff is not 0 or 1, it is not a valid
// ECDSA signature - move on to EIP1271 check.
let lenDiff := sub(ECDSA_MaxLength, signatureLength)
// If diff is 0 or 1, it may be an ECDSA signature.
// Try to recover signer.
if iszero(gt(lenDiff, 1)) {
// Read the signature `s` value.
let originalSignatureS := mload(add(signature, ECDSA_signature_s_offset))
// Read the first byte of the word after `s`. If the
// signature is 65 bytes, this will be the real `v` value.
// If not, it will need to be modified - doing it this way
// saves an extra condition.
v := byte(0, mload(add(signature, ECDSA_signature_v_offset)))
// If lenDiff is 1, parse 64-byte signature as ECDSA.
if lenDiff {
// Extract yParity from highest bit of vs and add 27 to
// get v.
v := add(shr(MaxUint8, originalSignatureS), Signature_lower_v)
// Extract canonical s from vs, all but the highest bit.
// Temporarily overwrite the original `s` value in the
// signature.
mstore(
add(signature, ECDSA_signature_s_offset),
and(originalSignatureS, EIP2098_allButHighestBitMask)
)
}
// Temporarily overwrite the signature length with `v` to
// conform to the expected input for ecrecover.
mstore(signature, v)
// Temporarily overwrite the word before the length with
// `digest` to conform to the expected input for ecrecover.
mstore(wordBeforeSignaturePtr, digest)
// Attempt to recover the signer for the given signature. Do
// not check the call status as ecrecover will return a null
// address if the signature is invalid.
pop(
staticcall(
gas(),
Ecrecover_precompile, // Call ecrecover precompile.
wordBeforeSignaturePtr, // Use data memory location.
Ecrecover_args_size, // Size of digest, v, r, and s.
0, // Write result to scratch space.
OneWord // Provide size of returned result.
)
)
// Restore cached word before signature.
mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
// Restore cached signature length.
mstore(signature, signatureLength)
// Restore cached signature `s` value.
mstore(add(signature, ECDSA_signature_s_offset), originalSignatureS)
// Read the recovered signer from the buffer given as return
// space for ecrecover.
recoveredSigner := mload(0)
}
}
// Restore the cached values overwritten by selector, digest and
// signature head.
mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
}
}
/**
* @dev Internal view function to get the EIP-712 domain separator. If the
* chainId matches the chainId set on deployment, the cached domain
* separator will be returned; otherwise, it will be derived from
* scratch.
*
* @return The domain separator.
*/
function _domainSeparator() internal view returns (bytes32) {
// prettier-ignore
return block.chainid == _CHAIN_ID
? _DOMAIN_SEPARATOR
: _deriveDomainSeparator();
}
/**
* @dev Internal view function to derive the EIP-712 domain separator.
*
* @return domainSeparator The derived domain separator.
*/
function _deriveDomainSeparator() internal view returns (bytes32 domainSeparator) {
bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH;
bytes32 nameHash = _NAME_HASH;
bytes32 versionHash = _VERSION_HASH;
// Leverage scratch space and other memory to perform an efficient hash.
assembly {
// Retrieve the free memory pointer; it will be replaced afterwards.
let freeMemoryPointer := mload(FreeMemoryPointerSlot)
// Retrieve value at 0x80; it will also be replaced afterwards.
let slot0x80 := mload(Slot0x80)
// Place typehash, name hash, and version hash at start of memory.
mstore(0, typehash)
mstore(OneWord, nameHash)
mstore(TwoWords, versionHash)
// Place chainId in the next memory location.
mstore(ThreeWords, chainid())
// Place the address of this contract in the next memory location.
mstore(FourWords, address())
// Hash relevant region of memory to derive the domain separator.
domainSeparator := keccak256(0, FiveWords)
// Restore the free memory pointer.
mstore(FreeMemoryPointerSlot, freeMemoryPointer)
// Restore the zero slot to zero.
mstore(ZeroSlot, 0)
// Restore the value at 0x80.
mstore(Slot0x80, slot0x80)
}
}
/**
* @dev Internal pure function to efficiently derive an digest to sign for
* an order in accordance with EIP-712.
*
* @param domainSeparator The domain separator.
* @param signedOrderHash The signedOrder hash.
*
* @return digest The digest hash.
*/
function _deriveEIP712Digest(
bytes32 domainSeparator,
bytes32 signedOrderHash
) internal pure returns (bytes32 digest) {
// Leverage scratch space to perform an efficient hash.
assembly {
// Place the EIP-712 prefix at the start of scratch space.
mstore(0, EIP_712_PREFIX)
// Place the domain separator in the next region of scratch space.
mstore(EIP712_DomainSeparator_offset, domainSeparator)
// Place the signed order hash in scratch space, spilling into the
// first two bytes of the free memory pointer — this should never be
// set as memory cannot be expanded to that size, and will be
// zeroed out after the hash is performed.
mstore(EIP712_SignedOrderHash_offset, signedOrderHash)
// Hash the relevant region
digest := keccak256(0, EIP712_DigestPayload_size)
// Clear out the dirtied bits in the memory pointer.
mstore(EIP712_SignedOrderHash_offset, 0)
}
}
/**
* @dev Private view function to revert if the caller is not the
* controller.
*/
function _assertCallerIsController() internal view {
// Get the controller address to use in the assembly block.
address controller = _controller;
assembly {
// Revert if the caller is not the controller.
if iszero(eq(caller(), controller)) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidController_error_selector)
// revert(abi.encodeWithSignature(
// "InvalidController()")
// )
revert(0x1c, InvalidController_error_length)
}
}
}
/**
* @dev Internal pure function to validate calldata offsets for the
* dyanamic type in ZoneParameters. This ensures that functions using
* the calldata object normally will be using the same data as the
* assembly functions and that values that are bound to a given range
* are within that range.
*/
function _assertValidZoneParameters() internal pure {
// Utilize assembly in order to read offset data directly from calldata.
assembly {
/*
* Checks:
* 1. Zone parameters struct offset == 0x20
*/
// Zone parameters at calldata 0x04 must have offset of 0x20.
if iszero(eq(calldataload(Zone_parameters_cdPtr), Zone_parameters_ptr)) {
// Store left-padded selector with push4 (reduces bytecode), mem[28:32] = selector
mstore(0, InvalidZoneParameterEncoding_error_selector)
// revert(abi.encodeWithSignature("InvalidZoneParameterEncoding()"))
revert(0x1c, InvalidZoneParameterEncoding_error_length)
}
}
}
/**
* @dev Internal pure function to ensure that the context argument for the
* supplied extra data follows the substandard #1 format. Returns the
* expected fulfiller of the order for deriving the signed order hash.
*
* @param orderHash The order hash.
*
* @return expectedFulfiller The expected fulfiller of the order.
*/
function _getExpectedFulfiller(
bytes32 orderHash
) internal pure returns (address expectedFulfiller) {
// Revert if the expected fulfiller is not the zero address and does
// not match the actual fulfiller
assembly {
// Get the actual fulfiller.
let actualFulfiller := calldataload(Zone_parameters_fulfiller_cdPtr)
let extraDataPtr := calldataload(Zone_extraData_cdPtr)
// Get the expected fulfiller.
expectedFulfiller := shr(96, calldataload(add(expectedFulfiller_offset, extraDataPtr)))
// Revert if expected fulfiller is not the zero address and does
// not match the actual fulfiller.
if and(iszero(iszero(expectedFulfiller)), iszero(eq(expectedFulfiller, actualFulfiller))) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidFulfiller_error_selector)
mstore(InvalidFulfiller_error_expectedFulfiller_ptr, expectedFulfiller)
mstore(InvalidFulfiller_error_actualFulfiller_ptr, actualFulfiller)
mstore(InvalidFulfiller_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "InvalidFulfiller(address,address,bytes32)", expectedFulfiller, actualFulfiller, orderHash)
// )
revert(0x1c, InvalidFulfiller_error_length)
}
}
}
/**
* @dev Internal pure function to ensure that the context argument for the
* supplied extra data follows the substandard #1 format. Returns the
* expected fulfiller of the order for deriving the signed order hash.
*
*/
function _assertValidSubstandard(bytes32 considerationHash, bytes32 orderHash) internal pure {
// identifier does not match the actual consideration.
assembly {
let extraDataPtr := calldataload(Zone_extraData_cdPtr)
let considerationPtr := calldataload(Zone_consideration_head_cdPtr)
// Get the actual consideration.
let actualConsideration := calldataload(add(actualConsideration_offset, considerationPtr))
// Get the expected consideration.
let expectedConsiderationHash := calldataload(
add(expectedConsideration_offset, extraDataPtr) //TODO rename
)
// Revert if expected consideration item does not match the actual
// consideration item.
if iszero(eq(considerationHash, expectedConsiderationHash)) {
// Store left-padded selector with push4, mem[28:32] = selector
mstore(0, InvalidConsideration_error_selector)
mstore(InvalidConsideration_error_expectedConsideration_ptr, expectedConsiderationHash)
mstore(InvalidConsideration_error_actualConsideration_ptr, actualConsideration)
mstore(InvalidConsideration_error_orderHash_ptr, orderHash)
// revert(abi.encodeWithSignature(
// "InvalidConsideration(uint256,uint256,bytes32)", expectedConsideration, actualConsideration, orderHash)
// )
revert(0x1c, InvalidConsideration_error_length)
}
}
}
/// @dev Calculates consideration hash
function _deriveConsiderationHash(
ReceivedItem[] calldata consideration
) internal pure returns (bytes32) {
uint256 numberOfItems = consideration.length;
bytes32[] memory considerationHashes = new bytes32[](numberOfItems);
for (uint256 i; i < numberOfItems; ) {
considerationHashes[i] = _deriveReceivedItemHash(consideration[i]);
unchecked {
++i;
}
}
return
keccak256(
abi.encode(CONSIDERATION_HASHTYPE, keccak256(abi.encodePacked(considerationHashes)))
);
}
/// @dev Calculates consideration item hash
function _deriveReceivedItemHash(
ReceivedItem calldata receivedItem
) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
RECEIVED_ITEM_HASHTYPE,
receivedItem.itemType,
receivedItem.token,
receivedItem.identifier,
receivedItem.amount,
receivedItem.recipient
)
);
}
}
ConsiderationEnums.sol 146 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// prettier-ignore
enum OrderType {
// 0: no partial fills, anyone can execute
FULL_OPEN,
// 1: partial fills supported, anyone can execute
PARTIAL_OPEN,
// 2: no partial fills, only offerer or zone can execute
FULL_RESTRICTED,
// 3: partial fills supported, only offerer or zone can execute
PARTIAL_RESTRICTED,
// 4: contract order type
CONTRACT
}
// prettier-ignore
enum BasicOrderType {
// 0: no partial fills, anyone can execute
ETH_TO_ERC721_FULL_OPEN,
// 1: partial fills supported, anyone can execute
ETH_TO_ERC721_PARTIAL_OPEN,
// 2: no partial fills, only offerer or zone can execute
ETH_TO_ERC721_FULL_RESTRICTED,
// 3: partial fills supported, only offerer or zone can execute
ETH_TO_ERC721_PARTIAL_RESTRICTED,
// 4: no partial fills, anyone can execute
ETH_TO_ERC1155_FULL_OPEN,
// 5: partial fills supported, anyone can execute
ETH_TO_ERC1155_PARTIAL_OPEN,
// 6: no partial fills, only offerer or zone can execute
ETH_TO_ERC1155_FULL_RESTRICTED,
// 7: partial fills supported, only offerer or zone can execute
ETH_TO_ERC1155_PARTIAL_RESTRICTED,
// 8: no partial fills, anyone can execute
ERC20_TO_ERC721_FULL_OPEN,
// 9: partial fills supported, anyone can execute
ERC20_TO_ERC721_PARTIAL_OPEN,
// 10: no partial fills, only offerer or zone can execute
ERC20_TO_ERC721_FULL_RESTRICTED,
// 11: partial fills supported, only offerer or zone can execute
ERC20_TO_ERC721_PARTIAL_RESTRICTED,
// 12: no partial fills, anyone can execute
ERC20_TO_ERC1155_FULL_OPEN,
// 13: partial fills supported, anyone can execute
ERC20_TO_ERC1155_PARTIAL_OPEN,
// 14: no partial fills, only offerer or zone can execute
ERC20_TO_ERC1155_FULL_RESTRICTED,
// 15: partial fills supported, only offerer or zone can execute
ERC20_TO_ERC1155_PARTIAL_RESTRICTED,
// 16: no partial fills, anyone can execute
ERC721_TO_ERC20_FULL_OPEN,
// 17: partial fills supported, anyone can execute
ERC721_TO_ERC20_PARTIAL_OPEN,
// 18: no partial fills, only offerer or zone can execute
ERC721_TO_ERC20_FULL_RESTRICTED,
// 19: partial fills supported, only offerer or zone can execute
ERC721_TO_ERC20_PARTIAL_RESTRICTED,
// 20: no partial fills, anyone can execute
ERC1155_TO_ERC20_FULL_OPEN,
// 21: partial fills supported, anyone can execute
ERC1155_TO_ERC20_PARTIAL_OPEN,
// 22: no partial fills, only offerer or zone can execute
ERC1155_TO_ERC20_FULL_RESTRICTED,
// 23: partial fills supported, only offerer or zone can execute
ERC1155_TO_ERC20_PARTIAL_RESTRICTED
}
// prettier-ignore
enum BasicOrderRouteType {
// 0: provide Ether (or other native token) to receive offered ERC721 item.
ETH_TO_ERC721,
// 1: provide Ether (or other native token) to receive offered ERC1155 item.
ETH_TO_ERC1155,
// 2: provide ERC20 item to receive offered ERC721 item.
ERC20_TO_ERC721,
// 3: provide ERC20 item to receive offered ERC1155 item.
ERC20_TO_ERC1155,
// 4: provide ERC721 item to receive offered ERC20 item.
ERC721_TO_ERC20,
// 5: provide ERC1155 item to receive offered ERC20 item.
ERC1155_TO_ERC20
}
// prettier-ignore
enum ItemType {
// 0: ETH on mainnet, MATIC on polygon, etc.
NATIVE,
// 1: ERC20 items (ERC777 and ERC20 analogues could also technically work)
ERC20,
// 2: ERC721 items
ERC721,
// 3: ERC1155 items
ERC1155,
// 4: ERC721 items where a number of tokenIds are supported
ERC721_WITH_CRITERIA,
// 5: ERC1155 items where a number of ids are supported
ERC1155_WITH_CRITERIA
}
// prettier-ignore
enum Side {
// 0: Items that can be spent
OFFER,
// 1: Items that must be received
CONSIDERATION
}
ConsiderationStructs.sol 266 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import { OrderType, BasicOrderType, ItemType, Side } from "./ConsiderationEnums.sol";
/**
* @dev An order contains eleven components: an offerer, a zone (or account that
* can cancel the order or restrict who can fulfill the order depending on
* the type), the order type (specifying partial fill support as well as
* restricted order status), the start and end time, a hash that will be
* provided to the zone when validating restricted orders, a salt, a key
* corresponding to a given conduit, a counter, and an arbitrary number of
* offer items that can be spent along with consideration items that must
* be received by their respective recipient.
*/
struct OrderComponents {
address offerer;
address zone;
OfferItem[] offer;
ConsiderationItem[] consideration;
OrderType orderType;
uint256 startTime;
uint256 endTime;
bytes32 zoneHash;
uint256 salt;
bytes32 conduitKey;
uint256 counter;
}
/**
* @dev An offer item has five components: an item type (ETH or other native
* tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and
* ERC1155), a token address, a dual-purpose "identifierOrCriteria"
* component that will either represent a tokenId or a merkle root
* depending on the item type, and a start and end amount that support
* increasing or decreasing amounts over the duration of the respective
* order.
*/
struct OfferItem {
ItemType itemType;
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
}
/**
* @dev A consideration item has the same five components as an offer item and
* an additional sixth component designating the required recipient of the
* item.
*/
struct ConsiderationItem {
ItemType itemType;
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
address payable recipient;
}
/**
* @dev A spent item is translated from a utilized offer item and has four
* components: an item type (ETH or other native tokens, ERC20, ERC721, and
* ERC1155), a token address, a tokenId, and an amount.
*/
struct SpentItem {
ItemType itemType;
address token;
uint256 identifier;
uint256 amount;
}
/**
* @dev A received item is translated from a utilized consideration item and has
* the same four components as a spent item, as well as an additional fifth
* component designating the required recipient of the item.
*/
struct ReceivedItem {
ItemType itemType;
address token;
uint256 identifier;
uint256 amount;
address payable recipient;
}
/**
* @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155
* matching, a group of six functions may be called that only requires a
* subset of the usual order arguments. Note the use of a "basicOrderType"
* enum; this represents both the usual order type as well as the "route"
* of the basic order (a simple derivation function for the basic order
* type is `basicOrderType = orderType + (4 * basicOrderRoute)`.)
*/
struct BasicOrderParameters {
// calldata offset
address considerationToken; // 0x24
uint256 considerationIdentifier; // 0x44
uint256 considerationAmount; // 0x64
address payable offerer; // 0x84
address zone; // 0xa4
address offerToken; // 0xc4
uint256 offerIdentifier; // 0xe4
uint256 offerAmount; // 0x104
BasicOrderType basicOrderType; // 0x124
uint256 startTime; // 0x144
uint256 endTime; // 0x164
bytes32 zoneHash; // 0x184
uint256 salt; // 0x1a4
bytes32 offererConduitKey; // 0x1c4
bytes32 fulfillerConduitKey; // 0x1e4
uint256 totalOriginalAdditionalRecipients; // 0x204
AdditionalRecipient[] additionalRecipients; // 0x224
bytes signature; // 0x244
// Total length, excluding dynamic array data: 0x264 (580)
}
/**
* @dev Basic orders can supply any number of additional recipients, with the
* implied assumption that they are supplied from the offered ETH (or other
* native token) or ERC20 token for the order.
*/
struct AdditionalRecipient {
uint256 amount;
address payable recipient;
}
/**
* @dev The full set of order components, with the exception of the counter,
* must be supplied when fulfilling more sophisticated orders or groups of
* orders. The total number of original consideration items must also be
* supplied, as the caller may specify additional consideration items.
*/
struct OrderParameters {
address offerer; // 0x00
address zone; // 0x20
OfferItem[] offer; // 0x40
ConsiderationItem[] consideration; // 0x60
OrderType orderType; // 0x80
uint256 startTime; // 0xa0
uint256 endTime; // 0xc0
bytes32 zoneHash; // 0xe0
uint256 salt; // 0x100
bytes32 conduitKey; // 0x120
uint256 totalOriginalConsiderationItems; // 0x140
// offer.length // 0x160
}
/**
* @dev Orders require a signature in addition to the other order parameters.
*/
struct Order {
OrderParameters parameters;
bytes signature;
}
/**
* @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill)
* and a denominator (the total size of the order) in addition to the
* signature and other order parameters. It also supports an optional field
* for supplying extra data; this data will be provided to the zone if the
* order type is restricted and the zone is not the caller, or will be
* provided to the offerer as context for contract order types.
*/
struct AdvancedOrder {
OrderParameters parameters;
uint120 numerator;
uint120 denominator;
bytes signature;
bytes extraData;
}
/**
* @dev Orders can be validated (either explicitly via `validate`, or as a
* consequence of a full or partial fill), specifically cancelled (they can
* also be cancelled in bulk via incrementing a per-zone counter), and
* partially or fully filled (with the fraction filled represented by a
* numerator and denominator).
*/
struct OrderStatus {
bool isValidated;
bool isCancelled;
uint120 numerator;
uint120 denominator;
}
/**
* @dev A criteria resolver specifies an order, side (offer vs. consideration),
* and item index. It then provides a chosen identifier (i.e. tokenId)
* alongside a merkle proof demonstrating the identifier meets the required
* criteria.
*/
struct CriteriaResolver {
uint256 orderIndex;
Side side;
uint256 index;
uint256 identifier;
bytes32[] criteriaProof;
}
/**
* @dev A fulfillment is applied to a group of orders. It decrements a series of
* offer and consideration items, then generates a single execution
* element. A given fulfillment can be applied to as many offer and
* consideration items as desired, but must contain at least one offer and
* at least one consideration that match. The fulfillment must also remain
* consistent on all key parameters across all offer items (same offerer,
* token, type, tokenId, and conduit preference) as well as across all
* consideration items (token, type, tokenId, and recipient).
*/
struct Fulfillment {
FulfillmentComponent[] offerComponents;
FulfillmentComponent[] considerationComponents;
}
/**
* @dev Each fulfillment component contains one index referencing a specific
* order and another referencing a specific offer or consideration item.
*/
struct FulfillmentComponent {
uint256 orderIndex;
uint256 itemIndex;
}
/**
* @dev An execution is triggered once all consideration items have been zeroed
* out. It sends the item in question from the offerer to the item's
* recipient, optionally sourcing approvals from either this contract
* directly or from the offerer's chosen conduit if one is specified. An
* execution is not provided as an argument, but rather is derived via
* orders, criteria resolvers, and fulfillments (where the total number of
* executions will be less than or equal to the total number of indicated
* fulfillments) and returned as part of `matchOrders`.
*/
struct Execution {
ReceivedItem item;
address offerer;
bytes32 conduitKey;
}
/**
* @dev Restricted orders are validated post-execution by calling validateOrder
* on the zone. This struct provides context about the order fulfillment
* and any supplied extraData, as well as all order hashes fulfilled in a
* call to a match or fulfillAvailable method.
*/
struct ZoneParameters {
bytes32 orderHash;
address fulfiller;
address offerer;
SpentItem[] offer;
ReceivedItem[] consideration;
bytes extraData;
bytes32[] orderHashes;
uint256 startTime;
uint256 endTime;
bytes32 zoneHash;
}
/**
* @dev Zones and contract offerers can communicate which schemas they implement
* along with any associated metadata related to each schema.
*/
struct Schema {
uint256 id;
bytes metadata;
}
ZoneInterfaceV16.sol 22 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {ZoneParameters, Schema} from "../lib/ConsiderationStructs.sol";
interface ZoneInterfaceV16 {
function authorizeOrder(
ZoneParameters calldata zoneParameters
) external returns (bytes4 authorizeOrderMagicValue);
function validateOrder(
ZoneParameters calldata zoneParameters
) external returns (bytes4 validOrderMagicValue);
function getSeaportMetadata()
external
view
returns (
string memory name,
Schema[] memory schemas // map to Seaport Improvement Proposal IDs
);
}
SignedZoneControllerV16.sol 605 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {SignedZoneV16} from "./SignedZoneV16.sol";
import {SignedZoneInterface} from "./interfaces/SignedZoneInterface.sol";
import {SignedZoneControllerInterface} from "./interfaces/SignedZoneControllerInterface.sol";
import {SignedZoneControllerEventsAndErrors} from "./interfaces/SignedZoneControllerEventsAndErrors.sol";
import "./lib/SignedZoneConstants.sol";
/**
* @title SignedZoneControllerV16
* @author BCLeFevre
* @notice SignedZoneControllerV16 enables the deploying of SignedZones.
* SignedZones are an implementation of SIP-7 that requires orders to
* be signed by an approved signer.
* https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
*/
contract SignedZoneControllerV16 is
SignedZoneControllerInterface,
SignedZoneControllerEventsAndErrors
{
/**
* @dev The struct for storing signer info.
*/
struct SignerInfo {
/// @dev If the signer is currently active.
bool active;
/// @dev If the signer has been active before.
bool previouslyActive;
}
// Properties used by the signed zone, stored on the controller.
struct SignedZoneProperties {
/// @dev Owner of the signed zone (used for permissioned functions)
address owner;
/// @dev Potential owner of the signed zone
address potentialOwner;
/// @dev The name for this zone returned in getSeaportMetadata().
string zoneName;
/// @dev The API endpoint where orders for this zone can be signed.
/// Request and response payloads are defined in SIP-7.
string apiEndpoint;
/// @dev The URI to the documentation describing the behavior of the
/// contract.
string documentationURI;
/// @dev The substandards supported by this zone.
/// Substandards are defined in SIP-7.
uint256[] substandards;
/// @dev Mapping of signer information keyed by signer Address
mapping(address => SignerInfo) signers;
/// @dev List of active signers
address[] activeSignerList;
}
/// @dev Mapping of signed zone properties keyed by the Signed Zone
/// address.
mapping(address => SignedZoneProperties) internal _signedZones;
/// @dev The EIP-712 digest parameters for the SignedZone.
bytes32 internal immutable _NAME_HASH = keccak256(bytes("SignedZone"));
bytes32 internal immutable _VERSION_HASH = keccak256(bytes("1.0"));
// prettier-ignore
bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH = keccak256(
abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"uint256 chainId,",
"address verifyingContract",
")"
)
);
uint256 internal immutable _CHAIN_ID = block.chainid;
// Set the signed zone creation code as an immutable argument.
bytes32 internal immutable _SIGNED_ZONE_CREATION_CODE_HASH;
/**
* @dev Initialize contract
*/
constructor() {
// Derive the signed zone creation code hash and set it as an
// immutable.
_SIGNED_ZONE_CREATION_CODE_HASH = keccak256(type(SignedZoneV16).creationCode);
}
/**
* @notice Deploy a SignedZoneV16 to a precomputed address.
*
* @param zoneName The name for the zone returned in
* getSeaportMetadata().
* @param apiEndpoint The API endpoint where orders for this zone can be
* signed.
* @param documentationURI The URI to the documentation describing the
* behavior of the contract.
* Request and response payloads are defined in SIP-7.
* @param salt The salt to be used to derive the zone address
* @param initialOwner The initial owner to set for the new zone.
*
* @return derivedAddress The derived address for the zone.
*/
function createZone(
string memory zoneName,
string memory apiEndpoint,
string memory documentationURI,
address initialOwner,
bytes32 salt
) external override returns (address derivedAddress) {
// Ensure that an initial owner has been supplied.
if (initialOwner == address(0)) {
revert InvalidInitialOwner();
}
// Ensure the first 20 bytes of the salt are the same as the msg.sender.
if ((address(uint160(bytes20(salt))) != msg.sender)) {
// Revert with an error indicating that the creator is invalid.
revert InvalidCreator();
}
// Derive the SignedZoneV16 address from the deployer, salt and creation
// code hash.
derivedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, _SIGNED_ZONE_CREATION_CODE_HASH)
)
)
)
);
// TODO : Check runtime code hash to ensure that the zone is not already
// deployed.
// Revert if a zone is currently deployed to the derived address.
if (derivedAddress.code.length != 0) {
revert ZoneAlreadyExists(derivedAddress);
}
// Deploy the zone using the supplied salt.
new SignedZoneV16{salt: salt}();
// Initialize storage variable referencing signed zone properties.
SignedZoneProperties storage signedZoneProperties = _signedZones[derivedAddress];
// Set the supplied intial owner as the owner of the zone.
signedZoneProperties.owner = initialOwner;
// Set the zone name.
signedZoneProperties.zoneName = zoneName;
// Set the API endpoint.
signedZoneProperties.apiEndpoint = apiEndpoint;
// Set the documentation URI.
signedZoneProperties.documentationURI = documentationURI;
// Set the substandard.
signedZoneProperties.substandards = [3];
// Emit an event signifying that the zone was created.
emit ZoneCreated(derivedAddress, zoneName, apiEndpoint, documentationURI, salt);
// Emit an event indicating that zone ownership has been assigned.
emit OwnershipTransferred(derivedAddress, address(0), initialOwner);
}
/**
* @notice Initiate zone ownership transfer by assigning a new potential
* owner for the given zone. Once set, the new potential owner
* may call `acceptOwnership` to claim ownership of the zone.
* Only the owner of the zone in question may call this function.
*
* @param zone The zone for which to initiate ownership transfer.
* @param newPotentialOwner The new potential owner of the zone.
*/
function transferOwnership(address zone, address newPotentialOwner) external override {
// Ensure the caller is the current owner of the zone in question.
_assertCallerIsZoneOwner(zone);
// Ensure the new potential owner is not an invalid address.
if (newPotentialOwner == address(0)) {
revert NewPotentialOwnerIsZeroAddress(zone);
}
// Ensure the new potential owner is not already set.
if (newPotentialOwner == _signedZones[zone].potentialOwner) {
revert NewPotentialOwnerAlreadySet(zone, newPotentialOwner);
}
// Emit an event indicating that the potential owner has been updated.
emit PotentialOwnerUpdated(newPotentialOwner);
// Set the new potential owner as the potential owner of the zone.
_signedZones[zone].potentialOwner = newPotentialOwner;
}
/**
* @notice Clear the currently set potential owner, if any, from a zone.
* Only the owner of the zone in question may call this function.
*
* @param zone The zone for which to cancel ownership transfer.
*/
function cancelOwnershipTransfer(address zone) external override {
// Ensure the caller is the current owner of the zone in question.
_assertCallerIsZoneOwner(zone);
// Ensure that ownership transfer is currently possible.
if (_signedZones[zone].potentialOwner == address(0)) {
revert NoPotentialOwnerCurrentlySet(zone);
}
// Emit an event indicating that the potential owner has been cleared.
emit PotentialOwnerUpdated(address(0));
// Clear the current new potential owner from the zone.
_signedZones[zone].potentialOwner = address(0);
}
/**
* @notice Accept ownership of a supplied zone. Only accounts that the
* current owner has set as the new potential owner may call this
* function.
*
* @param zone The zone for which to accept ownership.
*/
function acceptOwnership(address zone) external override {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// If caller does not match current potential owner of the zone...
if (msg.sender != _signedZones[zone].potentialOwner) {
// Revert, indicating that caller is not current potential owner.
revert CallerIsNotNewPotentialOwner(zone);
}
// Emit an event indicating that the potential owner has been cleared.
emit PotentialOwnerUpdated(address(0));
// Clear the current new potential owner from the zone.
_signedZones[zone].potentialOwner = address(0);
// Emit an event indicating zone ownership has been transferred.
emit OwnershipTransferred(zone, _signedZones[zone].owner, msg.sender);
// Set the caller as the owner of the zone.
_signedZones[zone].owner = msg.sender;
}
/**
* @notice Retrieve the current owner of a deployed zone.
*
* @param zone The zone for which to retrieve the associated owner.
*
* @return owner The owner of the supplied zone.
*/
function ownerOf(address zone) external view override returns (address owner) {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// Retrieve the current owner of the zone in question.
owner = _signedZones[zone].owner;
}
/**
* @notice Retrieve the potential owner, if any, for a given zone. The
* current owner may set a new potential owner via
* `transferOwnership` and that owner may then accept ownership of
* the zone in question via `acceptOwnership`.
*
* @param zone The zone for which to retrieve the potential owner.
*
* @return potentialOwner The potential owner, if any, for the zone.
*/
function getPotentialOwner(address zone) external view override returns (address potentialOwner) {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// Retrieve the current potential owner of the zone in question.
potentialOwner = _signedZones[zone].potentialOwner;
}
/**
* @notice Returns the active signers for the zone.
*
* @param zone The zone to return the active signers for.
*
* @return signers The active signers.
*/
function getActiveSigners(
address zone
) external view override returns (address[] memory signers) {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// Retrieve storage region where the singers for the signedZone are
// stored.
SignedZoneProperties storage signedZoneProperties = _signedZones[zone];
// Return the active signers for the zone.
signers = signedZoneProperties.activeSignerList;
}
/**
* @notice Update the API endpoint returned by a zone.
* Only the owner or an active signer of the supplied zone can call
* this function.
*
* @param zone The signed zone to update the API endpoint for.
* @param newApiEndpoint The new API endpoint.
*/
function updateAPIEndpoint(address zone, string calldata newApiEndpoint) external override {
// Ensure the caller is the owner or an active signer of the signed zone.
_assertCallerIsZoneOwnerOrSigner(zone);
// Retrieve storage region where the singers for the signedZone are
// stored.
SignedZoneProperties storage signedZoneProperties = _signedZones[zone];
// Update the API endpoint on the signed zone.
signedZoneProperties.apiEndpoint = newApiEndpoint;
}
/**
* @notice Add or remove a signer from the supplied zone.
* Only the owner or an active signer of the supplied zone can call
* this function.
*
* @param zone The signed zone to update the signer permissions for.
* @param signer The signer to update the permissions for.
* @param active Whether the signer should be active or not.
*/
function updateSigner(address zone, address signer, bool active) external override {
// Ensure the caller is the owner or an active signer of the signed zone.
_assertCallerIsZoneOwnerOrSigner(zone);
// Retrieve storage region where the singers for the signedZone are
// stored.
SignedZoneProperties storage signedZoneProperties = _signedZones[zone];
// Validate signer permissions.
_assertSignerPermissions(signedZoneProperties, signer, active);
// Update the signer on the signed zone.
SignedZoneInterface(zone).updateSigner(signer, active);
// Update the signer information.
signedZoneProperties.signers[signer].active = active;
signedZoneProperties.signers[signer].previouslyActive = true;
// Add the signer to the list of signers if they are active.
if (active) {
signedZoneProperties.activeSignerList.push(signer);
} else {
// Remove the signer from the list of signers.
for (uint256 i = 0; i < signedZoneProperties.activeSignerList.length; ) {
if (signedZoneProperties.activeSignerList[i] == signer) {
signedZoneProperties.activeSignerList[i] = signedZoneProperties.activeSignerList[
signedZoneProperties.activeSignerList.length - 1
];
signedZoneProperties.activeSignerList.pop();
break;
}
unchecked {
++i;
}
}
}
// Emit an event signifying that the signer was updated.
emit SignerUpdated(zone, signer, active);
}
/**
* @notice Derive the zone address associated with a salt.
*
* @param salt The salt to be used to derive the zone address.
*
* @return derivedAddress The derived address of the signed zone.
*/
function getZone(bytes32 salt) external view override returns (address derivedAddress) {
// Derive the SignedZoneV16 address from deployer, salt and creation code
// hash.
derivedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, _SIGNED_ZONE_CREATION_CODE_HASH)
)
)
)
);
}
/**
* @notice External call to return the signing information, substandards,
* and documentation about the zone.
*
* @return domainSeparator The domain separator used for signing.
* @return zoneName The name of the zone.
* @return apiEndpoint The API endpoint for the zone.
* @return substandards The substandards supported by the zone.
* @return documentationURI The documentation URI for the zone.
*/
function getAdditionalZoneInformation(
address zone
)
external
view
override
returns (
bytes32 domainSeparator,
string memory zoneName,
string memory apiEndpoint,
uint256[] memory substandards,
string memory documentationURI
)
{
// Ensure the zone exists.
_assertZoneExists(zone);
// Return the zone's additional information.
return _additionalZoneInformation(zone);
}
/**
* @notice Internal call to return the signing information, substandards,
* and documentation about the zone.
*
* @return domainSeparator The domain separator used for signing.
* @return zoneName The name of the zone.
* @return apiEndpoint The API endpoint for the zone.
* @return substandards The substandards supported by the zone.
* @return documentationURI The documentation URI for the zone.
*/
function _additionalZoneInformation(
address zone
)
internal
view
returns (
bytes32 domainSeparator,
string memory zoneName,
string memory apiEndpoint,
uint256[] memory substandards,
string memory documentationURI
)
{
// Get the zone properties.
SignedZoneProperties storage signedZoneProperties = _signedZones[zone];
// Return the SIP-7 information.
domainSeparator = _domainSeparator(zone);
zoneName = signedZoneProperties.zoneName;
apiEndpoint = signedZoneProperties.apiEndpoint;
substandards = signedZoneProperties.substandards;
documentationURI = signedZoneProperties.documentationURI;
}
/**
* @dev Internal view function to get the EIP-712 domain separator. If the
* chainId matches the chainId set on deployment, the cached domain
* separator will be returned; otherwise, it will be derived from
* scratch.
*
* @return The domain separator.
*/
function _domainSeparator(address zone) internal view returns (bytes32) {
// prettier-ignore
return _deriveDomainSeparator(zone);
}
/**
* @dev Internal view function to derive the EIP-712 domain separator.
*
* @return domainSeparator The derived domain separator.
*/
function _deriveDomainSeparator(address zone) internal view returns (bytes32 domainSeparator) {
bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH;
bytes32 nameHash = _NAME_HASH;
bytes32 versionHash = _VERSION_HASH;
// Leverage scratch space and other memory to perform an efficient hash.
assembly {
// Retrieve the free memory pointer; it will be replaced afterwards.
let freeMemoryPointer := mload(FreeMemoryPointerSlot)
// Retrieve value at 0x80; it will also be replaced afterwards.
let slot0x80 := mload(Slot0x80)
// Place typehash, name hash, and version hash at start of memory.
mstore(0, typehash)
mstore(OneWord, nameHash)
mstore(TwoWords, versionHash)
// Place chainId in the next memory location.
mstore(ThreeWords, chainid())
// Place the address of the signed zone contract in the next memory location.
mstore(FourWords, zone)
// Hash relevant region of memory to derive the domain separator.
domainSeparator := keccak256(0, FiveWords)
// Restore the free memory pointer.
mstore(FreeMemoryPointerSlot, freeMemoryPointer)
// Restore the zero slot to zero.
mstore(ZeroSlot, 0)
// Restore the value at 0x80.
mstore(Slot0x80, slot0x80)
}
}
/**
* @dev Private view function to revert if the caller is not the owner of a
* given zone.
*
* @param zone The zone for which to assert ownership.
*/
function _assertCallerIsZoneOwner(address zone) private view {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// If the caller does not match the current owner of the zone...
if (msg.sender != _signedZones[zone].owner) {
// Revert, indicating that the caller is not the owner.
revert CallerIsNotOwner(zone);
}
}
/**
* @dev Private view function to revert if the caller is not the owner or
* an active signer of a given zone.
*
* @param zone The zone for which to assert ownership.
*/
function _assertCallerIsZoneOwnerOrSigner(address zone) private view {
// Ensure that the zone in question exists.
_assertZoneExists(zone);
// Initialize storage variable referencing signed zone properties.
SignedZoneProperties storage signedZoneProperties = _signedZones[zone];
// Ensure the caller is the owner or an active signer of the signed zone.
if (
msg.sender != _signedZones[zone].owner && !signedZoneProperties.signers[msg.sender].active
) {
// Revert, indicating that the caller is not the owner.
revert CallerIsNotOwnerOrSigner(zone);
}
}
/**
* @dev Private view function to revert if a given zone does not exist.
*
* @param zone The zone for which to assert existence.
*/
function _assertZoneExists(address zone) private view {
// Attempt to retrieve a the owner for the zone in question.
if (_signedZones[zone].owner == address(0)) {
// Revert if no ownerwas located.
revert NoZone();
}
}
/**
* @dev Private view function to revert if a signer being added to a zone
* is the zero address or the signer already exists, or the signer was
* previously authorized. If the signer is being removed, the
* function will revert if the signer is not active.
*
* @param signedZoneProperties The signed zone properties for the zone.
* @param signer The signer to add or remove.
* @param active Whether the signer is being added or removed.
*/
function _assertSignerPermissions(
SignedZoneProperties storage signedZoneProperties,
address signer,
bool active
) private view {
// If the signer is being added...
if (active) {
// Do not allow the zero address to be added as a signer.
if (signer == address(0)) {
revert SignerCannotBeZeroAddress();
}
// Revert if the signer is already added.
if (signedZoneProperties.signers[signer].active) {
revert SignerAlreadyAdded(signer);
}
// Revert if the signer was previously authorized.
if (signedZoneProperties.signers[signer].previouslyActive) {
revert SignerCannotBeReauthorized(signer);
}
} else {
// Revert if the signer is not active.
if (!signedZoneProperties.signers[signer].active) {
revert SignerNotPresent(signer);
}
}
}
}
SignedZoneConstants.sol 171 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/// @dev ECDSA signature offsets.
uint256 constant ECDSA_MaxLength = 65;
uint256 constant ECDSA_signature_s_offset = 0x40;
uint256 constant ECDSA_signature_v_offset = 0x60;
/// @dev Helpers for memory offsets.
uint256 constant OneWord = 0x20;
uint256 constant TwoWords = 0x40;
uint256 constant ThreeWords = 0x60;
uint256 constant FourWords = 0x80;
uint256 constant FiveWords = 0xa0;
uint256 constant Signature_lower_v = 27;
uint256 constant MaxUint8 = 0xff;
bytes32 constant EIP2098_allButHighestBitMask = (
0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
uint256 constant Ecrecover_precompile = 1;
uint256 constant Ecrecover_args_size = 0x80;
uint256 constant FreeMemoryPointerSlot = 0x40;
uint256 constant ZeroSlot = 0x60;
uint256 constant Slot0x80 = 0x80;
/// @dev The EIP-712 digest offsets.
uint256 constant EIP712_DomainSeparator_offset = 0x02;
uint256 constant EIP712_SignedOrderHash_offset = 0x22;
uint256 constant EIP712_DigestPayload_size = 0x42;
uint256 constant EIP_712_PREFIX = (
0x1901000000000000000000000000000000000000000000000000000000000000
);
/*
* error InvalidController()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* Revert buffer is memory[0x1c:0x20]
*/
uint256 constant InvalidController_error_selector = 0x6d5769be;
uint256 constant InvalidController_error_length = 0x04;
/*
* error InvalidFulfiller(address expectedFulfiller, address actualFulfiller, bytes32 orderHash)
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: expectedFulfiller
* - 0x40: actualFullfiller
* - 0x60: orderHash
* Revert buffer is memory[0x1c:0x80]
*/
uint256 constant InvalidFulfiller_error_selector = 0x1bcf9bb7;
uint256 constant InvalidFulfiller_error_expectedFulfiller_ptr = 0x20;
uint256 constant InvalidFulfiller_error_actualFulfiller_ptr = 0x40;
uint256 constant InvalidFulfiller_error_orderHash_ptr = 0x60;
uint256 constant InvalidFulfiller_error_length = 0x64;
/*
* error InvalidConsideration(uint256 expectedConsideration, uint256 actualConsideration, bytes32 orderHash)
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: expectedConsideration
* - 0x40: actualConsideration
* - 0x60: orderHash
* Revert buffer is memory[0x1c:0x80]
*/
uint256 constant InvalidConsideration_error_selector = 0x59cb96d1;
uint256 constant InvalidConsideration_error_expectedConsideration_ptr = 0x20;
uint256 constant InvalidConsideration_error_actualConsideration_ptr = 0x40;
uint256 constant InvalidConsideration_error_orderHash_ptr = 0x60;
uint256 constant InvalidConsideration_error_length = 0x64;
/*
* error InvalidZoneParameterEncoding()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* Revert buffer is memory[0x1c:0x20]
*/
uint256 constant InvalidZoneParameterEncoding_error_selector = 0x46d5d895;
uint256 constant InvalidZoneParameterEncoding_error_length = 0x04;
/*
* error InvalidExtraDataLength()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: orderHash
* Revert buffer is memory[0x1c:0x40]
*/
uint256 constant InvalidExtraDataLength_error_selector = 0xd232fd2c;
uint256 constant InvalidExtraDataLength_error_orderHash_ptr = 0x20;
uint256 constant InvalidExtraDataLength_error_length = 0x24;
uint256 constant InvalidExtraDataLength_epected_length = 0x7e;
uint256 constant ExtraData_expiration_offset = 0x35;
uint256 constant ExtraData_substandard_version_byte_offset = 0x7d;
/*
* error InvalidSIP6Version()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: orderHash
* Revert buffer is memory[0x1c:0x40]
*/
uint256 constant InvalidSIP6Version_error_selector = 0x64115774;
uint256 constant InvalidSIP6Version_error_orderHash_ptr = 0x20;
uint256 constant InvalidSIP6Version_error_length = 0x24;
/*
* error InvalidSubstandardVersion()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: orderHash
* Revert buffer is memory[0x1c:0x40]
*/
uint256 constant InvalidSubstandardVersion_error_selector = 0x26787999;
uint256 constant InvalidSubstandardVersion_error_orderHash_ptr = 0x20;
uint256 constant InvalidSubstandardVersion_error_length = 0x24;
/*
* error InvalidSubstandardSupport()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: reason
* - 0x40: substandardVersion
* - 0x60: orderHash
* Revert buffer is memory[0x1c:0xe0]
*/
uint256 constant InvalidSubstandardSupport_error_selector = 0x2be76224;
uint256 constant InvalidSubstandardSupport_error_reason_offset_ptr = 0x20;
uint256 constant InvalidSubstandardSupport_error_substandard_version_ptr = 0x40;
uint256 constant InvalidSubstandardSupport_error_orderHash_ptr = 0x60;
uint256 constant InvalidSubstandardSupport_error_reason_length_ptr = 0x80;
uint256 constant InvalidSubstandardSupport_error_reason_ptr = 0xa0;
uint256 constant InvalidSubstandardSupport_error_reason_2_ptr = 0xc0;
uint256 constant InvalidSubstandardSupport_error_length = 0xc4;
/*
* error SignatureExpired()
* - Defined in SignedZoneEventsAndErrors.sol
* Memory layout:
* - 0x00: Left-padded selector (data begins at 0x1c)
* - 0x20: expiration
* - 0x40: orderHash
* Revert buffer is memory[0x1c:0x60]
*/
uint256 constant SignatureExpired_error_selector = 0x16546071;
uint256 constant SignatureExpired_error_expiration_ptr = 0x20;
uint256 constant SignatureExpired_error_orderHash_ptr = 0x40;
uint256 constant SignatureExpired_error_length = 0x44;
// Zone parameter calldata pointers
uint256 constant Zone_parameters_cdPtr = 0x04;
uint256 constant Zone_parameters_fulfiller_cdPtr = 0x44;
uint256 constant Zone_consideration_head_cdPtr = 0xa4;
uint256 constant Zone_extraData_cdPtr = 0xc4;
// Zone parameter memory pointers
uint256 constant Zone_parameters_ptr = 0x20;
// Zone parameter offsets
uint256 constant Zone_parameters_offset = 0x24;
uint256 constant expectedFulfiller_offset = 0x45;
uint256 constant actualConsideration_offset = 0x84;
uint256 constant expectedConsideration_offset = 0xa2;
SIP5Interface.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import { Schema } from "../../lib/ConsiderationStructs.sol";
/**
* @dev SIP-5: Contract Metadata Interface for Seaport Contracts
* https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-5.md
*/
interface SIP5Interface {
/**
* @dev An event that is emitted when a SIP-5 compatible contract is deployed.
*/
event SeaportCompatibleContractDeployed();
/**
* @dev Returns Seaport metadata for this contract, returning the
* contract name and supported schemas.
*
* @return name The contract name
* @return schemas The supported SIPs
*/
function getSeaportMetadata()
external
view
returns (string memory name, Schema[] memory schemas);
}
SignedZoneInterface.sol 30 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/**
* @title SignedZone
* @author ryanio, BCLeFevre
* @notice SignedZone is an implementation of SIP-7 that requires orders
* to be signed by an approved signer.
* https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
*
*/
interface SignedZoneInterface {
/**
* @notice Update the active status of a signer.
*
* @param signer The signer address to update.
* @param active The new active status of the signer.
*/
function updateSigner(address signer, bool active) external;
/**
* @notice Returns the active signers for the zone.
*
* @return signers The active signers.
*/
function getActiveSigners()
external
view
returns (address[] memory signers);
}
SignedZoneEventsAndErrors.sol 92 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/**
* @notice SignedZoneEventsAndErrors contains errors and events
* related to zone interaction.
*/
interface SignedZoneEventsAndErrors {
/**
* @dev Emit an event when a new signer is added.
*/
event SignerAdded(address signer);
/**
* @dev Emit an event when a signer is removed.
*/
event SignerRemoved(address signer);
/**
* @dev Revert with an error if msg.sender is not the owner
* or an active signer.
*/
error OnlyOwnerOrActiveSigner();
/**
* @dev Revert with an error when the signature has expired.
*/
error SignatureExpired(uint256 expiration, bytes32 orderHash);
/**
* @dev Revert with an error when attempting to update the signers of a
* the zone from a caller that is not the zone's controller.
*/
error InvalidController();
/**
* @dev Revert with an error if supplied order extraData is an invalid
* length.
*/
error InvalidExtraDataLength(bytes32 orderHash);
/**
* @dev Revert with an error if the supplied order extraData does not
* support the zone's SIP6 version.
*/
error InvalidSIP6Version(bytes32 orderHash);
/**
* @dev Revert with an error if the supplied order extraData does not
* support the zone's substandard requirements.
*/
error InvalidSubstandardSupport(
string reason,
uint256 substandardVersion,
bytes32 orderHash
);
/**
* @dev Revert with an error if the supplied order extraData does not
* support the zone's substandard version.
*/
error InvalidSubstandardVersion(bytes32 orderHash);
/**
* @dev Revert with an error if the fulfiller does not match.
*/
error InvalidFulfiller(
address expectedFulfiller,
address actualFulfiller,
bytes32 orderHash
);
/**
* @dev Revert with an error if the consideration does not match.
*/
error InvalidConsideration(
uint256 expectedConsiderationHash,
uint256 actualConsiderationHash,
bytes32 orderHash
);
/**
* @dev Revert with an error if the zone parameter encoding is invalid.
*/
error InvalidZoneParameterEncoding();
/**
* @dev Revert with an error when an order is signed with a signer
* that is not active.
*/
error SignerNotActive(address signer, bytes32 orderHash);
}
SignedZoneControllerInterface.sol 160 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/**
* @title SignedZoneControllerInterface
* @author BCLeFevre
* @notice SignedZoneControllerInterface enables the deploying of SignedZones.
* SignedZones are an implementation of SIP-7 that requires orders
* to be signed by an approved signer.
* https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
*
*/
interface SignedZoneControllerInterface {
/**
* @notice Deploy a SignedZone to a precomputed address.
*
* @param zoneName The name for the zone returned in
* getSeaportMetadata().
* @param apiEndpoint The API endpoint where orders for this zone can be
* signed.
* @param documentationURI The URI to the documentation describing the
* behavior of the contract.
* Request and response payloads are defined in SIP-7.
* @param salt The salt to be used to derive the zone address
* @param initialOwner The initial owner to set for the new zone.
*
* @return derivedAddress The derived address for the zone.
*/
function createZone(
string memory zoneName,
string memory apiEndpoint,
string memory documentationURI,
address initialOwner,
bytes32 salt
) external returns (address derivedAddress);
/**
* @notice Returns the active signers for the zone.
*
* @param signedZone The signed zone to get the active signers for.
*
* @return signers The active signers.
*/
function getActiveSigners(address signedZone)
external
view
returns (address[] memory signers);
/**
* @notice Returns additional information about the zone.
*
* @param zone The zone to get the additional information for.
*
* @return domainSeparator The domain separator used for signing.
* @return zoneName The name of the zone.
* @return apiEndpoint The API endpoint for the zone.
* @return substandards The substandards supported by the zone.
* @return documentationURI The documentation URI for the zone.
*/
function getAdditionalZoneInformation(address zone)
external
view
returns (
bytes32 domainSeparator,
string memory zoneName,
string memory apiEndpoint,
uint256[] memory substandards,
string memory documentationURI
);
/**
* @notice Update the API endpoint returned by the supplied zone.
* Only the owner or an active signer can call this function.
*
* @param signedZone The signed zone to update the API endpoint for.
* @param newApiEndpoint The new API endpoint.
*/
function updateAPIEndpoint(
address signedZone,
string calldata newApiEndpoint
) external;
/**
* @notice Update the signer for a given signed zone.
*
* @param signedZone The signed zone to update the signer for.
* @param signer The signer to update.
* @param active If the signer should be active or not.
*/
function updateSigner(
address signedZone,
address signer,
bool active
) external;
/**
* @notice Initiate zone ownership transfer by assigning a new potential
* owner for the given zone. Once set, the new potential owner
* may call `acceptOwnership` to claim ownership of the zone.
* Only the owner of the zone in question may call this function.
*
* @param zone The zone for which to initiate ownership transfer.
* @param newPotentialOwner The new potential owner of the zone.
*/
function transferOwnership(address zone, address newPotentialOwner)
external;
/**
* @notice Clear the currently set potential owner, if any, from a zone.
* Only the owner of the zone in question may call this function.
*
* @param zone The zone for which to cancel ownership transfer.
*/
function cancelOwnershipTransfer(address zone) external;
/**
* @notice Accept ownership of a supplied zone. Only accounts that the
* current owner has set as the new potential owner may call this
* function.
*
* @param zone The zone for which to accept ownership.
*/
function acceptOwnership(address zone) external;
/**
* @notice Retrieve the current owner of a deployed zone.
*
* @param zone The zone for which to retrieve the associated owner.
*
* @return owner The owner of the supplied zone.
*/
function ownerOf(address zone) external view returns (address owner);
/**
* @notice Retrieve the potential owner, if any, for a given zone. The
* current owner may set a new potential owner via
* `transferOwnership` and that owner may then accept ownership of
* the zone in question via `acceptOwnership`.
*
* @param zone The zone for which to retrieve the potential owner.
*
* @return potentialOwner The potential owner, if any, for the zone.
*/
function getPotentialOwner(address zone)
external
view
returns (address potentialOwner);
/**
* @notice Derive the zone address associated with a salt.
*
* @param salt The salt to be used to derive the zone address
*
* @return derivedAddress The derived address of the signed zone.
*/
function getZone(bytes32 salt)
external
view
returns (address derivedAddress);
}
SignedZoneControllerEventsAndErrors.sol 141 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/**
* @notice SignedZoneControllerEventsAndErrors contains errors and events
* related to deploying and managing new signed zones.
*/
interface SignedZoneControllerEventsAndErrors {
/**
* @dev Emit an event whenever a new zone is created.
*
* @param zoneAddress The address of the zone.
* @param zoneName The name for the zone returned in
* getSeaportMetadata().
* @param apiEndpoint The API endpoint where orders for this zone can be
* signed.
* @param documentationURI The URI to the documentation describing the
* behavior of the contract.
* Request and response payloads are defined in SIP-7.
* @param salt The salt used to deploy the zone.
*/
event ZoneCreated(
address zoneAddress,
string zoneName,
string apiEndpoint,
string documentationURI,
bytes32 salt
);
/**
* @dev Emit an event whenever zone ownership is transferred.
*
* @param zone The zone for which ownership has been
* transferred.
* @param previousOwner The previous owner of the zone.
* @param newOwner The new owner of the zone.
*/
event OwnershipTransferred(
address indexed zone,
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Emit an event whenever a zone owner registers a new potential
* owner for that zone.
*
* @param newPotentialOwner The new potential owner of the zone.
*/
event PotentialOwnerUpdated(address indexed newPotentialOwner);
/**
* @dev Emit an event when a signer has been updated.
*/
event SignerUpdated(address signedZone, address signer, bool active);
/**
* @dev Revert with an error when attempting to update channels or transfer
* ownership of a zone when the caller is not the owner of the
* zone in question.
*/
error CallerIsNotOwner(address zone);
/**
* @dev Revert with an error when the caller is not the owner or an active
* signer of the signed zone in question.
*/
error CallerIsNotOwnerOrSigner(address zone);
/**
* @dev Revert with an error when attempting to claim ownership of a zone
* with a caller that is not the current potential owner for the
* zone in question.
*/
error CallerIsNotNewPotentialOwner(address zone);
/**
* @dev Revert with an error when attempting to create a new signed zone
* using a salt where the first twenty bytes do not match the address
* of the caller or are not set to zero.
*/
error InvalidCreator();
/**
* @dev Revert with an error when attempting to create a new zone when no
* initial owner address is supplied.
*/
error InvalidInitialOwner();
/**
* @dev Revert with an error when attempting to set a new potential owner
* that is already set.
*/
error NewPotentialOwnerAlreadySet(address zone, address newPotentialOwner);
/**
* @dev Revert with an error when attempting to cancel ownership transfer
* when no new potential owner is currently set.
*/
error NoPotentialOwnerCurrentlySet(address zone);
/**
* @dev Revert with an error when attempting to register a new potential
* owner and supplying the null address.
*/
error NewPotentialOwnerIsZeroAddress(address zone);
/**
* @dev Revert with an error when attempting to interact with a zone that
* does not yet exist.
*/
error NoZone();
/**
* @dev Revert with an error if trying to add a signer that is
* already active.
*/
error SignerAlreadyAdded(address signer);
/**
* @dev Revert with an error if a new signer is the zero address.
*/
error SignerCannotBeZeroAddress();
/**
* @dev Revert with an error if a removed signer is trying to be
* reauthorized.
*/
error SignerCannotBeReauthorized(address signer);
/**
* @dev Revert with an error if trying to remove a signer that is
* not present.
*/
error SignerNotPresent(address signer);
/**
* @dev Revert with an error when attempting to deploy a zone that is
* currently deployed.
*/
error ZoneAlreadyExists(address zone);
}
Read Contract
getActiveSigners 0x66a2489f → address[]
getAdditionalZoneInformation 0x04789c98 → bytes32, string, string, uint256[], string
getPotentialOwner 0x906c87cc → address
getZone 0x4b42e8d5 → address
ownerOf 0x14afd79e → address
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x51710e45
address zone
cancelOwnershipTransfer 0x7b37e561
address zone
createZone 0x0eb92516
string zoneName
string apiEndpoint
string documentationURI
address initialOwner
bytes32 salt
returns: address
transferOwnership 0x6d435421
address zone
address newPotentialOwner
updateAPIEndpoint 0xe89fad58
address zone
string newApiEndpoint
updateSigner 0xdca09383
address zone
address signer
bool active
Recent Transactions
No transactions found for this address