Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0xC5d6A7B61d18AfA11435a889557b068BB9f29930
Balance 0 ETH
Nonce 1
Code Size 11085 bytes
Last Active
Indexed Transactions 1 (24,604,15524,604,155)
Gas Used (indexed) 158,058
External Etherscan · Sourcify

Contract Bytecode

11085 bytes
0x608060405234801561000f575f5ffd5b506004361061023f575f3560e01c806370a0823111610135578063ba087652116100b4578063ce96cb7711610079578063ce96cb77146105d3578063d505accf146105e6578063d905777e146105f9578063dd62ed3e14610621578063ef8b30f71461064b575f5ffd5b8063ba0876521461055f578063c63d75b6146103f5578063c6e6f59214610572578063c78d6d2114610585578063cd0d0096146105ac575f5ffd5b80639fd5a6cf116100fa5780639fd5a6cf146104fe578063a457c2d714610513578063a9059cbb14610526578063b3d7f6b914610539578063b460af941461054c575f5ffd5b806370a08231146104765780637ecebe001461049557806394bf804d146104b457806395d89b41146104c75780639b8d6d38146104eb575f5ffd5b8063313ce567116101c1578063402d267d11610186578063402d267d146103f55780634ba2363a146104095780634cdad5061461043057806354fd4d50146104435780636e553f6514610463575f5ffd5b8063313ce567146103735780633644e5151461038d57806336569e771461039557806338d52e0f146103bc57806339509351146103e2575f5ffd5b80630c30bc02116102075780630c30bc02146102df57806318160ddd1461031e578063216740a01461032657806323b872dd1461033957806330adf81f1461034c575f5ffd5b806301e1d1141461024357806306fdde031461025e57806307a2d13a14610296578063095ea7b3146102a95780630a28a477146102cc575b5f5ffd5b61024b61065e565b6040519081526020015b60405180910390f35b6102896040518060400160405280600c81526020016b14d85d9a5b99dcc8155cd91960a21b81525081565b6040516102559190612626565b61024b6102a4366004612638565b61066e565b6102bc6102b736600461266a565b6108db565b6040519015158152602001610255565b61024b6102da366004612638565b610934565b6103067f0000000000000000000000004f8e5de400de08b164e7421b3ee387f461becd1a81565b6040516001600160a01b039091168152602001610255565b61024b5f5481565b61024b610334366004612692565b610b64565b6102bc6103473660046126d5565b610bc9565b61024b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b61037b601281565b60405160ff9091168152602001610255565b61024b610d2e565b6103067f000000000000000000000000ff77f6209239deb2c076179499f2346b0032097f81565b7f0000000000000000000000004f8e5de400de08b164e7421b3ee387f461becd1a610306565b6102bc6103f036600461266a565b610d84565b61024b61040336600461270f565b505f1990565b6103067f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca50081565b61024b61043e366004612638565b610e08565b610289604051806040016040528060018152602001603160f81b81525081565b61024b610471366004612728565b610e12565b61024b61048436600461270f565b60016020525f908152604090205481565b61024b6104a336600461270f565b60036020525f908152604090205481565b61024b6104c2366004612728565b610fd6565b610289604051806040016040528060058152602001641cd554d11160da1b81525081565b61024b6104f9366004612692565b611191565b61051161050c366004612766565b6111e7565b005b6102bc61052136600461266a565b61145e565b6102bc61053436600461266a565b6114ea565b61024b610547366004612638565b6115a0565b61024b61055a36600461284c565b6117bf565b61024b61056d36600461284c565b61197d565b61024b610580366004612638565b611b3b565b6103067f000000000000000000000000983dfef6d71862d809e239845da5a959492f63b881565b61024b7f000000000000000000000000000000000000000000000000000000000000000181565b61024b6105e136600461270f565b611d63565b6105116105f4366004612885565b611d84565b61024b61060736600461270f565b6001600160a01b03165f9081526001602052604090205490565b61024b61062f3660046128f2565b600260209081525f928352604080842090915290825290205481565b61024b610659366004612638565b611ddb565b5f6106695f5461066e565b905090565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106cc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106f0919061291a565b90505f81421161077f577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610756573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077a919061291a565b6108b1565b676765c793fa10079d601b1b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107e7573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080b919061291a565b61089d7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663487bf0826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061088e919061291a565b6108988642612945565b611de5565b6108a79190612958565b6108b19190612983565b9050676765c793fa10079d601b1b6108c98286612958565b6108d39190612983565b949350505050565b335f8181526002602090815260408083206001600160a01b038716808552925280832085905551919290915f516020612af85f395f51905f52906109229086815260200190565b60405180910390a35060015b92915050565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610992573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b6919061291a565b90505f814211610a45577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a1c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a40919061291a565b610b44565b676765c793fa10079d601b1b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aad573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad1919061291a565b610b307f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663487bf0826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086a573d5f5f3e3d5ffd5b610b3a9190612958565b610b449190612983565b90506108d3610b5e676765c793fa10079d601b1b86612958565b82611ed0565b5f610b6f8484610fd6565b9050826001600160a01b03168261ffff167fb30a03a0e2a407f18ae0e83491331dc069d1521e292feffb071e61c8f7f406368387604051610bba929190918252602082015260400190565b60405180910390a39392505050565b5f6001600160a01b03831615801590610beb57506001600160a01b0383163014155b610c105760405162461bcd60e51b8152600401610c07906129a2565b60405180910390fd5b6001600160a01b0384165f9081526001602052604090205482811015610c485760405162461bcd60e51b8152600401610c07906129d9565b6001600160a01b0385163314610ccd576001600160a01b0385165f9081526002602090815260408083203384529091529020545f198114610ccb5783811015610ca35760405162461bcd60e51b8152600401610c0790612a0e565b6001600160a01b0386165f908152600260209081526040808320338452909152902084820390555b505b6001600160a01b038086165f8181526001602052604080822087860390559287168082529083902080548701905591515f516020612ad85f395f51905f5290610d199087815260200190565b60405180910390a360019150505b9392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000014614610d5f5761066946611efb565b507ff23e5de26f0a3165c57f379f00307e9c590d5c306c0d3441f6ce96b70a83ed2c90565b335f9081526002602090815260408083206001600160a01b03861684529091528120548190610db4908490612a50565b335f8181526002602090815260408083206001600160a01b038a16808552908352928190208590555184815293945090925f516020612af85f395f51905f5291015b60405180910390a35060019392505050565b5f61092e8261066e565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e94919061291a565b4211610f1f577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ef6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1a919061291a565b610fa0565b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b0316639f678cca6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015610f7c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fa0919061291a565b905080610fb8676765c793fa10079d601b1b86612958565b610fc29190612983565b9150610fcf848385611fd0565b5092915050565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611034573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611058919061291a565b42116110e3577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110de919061291a565b611164565b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b0316639f678cca6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611140573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611164919061291a565b90506111846111738286612958565b676765c793fa10079d601b1b611ed0565b9150610fcf828585611fd0565b5f61119c8484610e12565b9050826001600160a01b03168261ffff167fb30a03a0e2a407f18ae0e83491331dc069d1521e292feffb071e61c8f7f406368684604051610bba929190918252602082015260400190565b814211156112375760405162461bcd60e51b815260206004820152601a60248201527f536176696e6773557364642f7065726d69742d657870697265640000000000006044820152606401610c07565b6001600160a01b03851661128d5760405162461bcd60e51b815260206004820152601960248201527f536176696e6773557364642f696e76616c69642d6f776e6572000000000000006044820152606401610c07565b6001600160a01b0385165f90815260036020526040812080546001810190915590467f0000000000000000000000000000000000000000000000000000000000000001146112e3576112de46611efb565b611305565b7ff23e5de26f0a3165c57f379f00307e9c590d5c306c0d3441f6ce96b70a83ed2c5b604080517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c960208201526001600160a01b03808b169282019290925290881660608201526080810187905260a0810184905260c0810186905260e0016040516020818303038152906040528051906020012060405160200161139e92919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090506113c1878285612223565b61140d5760405162461bcd60e51b815260206004820152601a60248201527f536176696e6773557364642f696e76616c69642d7065726d69740000000000006044820152606401610c07565b6001600160a01b038781165f818152600260209081526040808320948b168084529482529182902089905590518881525f516020612af85f395f51905f52910160405180910390a350505050505050565b335f9081526002602090815260408083206001600160a01b0386168452909152812054828110156114a15760405162461bcd60e51b8152600401610c0790612a0e565b335f8181526002602090815260408083206001600160a01b038916808552908352928190209487900394859055518481529192915f516020612af85f395f51905f529101610df6565b5f6001600160a01b0383161580159061150c57506001600160a01b0383163014155b6115285760405162461bcd60e51b8152600401610c07906129a2565b335f90815260016020526040902054828110156115575760405162461bcd60e51b8152600401610c07906129d9565b335f81815260016020908152604080832087860390556001600160a01b03881680845292819020805488019055518681529192915f516020612ad85f395f51905f529101610df6565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115fe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611622919061291a565b90505f8142116116b1577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611688573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116ac919061291a565b6117b0565b676765c793fa10079d601b1b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611719573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061173d919061291a565b61179c7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663487bf0826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086a573d5f5f3e3d5ffd5b6117a69190612958565b6117b09190612983565b90506108d36111738286612958565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561181d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611841919061291a565b42116118cc577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118c7919061291a565b61194d565b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b0316639f678cca6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611929573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061194d919061291a565b9050611967610b5e676765c793fa10079d601b1b87612958565b9150611975858386866123ac565b509392505050565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ff919061291a565b4211611a8a577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a61573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a85919061291a565b611b0b565b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b0316639f678cca6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611ae7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0b919061291a565b9050676765c793fa10079d601b1b611b238287612958565b611b2d9190612983565b9150611975828686866123ac565b5f5f7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b99573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbd919061291a565b90505f814211611c4c577f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c23573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c47919061291a565b611d4b565b676765c793fa10079d601b1b7f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cb4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cd8919061291a565b611d377f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b031663487bf0826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086a573d5f5f3e3d5ffd5b611d419190612958565b611d4b9190612983565b9050806108c9676765c793fa10079d601b1b86612958565b6001600160a01b0381165f9081526001602052604081205461092e9061066e565b611dd287878787868689604051602001611dbe93929190928352602083019190915260f81b6001600160f81b031916604082015260410190565b6040516020818303038152906040526111e7565b50505050505050565b5f61092e82611b3b565b5f828015611eaa57600183168015611dff57849250611e0e565b676765c793fa10079d601b1b92505b506002909204916b019d971e4fe8401e740000005b8315611ea4578485028586820414611e39575f5ffd5b81810181811015611e48575f5ffd5b676765c793fa10079d601b1b90049550506001841615611e99578483028386820414158615151615611e78575f5ffd5b81810181811015611e87575f5ffd5b676765c793fa10079d601b1b90049350505b600284049350611e23565b50610fcf565b828015611eb9575f9250611ec8565b676765c793fa10079d601b1b92505b505092915050565b5f825f03611ede575f610d27565b816001840381611ef057611ef061296f565b046001019392505050565b604080518082018252600c81526b14d85d9a5b99dcc8155cd91960a21b6020918201528151808301835260018152603160f81b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527fd8187624be2f1af878d75953ca9c210ff856e4a346d04ec98490f6344034d7c4818401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101939093523060a0808501919091528251808503909101815260c0909301909152815191012090565b6001600160a01b03811615801590611ff157506001600160a01b0381163014155b61200d5760405162461bcd60e51b8152600401610c07906129a2565b6040516323b872dd60e01b8152336004820152306024820152604481018490527f0000000000000000000000004f8e5de400de08b164e7421b3ee387f461becd1a6001600160a01b0316906323b872dd906064016020604051808303815f875af115801561207d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120a19190612a63565b50604051633b4da69f60e01b8152306004820152602481018490527f000000000000000000000000983dfef6d71862d809e239845da5a959492f63b86001600160a01b031690633b4da69f906044015f604051808303815f87803b158015612107575f5ffd5b505af1158015612119573d5f5f3e3d5ffd5b505060405163049878f360e01b8152600481018590527f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca5006001600160a01b0316925063049878f391506024015f604051808303815f87803b15801561217c575f5ffd5b505af115801561218e573d5f5f3e3d5ffd5b505050506001600160a01b0381165f81815260016020908152604080832080548701905582548601909255815186815290810185905233917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a36040518281526001600160a01b038216905f905f516020612ad85f395f51905f529060200160405180910390a3505050565b5f81516041036122bc5760208281015160408085015160608087015183515f8082529681018086528a9052951a928501839052840183905260808401819052919260019060a0016020604051602081039080840390855afa15801561228a573d5f5f3e3d5ffd5b505050602060405103516001600160a01b0316876001600160a01b0316036122b85760019350505050610d27565b5050505b5f5f856001600160a01b0316631626ba7e60e01b86866040516024016122e3929190612a82565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516123219190612a9a565b5f60405180830381855afa9150503d805f8114612359576040519150601f19603f3d011682016040523d82523d5f602084013e61235e565b606091505b5091509150818015612371575080516020145b80156123a257508051630b135d3f60e11b906123969083016020908101908401612ab0565b6001600160e01b031916145b9695505050505050565b6001600160a01b0381165f90815260016020526040902054838110156123e45760405162461bcd60e51b8152600401610c07906129d9565b6001600160a01b0382163314612469576001600160a01b0382165f9081526002602090815260408083203384529091529020545f198114612467578481101561243f5760405162461bcd60e51b8152600401610c0790612a0e565b6001600160a01b0383165f908152600260209081526040808320338452909152902085820390555b505b6001600160a01b038281165f908152600160205260408082208785039055815487900390915551637f8661a160e01b8152600481018690527f000000000000000000000000e789578252cc026ffb3413a1104ba223fdeca50090911690637f8661a1906024015f604051808303815f87803b1580156124e6575f5ffd5b505af11580156124f8573d5f5f3e3d5ffd5b505060405163ef693bed60e01b81526001600160a01b038681166004830152602482018990527f000000000000000000000000983dfef6d71862d809e239845da5a959492f63b816925063ef693bed91506044015f604051808303815f87803b158015612563575f5ffd5b505af1158015612575573d5f5f3e3d5ffd5b50506040518681525f92506001600160a01b03851691505f516020612ad85f395f51905f529060200160405180910390a360408051868152602081018690526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a45050505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610d2760208301846125f8565b5f60208284031215612648575f5ffd5b5035919050565b80356001600160a01b0381168114612665575f5ffd5b919050565b5f5f6040838503121561267b575f5ffd5b6126848361264f565b946020939093013593505050565b5f5f5f606084860312156126a4575f5ffd5b833592506126b46020850161264f565b9150604084013561ffff811681146126ca575f5ffd5b809150509250925092565b5f5f5f606084860312156126e7575f5ffd5b6126f08461264f565b92506126fe6020850161264f565b929592945050506040919091013590565b5f6020828403121561271f575f5ffd5b610d278261264f565b5f5f60408385031215612739575f5ffd5b823591506127496020840161264f565b90509250929050565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f5f5f60a0868803121561277a575f5ffd5b6127838661264f565b94506127916020870161264f565b93506040860135925060608601359150608086013567ffffffffffffffff8111156127ba575f5ffd5b8601601f810188136127ca575f5ffd5b803567ffffffffffffffff8111156127e4576127e4612752565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561281357612813612752565b6040528181528282016020018a101561282a575f5ffd5b816020840160208301375f602083830101528093505050509295509295909350565b5f5f5f6060848603121561285e575f5ffd5b8335925061286e6020850161264f565b915061287c6040850161264f565b90509250925092565b5f5f5f5f5f5f5f60e0888a03121561289b575f5ffd5b6128a48861264f565b96506128b26020890161264f565b95506040880135945060608801359350608088013560ff811681146128d5575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f60408385031215612903575f5ffd5b61290c8361264f565b91506127496020840161264f565b5f6020828403121561292a575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561092e5761092e612931565b808202811582820484141761092e5761092e612931565b634e487b7160e01b5f52601260045260245ffd5b5f8261299d57634e487b7160e01b5f52601260045260245ffd5b500490565b6020808252601b908201527f536176696e6773557364642f696e76616c69642d616464726573730000000000604082015260600190565b6020808252818101527f536176696e6773557364642f696e73756666696369656e742d62616c616e6365604082015260600190565b60208082526022908201527f536176696e6773557364642f696e73756666696369656e742d616c6c6f77616e604082015261636560f01b606082015260800190565b8082018082111561092e5761092e612931565b5f60208284031215612a73575f5ffd5b81518015158114610d27575f5ffd5b828152604060208201525f6108d360408301846125f8565b5f82518060208501845e5f920191825250919050565b5f60208284031215612ac0575f5ffd5b81516001600160e01b031981168114610d27575f5ffdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a264697066735822122078a6aa2ba4fbad9cf9377b874fcb1e957f57ce689aef8c21cfefe8d1534fda4a64736f6c634300081e0033

