Address Contract Verified
Address
0x75EF8d7366285857982d8443110ececb1930853C
Balance
0 ETH
Nonce
1
Code Size
10546 bytes
Creator
0x89E89C39...7eb3 at tx 0x8af37d2e...1d5df5
Indexed Transactions
0
Contract Bytecode
10546 bytes
0x60806040526004361015610018575b361561001657005b005b5f3560e01c80630bc8e05f146102c75780631626ba7e146102c257806316c38b3c146102bd5780631be19560146102b85780631d3c2b2f146102b3578063260ee14d146102ae5780632a5b5d13146102a95780632b7ac3f3146102a45780633a16b85a1461029f57806349bfe4111461029a5780635834d435146102955780635c975abb146102905780635f477c571461028b5780636052970c1461028657806363f2615d14610281578063645210701461027c578063715018a6146102775780637487432314610272578063759cb53b1461026d578063858a43d11461026857806389476069146102635780638cedddb51461025e5780638d68f9ff146102595780638da5cb5b146102545780639281aa0b1461024f57806392f25ea01461024a57806397fc007c146102455780639bec828814610240578063a67853481461023b578063a91ee0dc14610236578063a98a930414610231578063abc0ab511461022c578063b17fb9d614610227578063bbea097414610222578063c53b573d1461021d578063ce62d8eb14610218578063d936547e14610213578063e6a17b9a1461020e578063eb2578ef14610209578063edf187f014610204578063f2fde38b146101ff578063f9216f11146101fa5763fc6530c10361000e5761184c565b611824565b61175d565b6116d5565b61165e565b611636565b6115f6565b61157f565b6113ce565b6113b1565b61133a565b6112c0565b611298565b6111c8565b611174565b611130565b6110e9565b6110c1565b611069565b611041565b611019565b610e50565b610cdc565b610c98565b610c54565b610b9b565b610b40565b610b1b565b610af9565b610ad1565b6109a7565b610982565b61093e565b6108aa565b610833565b61080b565b6107e3565b610726565b610678565b6104a4565b61044f565b6103cd565b6102da565b5f9103126102d657565b5f80fd5b346102d6575f3660031901126102d6576003546102fc60ff8260a81c166118d2565b610304612306565b6001600160a01b0316801561038857600554610330906001600160a01b03165b6001600160a01b031690565b803b156102d65760405163d36f12fb60e01b81526001600160a01b0383166004820152905f908290818381602481015b03925af180156103835761037057005b8061037d610016926105df565b806102cc565b611917565b60405162461bcd60e51b815260206004820152601a60248201527f656d657267656e6379206d69677261746f72206e6f74207365740000000000006044820152606490fd5b346102d65760403660031901126102d6576001600160401b036024358181116102d657366023820112156102d65780600401359182116102d65736602483830101116102d657610441916024610426920160043561193a565b6040516001600160e01b031990911681529081906020820190565b0390f35b801515036102d657565b346102d65760203660031901126102d65760043561046c81610445565b610474612306565b6003805460ff60a81b191691151560a81b60ff60a81b16919091179055005b6001600160a01b038116036102d657565b346102d65760203660031901126102d6576004356104c181610493565b6104d360ff60035460a81c16156119e6565b61052260018060a01b0380928160015416331480156105b3575b6104f690611aba565b16917f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b16821415611aff565b600c5461053990610324906001600160a01b031681565b81146105a6575b6040516370a0823160e01b815230600482015290602082602481845afa90811561038357610016925f92610575575b506123a7565b61059891925060203d60201161059f575b610590818361062d565b810190611b43565b905f61056f565b503d610586565b6105ae61235e565b610540565b50335f908152600b602052604090205460ff166104ed565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116105f257604052565b6105cb565b604081019081106001600160401b038211176105f257604052565b606081019081106001600160401b038211176105f257604052565b90601f801991011681019081106001600160401b038211176105f257604052565b6040519061065b82610612565b565b6001600160401b0381116105f257601f01601f191660200190565b346102d65760403660031901126102d6576004356001600160401b0381116102d657366023820112156102d65780600401356106b38161065d565b906106c1604051928361062d565b80825236602482850101116102d6576020815f92602461001696018386013783010152602435906106f182610445565b611b52565b9181601f840112156102d6578235916001600160401b0383116102d6576020808501948460051b0101116102d657565b346102d65760803660031901126102d65760043561074381610493565b6024359061075082610493565b606435916001600160401b0383116102d6576107736107b79336906004016106f6565b92909161078860ff60035460a81c16156119e6565b6107906124e3565b6001546001600160a01b0316331480156107bd575b6107ae90611aba565b60443591611d68565b60015f55005b50335f908152600b602052604090206107ae906107dc905b5460ff1690565b90506107a5565b346102d6575f3660031901126102d6576007546040516001600160a01b039091168152602090f35b346102d6575f3660031901126102d657600a546040516001600160a01b039091168152602090f35b346102d65760203660031901126102d6577f4868fa91d0121ea114513fb5c8b97b23ac9a10919980673c71461ff73e8501a3602060043561087381610493565b61087b612306565b6001600160a01b031661088f811515611f08565b600780546001600160a01b03191682179055604051908152a1005b346102d65760203660031901126102d6576004356001600160401b0381116102d6576108dd6107b79136906004016106f6565b906108f060ff60035460a81c16156119e6565b6108f86124e3565b6001546001600160a01b03163314801561091b575b61091690611aba565b6120dc565b50335f908152600b6020526040902061091690610937906107d5565b905061090d565b346102d65760203660031901126102d65760043561095b81610445565b610963612306565b6003805460ff60a01b191691151560a01b60ff60a01b16919091179055005b346102d6575f3660031901126102d657602060ff60035460a81c166040519015158152f35b346102d65760203660031901126102d6576004356109c481610493565b6109cc612306565b6001600160a01b0390808216906109e4821515611f08565b82600554168214610a9e57610a7f610a9992610a627f4923a3f3d9b7bd17a0d6fba89d92eba850a8f34176116be31bc27e12c4fef781957f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b16610a478582612537565b600554610a5c906001600160a01b0316610324565b90612614565b60018060a01b03166001600160601b0360a01b6005541617600555565b6040516001600160a01b0390911681529081906020820190565b0390a1005b60405162461bcd60e51b815260206004820152600b60248201526a105b1c9958591e481cd95d60aa1b6044820152606490fd5b346102d6575f3660031901126102d6576006546040516001600160a01b039091168152602090f35b346102d6575f3660031901126102d6576020610b1361228f565b604051908152f35b346102d6575f3660031901126102d657602060ff60035460a01c166040519015158152f35b346102d6575f3660031901126102d657610b58612306565b600180546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346102d65760203660031901126102d657600435610bb881610493565b610bc0612306565b7f906903afca224114603eddea72fbada90dcce859ee67b20861e842b79fc82ac060206001600160a01b038316610bf8811515611f08565b604051908152a1600854610c14906001600160a01b0316610324565b9060025490823b156102d6576040516317b0dca160e31b815260048101929092526001600160a01b03166024820152905f90829081838160448101610360565b346102d6575f3660031901126102d6576040517f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b03168152602090f35b346102d6575f3660031901126102d6576040517f0000000000000000000000000655977feb2f289a4ab78af67bab0d17aab843676001600160a01b03168152602090f35b346102d6576020806003193601126102d657600435610cfa81610493565b610d026124e3565b610d1360ff60035460a81c166118d2565b610d1b612306565b6040516370a0823160e01b815230600482015282816024816001600160a01b0386165afa918215610383575f9283928391610e33575b5060405163a9059cbb60e01b86820190815233602483015260448201929092528390610d8a81606481015b03601f19810183528261062d565b51925af1610d96612260565b81610e03575b5015610dab5761001660015f55565b6084906040519062461bcd60e51b82526004820152602b60248201527f455243323048656c706572733a3a736166655472616e736665723a207472616e60448201526a1cd9995c8819985a5b195960aa1b6064820152fd5b80518015925083908315610e1b575b5050505f610d9c565b610e2b9350820181019101611922565b5f8281610e12565b610e4a9150853d871161059f57610590818361062d565b5f610d51565b346102d6575f3660031901126102d657610e686124e3565b600180546001600160a01b0390811633148015611001575b610e8990611aba565b610e916127aa565b600554610ea6906001600160a01b0316610324565b90813b156102d65760408051637050ccd960e01b81523060048201525f6024820181905290939192918490604490829084905af1928315610383578593610fee575b5090915f905b610f27575b610f1e847f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e16611a27565b61001660015f55565b8151811015610fe957908482610f50610f42839695856122f2565b51516001600160a01b031690565b7fc469fb3cff504b129a86c67aa7285a806d0a52ae22af6bbded54359b4f23292060209182610f7f85886122f2565b51015187514281526001600160a01b039290921660208301526040820152606090a180610fac83866122f2565b510151610fbe575b5001909192610eee565b610fe390610fcf610f4284876122f2565b90610fda84876122f2565b510151906123a7565b5f610fb4565b610ef3565b8061037d610ffb926105df565b5f610ee8565b50335f908152600b602052604090205460ff16610e80565b346102d6575f3660031901126102d6576005546040516001600160a01b039091168152602090f35b346102d6575f3660031901126102d6576001546040516001600160a01b039091168152602090f35b346102d65760403660031901126102d65760043561108681610493565b6024359061109382610445565b61109b612306565b60018060a01b03165f52600b60205260405f209060ff8019835416911515161790555f80f35b346102d6575f3660031901126102d6576009546040516001600160a01b039091168152602090f35b346102d65760203660031901126102d65760043561110681610493565b61110e612306565b600a80546001600160a01b0319166001600160a01b0392909216919091179055005b346102d6575f3660031901126102d6576040517f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e6001600160a01b03168152602090f35b346102d65760203660031901126102d65760043561119181610493565b600354906111a460ff8360a81c166118d2565b6111ac612306565b6001600160a01b03166001600160a01b03199190911617600355005b346102d65760203660031901126102d6576004356111e581610493565b6111ed612306565b6001600160a01b036112028282161515611f08565b6009541690813b156102d657604051632a47b83760e21b81526001600160a01b0382166004820152915f908390602490829084905af1908115610383577f278c70ced5f3e0e5eeb385b5ff9cb735748ba00a625147e66065ed48fc1562cd92610a9992611285575b506040516001600160a01b0390911681529081906020820190565b8061037d611292926105df565b5f61126a565b346102d6575f3660031901126102d6576004546040516001600160a01b039091168152602090f35b346102d65760203660031901126102d6576004356112dd81610493565b6112e5612306565b6001600160a01b03166112f9811515611f08565b7fc847328f5f08e3e6d7560b2fe64b4d448c99e6b7069d5bb25daa0dc4b9aba0e46020604051838152a16001600160601b0360a01b60095416176009555f80f35b346102d65760203660031901126102d6577f0816fa01d8b9b2a738d759950319611d0d7362176e5046cc25e2fef245f40f62602060043561137a81610493565b611382612306565b6001600160a01b0316611396811515611f08565b600680546001600160a01b03191682179055604051908152a1005b346102d6575f3660031901126102d6576020600254604051908152f35b346102d6575f3660031901126102d6576003546113f160ff8260a81c16156119e6565b6001546001600160a01b039160ff91831633148015611568575b61141490611aba565b60a01c161561141f57005b61142761228f565b611506575b6040516370a0823160e01b815230600482015290602090829060249082907f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b165afa908115610383575f916114e7575b508061148457005b600554611499906001600160a01b0316610324565b803b156102d65760405163e2ab691d60e01b815230600482015260248101929092525f60448301819052908290606490829084905af180156103835715610016578061037d610016926105df565b611500915060203d60201161059f57610590818361062d565b5f61147c565b60055461151b906001600160a01b0316610324565b803b156102d65760405163312ff83960e01b815260016004820152905f908290602490829084905af1801561038357611555575b5061142c565b8061037d611562926105df565b5f61154f565b50335f908152600b6020526040902054821661140b565b346102d65760203660031901126102d6577f5fce0723deeb6bf17731a5014d16c200d595ce4be09aab825145ca070cd35bf860206004356115bf81610493565b6115c7612306565b6001600160a01b03166115db811515611f08565b600880546001600160a01b03191682179055604051908152a1005b346102d65760203660031901126102d65760043561161381610493565b60018060a01b03165f52600b602052602060ff60405f2054166040519015158152f35b346102d6575f3660031901126102d6576008546040516001600160a01b039091168152602090f35b346102d65760203660031901126102d6577f4c0dc15273d1f148c7ea4bec6677928a493bbadcff873a85943f2c21b8186219602060043561169e81610493565b6116a6612306565b6001600160a01b03166116ba811515611f08565b600480546001600160a01b03191682179055604051908152a1005b346102d6575f806003193601126102d6576116ee612306565b6040517ffc6c5ac637f59dfbd7866ad96839e5f10712c8ee8f74ac0a28b2126ba34ffa2b5f80a1600854600254906001600160a01b0316803b156102d6576024835f8193819563785f6df160e11b845260048401525af1801561038357611753575080f35b61001691506105df565b346102d65760203660031901126102d65760043561177a81610493565b611782612306565b6001600160a01b039081169081156117d057600154826001600160601b0360a01b821617600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b346102d6575f3660031901126102d6576003546040516001600160a01b039091168152602090f35b346102d6575f3660031901126102d657611864612306565b6009546001600160a01b031661187b811515611f08565b604051907f89e2b1447ef7d47afaffbb3e1f1720cae5372df517f9992eed2528a8649b0c3e5f80a1803b156102d657816004815f8094634b687eed60e11b83525af18015610383576118c957005b610016906105df565b156118d957565b60405162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9858dd081a5cc81b9bdd081c185d5cd95960521b6044820152606490fd5b6040513d5f823e3d90fd5b908160209103126102d6575161193781610445565b90565b8290602092606460018060a01b03600a54169260405196879586948593631b594def60e31b8552600485015260406024850152816044850152848401375f828201840152601f01601f191681010301915afa908115610383575f916119b7575b50156119ab57630b135d3f60e11b90565b6001600160e01b031990565b6119d9915060203d6020116119df575b6119d1818361062d565b810190611922565b5f61199a565b503d6119c7565b156119ed57565b60405162461bcd60e51b815260206004820152601260248201527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b6044820152606490fd5b611a3960ff60035460a81c16156119e6565b611a5b60018060a01b0380928160015416331480156105b3576104f690611aba565b600c54611a7290610324906001600160a01b031681565b8114611aad575b6040516370a0823160e01b815230600482015290602082602481845afa9081156103835761065b925f9261057557506123a7565b611ab561235e565b611a79565b15611ac157565b60405162461bcd60e51b81526020600482015260166024820152751cd95b99195c881b9bdd081dda1a5d195b1a5cdd195960521b6044820152606490fd5b15611b0657565b60405162461bcd60e51b8152602060048201526015602482015274086c2dc40dcdee840e6eecacae040c2d8d84086acb605b1b6044820152606490fd5b908160209103126102d6575190565b9080611b5c612306565b611bb4575b81611b8f7f4969e7d59c970ec13a80e7e632b460c9202863355217c5d7ee7d0b5d7782e7c793511515611c59565b611ba0611b9b82611ca5565b600255565b611baf60405192839283611cc7565b0390a1565b611bbc612306565b604051917ffc6c5ac637f59dfbd7866ad96839e5f10712c8ee8f74ac0a28b2126ba34ffa2b5f80a1600854600254906001600160a01b0316803b156102d6576024855f8193819563785f6df160e11b845260048401525af1928315610383577f4969e7d59c970ec13a80e7e632b460c9202863355217c5d7ee7d0b5d7782e7c793611c4a575b509150611b61565b611c53906105df565b5f611c42565b15611c6057565b60405162461bcd60e51b815260206004820152601860248201527f6d757374206e6f7420626520656d70747920737472696e6700000000000000006044820152606490fd5b602081519101519060208110611cb9575090565b5f199060200360031b1b1690565b90606060208092959495604085528051918291826040880152018386015e5f828286010152601f8019910116830101931515910152565b6001600160a01b03918216815291166020820152604081019190915260806060820181905281018390526001600160fb1b0383116102d65760a09260051b809284830137010190565b91908203918211611d5457565b634e487b7160e01b5f52601160045260245ffd5b6040516370a0823160e01b8082523060048301526001600160a01b03848116979096949560209593949186866024818d5afa95861561038357879389915f98611ee7575b506004545f9190611de790611dc9906001600160a01b0316610324565b94604051998a9788968795637d5f6a0960e11b875260048701611cfe565b03925af1918215610383578492611eca575b5060405190815230600482015295869060249082905afa80156103835761065b95611e2c935f92611ead575b5050611d47565b604080514281526001600160a01b03841660208201529081018290527f3dd299e38bc729d3874c3f50136afc29585dfdaec4766d1e1231d0e56da9672690606090a180611e9d575b50507f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e16611a27565b611ea6916123a7565b5f80611e74565b611ec39250803d1061059f57610590818361062d565b5f80611e25565b611ee090833d851161059f57610590818361062d565b505f611df9565b5f919850611f0190863d881161059f57610590818361062d565b9790611dac565b15611f0f57565b60405162461bcd60e51b815260206004820152601860248201527f6d757374206e6f74206265207a65726f206164647265737300000000000000006044820152606490fd5b634e487b7160e01b5f52603260045260245ffd5b9190811015611f8a5760051b81013590607e19813603018212156102d6570190565b611f54565b3561193781610493565b903590601e19813603018212156102d657018035906001600160401b0382116102d657602001918160051b360383136102d657565b6001600160401b0381116105f25760051b60200190565b9291611ff082611fce565b91611ffe604051938461062d565b829481845260208094019160051b81019283116102d657905b8282106120245750505050565b81358152908301908301612017565b1561203a57565b60405162461bcd60e51b815260206004820152601f60248201527f726577617264206d757374206e6f74206265207a65726f2061646472657373006044820152606490fd5b6020929460c09260a083019560018060a01b038092168452859786850152166040830152606082015260a060808201528551809452019301915f5b8281106120c8575050505090565b8351855293810193928101926001016120ba565b5f5b82811061211b575061065b9150507f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e6001600160a01b0316611a27565b61212e612129828585611f68565b611f8f565b90602061213c828686611f68565b01359160408061214d848888611f68565b01359061217261216b612161868a8a611f68565b6060810190611f99565b3691611fe5565b6121866001600160a01b0385161515612033565b60075461219b906001600160a01b0316610324565b803b156102d6578251630968c76b60e11b8152915f9183918290849082906121ca908a308f8e6004870161207f565b03925af19586156103835761222c7fc8fb114192ae3823bff69d1b8922f93f9e88da0ae61a2145277ca71bd550773b93859360019961224d575b50516001600160a01b0387168152602081019290925260408201929092529081906060820190565b0390a18061223d575b5050016120de565b612246916123a7565b5f80612235565b8061037d61225a926105df565b5f612204565b3d1561228a573d906122718261065d565b9161227f604051938461062d565b82523d5f602084013e565b606090565b5f8060405160208101630241d3fb60e11b8152306024830152602482526122b582610612565b6005549151916001600160a01b03165afa6122ce612260565b901580156122e7575b6122e2576040015190565b505f90565b5060408151106122d7565b8051821015611f8a5760209160051b010190565b6001546001600160a01b0316330361231a57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b47806123675750565b600c546001600160a01b0316803b156102d6575f90600460405180948193630d0e30db60e41b83525af180156103835761239e5750565b61065b906105df565b6001600160a01b038181167f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e82161461246457506006546123fc9083906123f6906001600160a01b0316610324565b83612651565b600654612411906001600160a01b0316610324565b91823b156102d657604051631f72642160e31b81526001600160a01b039290921660048301526024820152905f908290604490829084905af18015610383576124575750565b8061037d61065b926105df565b604051636e553f6560e01b81525f19600482015230602482015292507f0000000000000000000000000655977feb2f289a4ab78af67bab0d17aab843671690506020826044815f855af19182156103835761065b926124c4575b50611a27565b6124dc9060203d60201161059f57610590818361062d565b505f6124be565b60025f54146124f25760025f55565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60405163095ea7b360e01b602082019081526001600160a01b0390931660248201525f1960448201525f9283929183906125748160648101610d7c565b51925af1612580612260565b816125e5575b501561258e57565b60405162461bcd60e51b815260206004820152602960248201527f455243323048656c706572733a3a73616665417070726f76653a20617070726f6044820152681d994819985a5b195960ba1b6064820152608490fd5b80518015925082156125fa575b50505f612586565b61260d9250602080918301019101611922565b5f806125f2565b60405163095ea7b360e01b602082019081526001600160a01b0390931660248201525f604482018190529283929183906125748160648101610d7c565b60405163095ea7b360e01b602082019081526001600160a01b03909316602482015260448101939093525f9283929083906125748160648101610d7c565b9060209182818303126102d6578051906001600160401b0382116102d6570181601f820112156102d6578051926126c584611fce565b936040936126d6604051968761062d565b818652828087019260061b850101938185116102d6578301915b8483106127005750505050505090565b85838303126102d6578386918251612717816105f7565b855161272281610493565b815282860151838201528152019201916126f0565b9061274182611fce565b6040612750604051928361062d565b8382528193612761601f1991611fce565b01905f5b8281106127725750505050565b81519060608201918083106001600160401b038411176105f25760209284525f8152825f818301525f85830152828701015201612765565b6005546127bf906001600160a01b0316610324565b6040805163dc01f60d60e01b8152306004808301919091529093925f90859060249082905afa938415610383575f946128d8575b506127fe8451612737565b915f5b85518110156128d157612817610f4282886122f2565b9060209182612826838a6122f2565b5101519261283d610324610324610f42868d6122f2565b85516370a0823160e01b81523088820190815290959183918791908290819060200103915afa918215610383576001955f936128b2575b5061288f61288061064e565b6001600160a01b039095168552565b830152848201526128a082876122f2565b526128ab81866122f2565b5001612801565b816128ca9294503d851161059f57610590818361062d565b915f612874565b5050509150565b6128f59194503d805f833e6128ed818361062d565b81019061268f565b925f6127f356fea2646970667358221220ec785b8d30a2ebdee2e8276dc7b236de6535ad1aa8ba2e2d3f02100f1aa5c2ee64736f6c63430008190033
Verified Source Code Full Match
Compiler: v0.8.25+commit.b61c2a91
EVM: cancun
Optimization: Yes (200 runs)
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
IERC20Metadata.sol 6 lines
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC20/extensions/IERC20Metadata.sol";
ReentrancyGuard.sol 77 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
Strings.sol 85 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
ECDSA.sol 217 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}
Math.sol 339 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
SignedMath.sol 43 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
IUniswapV2Pair.sol 52 lines
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
Manager.sol 482 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {IVotiumMultiMerkleStash} from "./interfaces/IVotiumMultiMerkleStash.sol";
import {ICvxDelegateRegistry} from "./interfaces/ICvxDelegateRegistry.sol";
import {ICvxLocker} from "./interfaces/ICvxLocker.sol";
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IRegistryDelegate.sol";
import "./interfaces/IFeeSplitter.sol";
import "./libraries/ERC20Helpers.sol";
import "./interfaces/IVoteMarket.sol";
import "./interfaces/IDeposit.sol";
import "./SignatureVerifier.sol";
import "./interfaces/IWETH.sol";
/**
* @title Manager
* @notice Contract that manages locked cvx
*/
contract Manager is ReentrancyGuard, Ownable {
event SetVotium(address votium);
event SetVoteMarket(address voteMarket);
event SetFeeSplitter(address feeSplitter);
event SetCvxLocker(address locker);
event SetCvxDelegate(address delegate);
event SetDelegationSpace(string _delegationSpace, bool shouldClear);
event SetVoteDelegate(address voteDelegate);
event ClearVoteDelegate();
event ClaimVoteMarketRewards(uint256 timestamp, address reward, uint256 amount);
event ClaimConvexRewards(uint256 timestamp, address reward, uint256 amount);
event ClaimVotiumReward(address token, uint256 index, uint256 amount);
event SetRegistryDelegate(address _registryDelegate);
event SetRegistry(address registryDelegate);
event RegistryCleared();
bytes32 public delegationSpace = bytes32("cvx.eth");
IDeposit public immutable scrvUSD;
address public emergencyMigrator;
IERC20 public immutable crvUSD;
IERC20 public immutable CVX;
bool public relockPaused;
bool public paused;
IVoteMarket public voteMarket;
ICvxLocker public cvxLocker;
IFeeSplitter public feeSplitter;
IVotiumMultiMerkleStash public votium;
ICvxDelegateRegistry public cvxDelegate;
IRegistryDelegate public registryDelegate;
SignatureVerifier public verifier;
mapping(address => bool) public whitelisted;
IWETH weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
/**
@notice Convex reward details
@param token address Token
@param amount uint256 Amount
@param balance uint256 Balance (used for calculating the actual received amount)
*/
struct ConvexReward {
address token;
uint256 amount;
uint256 balance;
}
/**
@param _CVX address CVX address
@param _feeSplitter address FeeSplitter address
@param _cvxLocker address CvxLocker address
@param _cvxDelegate address CvxDelegateRegistry address
@param _votium address VotiumMultiMerkleStash address
@param _voteMarket address VoteMarket address
*/
constructor(
address _CVX,
address _crvUSD,
address _scrvUSD,
address _feeSplitter,
address _cvxLocker,
address _cvxDelegate,
address _votium,
address _voteMarket,
address _verifier
) {
cvxDelegate = ICvxDelegateRegistry(_cvxDelegate);
votium = IVotiumMultiMerkleStash(_votium);
feeSplitter = IFeeSplitter(_feeSplitter);
verifier = SignatureVerifier(_verifier);
voteMarket = IVoteMarket(_voteMarket);
cvxLocker = ICvxLocker(_cvxLocker);
scrvUSD = IDeposit(_scrvUSD);
crvUSD = IERC20(_crvUSD);
CVX = IERC20(_CVX);
crvUSD.approve(_scrvUSD, type(uint256).max);
CVX.approve(_cvxLocker, type(uint256).max);
}
/**
* @notice Sets whitelisted status of an address
* @param user address user to set
* @param _whitelisted bool whether or not the user should become whitelisted
*/
function setWhitelisted(address user, bool _whitelisted) external onlyOwner {
whitelisted[user] = _whitelisted;
}
/**
* @notice withdraws the specified token to the msg sender. Can only do when paused
* @param _token address The token to withdraw
*/
function withdrawToken(address _token) external nonReentrant whenPaused onlyOwner {
IERC20 token = IERC20(_token);
uint256 amount = token.balanceOf(address(this));
ERC20Helpers.safeTransfer(_token, msg.sender, amount);
}
/**
* @notice sweeps the specified token to the fee distributor
* @param _token address The token to sweep
*/
function sweepToken(address _token) public whenNotPaused isWhitelisted {
require(_token != address(CVX), "Can not sweep all CVX");
if (_token == address(weth)) wrapEth();
IERC20 token = IERC20(_token);
uint256 amount = token.balanceOf(address(this));
_sweepToken(address(token), amount);
}
/**
* @notice Internal function that wraps eth into WETH
*/
function wrapEth() internal {
uint256 balance = address(this).balance;
if (balance > 0) weth.deposit{ value: balance }();
}
/**
* @notice Internal function that sweeps specific amounts of tokens
*/
function _sweepToken(address _token, uint256 amount) internal {
if (_token == address(crvUSD)) return _wrapAndSweepCrvUsd();
ERC20Helpers.safeApprove(_token, address(feeSplitter), amount);
feeSplitter.distribute(_token, amount);
}
/**
* @notice wraps crvUSD in scrvUSD and sweeps to the fee distributor
*/
function _wrapAndSweepCrvUsd() internal {
scrvUSD.deposit(type(uint256).max, address(this));
sweepToken(address(scrvUSD));
}
/**
* @notice Get claimable rewards and balances
* @return rewards ConvexReward[] Claimable rewards and balances
*/
function _claimableConvexRewards() internal view
returns (ConvexReward[] memory rewards) {
// Get claimable rewards
ICvxLocker.EarnedData[] memory earnings = cvxLocker.claimableRewards(address(this));
rewards = new ConvexReward[](earnings.length);
// Get the current balances for each token to calculate the amount received
for (uint256 i; i < earnings.length; ++i)
rewards[i] = ConvexReward({
token: earnings[i].token,
amount: earnings[i].amount,
balance: IERC20(earnings[i].token).balanceOf(address(this))
});
}
/**
* @notice Claim rewards from convex (e.g. emissions) and distribute
*/
function claimConvexRewards() external nonReentrant isWhitelisted {
ConvexReward[] memory rewards = _claimableConvexRewards();
// claim rewards
cvxLocker.getReward(address(this), false);
// Iterate over rewards and distribute
for (uint256 i; i < rewards.length; ++i) {
emit ClaimConvexRewards(block.timestamp, rewards[i].token, rewards[i].amount);
if (rewards[i].amount > 0) _sweepToken(rewards[i].token, rewards[i].amount);
} sweepToken(address(crvUSD));
}
/**
* @notice Claim multiple VoteMarket rewards
* @param account address account for which to claim
* @param reward address token address of reward to claim
* @param claimable uint256 amount of token to claim
* @param proof bytes32[] claim merkle proof
*/
function claimVoteMarketRewards(
address account, address reward, uint256 claimable, bytes32[] calldata proof
) external whenNotPaused nonReentrant isWhitelisted {
uint256 balanceWas = IERC20(reward).balanceOf(address(this));
voteMarket.claim(account, reward, claimable, proof);
claimable = IERC20(reward).balanceOf(address(this)) - balanceWas;
emit ClaimVoteMarketRewards(block.timestamp, reward, claimable);
if (claimable > 0) _sweepToken(reward, claimable);
sweepToken(address(crvUSD));
}
/**
* @notice Claim multiple Votium rewards
* @param votiumRewards VotiumRewards[] Votium rewards metadata
*/
function claimVotiumRewards(
IVotiumMultiMerkleStash.claimParam[] calldata votiumRewards
) external whenNotPaused nonReentrant isWhitelisted {
for (uint256 i; i < votiumRewards.length; ++i) {
address token = votiumRewards[i].token;
uint256 index = votiumRewards[i].index;
uint256 amount = votiumRewards[i].amount;
bytes32[] memory merkleProof = votiumRewards[i].merkleProof;
require(token != address(0), "reward must not be zero address");
// Validates `token`, `index`, `amount`, and `merkleProof`
votium.claim(
token, index, address(this),
amount, merkleProof
);
emit ClaimVotiumReward(token, index, amount);
if (amount > 0) _sweepToken(token, amount);
} sweepToken(address(crvUSD));
}
/**
* @notice Set delegationSpace
* @param _delegationSpace string Convex Snapshot delegation space
* @param shouldClear bool Whether to clear the vote delegate for current delegation space
*/
function setDelegationSpace(
string memory _delegationSpace,
bool shouldClear
) external onlyOwner {
if (shouldClear) clearVoteDelegate();
bytes memory space = bytes(_delegationSpace);
require(space.length != 0, "must not be empty string");
delegationSpace = bytes32(space);
emit SetDelegationSpace(_delegationSpace, shouldClear);
}
/**
* @notice Set vote delegate
* @param voteDelegate address Account to delegate votes to
*/
function setVoteDelegate(address voteDelegate) external onlyOwner {
require(voteDelegate != address(0), "must not be zero address");
emit SetVoteDelegate(voteDelegate);
cvxDelegate.setDelegate(delegationSpace, voteDelegate);
}
/**
* @notice sets registry delegate
* @param _registryDelegate address of delegate
*/
function setRegistryDelegate(address _registryDelegate) external onlyOwner {
require(_registryDelegate != address(0), "must not be zero address");
emit SetRegistryDelegate(_registryDelegate);
registryDelegate = IRegistryDelegate(_registryDelegate);
}
/**
* @notice clears registry
*/
function clearRegistry() external onlyOwner {
require(address(registryDelegate) != address(0), "must not be zero address");
emit RegistryCleared();
registryDelegate.setToExpire();
}
/**
* @notice Sets registry
* @param registry address Account to receive rewards from votium
*/
function setRegistry(address registry) external onlyOwner {
require(registry != address(0), "must not be zero address");
registryDelegate.setRegistry(registry);
emit SetRegistry(registry);
}
/**
* @notice Remove vote delegate
*/
function clearVoteDelegate() public onlyOwner {
emit ClearVoteDelegate();
cvxDelegate.clearDelegate(delegationSpace);
}
/**
* @notice Set feeSplitter address
* @param _feeSplitter address _feeSplitter address
*/
function setFeeSplitter(address _feeSplitter) external onlyOwner {
require(_feeSplitter != address(0), "must not be zero address");
feeSplitter = IFeeSplitter(_feeSplitter);
emit SetFeeSplitter(_feeSplitter);
}
/**
* @notice Set cvx locker address
* @param locker address Locker address
*/
function setCvxLocker(address locker) external onlyOwner {
require(locker != address(0), "must not be zero address");
require(locker != address(cvxLocker), "Already set");
ERC20Helpers.safeApprove(address(CVX), address(locker), type(uint256).max);
ERC20Helpers.safeApprove(address(CVX), address(cvxLocker), 0);
cvxLocker = ICvxLocker(locker);
emit SetCvxLocker(locker);
}
/**
* @notice Set votium
* @param _votium address votium address
*/
function setVotium(address _votium) external onlyOwner {
require(_votium != address(0), "must not be zero address");
votium = IVotiumMultiMerkleStash(_votium);
emit SetVotium(_votium);
}
/**
* @notice Set voteMarket
* @param _voteMarket address voteMarket address
*/
function setVoteMarket(address _voteMarket) external onlyOwner {
require(_voteMarket != address(0), "must not be zero address");
voteMarket = IVoteMarket(_voteMarket);
emit SetVoteMarket(_voteMarket);
}
/// @notice Sets the Convex delegate registry address for managing vote delegation.
/// @param delegate The address of the `ICvxDelegateRegistry` to use for delegations.
function setCvxDelegate(address delegate) external onlyOwner {
require(delegate != address(0), "must not be zero address");
cvxDelegate = ICvxDelegateRegistry(delegate);
emit SetCvxDelegate(delegate);
}
/**
* @notice Relocks cvx in cvxLocker,
* or cvx that has been kicked to this contract
*/
function relock() public whenNotPaused isWhitelisted {
if (!relockPaused) {
(uint256 unlockable) = _fetchUnlockable();
if (unlockable > 0) cvxLocker.processExpiredLocks(true);
uint256 cvxBalance = CVX.balanceOf(address(this));
if (cvxBalance > 0) cvxLocker.lock(address(this), cvxBalance, 0);
}
}
// Due to a strange bug involving unbounded arrays,
// we use this safe version of accessing unlockable
// amounts from the cvxLocker.
function _fetchUnlockable() public view returns (uint256 unlockable) {
// build the calldata for lockedBalances(address)
bytes memory data = abi.encodeWithSelector(
ICvxLocker.lockedBalances.selector,
address(this)
);
// staticcall so any internal revert just gives ok=false
(bool ok, bytes memory ret) = address(cvxLocker).staticcall(data);
// if the call reverted or returned < 2 words, bail with 0
if (!ok || ret.length < 64) return 0;
// otherwise the 2nd returned word is at offset 32 (length) + 32 (total) = 64
assembly {
unlockable := mload(add(ret, 64))
}
}
modifier isWhitelisted() {
require(msg.sender == owner() || whitelisted[msg.sender], "sender not whitelisted");
_;
}
/*//////////////////////////////////////////////////////////////
EMERGENCY/MIGRATION LOGIC
//////////////////////////////////////////////////////////////*/
modifier whenPaused() {
require(paused, "Contract is not paused");
_;
}
modifier whenNotPaused() {
require(!paused, "Contract is paused");
_;
}
/**
* @notice Set the contract's relockPaused state
* @param state relockPaused state
*/
function setRelockPaused(bool state) external onlyOwner {
relockPaused = state;
}
/**
* @notice Set the contract's pause state
* @param state Pause state
*/
function setPaused(bool state) external onlyOwner {
paused = state;
}
/**
* @notice Sets the emergency migrator, but only when paused
*/
function setEmergencyMigrator(address _migrator) external whenPaused onlyOwner {
emergencyMigrator = _migrator;
}
/**
* @notice Emergency withdraw to the emergency Migrator
*/
function triggerEmergencyMigration() external whenPaused onlyOwner {
require(emergencyMigrator != address(0), "emergency migrator not set");
cvxLocker.withdrawExpiredLocksTo(emergencyMigrator);
}
/// @notice Updates the on-chain signature verifier contract.
/// @param _auctioneer The address of the new `SignatureVerifier` instance.
function updateVerifier(address _auctioneer) public onlyOwner {
verifier = SignatureVerifier(_auctioneer);
}
/// @notice Implements ERC-1271: validates a signature against the approved team.
/// @param _hash The hash of the data signed.
/// @param _signature The signature to validate.
/// @return magicValue Returns `0x1626ba7e` if valid, else `0xffffffff` as per ERC-1271.
function isValidSignature(bytes32 _hash, bytes calldata _signature) external view returns (bytes4) {
if (verifier.verifySignature(_hash, _signature))
return 0x1626ba7e;
else return 0xffffffff;
}
/// @notice Receive native ETH
receive() external payable { }
/// @notice Fallback to receive native ETH
fallback() external payable { }
}
SignatureVerifier.sol 29 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract SignatureVerifier is Ownable {
mapping(address => bool) public approvedTeam;
constructor() {
approvedTeam[msg.sender] = true;
}
/// @notice Approve or revoke a team member for signature verification.
/// @param _member The address of the team member to update.
/// @param _approval True to approve the member; false to revoke approval.
function modifyTeam(address _member, bool _approval) public onlyOwner {
approvedTeam[_member] = _approval;
}
/// @notice Checks whether a signature over a given hash was made by an approved team member.
/// @param _hash The hash of the signed message.
/// @param _signature The signature bytes.
/// @return True if the recovered signer is in the approved team; otherwise false.
function verifySignature(bytes32 _hash, bytes memory _signature) public view returns (bool) {
address signer = ECDSA.recover(_hash, _signature);
return approvedTeam[signer];
}
}
ICvxDelegateRegistry.sol 10 lines
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.25;
interface ICvxDelegateRegistry {
function setDelegate(bytes32 id, address delegate) external;
function clearDelegate(bytes32 id) external;
function delegation(address account, bytes32 id) external view returns (address);
}
ICvxLocker.sol 52 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
interface ICvxLocker {
struct LockedBalance {
uint112 amount;
uint112 boosted;
uint32 unlockTime;
}
struct EarnedData {
address token;
uint256 amount;
}
struct Balances {
uint112 locked;
uint112 boosted;
uint32 nextUnlockIndex;
}
function lock(
address _account,
uint256 _amount,
uint256 _spendRatio
) external;
function userLocks(address _user, uint256 index) external view returns (LockedBalance memory);
function balances(address _user) external view returns (Balances memory);
function lockedBalances(address _user)
external
view
returns (
uint256 total,
uint256 unlockable,
uint256 locked,
LockedBalance[] memory lockData
);
function withdrawExpiredLocksTo(address recipient) external;
function processExpiredLocks(bool _relock) external;
function claimableRewards(address _account)
external
view
returns (EarnedData[] memory userRewards);
function getReward(address _account, bool _stake) external;
function lockedBalanceOf(address _user) external view returns (uint256 amount);
function balanceOf(address _user) external view returns (uint256 amount);
}
IDeposit.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
interface IDeposit {
function balanceOf(address account) external view returns (uint256);
function previewRedeem(uint256 amount) external view returns (uint256);
function previewWithdraw(uint256 amount) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function deposit(uint256 amount, address receiver) external returns (uint256);
function withdraw(uint256 amount, address receiver, address owner) external returns (uint256);
function redeem(uint256 amount, address receiver, address owner) external returns (uint256);
}
IFeeSplitter.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
interface IFeeSplitter {
function requestRewards() external returns (uint256);
function distribute(address token, uint256 amount) external;
}
IRegistryDelegate.sol 15 lines
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.25;
interface IRegistryDelegate {
function setRegistry(address registry) external;
function setToExpire() external;
struct Registry {
uint256 start; // when first registering, there is a delay until the next vlCVX voting epoch starts
address to; // forward rewards to alternate address OR 0x0 address for OPT OUT of rewards
uint256 expiration; // when ending an active registration, expiration is set to the next vlCVX voting epoch
// an active registration cannot be changed until after it is expired (one vote round delay when changing active registration)
}
function registry(address from) external view returns (Registry memory);
}
IVoteMarket.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
interface IVoteMarket {
function claim(
address account,
address reward,
uint256 claimable,
bytes32[] calldata proof
) external returns (uint256 amount);
}
IVotiumMultiMerkleStash.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
interface IVotiumMultiMerkleStash {
struct claimParam {
address token;
uint256 index;
uint256 amount;
bytes32[] merkleProof;
}
function claim(
address token,
uint256 index,
address account,
uint256 amount,
bytes32[] calldata merkleProof
) external;
}
IWETH.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
interface IWETH {
function deposit() external payable;
}
ERC20Helpers.sol 58 lines
// SPDX-License-Identifier: GPL-3.0-or-later
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
pragma solidity >=0.6.0;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library ERC20Helpers {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'ERC20Helpers::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'ERC20Helpers::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'ERC20Helpers::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'ERC20Helpers::safeTransferETH: ETH transfer failed');
}
}
Read Contract
CVX 0x759cb53b → address
_fetchUnlockable 0x63f2615d → uint256
crvUSD 0x9bec8288 → address
cvxDelegate 0xe6a17b9a → address
cvxLocker 0x8d68f9ff → address
delegationSpace 0xbbea0974 → bytes32
emergencyMigrator 0xf9216f11 → address
feeSplitter 0x6052970c → address
isValidSignature 0x1626ba7e → bytes4
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
registryDelegate 0x92f25ea0 → address
relockPaused 0x64521070 → bool
scrvUSD 0x858a43d1 → address
verifier 0x2b7ac3f3 → address
voteMarket 0xa98a9304 → address
votium 0x2a5b5d13 → address
whitelisted 0xd936547e → bool
Write Contract 25 functions
These functions modify contract state and require a wallet transaction to execute.
claimConvexRewards 0x8cedddb5
No parameters
claimVoteMarketRewards 0x260ee14d
address account
address reward
uint256 claimable
bytes32[] proof
claimVotiumRewards 0x3532b32c
tuple[] votiumRewards
clearRegistry 0xfc6530c1
No parameters
clearVoteDelegate 0xedf187f0
No parameters
relock 0xc53b573d
No parameters
renounceOwnership 0x715018a6
No parameters
setCvxDelegate 0xce62d8eb
address delegate
setCvxLocker 0x5f477c57
address locker
setDelegationSpace 0x1d3c2b2f
string _delegationSpace
bool shouldClear
setEmergencyMigrator 0xa6785348
address _migrator
setFeeSplitter 0xb17fb9d6
address _feeSplitter
setPaused 0x16c38b3c
bool state
setRegistry 0xa91ee0dc
address registry
setRegistryDelegate 0xabc0ab51
address _registryDelegate
setRelockPaused 0x5834d435
bool state
setVoteDelegate 0x74874323
address voteDelegate
setVoteMarket 0xeb2578ef
address _voteMarket
setVotium 0x3a16b85a
address _votium
setWhitelisted 0x9281aa0b
address user
bool _whitelisted
sweepToken 0x1be19560
address _token
transferOwnership 0xf2fde38b
address newOwner
triggerEmergencyMigration 0x0bc8e05f
No parameters
updateVerifier 0x97fc007c
address _auctioneer
withdrawToken 0x89476069
address _token
Recent Transactions
No transactions found for this address