Address Contract Partially Verified
Address
0x99161BA892ECae335616624c84FAA418F64FF9A6
Balance
0 ETH
Nonce
1
Code Size
14056 bytes
Creator
0xE78615F8...3Cc1 at tx 0xc556ea49...2de8d9
Indexed Transactions
0
Contract Bytecode
14056 bytes
0x60806040526004361015610013575b611204565b61001d5f356101ec565b806301ffc9a7146101e757806304554443146101e25780630e18b681146101dd578063248a9ca3146101d85780632f2ff15d146101d357806336568abe146101ce5780633df32c16146101c95780633f4ba83a146101c45780635c975abb146101bf5780635e7db13d146101ba57806374e00d5f146101b557806375829def146101b05780638456cb59146101ab5780638da5cb5b146101a65780638edce3e3146101a157806391d148541461019c578063a217fddf14610197578063a2befa4914610192578063ab90aee81461018d578063afad2e1614610188578063c34b697e14610183578063d547741f1461017e578063d8fb933714610179578063debc4aca14610174578063df3113ce1461016f578063e63ab1e91461016a578063e6ec7e6f14610165578063ec87621c146101605763f294d3b70361000e576111d0565b611161565b6110fb565b61105d565b610ff8565b610e7d565b610e02565b610d1d565b610cea565b610c74565b610bf3565b610a49565b6108f8565b610887565b610853565b6107e4565b61078f565b61075c565b610709565b610696565b61060e565b6105db565b6105a7565b610523565b6104ef565b610453565b6103ba565b61037f565b610278565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b63ffffffff60e01b1690565b61021981610204565b0361022057565b5f80fd5b9050359061023182610210565b565b9060208282031261024c57610249915f01610224565b90565b6101fc565b151590565b61025f90610251565b9052565b9190610276905f60208501940190610256565b565b346102a8576102a461029361028e366004610233565b61120c565b61029b6101f2565b91829182610263565b0390f35b6101f8565b5f9103126102b757565b6101fc565b5f1c90565b6fffffffffffffffffffffffffffffffff1690565b6102e26102e7916102bc565b6102c1565b90565b6102f490546102d6565b90565b60801c90565b61030961030e916102f7565b6102c1565b90565b61031b90546102fd565b90565b6003906103375f6103308185016102ea565b9301610311565b90565b6fffffffffffffffffffffffffffffffff1690565b6103589061033a565b9052565b91602061037d92949361037660408201965f83019061034f565b019061034f565b565b346103b05761038f3660046102ad565b61039761031e565b906103ac6103a36101f2565b9283928361035c565b0390f35b6101f8565b5f0190565b346103e8576103ca3660046102ad565b6103d2611278565b6103da6101f2565b806103e4816103b5565b0390f35b6101f8565b90565b6103f9816103ed565b0361040057565b5f80fd5b90503590610411826103f0565b565b9060208282031261042c57610429915f01610404565b90565b6101fc565b61043a906103ed565b9052565b9190610451905f60208501940190610431565b565b346104835761047f61046e610469366004610413565b611322565b6104766101f2565b9182918261043e565b0390f35b6101f8565b60018060a01b031690565b61049c90610488565b90565b6104a881610493565b036104af57565b5f80fd5b905035906104c08261049f565b565b91906040838203126104ea57806104de6104e7925f8601610404565b936020016104b3565b90565b6101fc565b3461051e576105086105023660046104c2565b906113b3565b6105106101f2565b8061051a816103b5565b0390f35b6101f8565b346105525761053c6105363660046104c2565b90611412565b6105446101f2565b8061054e816103b5565b0390f35b6101f8565b6105608161033a565b0361056757565b5f80fd5b9050359061057882610557565b565b91906040838203126105a2578061059661059f925f860161056b565b9360200161056b565b90565b6101fc565b346105d6576105c06105ba36600461057a565b90611446565b6105c86101f2565b806105d2816103b5565b0390f35b6101f8565b34610609576105eb3660046102ad565b6105f3611476565b6105fb6101f2565b80610605816103b5565b0390f35b6101f8565b3461063e5761061e3660046102ad565b61063a6106296114a7565b6106316101f2565b91829182610263565b0390f35b6101f8565b90565b61064f81610643565b0361065657565b5f80fd5b9050359061066782610646565b565b9190604083820312610691578061068561068e925f86016104b3565b9360200161065a565b90565b6101fc565b346106c5576106af6106a9366004610669565b90611c7c565b6106b76101f2565b806106c1816103b5565b0390f35b6101f8565b1c90565b60ff1690565b6106e49060086106e993026106ca565b6106ce565b90565b906106f791546106d4565b90565b61070660075f906106ec565b90565b34610739576107193660046102ad565b6107356107246106fa565b61072c6101f2565b91829182610263565b0390f35b6101f8565b9060208282031261075757610754915f016104b3565b90565b6101fc565b3461078a5761077461076f36600461073e565b611da6565b61077c6101f2565b80610786816103b5565b0390f35b6101f8565b346107bd5761079f3660046102ad565b6107a7611dd5565b6107af6101f2565b806107b9816103b5565b0390f35b6101f8565b6107cb90610493565b9052565b91906107e2905f602085019401906107c2565b565b34610814576107f43660046102ad565b6108106107ff611de3565b6108076101f2565b918291826107cf565b0390f35b6101f8565b909160608284031261084e5761084b610834845f85016104b3565b9361084281602086016104b3565b9360400161065a565b90565b6101fc565b346108825761086c610866366004610819565b91612001565b6108746101f2565b8061087e816103b5565b0390f35b6101f8565b346108b8576108b46108a361089d3660046104c2565b90612024565b6108ab6101f2565b91829182610263565b0390f35b6101f8565b90565b5f1b90565b6108d96108d46108de926108bd565b6108c0565b6103ed565b90565b6108ea5f6108c5565b90565b6108f56108e1565b90565b34610928576109083660046102ad565b6109246109136108ed565b61091b6101f2565b9182918261043e565b0390f35b6101f8565b91906040838203126109555780610949610952925f86016104b3565b936020016104b3565b90565b6101fc565b5190565b60209181520190565b60200190565b6109769061033a565b9052565b67ffffffffffffffff1690565b6109909061097a565b9052565b906040806109c8936109ac5f8201515f86019061096d565b6109be60208201516020860190610987565b0151910190610987565b565b906109d781606093610994565b0190565b60200190565b906109fe6109f86109f18461095a565b809361095e565b92610967565b905f5b818110610a0e5750505090565b909192610a27610a2160019286516109ca565b946109db565b9101919091610a01565b610a469160208201915f8184039101526109e1565b90565b34610a7a57610a76610a65610a5f36600461092d565b906120ed565b610a6d6101f2565b91829182610a31565b0390f35b6101f8565b5f80fd5b5f80fd5b5f80fd5b909182601f83011215610ac55781359167ffffffffffffffff8311610ac0576020019260208302840111610abb57565b610a87565b610a83565b610a7f565b90602082820312610afb575f82013567ffffffffffffffff8111610af657610af29201610a8b565b9091565b610200565b6101fc565b5190565b60209181520190565b60200190565b610b1c90610251565b9052565b6bffffffffffffffffffffffff1690565b610b3a90610b20565b9052565b90604080610b7293610b565f8201515f860190610b13565b610b686020820151602086019061096d565b0151910190610b31565b565b90610b8181606093610b3e565b0190565b60200190565b90610ba8610ba2610b9b84610b00565b8093610b04565b92610b0d565b905f5b818110610bb85750505090565b909192610bd1610bcb6001928651610b74565b94610b85565b9101919091610bab565b610bf09160208201915f818403910152610b8b565b90565b34610c2457610c20610c0f610c09366004610aca565b9061234b565b610c176101f2565b91829182610bdb565b0390f35b6101f8565b90604080610c5d93610c415f8201515f860190610b13565b610c536020820151602086019061096d565b0151910190610b31565b565b9190610c72905f60608501940190610c29565b565b34610ca457610ca0610c8f610c8a36600461073e565b6123f3565b610c976101f2565b91829182610c5f565b0390f35b6101f8565b610cb281610251565b03610cb957565b5f80fd5b90503590610cca82610ca9565b565b90602082820312610ce557610ce2915f01610cbd565b90565b6101fc565b34610d1857610d02610cfd366004610ccc565b612438565b610d0a6101f2565b80610d14816103b5565b0390f35b6101f8565b34610d4c57610d36610d303660046104c2565b906124b3565b610d3e6101f2565b80610d48816103b5565b0390f35b6101f8565b90565b610d68610d63610d6d92610488565b610d51565b610488565b90565b610d7990610d54565b90565b610d8590610d70565b90565b90610d9290610d7c565b5f5260205260405f2090565b90565b610db1906008610db693026106ca565b610d9e565b90565b90610dc49154610da1565b90565b610ddd90610dd86006915f92610d88565b610db9565b90565b610de990610643565b9052565b9190610e00905f60208501940190610de0565b565b34610e3257610e2e610e1d610e1836600461073e565b610dc7565b610e256101f2565b91829182610ded565b0390f35b6101f8565b608081830312610e7857610e4d825f83016104b3565b92610e75610e5e84602085016104b3565b93610e6c816040860161056b565b9360600161056b565b90565b6101fc565b34610eaf57610e99610e90366004610e37565b9291909161274b565b610ea16101f2565b80610eab816103b5565b0390f35b6101f8565b919091604081840312610ef557610ecd835f83016104b3565b92602082013567ffffffffffffffff8111610ef057610eec9201610a8b565b9091565b610200565b6101fc565b5190565b60209181520190565b60200190565b60209181520190565b90610f33610f2d610f268461095a565b8093610f0d565b92610967565b905f5b818110610f435750505090565b909192610f5c610f5660019286516109ca565b946109db565b9101919091610f36565b90610f7091610f16565b90565b60200190565b90610f8d610f8683610efa565b8092610efe565b9081610f9e60208302840194610f07565b925f915b838310610fb157505050505090565b90919293946020610fd3610fcd83856001950387528951610f66565b97610f73565b9301930191939290610fa2565b610ff59160208201915f818403910152610f79565b90565b346110295761102561101461100e366004610eb4565b91612801565b61101c6101f2565b91829182610fe0565b0390f35b6101f8565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a90565b61105a61102e565b90565b3461108d5761106d3660046102ad565b611089611078611052565b6110806101f2565b9182918261043e565b0390f35b6101f8565b61109b81610b20565b036110a257565b5f80fd5b905035906110b382611092565b565b6080818303126110f6576110cb825f83016104b3565b926110f36110dc8460208501610cbd565b936110ea816040860161056b565b936060016110a6565b90565b6101fc565b3461112d5761111761110e3660046110b5565b929190916128d8565b61111f6101f2565b80611129816103b5565b0390f35b6101f8565b7f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0890565b61115e611132565b90565b34611191576111713660046102ad565b61118d61117c611156565b6111846101f2565b9182918261043e565b0390f35b6101f8565b90916060828403126111cb576111c86111b1845f85016104b3565b936111bf816020860161056b565b9360400161056b565b90565b6101fc565b346111ff576111e96111e3366004611196565b91612a6a565b6111f16101f2565b806111fb816103b5565b0390f35b6101f8565b5f80fd5b5f90565b611214611208565b508061122f611229637965db0b60e01b610204565b91610204565b1490811561123c575b5090565b6112469150612a77565b5f611238565b60018060a01b031690565b611263611268916102bc565b61124c565b90565b6112759054611257565b90565b611280612a9d565b61129b611295611290600261126b565b610493565b91610493565b036112bc576112b96112ab6108e1565b6112b3612a9d565b90612b0a565b50565b5f63058d9a1b60e01b8152806112d4600482016103b5565b0390fd5b5f90565b6112e5906103ed565b90565b906112f2906112dc565b5f5260205260405f2090565b90565b61130d611312916102bc565b6112fe565b90565b61131f9054611301565b90565b600161133a611340926113336112d8565b505f6112e8565b01611315565b90565b9061135d916113586113536108e1565b612bcb565b61135f565b565b908161137a61137461136f6108e1565b6103ed565b916103ed565b1461138a57611388916113a6565b565b5f63318bd07d60e11b8152806113a2600482016103b5565b0390fd5b906113b091612b0a565b50565b906113bd91611343565b565b90816113da6113d46113cf6108e1565b6103ed565b916103ed565b146113ea576113e891611406565b565b5f63318bd07d60e11b815280611402600482016103b5565b0390fd5b9061141091612bdf565b565b9061141c916113bf565b565b906114389161143361142e611132565b612bcb565b61143a565b565b9061144491612cb8565b565b906114509161141e565b565b61146261145d61102e565b612bcb565b61146a61146c565b565b611474612e03565b565b61147e611452565b565b60a01c90565b61149261149791611480565b6106ce565b90565b6114a49054611486565b90565b6114af611208565b506114ba600261149a565b90565b906114cf916114ca612e0d565b611a3d565b565b6114e56114e06114ea926108bd565b610d51565b610488565b90565b6114f6906114d1565b90565b9061150390610d7c565b5f5260205260405f2090565b9061151990610d7c565b5f5260205260405f2090565b90565b5490565b634e487b7160e01b5f52603260045260245ffd5b5f5260205f2090565b61155281611528565b82101561156c57611564600191611540565b910201905f90565b61152c565b9061157b9061033a565b9052565b67ffffffffffffffff1690565b61159861159d916102f7565b61157f565b90565b6115aa905461158c565b90565b906115b79061097a565b9052565b60c01c90565b6115cd6115d2916115bb565b61157f565b90565b6115df90546115c1565b90565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061160a906115e2565b810190811067ffffffffffffffff82111761162457604052565b6115ec565b9061163c6116356101f2565b9283611600565b565b6116486060611629565b90565b9061169861168f5f61165b61163e565b9461167261166a8383016102ea565b838801611571565b6116896116808383016115a0565b602088016115ad565b016115d5565b604084016115ad565b565b6116a39061164b565b90565b6116b0905161033a565b90565b6116c76116c26116cc926108bd565b610d51565b61033a565b90565b6116db6116e0916102bc565b6106ce565b90565b6116ed90546116cf565b90565b6116fa905161097a565b90565b61171161170c6117169261097a565b610d51565b610643565b90565b90565b61173061172b61173592611719565b610d51565b610643565b90565b634e487b7160e01b5f52601160045260245ffd5b61175b61176191939293610643565b92610643565b820391821161176c57565b611738565b634e487b7160e01b5f525f60045260245ffd5b9061179f6fffffffffffffffffffffffffffffffff916108c0565b9181191691161790565b6117bd6117b86117c29261033a565b610d51565b61033a565b90565b90565b906117dd6117d86117e4926117a9565b6117c5565b8254611784565b9055565b60801b90565b9061180467ffffffffffffffff60801b916117e8565b9181191691161790565b61182261181d6118279261097a565b610d51565b61097a565b90565b90565b9061184261183d6118499261180e565b61182a565b82546117ee565b9055565b60c01b90565b9061186967ffffffffffffffff60c01b9161184d565b9181191691161790565b9061188861188361188f9261180e565b61182a565b8254611853565b9055565b908082036118a0575b5050565b6118df5f80846118c0826118e597016118ba8488016102ea565b906117c8565b6118d78282016118d18488016115a0565b9061182d565b0192016115d5565b90611873565b5f8061189c565b91906118fd576118fb91611893565b565b611771565b634e487b7160e01b5f52603160045260245ffd5b5f80910155565b905f0361192f5761192d90611916565b565b611771565b61193d81611528565b801561195e57600190039061195b6119558383611549565b9061191d565b55565b611902565b61197761197261197c9261033a565b610d51565b610643565b90565b61198b611990916102bc565b610d9e565b90565b61199d905461197f565b90565b906119ac5f19916108c0565b9181191691161790565b6119ca6119c56119cf92610643565b610d51565b610643565b90565b90565b906119ea6119e56119f1926119b6565b6119d2565b82546119a0565b9055565b6119fe90610d54565b90565b611a0a906119f5565b90565b611a1690611963565b9052565b916020611a3b929493611a3460408201965f830190611a0d565b0190610de0565b565b611a465f6114ed565b611a58611a5283610493565b91610493565b14611c6057611a7b611a76611a6f600433906114f9565b839061150f565b611525565b9082611a97611a91611a8c85611528565b610643565b91610643565b1015611c4457611ab1611aab838590611549565b5061169a565b91611abd5f84016116a6565b611acf611ac95f6116b3565b9161033a565b14611c2857611ade60076116e3565b80611c03575b611be75780611b27611b15611b2c93611b0f611aff85611528565b611b09600161171c565b9061174c565b90611549565b50611b21838890611549565b906118ec565b611934565b611b66611b42611b3d5f85016116a6565b611963565b611b60611b5160068590610d88565b91611b5b83611993565b61174c565b906119d5565b611b8c611b7282611a01565b33611b86611b815f87016116a6565b611963565b91612e91565b611b995f339293016116a6565b92611bcd611bc77f2adb11f11ec869098f3647cd7c8583d66b214a5ab422473ee1bd287f8e6f88ce93610d7c565b93610d7c565b93611be2611bd96101f2565b92839283611a1a565b0390a3565b5f63212a7e7960e01b815280611bff600482016103b5565b0390fd5b5042611c22611c1c611c17604087016116f0565b6116fd565b91610643565b10611ae4565b5f6333edfc1360e01b815280611c40600482016103b5565b0390fd5b5f6303f6666760e51b815280611c5c600482016103b5565b0390fd5b5f63af458c0760e01b815280611c78600482016103b5565b0390fd5b90611c86916114bd565b565b611ca190611c9c611c976108e1565b612bcb565b611ce1565b565b90611cb460018060a01b03916108c0565b9181191691161790565b90565b90611cd6611cd1611cdd92610d7c565b611cbe565b8254611ca3565b9055565b80611cfc611cf6611cf15f6114ed565b610493565b91610493565b148015611d85575b611d6957611d13816002611cc1565b611d1d600161126b565b90611d51611d4b7fefdcbba819467e00b0262c12892dda980bac68580b72178e57a162368b80876693610d7c565b91610d7c565b91611d5a6101f2565b80611d64816103b5565b0390a3565b5f63318bd07d60e11b815280611d81600482016103b5565b0390fd5b5080611da0611d9a611d95612a9d565b610493565b91610493565b14611d04565b611daf90611c88565b565b611dc1611dbc61102e565b612bcb565b611dc9611dcb565b565b611dd3612f40565b565b611ddd611db1565b565b5f90565b611deb611ddf565b50611df6600161126b565b90565b90611e149291611e0f611e0a611132565b612bcb565b611e16565b565b90611e205f6114ed565b611e32611e2c83610493565b91610493565b14611fe557611e55611e50611e49600485906114f9565b839061150f565b611525565b9183611e71611e6b611e6686611528565b610643565b91610643565b1015611fc957611e8b611e85848690611549565b5061169a565b92611e975f85016116a6565b611ea9611ea35f6116b3565b9161033a565b14611fad57611f5f91611ef782611ef2611ee05f95611eda611eca85611528565b611ed4600161171c565b9061174c565b90611549565b50611eec838b90611549565b906118ec565b611934565b611f31611f0d611f088488016116a6565b611963565b611f2b611f1c60068890610d88565b91611f2683611993565b61174c565b906119d5565b611f57611f3d85611a01565b82611f51611f4c868a016116a6565b611963565b91612e91565b9293016116a6565b92611f93611f8d7f2adb11f11ec869098f3647cd7c8583d66b214a5ab422473ee1bd287f8e6f88ce93610d7c565b93610d7c565b93611fa8611f9f6101f2565b92839283611a1a565b0390a3565b5f6333edfc1360e01b815280611fc5600482016103b5565b0390fd5b5f6303f6666760e51b815280611fe1600482016103b5565b0390fd5b5f63af458c0760e01b815280611ffd600482016103b5565b0390fd5b9061200c9291611df9565b565b9061201890610d7c565b5f5260205260405f2090565b61204a915f61203f61204593612038611208565b50826112e8565b0161200e565b6116e3565b90565b606090565b5490565b67ffffffffffffffff811161206e5760208091020190565b6115ec565b9061208561208083612056565b611629565b918252565b5f5260205f2090565b9061209d82612052565b6120a681612073565b926120b4602085019161208a565b5f915b8383106120c45750505050565b6001602081926120d38561169a565b8152019201920191906120b7565b6120ea90612093565b90565b6121129161210861210d9261210061204d565b5060046114f9565b61150f565b6120e1565b90565b606090565b5090565b67ffffffffffffffff81116121365760208091020190565b6115ec565b9061214d6121488361211e565b611629565b918252565b61215c6060611629565b90565b5f90565b5f90565b5f90565b612173612152565b90602080808461218161215f565b81520161218c612163565b815201612197612167565b81525050565b6121a561216b565b90565b5f5b8281106121b657505050565b6020906121c161219d565b81840152016121aa565b906121f06121d88361213b565b926020806121e6869361211e565b92019103906121a8565b565b61220661220161220b926108bd565b610d51565b610643565b90565b600161221a9101610643565b90565b919081101561222d576020020190565b61152c565b3561223c8161049f565b90565b9061224990610d7c565b5f5260205260405f2090565b9061225f82610b00565b811015612270576020809102010190565b61152c565b9061227f90610251565b9052565b60081c90565b61229561229a91612283565b6102c1565b90565b6122a79054612289565b90565b60881c90565b6bffffffffffffffffffffffff1690565b6122cd6122d2916122aa565b6122b0565b90565b6122df90546122c1565b90565b906122ec90610b20565b9052565b9061233d6123345f612300612152565b9461231761230f8383016116e3565b838801612275565b61232e61232583830161229d565b60208801611571565b016122d5565b604084016122e2565b565b612348906122f0565b90565b612353612115565b5061236761236282849061211a565b6121cb565b916123715f6121f2565b5b8061238f61238961238486869061211a565b610643565b91610643565b10156123e2576123dd906123d66123bb60056123b56123b08888879161221d565b612232565b9061223f565b866123c6849261233f565b6123d08383612255565b52612255565b515061220e565b612372565b50505090565b6123f061216b565b90565b61240a61240f916124026123e8565b50600561223f565b61233f565b90565b61242b906124266124216108e1565b612bcb565b61242d565b565b61243690612f80565b565b61244190612412565b565b9061245d916124586124536108e1565b612bcb565b61245f565b565b908161247a61247461246f6108e1565b6103ed565b916103ed565b1461248a57612488916124a6565b565b5f63318bd07d60e11b8152806124a2600482016103b5565b0390fd5b906124b091612fc6565b50565b906124bd91612443565b565b906124db9392916124d66124d1611132565b612bcb565b61261c565b565b6124ec6124f291939293610643565b92610643565b82018092116124fd57565b611738565b61251661251161251b92610643565b610d51565b61097a565b90565b6125286060611629565b90565b9061256d60405f6125739461254d8282016125478488016116a6565b906117c8565b61256582820161255f602088016116f0565b9061182d565b0192016116f0565b90611873565b565b9190612586576125849161252b565b565b611771565b1b90565b90815491680100000000000000008310156125bf57826125b79160016125bd95018155611549565b90612575565b565b6115ec565b6125cd90610d70565b90565b6125e46125df6125e99261097a565b610d51565b61033a565b90565b6125f5906125d0565b9052565b91602061261a92949361261360408201965f830190611a0d565b01906125ec565b565b92612640612645916126308486839161309d565b61263a4291611963565b906124dd565b612502565b926126a561266761266261265b600485906114f9565b859061150f565b611525565b84906126a061267542612502565b612697899161268e61268561251e565b965f8801611571565b602086016115ad565b604084016115ad565b61258f565b6126d56126b184611963565b6126cf6126c060068690610d88565b916126ca83611993565b6124dd565b906119d5565b6126fb6126e183611a01565b336126eb306125c4565b906126f587611963565b9261322f565b90919261273161272b7f268464d6ecafe069c26e10a65fd45bb8ab70b43c6d40afb2423a6b47af771a5593610d7c565b93610d7c565b9361274661273d6101f2565b928392836125f9565b0390a3565b906127579392916124bf565b565b606090565b67ffffffffffffffff81116127765760208091020190565b6115ec565b9061278d6127888361275e565b611629565b918252565b606090565b5f5b8281106127a557505050565b6020906127b0612792565b8184015201612799565b906127df6127c78361277b565b926020806127d5869361275e565b9201910390612797565b565b906127eb82610efa565b8110156127fc576020809102010190565b61152c565b9161280a612759565b5061281e61281983839061211a565b6127ba565b926128285f6121f2565b5b8061284661284061283b87879061211a565b610643565b91610643565b10156128a35761289e9061289761287c612862600486906114f9565b6128766128718989879161221d565b612232565b9061150f565b8761288784926120e1565b61289183836127e1565b526127e1565b515061220e565b612829565b5050505090565b906128c69392916128c16128bc611132565b612bcb565b6128c8565b565b916128d693919091926133f2565b565b906128e49392916128aa565b565b906128f992916128f4612e0d565b6128fb565b565b916129088383839161309d565b8061292661292061291b5f6003016102ea565b61033a565b9161033a565b10612a4e576129426129479161293c4291611963565b906124dd565b612502565b916129a761296961296461295d600433906114f9565b849061150f565b611525565b83906129a261297742612502565b612999889161299061298761251e565b965f8801611571565b602086016115ad565b604084016115ad565b61258f565b6129d76129b383611963565b6129d16129c260068590610d88565b916129cc83611993565b6124dd565b906119d5565b6129fd6129e382611a01565b336129ed306125c4565b906129f786611963565b9261322f565b33909192612a34612a2e7f268464d6ecafe069c26e10a65fd45bb8ab70b43c6d40afb2423a6b47af771a5593610d7c565b93610d7c565b93612a49612a406101f2565b928392836125f9565b0390a3565b5f630f962f3d60e31b815280612a66600482016103b5565b0390fd5b90612a7592916128e6565b565b612a7f611208565b50612a99612a936301ffc9a760e01b610204565b91610204565b1490565b612aa5611ddf565b503390565b91906008612aca910291612ac460018060a01b038461258b565b9261258b565b9181191691161790565b9190612aea612ae5612af293610d7c565b611cbe565b908354612aaa565b9055565b612b0891612b02611ddf565b91612ad4565b565b90612b3d91612b17611208565b5080612b32612b2c612b276108e1565b6103ed565b916103ed565b14612b40575b6134be565b90565b612b4a600161126b565b82612b7e612b787ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec693610d7c565b91610d7c565b91612b876101f2565b80612b91816103b5565b0390a3612baf612b9f6108e1565b612ba9600161126b565b90612fc6565b50612bbb826001611cc1565b612bc65f6002612af6565b612b38565b612bdd90612bd7612a9d565b9061358c565b565b9080612bfa612bf4612bef612a9d565b610493565b91610493565b03612c0b57612c0891612fc6565b50565b5f63334bd91960e11b815280612c23600482016103b5565b0390fd5b612c316040611629565b90565b90612c506fffffffffffffffffffffffffffffffff19916117e8565b9181191691161790565b90612c6f612c6a612c76926117a9565b6117c5565b8254612c34565b9055565b90612ca460205f612caa94612c9c828201612c968488016116a6565b906117c8565b0192016116a6565b90612c5a565b565b90612cb691612c7a565b565b80612ccb612cc58461033a565b9161033a565b1015612d3957612cfd81612cf684612ced612ce4612c27565b935f8501611571565b60208301611571565b6003612cac565b907f27f0645d0020a6e875a4860752b756333c988ba94bfe11e4994d94ed83d0d27c91612d34612d2b6101f2565b9283928361035c565b0390a1565b5f630f962f3d60e31b815280612d51600482016103b5565b0390fd5b612d5d6135c7565b612d65612db5565b565b60a01b90565b90612d7c60ff60a01b91612d67565b9181191691161790565b612d8f90610251565b90565b90565b90612daa612da5612db192612d86565b612d92565b8254612d6d565b9055565b612dc05f6002612d95565b612dc8612a9d565b612dfe7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa91612df56101f2565b918291826107cf565b0390a1565b612e0b612d55565b565b612e156114a7565b612e1b57565b5f63d93c066560e01b815280612e33600482016103b5565b0390fd5b612e4090610d70565b90565b63ffffffff1690565b60e01b90565b612e66612e61612e6b92612e43565b612e4c565b610204565b90565b916020612e8f929493612e8860408201965f8301906107c2565b0190610de0565b565b90612ed8612edd93612ec960049493612eb063a9059cbb919391612e52565b92612eb96101f2565b9687946020860190815201612e6e565b60208201810382520383611600565b6135fe565b565b612ee7612e0d565b612eef612ef1565b565b612efd60016002612d95565b612f05612a9d565b612f3b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25891612f326101f2565b918291826107cf565b0390a1565b612f48612edf565b565b90612f5660ff916108c0565b9181191691161790565b90612f75612f70612f7c92612d86565b612d92565b8254612f4a565b9055565b612f8b816007612f60565b612fc17ff394e5ff8dc01b6af18c4d3ea4b5bf019825350d405a0745b5680fdeda8b6f7091612fb86101f2565b91829182610263565b0390a1565b612fce611208565b50612fda818390612024565b5f14613061576130005f612ffb5f612ff38186906112e8565b01859061200e565b612f60565b90613009612a9d565b9061304661304061303a7ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b956112dc565b92610d7c565b92610d7c565b9261304f6101f2565b80613059816103b5565b0390a4600190565b50505f90565b6130719051610251565b90565b61307e9051610b20565b90565b61309561309061309a92610b20565b610d51565b61033a565b90565b816130b06130aa5f6116b3565b9161033a565b146131e1576130c96130c46005839061223f565b61233f565b916130de6130d85f8501613067565b15610251565b6131c557806131006130fa6130f560408701613074565b613081565b9161033a565b106131a95761313d60206131366131429361313061312a613125613148986006610d88565b611993565b91611963565b906124dd565b94016116a6565b611963565b91610643565b1161318d5761316a61316461315f5f600301610311565b61033a565b9161033a565b1161317157565b5f630f962f3d60e31b815280613189600482016103b5565b0390fd5b5f63d8592f1f60e01b8152806131a5600482016103b5565b0390fd5b5f6367108dff60e11b8152806131c1600482016103b5565b0390fd5b5f630928045160e21b8152806131dd600482016103b5565b0390fd5b5f63af458c0760e01b8152806131f9600482016103b5565b0390fd5b60409061322661322d949695939661321c60608401985f8501906107c2565b60208301906107c2565b0190610de0565b565b60049261326961327d959361327893946132506323b872dd92949192612e52565b936132596101f2565b97889560208701908152016131fd565b60208201810382520383611600565b6135fe565b565b6132896060611629565b90565b60081b90565b906132ae70ffffffffffffffffffffffffffffffff009161328c565b9181191691161790565b906132cd6132c86132d4926117a9565b6117c5565b8254613292565b9055565b60881b90565b906132f86bffffffffffffffffffffffff60881b916132d8565b9181191691161790565b61331661331161331b92610b20565b610d51565b610b20565b90565b90565b9061333661333161333d92613302565b61331e565b82546132de565b9055565b9061338360405f6133899461336382820161335d848801613067565b90612f60565b61337b828201613375602088016116a6565b906132b8565b019201613074565b90613321565b565b9061339591613341565b565b6133ab6133a66133b092610b20565b610d51565b610643565b90565b6133bc90613397565b9052565b6040906133e96133f094969593966133df60608401985f850190610256565b6020830190611a0d565b01906133b3565b565b929091928061341161340b6134065f6114ed565b610493565b91610493565b146134a25761345a8361344986613440869161343761342e61327f565b955f8701612275565b60208501611571565b604083016122e2565b6134556005849061223f565b61338b565b9192909261349d61348b7fa7b5027b1b3e95c29bf96337f271f156a0f9dcff496408cdf3774b37d4c54a7a94610d7c565b946134946101f2565b938493846133c0565b0390a2565b5f63af458c0760e01b8152806134ba600482016103b5565b0390fd5b6134c6611208565b506134db6134d5828490612024565b15610251565b5f146135635761350260016134fd5f6134f58186906112e8565b01859061200e565b612f60565b9061350b612a9d565b9061354861354261353c7f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d956112dc565b92610d7c565b92610d7c565b926135516101f2565b8061355b816103b5565b0390a4600190565b50505f90565b91602061358a92949361358360408201965f8301906107c2565b0190610431565b565b906135a161359b838390612024565b15610251565b6135a9575050565b6135c35f92839263e2517d3f60e01b845260048401613569565b0390fd5b6135d86135d26114a7565b15610251565b6135de57565b5f638dfc202b60e01b8152806135f6600482016103b5565b0390fd5b5f90565b905f60209161360b6135fa565b506136146135fa565b50828151910182855af1156136a7573d5f51906136396136335f6121f2565b91610643565b145f1461368d575061364a81612e37565b3b61365d6136575f6121f2565b91610643565b145b6136665750565b61367261368991612e37565b5f918291635274afe760e01b8352600483016107cf565b0390fd5b6136a061369a600161171c565b91610643565b141561365f565b6040513d5f823e3d90fdfea264697066735822122054a69b6b35c2bac90d346caf8b410d3be9616f6136d8ef090cd423e6fbe9aea264736f6c634300081a0033
Verified Source Code Partial Match
Compiler: v0.8.26+commit.8a97fa7a
EVM: cancun
Optimization: No
AssetLock.sol 351 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {SingleAdminAccessControl} from "src/utils/SingleAdminAccessControl.sol";
struct UserLock {
uint128 amount;
uint64 lockStartTime;
uint64 lockEndTime;
}
struct AssetInfo {
bool isSupported;
uint128 maxLockCapacity;
uint96 minLockAmount;
}
struct LockDuration {
uint128 minDuration;
uint128 maxDuration;
}
/// @title AssetLock
/// @notice AssetLock is a contract that allows users to lock their assets for a certain duration
contract AssetLock is SingleAdminAccessControl, Pausable {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error UnsupportedAsset();
error InvalidLockDuration();
error MaxLockCapacityExceeded();
error LockNotEnded();
error NoActiveLock();
error ZeroInput();
error BelowMinimumLock();
error InvalidLockIndex();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event AssetInfoSet(address indexed asset, bool isSupported, uint256 maxLockCapacity, uint256 minLockAmount);
event LockDurationSet(uint128 minDuration, uint128 maxDuration);
event AssetLocked(address indexed user, address indexed asset, uint256 amount, uint128 unlockTime);
event AssetUnlocked(address indexed user, address indexed asset, uint256 amount, uint256 lockIndex);
event EnforceLockSet(bool enforceLock);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice The role for the manager
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
/// @notice The role that is allowed to pause and unpause the contract
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
/// @notice The range of lock duration
LockDuration public lockDuration;
/// @notice The mapping of user locks
mapping(address user => mapping(address asset => UserLock[] locks)) private userLocks;
/// @notice The mapping of asset info
mapping(address asset => AssetInfo assetInfo) private assetInfo;
/// @notice The mapping of total locked assets
mapping(address asset => uint256 totalLocked) public totalLocked;
/// @notice Whether to enforce locking, if false, users can withdraw their assets at any time
bool public enforceLock;
/*//////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////*/
constructor(address _admin) {
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_setEnforceLock(true);
_setLockDuration(90 days, 365 days);
}
/*//////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Set whether to enforce locking
/// @param _enforceLock Whether to enforce locking
function setEnforceLock(bool _enforceLock) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setEnforceLock(_enforceLock);
}
/// @notice Pauses the contract
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
/// @notice Unpauses the contract
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
/*//////////////////////////////////////////////////////////////
MANAGER FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Set the info of an asset
/// @param _asset The asset address
/// @param _isSupported Whether the asset is supported
/// @param _maxLockCapacity The maximum lock capacity of the asset
/// @param _minLockAmount The minimum lock amount of the asset
function setAssetInfo(address _asset, bool _isSupported, uint128 _maxLockCapacity, uint96 _minLockAmount)
external
onlyRole(MANAGER_ROLE)
{
_setAssetInfo(_asset, _isSupported, _maxLockCapacity, _minLockAmount);
}
/// @notice Set the range of lock duration
/// @param _minDuration The minimum duration
/// @param _maxDuration The maximum duration
function setLockDuration(uint128 _minDuration, uint128 _maxDuration) external onlyRole(MANAGER_ROLE) {
_setLockDuration(_minDuration, _maxDuration);
}
/*//////////////////////////////////////////////////////////////
USER FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Lock an asset
/// @param _asset The asset address
/// @param _amount The amount of the asset to lock
/// @param _lockDuration The duration of the lock
function lockAsset(address _asset, uint128 _amount, uint128 _lockDuration) external whenNotPaused {
_checkLock(_asset, _amount, _lockDuration);
if (_lockDuration < lockDuration.minDuration) {
revert InvalidLockDuration();
}
uint64 lockEndTime = uint64(block.timestamp + _lockDuration);
userLocks[msg.sender][_asset].push(
UserLock({amount: _amount, lockStartTime: uint64(block.timestamp), lockEndTime: lockEndTime})
);
totalLocked[_asset] += _amount;
IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);
emit AssetLocked(msg.sender, _asset, _amount, lockEndTime);
}
/// @notice Lock an asset on behalf of a user
/// @param _user The user address
/// @param _asset The asset address
/// @param _amount The amount of the asset to lock
/// @param _lockDuration The duration of the lock
function lockAssetOnBehalf(address _user, address _asset, uint128 _amount, uint128 _lockDuration)
external
onlyRole(MANAGER_ROLE)
{
_checkLock(_asset, _amount, _lockDuration);
uint64 lockEndTime = uint64(block.timestamp + _lockDuration);
userLocks[_user][_asset].push(
UserLock({amount: _amount, lockStartTime: uint64(block.timestamp), lockEndTime: lockEndTime})
);
totalLocked[_asset] += _amount;
IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);
emit AssetLocked(_user, _asset, _amount, lockEndTime);
}
/// @notice Unlock a specific lock position
/// @param _asset The asset address
/// @param _lockIndex The index of the lock to unlock
function unlockAsset(address _asset, uint256 _lockIndex) external whenNotPaused {
if (address(0) == _asset) {
revert ZeroInput();
}
UserLock[] storage locks = userLocks[msg.sender][_asset];
if (_lockIndex >= locks.length) {
revert InvalidLockIndex();
}
UserLock memory lock = locks[_lockIndex];
if (lock.amount == 0) {
revert NoActiveLock();
}
// If enforceLock is true, the user cannot unlock the asset before the lock duration ends
// If enforceLock is false, the user can unlock the asset at any time
if (enforceLock && block.timestamp < lock.lockEndTime) {
revert LockNotEnded();
}
// Swap-and-pop deletion
locks[_lockIndex] = locks[locks.length - 1];
locks.pop();
totalLocked[_asset] -= lock.amount;
IERC20(_asset).safeTransfer(msg.sender, lock.amount);
emit AssetUnlocked(msg.sender, _asset, lock.amount, _lockIndex);
}
function unlockAssetOnBehalf(address _user, address _asset, uint256 _lockIndex) external onlyRole(MANAGER_ROLE) {
if (address(0) == _asset) {
revert ZeroInput();
}
UserLock[] storage locks = userLocks[_user][_asset];
if (_lockIndex >= locks.length) {
revert InvalidLockIndex();
}
UserLock memory lock = locks[_lockIndex];
if (lock.amount == 0) {
revert NoActiveLock();
}
// Swap-and-pop deletion
locks[_lockIndex] = locks[locks.length - 1];
locks.pop();
totalLocked[_asset] -= lock.amount;
IERC20(_asset).safeTransfer(_user, lock.amount);
emit AssetUnlocked(_user, _asset, lock.amount, _lockIndex);
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Get the info of an asset
/// @param _asset The asset address
/// @return The info of the asset
function getAssetInfo(address _asset) external view returns (AssetInfo memory) {
return assetInfo[_asset];
}
/// @notice Get the info of multiple assets
/// @param _assets The assets addresses
/// @return The info of the assets
function getAssetInfos(address[] calldata _assets) external view returns (AssetInfo[] memory) {
AssetInfo[] memory infos = new AssetInfo[](_assets.length);
for (uint256 i = 0; i < _assets.length; i++) {
infos[i] = assetInfo[_assets[i]];
}
return infos;
}
/// @notice Get all locks of a user for an asset
/// @param _user The user address
/// @param _asset The asset address
/// @return The array of locks for the user and asset
function getUserLocks(address _user, address _asset) external view returns (UserLock[] memory) {
return userLocks[_user][_asset];
}
/// @notice Get the locks of a user for multiple assets
/// @param _user The user address
/// @param _assets The assets addresses
/// @return The locks of the user for the assets
function getUserLocksForAssets(address _user, address[] calldata _assets)
external
view
returns (UserLock[][] memory)
{
UserLock[][] memory allLocks = new UserLock[][](_assets.length);
for (uint256 i = 0; i < _assets.length; i++) {
allLocks[i] = userLocks[_user][_assets[i]];
}
return allLocks;
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Check if the lock is valid
/// @param _asset The asset address
/// @param _amount The amount of the asset to lock
/// @param _lockDuration The duration of the lock
function _checkLock(address _asset, uint128 _amount, uint128 _lockDuration) internal view {
if (_amount == 0) {
revert ZeroInput();
}
AssetInfo memory asset = assetInfo[_asset];
if (!asset.isSupported) {
revert UnsupportedAsset();
}
if (_amount < asset.minLockAmount) {
revert BelowMinimumLock();
}
if (totalLocked[_asset] + _amount > asset.maxLockCapacity) {
revert MaxLockCapacityExceeded();
}
if (_lockDuration > lockDuration.maxDuration) {
revert InvalidLockDuration();
}
}
/// @notice Set whether to enforce locking
/// @param _enforceLock Whether to enforce locking
function _setEnforceLock(bool _enforceLock) internal {
enforceLock = _enforceLock;
emit EnforceLockSet(_enforceLock);
}
/// @notice Set the range of lock duration
/// @param _minDuration The minimum duration
/// @param _maxDuration The maximum duration
function _setLockDuration(uint128 _minDuration, uint128 _maxDuration) internal {
if (_minDuration >= _maxDuration) {
revert InvalidLockDuration();
}
lockDuration = LockDuration({minDuration: _minDuration, maxDuration: _maxDuration});
emit LockDurationSet(_minDuration, _maxDuration);
}
/// @notice Set the info of an asset
/// @param _asset The asset address
/// @param _isSupported Whether the asset is supported
/// @param _maxLockCapacity The maximum lock capacity of the asset
/// @param _minLockAmount The minimum lock amount of the asset
function _setAssetInfo(address _asset, bool _isSupported, uint128 _maxLockCapacity, uint96 _minLockAmount)
internal
{
if (_asset == address(0)) {
revert ZeroInput();
}
assetInfo[_asset] =
AssetInfo({isSupported: _isSupported, maxLockCapacity: _maxLockCapacity, minLockAmount: _minLockAmount});
emit AssetInfoSet(_asset, _isSupported, _maxLockCapacity, _minLockAmount);
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
Pausable.sol 112 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
SingleAdminAccessControl.sol 88 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/interfaces/IERC5313.sol";
/**
* @title SingleAdminAccessControl
* @notice SingleAdminAccessControl is a contract that provides a single admin role
* @notice This contract is a simplified alternative to OpenZeppelin's AccessControlDefaultAdminRules
*/
abstract contract SingleAdminAccessControl is IERC5313, AccessControl {
error InvalidAdminChange();
error NotPendingAdmin();
event AdminTransferred(address indexed oldAdmin, address indexed newAdmin);
event AdminTransferRequested(address indexed oldAdmin, address indexed newAdmin);
address private _currentDefaultAdmin;
address private _pendingDefaultAdmin;
modifier notAdmin(bytes32 role) {
if (role == DEFAULT_ADMIN_ROLE) revert InvalidAdminChange();
_;
}
/// @notice Transfer the admin role to a new address
/// @notice This can ONLY be executed by the current admin
/// @param newAdmin address
function transferAdmin(address newAdmin) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (newAdmin == address(0) || newAdmin == _msgSender()) {
revert InvalidAdminChange();
}
_pendingDefaultAdmin = newAdmin;
emit AdminTransferRequested(_currentDefaultAdmin, newAdmin);
}
function acceptAdmin() external {
if (_msgSender() != _pendingDefaultAdmin) revert NotPendingAdmin();
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @notice grant a role
/// @notice can only be executed by the current single admin
/// @notice admin role cannot be granted externally
/// @param role bytes32
/// @param account address
function grantRole(bytes32 role, address account) public override onlyRole(DEFAULT_ADMIN_ROLE) notAdmin(role) {
_grantRole(role, account);
}
/// @notice revoke a role
/// @notice can only be executed by the current admin
/// @notice admin role cannot be revoked
/// @param role bytes32
/// @param account address
function revokeRole(bytes32 role, address account) public override onlyRole(DEFAULT_ADMIN_ROLE) notAdmin(role) {
_revokeRole(role, account);
}
/// @notice renounce the role of _msgSender()
/// @notice admin role cannot be renounced
/// @param role bytes32
/// @param account address
function renounceRole(bytes32 role, address account) public virtual override notAdmin(role) {
super.renounceRole(role, account);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() external view virtual returns (address) {
return _currentDefaultAdmin;
}
/**
* @notice no way to change admin without removing old admin first
*/
function _grantRole(bytes32 role, address account) internal override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE) {
emit AdminTransferred(_currentDefaultAdmin, account);
_revokeRole(DEFAULT_ADMIN_ROLE, _currentDefaultAdmin);
_currentDefaultAdmin = account;
delete _pendingDefaultAdmin;
}
return super._grantRole(role, account);
}
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
AccessControl.sol 209 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
IERC5313.sol 16 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface for the Light Contract Ownership Standard.
*
* A standardized minimal interface required to identify an account that controls a contract
*/
interface IERC5313 {
/**
* @dev Gets the address of the owner.
*/
function owner() external view returns (address);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
IAccessControl.sol 98 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
ERC165.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Read Contract
DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
MANAGER_ROLE 0xec87621c → bytes32
PAUSER_ROLE 0xe63ab1e9 → bytes32
enforceLock 0x74e00d5f → bool
getAssetInfo 0xafad2e16 → tuple
getAssetInfos 0xab90aee8 → tuple[]
getRoleAdmin 0x248a9ca3 → bytes32
getUserLocks 0xa2befa49 → tuple[]
getUserLocksForAssets 0xdf3113ce → tuple[][]
hasRole 0x91d14854 → bool
lockDuration 0x04554443 → uint128, uint128
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
supportsInterface 0x01ffc9a7 → bool
totalLocked 0xd8fb9337 → uint256
Write Contract 14 functions
These functions modify contract state and require a wallet transaction to execute.
acceptAdmin 0x0e18b681
No parameters
grantRole 0x2f2ff15d
bytes32 role
address account
lockAsset 0xf294d3b7
address _asset
uint128 _amount
uint128 _lockDuration
lockAssetOnBehalf 0xdebc4aca
address _user
address _asset
uint128 _amount
uint128 _lockDuration
pause 0x8456cb59
No parameters
renounceRole 0x36568abe
bytes32 role
address account
revokeRole 0xd547741f
bytes32 role
address account
setAssetInfo 0xe6ec7e6f
address _asset
bool _isSupported
uint128 _maxLockCapacity
uint96 _minLockAmount
setEnforceLock 0xc34b697e
bool _enforceLock
setLockDuration 0x3df32c16
uint128 _minDuration
uint128 _maxDuration
transferAdmin 0x75829def
address newAdmin
unlockAsset 0x5e7db13d
address _asset
uint256 _lockIndex
unlockAssetOnBehalf 0x8edce3e3
address _user
address _asset
uint256 _lockIndex
unpause 0x3f4ba83a
No parameters
Recent Transactions
No transactions found for this address