Verified Source Code Full Match

Compiler: v0.8.30+commit.73712a01 EVM: cancun Optimization: Yes (200 runs)
SavingsUsdd.sol 434 lines
// SPDX-License-Identifier: AGPL-3.0-or-later

/// SavingsUsdd.sol -- A tokenized representation USDD in the DSR (pot)

// Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico
// Copyright (C) 2021-2022 Dai Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.17;

interface IERC1271 {
    function isValidSignature(
        bytes32,
        bytes memory
    ) external view returns (bytes4);
}

interface VatLike {
    function hope(address) external;
}

interface PotLike {
    function chi() external view returns (uint256);
    function rho() external view returns (uint256);
    function dsr() external view returns (uint256);
    function drip() external returns (uint256);
    function join(uint256) external;
    function exit(uint256) external;
}

interface UsddJoinLike {
    function vat() external view returns (address);
    function usdd() external view returns (address);
    function join(address, uint256) external;
    function exit(address, uint256) external;
}

interface UsddLike {
    function transferFrom(address, address, uint256) external returns (bool);
    function approve(address, uint256) external returns (bool);
}

contract SavingsUsdd {

    // --- ERC20 Data ---
    string  public constant name     = "Savings Usdd";
    string  public constant symbol   = "sUSDD";
    string  public constant version  = "1";
    uint8   public constant decimals = 18;
    uint256 public totalSupply;

    mapping (address => uint256)                      public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;
    mapping (address => uint256)                      public nonces;

    // --- Data ---
    VatLike     public immutable vat;
    UsddJoinLike public immutable usddJoin;
    UsddLike     public immutable usdd;
    PotLike     public immutable pot;

    // --- Events ---
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
    event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
    event Referral(uint16 indexed referral, address indexed owner, uint256 assets, uint256 shares);

    // --- EIP712 niceties ---
    uint256 public immutable deploymentChainId;
    bytes32 private immutable _DOMAIN_SEPARATOR;
    bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    
    uint256 private constant RAY = 10 ** 27;

    constructor(address _usddJoin, address _pot) {
        usddJoin = UsddJoinLike(_usddJoin);
        vat = VatLike(usddJoin.vat());
        usdd = UsddLike(usddJoin.usdd());
        pot = PotLike(_pot);

        deploymentChainId = block.chainid;
        _DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid);

        vat.hope(address(usddJoin));
        vat.hope(address(pot));

        usdd.approve(address(usddJoin), type(uint256).max);
    }

    function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
        return keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                chainId,
                address(this)
            )
        );
    }

    function DOMAIN_SEPARATOR() external view returns (bytes32) {
        return block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid);
    }

    function _rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
        assembly {
            switch x case 0 {switch n case 0 {z := RAY} default {z := 0}}
            default {
                switch mod(n, 2) case 0 { z := RAY } default { z := x }
                let half := div(RAY, 2)  // for rounding.
                for { n := div(n, 2) } n { n := div(n,2) } {
                    let xx := mul(x, x)
                    if iszero(eq(div(xx, x), x)) { revert(0,0) }
                    let xxRound := add(xx, half)
                    if lt(xxRound, xx) { revert(0,0) }
                    x := div(xxRound, RAY)
                    if mod(n,2) {
                        let zx := mul(z, x)
                        if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) }
                        let zxRound := add(zx, half)
                        if lt(zxRound, zx) { revert(0,0) }
                        z := div(zxRound, RAY)
                    }
                }
            }
        }
    }

    function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x != 0 ? ((x - 1) / y) + 1 : 0;
        }
    }

    // --- ERC20 Mutations ---

    function transfer(address to, uint256 value) external returns (bool) {
        require(to != address(0) && to != address(this), "SavingsUsdd/invalid-address");
        uint256 balance = balanceOf[msg.sender];
        require(balance >= value, "SavingsUsdd/insufficient-balance");

        unchecked {
            balanceOf[msg.sender] = balance - value;
            balanceOf[to] += value;
        }

        emit Transfer(msg.sender, to, value);

        return true;
    }

    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        require(to != address(0) && to != address(this), "SavingsUsdd/invalid-address");
        uint256 balance = balanceOf[from];
        require(balance >= value, "SavingsUsdd/insufficient-balance");

        if (from != msg.sender) {
            uint256 allowed = allowance[from][msg.sender];
            if (allowed != type(uint256).max) {
                require(allowed >= value, "SavingsUsdd/insufficient-allowance");

                unchecked {
                    allowance[from][msg.sender] = allowed - value;
                }
            }
        }

        unchecked {
            balanceOf[from] = balance - value;
            balanceOf[to] += value;
        }

        emit Transfer(from, to, value);

        return true;
    }

    function approve(address spender, uint256 value) external returns (bool) {
        allowance[msg.sender][spender] = value;

        emit Approval(msg.sender, spender, value);

        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
        uint256 newValue = allowance[msg.sender][spender] + addedValue;
        allowance[msg.sender][spender] = newValue;

        emit Approval(msg.sender, spender, newValue);

        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
        uint256 allowed = allowance[msg.sender][spender];
        require(allowed >= subtractedValue, "SavingsUsdd/insufficient-allowance");
        unchecked{
            allowed = allowed - subtractedValue;
        }
        allowance[msg.sender][spender] = allowed;

        emit Approval(msg.sender, spender, allowed);

        return true;
    }

    // --- Mint/Burn Internal ---

    function _mint(uint256 assets, uint256 shares, address receiver) internal {
        require(receiver != address(0) && receiver != address(this), "SavingsUsdd/invalid-address");

        usdd.transferFrom(msg.sender, address(this), assets);
        usddJoin.join(address(this), assets);
        pot.join(shares);

        // note: we don't need an overflow check here b/c shares totalSupply will always be <= usdd totalSupply
        unchecked {
            balanceOf[receiver] = balanceOf[receiver] + shares;
            totalSupply = totalSupply + shares;
        }

        emit Deposit(msg.sender, receiver, assets, shares);
        emit Transfer(address(0), receiver, shares);
    }

    function _burn(uint256 assets, uint256 shares, address receiver, address owner) internal {
        uint256 balance = balanceOf[owner];
        require(balance >= shares, "SavingsUsdd/insufficient-balance");

        if (owner != msg.sender) {
            uint256 allowed = allowance[owner][msg.sender];
            if (allowed != type(uint256).max) {
                require(allowed >= shares, "SavingsUsdd/insufficient-allowance");

                unchecked {
                    allowance[owner][msg.sender] = allowed - shares;
                }
            }
        }

        unchecked {
            balanceOf[owner] = balance - shares; // note: we don't need overflow checks b/c require(balance >= value) and balance <= totalSupply
            totalSupply      = totalSupply - shares;
        }

        pot.exit(shares);
        usddJoin.exit(receiver, assets);

        emit Transfer(owner, address(0), shares);
        emit Withdraw(msg.sender, receiver, owner, assets, shares);
    }

    // --- ERC-4626 ---

    function asset() external view returns (address) {
        return address(usdd);
    }

    function totalAssets() external view returns (uint256) {
        return convertToAssets(totalSupply);
    }

    function convertToShares(uint256 assets) public view returns (uint256) {
        uint256 rho = pot.rho();
        uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi();
        return assets * RAY / chi;
    }

    function convertToAssets(uint256 shares) public view returns (uint256) {
        uint256 rho = pot.rho();
        uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi();
        return shares * chi / RAY;
    }

    function maxDeposit(address) external pure returns (uint256) {
        return type(uint256).max;
    }

    function previewDeposit(uint256 assets) external view returns (uint256) {
        return convertToShares(assets);
    }

    function deposit(uint256 assets, address receiver) public returns (uint256 shares) {
        uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi();
        shares = assets * RAY / chi;
        _mint(assets, shares, receiver);
    }

    function deposit(uint256 assets, address receiver, uint16 referral) external returns (uint256 shares) {
        shares = deposit(assets, receiver);
        emit Referral(referral, receiver, assets, shares);
    }

    function maxMint(address) external pure returns (uint256) {
        return type(uint256).max;
    }

    function previewMint(uint256 shares) external view returns (uint256) {
        uint256 rho = pot.rho();
        uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi();
        return _divup(shares * chi, RAY);
    }

    function mint(uint256 shares, address receiver) public returns (uint256 assets) {
        uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi();
        assets = _divup(shares * chi, RAY);
        _mint(assets, shares, receiver);
    }

    function mint(uint256 shares, address receiver, uint16 referral) external returns (uint256 assets) {
        assets = mint(shares, receiver);
        emit Referral(referral, receiver, assets, shares);
    }

    function maxWithdraw(address owner) external view returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function previewWithdraw(uint256 assets) external view returns (uint256) {
        uint256 rho = pot.rho();
        uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi();
        return _divup(assets * RAY, chi);
    }

    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
        uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi();
        shares = _divup(assets * RAY, chi);
        _burn(assets, shares, receiver, owner);
    }

    function maxRedeem(address owner) external view returns (uint256) {
        return balanceOf[owner];
    }

    function previewRedeem(uint256 shares) external view returns (uint256) {
        return convertToAssets(shares);
    }

    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets) {
        uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi();
        assets = shares * chi / RAY;
        _burn(assets, shares, receiver, owner);
    }

    // --- Approve by signature ---

    function _isValidSignature(
        address signer,
        bytes32 digest,
        bytes memory signature
    ) internal view returns (bool) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            if (signer == ecrecover(digest, v, r, s)) {
                return true;
            }
        }

        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(IERC1271.isValidSignature.selector, digest, signature)
        );
        return (success &&
            result.length == 32 &&
            abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        bytes memory signature
    ) public {
        require(block.timestamp <= deadline, "SavingsUsdd/permit-expired");
        require(owner != address(0), "SavingsUsdd/invalid-owner");

        uint256 nonce;
        unchecked { nonce = nonces[owner]++; }

        bytes32 digest =
            keccak256(abi.encodePacked(
                "\x19\x01",
                block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid),
                keccak256(abi.encode(
                    PERMIT_TYPEHASH,
                    owner,
                    spender,
                    value,
                    nonce,
                    deadline
                ))
            ));

        require(_isValidSignature(owner, digest, signature), "SavingsUsdd/invalid-permit");

        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));
    }

}

Read Contract

DOMAIN_SEPARATOR 0x3644e515 → bytes32
PERMIT_TYPEHASH 0x30adf81f → bytes32
allowance 0xdd62ed3e → uint256
asset 0x38d52e0f → address
balanceOf 0x70a08231 → uint256
convertToAssets 0x07a2d13a → uint256
convertToShares 0xc6e6f592 → uint256
decimals 0x313ce567 → uint8
deploymentChainId 0xcd0d0096 → uint256
maxDeposit 0x402d267d → uint256
maxMint 0xc63d75b6 → uint256
maxRedeem 0xd905777e → uint256
maxWithdraw 0xce96cb77 → uint256
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
pot 0x4ba2363a → address
previewDeposit 0xef8b30f7 → uint256
previewMint 0xb3d7f6b9 → uint256
previewRedeem 0x4cdad506 → uint256
previewWithdraw 0x0a28a477 → uint256
symbol 0x95d89b41 → string
totalAssets 0x01e1d114 → uint256
totalSupply 0x18160ddd → uint256
usdd 0x0c30bc02 → address
usddJoin 0xc78d6d21 → address
vat 0x36569e77 → address
version 0x54fd4d50 → string

Write Contract 13 functions

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

approve 0x095ea7b3
address spender
uint256 value
returns: bool
decreaseAllowance 0xa457c2d7
address spender
uint256 subtractedValue
returns: bool
deposit 0x6e553f65
uint256 assets
address receiver
returns: uint256
deposit 0x9b8d6d38
uint256 assets
address receiver
uint16 referral
returns: uint256
increaseAllowance 0x39509351
address spender
uint256 addedValue
returns: bool
mint 0x216740a0
uint256 shares
address receiver
uint16 referral
returns: uint256
mint 0x94bf804d
uint256 shares
address receiver
returns: uint256
permit 0x9fd5a6cf
address owner
address spender
uint256 value
uint256 deadline
bytes signature
permit 0xd505accf
address owner
address spender
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
redeem 0xba087652
uint256 shares
address receiver
address owner
returns: uint256
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 value
returns: bool
withdraw 0xb460af94
uint256 assets
address receiver
address owner
returns: uint256

Top Interactions

AddressTxnsSentReceived
0x2D9D34f2...4d3A 1 1

Recent Transactions

CSV
|
Hash Method Block Age From/To Value Txn Fee Type
0xb899b79b...2eb411 deposit 24,604,155 IN 0x2D9D34f2...4d3A 0 ETH 0.000007120186 ETH EIP-1559