Address Contract Partially Verified
Address
0xCaC15044a1F67238D761Aa4C7650DaB59cEF849D
Balance
0 ETH
Nonce
1
Code Size
21505 bytes
Creator
0x51Ae6ff2...b03f at tx 0x8ea3e121...66b924
Indexed Transactions
0
Contract Bytecode
21505 bytes
0x6080604052600436106103c75760003560e01c8063b1d4cfca116101f2578063e2bbb1581161010d578063f3fef3a3116100a0578063f9f293561161006f578063f9f2935614610b56578063fa09e63014610b6b578063fdda34fe14610b8b578063ffa1ad7414610bab57600080fd5b8063f3fef3a314610add578063f65baefa14610afd578063f7888aec14610b20578063f7c649dd14610b4057600080fd5b8063e6a6e7a2116100dc578063e6a6e7a214610a26578063ea4d3c9b14610a46578063ecf7477714610a66578063f2fde38b14610abd57600080fd5b8063e2bbb158146109a8578063e30c3978146109c8578063e4cc3f90146109e6578063e69bb20d14610a0657600080fd5b8063c822adda11610185578063d9ece25911610154578063d9ece25914610928578063da3e339714610948578063da9d3be714610968578063e1b971391461098857600080fd5b8063c822adda146108af578063c89e4361146108dd578063cdaf200f146108f2578063d3e7c45b1461090857600080fd5b8063b6234f9d116101c1578063b6234f9d14610845578063b6703fcd1461085a578063b7fcb8311461087a578063c4e2c1e61461088f57600080fd5b8063b1d4cfca146107be578063b381cf40146107de578063b501d66014610812578063b61d27f61461083257600080fd5b80635c6b7a1d116102e25780638b266206116102755780639ac2a011116102445780639ac2a011146107395780639b1209b514610769578063adb5d7bd1461077e578063b199329b1461079e57600080fd5b80638b266206146106cd5780638da5cb5b146106e65780639169d8331461070457806392ab89bb1461072457600080fd5b8063715018a6116102b1578063715018a61461066e57806372068dce1461068357806379ba5097146106985780638a2fc4e3146106ad57600080fd5b80635c6b7a1d146105f457806362cef7911461061957806368dbd7a9146106395780636ed625ab1461064e57600080fd5b80632b5af7481161035a5780633ccc861d116103295780633ccc861d1461057f5780634c7e972b1461059f57806351fb9283146105b457806354621b42146105d457600080fd5b80632b5af748146104e75780633419ba231461050757806334b10a6d1461052757806339b70e381461054757600080fd5b80631761b7ce116103965780631761b7ce146104525780631b51d9b5146104875780631f5a0bbe146104a757806324788429146104c757600080fd5b806303160940146103d3578063077d97d7146103fb578063087ed837146104105780630dd8dd021461043257600080fd5b366103ce57005b600080fd5b3480156103df57600080fd5b506103e8610bdf565b6040519081526020015b60405180910390f35b61040e610409366004613e50565b610c52565b005b34801561041c57600080fd5b50610425610dc8565b6040516103f29190613f2d565b34801561043e57600080fd5b5061040e61044d3660046140e2565b610e2b565b34801561045e57600080fd5b5061047261046d366004614202565b610e3f565b604080519283526020830191909152016103f2565b34801561049357600080fd5b506104726104a2366004614202565b610ee9565b3480156104b357600080fd5b5061040e6104c236600461421b565b610fdf565b3480156104d357600080fd5b5061040e6104e236600461421b565b61104a565b3480156104f357600080fd5b5061040e610502366004614238565b6110b2565b34801561051357600080fd5b5061040e6105223660046142dd565b6110f2565b34801561053357600080fd5b5061040e610542366004614202565b61110a565b34801561055357600080fd5b50600654610567906001600160a01b031681565b6040516001600160a01b0390911681526020016103f2565b34801561058b57600080fd5b5061040e61059a366004614329565b6111db565b3480156105ab57600080fd5b50610472611228565b3480156105c057600080fd5b5061040e6105cf36600461421b565b6112f1565b3480156105e057600080fd5b506103e86105ef366004614202565b611350565b34801561060057600080fd5b506106096113e7565b60405190151581526020016103f2565b34801561062557600080fd5b50610609610634366004614202565b6113f0565b34801561064557600080fd5b506103e86115a2565b34801561065a57600080fd5b506103e861066936600461436f565b61176f565b34801561067a57600080fd5b5061040e61191f565b34801561068f57600080fd5b506103e8611933565b3480156106a457600080fd5b5061040e611943565b3480156106b957600080fd5b50600854610567906001600160a01b031681565b3480156106d957600080fd5b50600b54600a5411610609565b3480156106f257600080fd5b506000546001600160a01b0316610567565b34801561071057600080fd5b5061040e61071f366004614202565b6119ba565b34801561073057600080fd5b5061040e611a84565b34801561074557600080fd5b5061060961075436600461421b565b60026020526000908152604090205460ff1681565b34801561077557600080fd5b506103e8611b46565b34801561078a57600080fd5b5061040e61079936600461421b565b611b62565b3480156107aa57600080fd5b506106096107b9366004614202565b611bba565b3480156107ca57600080fd5b5061040e6107d936600461421b565b611cad565b3480156107ea57600080fd5b506105677f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561081e57600080fd5b5061040e61082d36600461421b565b611d05565b61040e610840366004614391565b611d3f565b34801561085157600080fd5b5061040e611dcc565b34801561086657600080fd5b5061040e6108753660046142dd565b611ddc565b34801561088657600080fd5b506103e8611dfc565b34801561089b57600080fd5b5061040e6108aa366004614419565b611e0c565b3480156108bb57600080fd5b506108cf6108ca366004614202565b611e1f565b6040516103f2929190614508565b3480156108e957600080fd5b5061040e611f3e565b3480156108fe57600080fd5b506103e8600b5481565b34801561091457600080fd5b5061040e610923366004614521565b612084565b34801561093457600080fd5b5061047261094336600461436f565b6120e1565b34801561095457600080fd5b5061040e610963366004614555565b612434565b34801561097457600080fd5b5061040e61098336600461436f565b612447565b34801561099457600080fd5b5061040e6109a336600461421b565b6124a5565b3480156109b457600080fd5b506103e86109c336600461436f565b612503565b3480156109d457600080fd5b506001546001600160a01b0316610567565b3480156109f257600080fd5b5061040e610a013660046145cc565b6126b6565b348015610a1257600080fd5b5061040e610a21366004614202565b6126c9565b348015610a3257600080fd5b506103e8610a41366004614202565b612b4a565b348015610a5257600080fd5b50600754610567906001600160a01b031681565b348015610a7257600080fd5b50600354600454600554610a93926001600160a01b03908116928116911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016103f2565b348015610ac957600080fd5b5061040e610ad836600461421b565b612cec565b348015610ae957600080fd5b5061040e610af83660046146df565b612d5d565b348015610b0957600080fd5b50610b12612d70565b6040516103f292919061470b565b348015610b2c57600080fd5b506103e8610b3b3660046142dd565b612e66565b348015610b4c57600080fd5b506103e8600a5481565b348015610b6257600080fd5b50610609612ed4565b348015610b7757600080fd5b5061040e610b8636600461421b565b612ef2565b348015610b9757600080fd5b5061040e610ba6366004614730565b612f12565b348015610bb757600080fd5b5060408051808201825260058152640312e302e360dc1b602082015290516103f291906147cc565b600754604080516318891fd760e31b815290516000926001600160a01b03169163c448feb89160048083019260209291908290030181865afa158015610c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4d91906147df565b905090565b610c5a613160565b8483148015610c6857508481145b610cb95760405162461bcd60e51b815260206004820152601960248201527f417267756d656e7473206c656e677468206d69736d617463680000000000000060448201526064015b60405180910390fd5b60005b85811015610dbf57600080888884818110610cd957610cd96147f8565b9050602002016020810190610cee919061421b565b6001600160a01b0316878785818110610d0957610d096147f8565b90506020020135868686818110610d2257610d226147f8565b9050602002810190610d34919061480e565b604051610d42929190614854565b60006040518083038185875af1925050503d8060008114610d7f576040519150601f19603f3d011682016040523d82523d6000602084013e610d84565b606091505b5091509150818190610da95760405162461bcd60e51b8152600401610cb091906147cc565b5050508080610db79061487a565b915050610cbc565b50505050505050565b6040805160018082528183019092526060916000919060208083019080368337505060045482519293506001600160a01b031691839150600090610e0e57610e0e6147f8565b6001600160a01b0390921660209283029190910190910152919050565b610e33613160565b610e3c816131ba565b50565b60008033610e556000546001600160a01b031690565b6001600160a01b03161480610e7957503360009081526002602052604090205460ff165b610e955760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b0316610ebd5760405162461bcd60e51b8152600401610cb0906148d9565b600b80549081906000610ecf8361487a565b9190505550610ede81856120e1565b909590945092505050565b60008033610eff6000546001600160a01b031690565b6001600160a01b03161480610f2357503360009081526002602052604090205460ff165b610f3f5760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b0316610f675760405162461bcd60e51b8152600401610cb0906148d9565b610f6f612ed4565b15610fa557600080610f816000610e3f565b9092509050610f9082856148f5565b9350610f9c81846148f5565b92505050610f67565b82811015610fda5760405162461bcd60e51b815260206004820152600260248201526115cd60f21b6044820152606401610cb0565b915091565b610fe7613160565b604051600181526001600160a01b038216907f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea29060200160405180910390a26001600160a01b03166000908152600260205260409020805460ff19166001179055565b611052613160565b604051600081526001600160a01b038216907f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea29060200160405180910390a26001600160a01b03166000908152600260205260409020805460ff19169055565b6110ba613160565b6003546001600160a01b03166110e25760405162461bcd60e51b8152600401610cb0906148d9565b6110ed838383613231565b505050565b6110fa613160565b61110682826000613370565b5050565b3361111d6000546001600160a01b031690565b6001600160a01b0316148061114157503360009081526002602052604090205460ff165b61115d5760405162461bcd60e51b8152600401610cb090614893565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d906024015b600060405180830381600087803b1580156111c057600080fd5b505af11580156111d4573d6000803e3d6000fd5b5050505050565b6111e3613160565b6001600160a01b03811661121e5760405162461bcd60e51b8152602060048201526002602482015261433160f01b6044820152606401610cb0565b611106828261345f565b6007546000908190819081906001600160a01b031663c978f7ac3061124b6134ab565b6040518363ffffffff1660e01b815260040161126892919061490d565b600060405180830381865afa158015611285573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112ad919081019061498c565b91509150816000815181106112c4576112c46147f8565b6020026020010151816000815181106112df576112df6147f8565b60200260200101519350935050509091565b6112f9613160565b600880546001600160a01b0319166001600160a01b03831690811790915560405190815233907fafb362edf254e5d46e9172b334f951e466253596d8960dae0876b7727b528bcf906020015b60405180910390a250565b6000336113656000546001600160a01b031690565b6001600160a01b0316148061138957503360009081526002602052604090205460ff165b6113a55760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b03166113cd5760405162461bcd60e51b8152600401610cb0906148d9565b6113df670de0b6b3a76400008361176f565b90505b919050565b6000610c4d600b545b600081815260096020908152604080832081516060810183528154815260018201805484518187028101870190955280855286959294858401939092919083018282801561146757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611449575b50505091835250506040805160e0810182526002840180546001600160a01b0390811683526003860154811660208481019190915260048701549091168385015260058601546060840152600686015463ffffffff166080840152600786018054855181840281018401909652808652958201959394929360a08601939283018282801561151e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611500575b505050505081526020016006820180548060200260200160405190810160405280929190818152602001828054801561157657602002820191906000526020600020905b815481526020019060010190808311611562575b50505050508152505081525050905061158e83611bba565b801561159b575080514310155b9392505050565b600b546000905b600a5481101561176b5760008181526009602090815260409182902082516060810184528154815260018201805485518186028101860190965280865261174d9592948581019392919083018282801561162c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161160e575b50505091835250506040805160e0810182526002840180546001600160a01b0390811683526003860154811660208481019190915260048701549091168385015260058601546060840152600686015463ffffffff166080840152600786018054855181840281018401909652808652958201959394929360a0860193928301828280156116e357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116c5575b505050505081526020016006820180548060200260200160405190810160405280929190818152602001828054801561173b57602002820191906000526020600020905b815481526020019060010190808311611727575b50505050508152505081525050613510565b61175790836148f5565b9150806117638161487a565b9150506115a9565b5090565b6000336117846000546001600160a01b031690565b6001600160a01b031614806117a857503360009081526002602052604090205460ff165b6117c45760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b03166117ec5760405162461bcd60e51b8152600401610cb0906148d9565b670de0b6b3a76400008311156118295760405162461bcd60e51b8152602060048201526002602482015261503160f01b6044820152606401610cb0565b6000831561185157600061184461183e611933565b8661368f565b905061184f816126c9565b505b61185a83610ee9565b925090506000611868610dc8565b9050600081516001600160401b0381111561188557611885613f40565b6040519080825280602002602001820160405280156118ae578160200160208202803683370190505b50905083816000815181106118c5576118c56147f8565b602002602001018181525050336001600160a01b03167f5ee5e243dcd2dfdba09d22c56585c4a3fcc188b1689ef919b3f8b908a73184c283838660405161190e939291906149ef565b60405180910390a250505092915050565b611927613160565b61193160006136ae565b565b600061193d611228565b92915050565b60015433906001600160a01b031681146119b15760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610cb0565b610e3c816136ae565b336119cd6000546001600160a01b031690565b6001600160a01b031614806119f157503360009081526002602052604090205460ff165b611a0d5760405162461bcd60e51b8152600401610cb090614893565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611a6857600080fd5b505af1158015611a7c573d6000803e3d6000fd5b505050505050565b33611a976000546001600160a01b031690565b6001600160a01b03161480611abb57503360009081526002602052604090205460ff165b611ad75760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b0316611aff5760405162461bcd60e51b8152600401610cb0906148d9565b6000611b09611b46565b90508015611b3e5760405162461bcd60e51b8152602060048201526002602482015261553160f01b6044820152606401610cb0565b610e3c6136c7565b6000611b506115a2565b611b58611dfc565b610c4d91906148f5565b611b6a613160565b600780546001600160a01b0319166001600160a01b03831690811790915560405190815233907f911dc338bce1f8de008a6f5b4152fedfd569ddfa81e9cf39ec5a184973d2e87290602001611345565b6007546000828152600960205260408082209051632cbd9b6d60e11b8152919283926001600160a01b039091169163597b36da91611bfe9160020190600401614a98565b602060405180830381865afa158015611c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3f91906147df565b600754604051635bf8375f60e11b8152600481018390529192506001600160a01b03169063b7f06ebe90602401602060405180830381865afa158015611c89573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b9190614b3d565b611cb5613160565b600680546001600160a01b0319166001600160a01b03831690811790915560405190815233907f91bb70ab6663d2e4daa4cf09d675f7d8521a09519b2865cc11f2f97314fa1aab90602001611345565b611d0d613160565b60085460405163a0169ddd60e01b81526001600160a01b0383811660048301529091169063a0169ddd906024016111a6565b611d47613160565b600080856001600160a01b0316858585604051611d65929190614854565b60006040518083038185875af1925050503d8060008114611da2576040519150601f19603f3d011682016040523d82523d6000602084013e611da7565b606091505b5091509150818190610dbf5760405162461bcd60e51b8152600401610cb091906147cc565b611dd4613160565b6119316136c7565b611de4613160565b6000611def83613739565b90506110ed83828461375f565b6000611e06611228565b50919050565b611e14613160565b6110ed83838361375f565b6009602090815260009182526040918290208054835160e0810185526002830180546001600160a01b03908116835260038501548116838701526004850154168287015260058401546060830152600684015463ffffffff166080830152600784018054875181880281018801909852808852939694959294919360a0860193830182828015611ed857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611eba575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020018280548015611f3057602002820191906000526020600020905b815481526020019060010190808311611f1c575b505050505081525050905082565b33611f516000546001600160a01b031690565b6001600160a01b03161480611f7557503360009081526002602052604090205460ff165b611f915760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b0316611fb95760405162461bcd60e51b8152600401610cb0906148d9565b6007546005546040516301e6f5af60e51b81526001600160a01b0391821660048201526000929190911690633cdeb5e090602401602060405180830381865afa15801561200a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202e9190614b65565b6001600160a01b03161461206a5760405162461bcd60e51b815260206004820152600360248201526222261960e91b6044820152606401610cb0565b604080516000808252602082019092526119319180613231565b336120976000546001600160a01b031690565b6001600160a01b031614806120bb57503360009081526002602052604090205460ff165b6120d75760405162461bcd60e51b8152600401610cb090614893565b610e3c813061345f565b600080336120f76000546001600160a01b031690565b6001600160a01b0316148061211b57503360009081526002602052604090205460ff165b6121375760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b031661215f5760405162461bcd60e51b8152600401610cb0906148d9565b612168846113f0565b6121995760405162461bcd60e51b81526020600482015260026024820152612b9960f11b6044820152606401610cb0565b6000848152600960209081526040808320815160608101835281548152600182018054845181870281018701909552808552919492938584019390929083018282801561220f57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116121f1575b50505091835250506040805160e0810182526002840180546001600160a01b0390811683526003860154811660208481019190915260048701549091168385015260058601546060840152600686015463ffffffff166080840152600786018054855181840281018401909652808652958201959394929360a0860193928301828280156122c657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122a8575b505050505081526020016006820180548060200260200160405190810160405280929190818152602001828054801561231e57602002820191906000526020600020905b81548152602001906001019080831161230a575b50505050508152505081525050905060008160200151600081518110612346576123466147f8565b60200260200101519050600061235b82613739565b9050612371836040015184602001516001613917565b61237a83613510565b94508061238683613739565b6123909190614b82565b9350858410156123c75760405162461bcd60e51b8152602060048201526002602482015261573360f01b6044820152606401610cb0565b60408084015160609081015182516001600160a01b0386168152602081019190915291820189905281018590526080810186905233907f7ff9a08662c21e17b8071f3aef03a9712ea9d3824dfb0139bba272915d59a9199060a00160405180910390a25050509250929050565b61243c613160565b6110ed838383613370565b3361245a6000546001600160a01b031690565b6001600160a01b0316148061247e57503360009081526002602052604090205460ff165b61249a5760405162461bcd60e51b8152600401610cb090614893565b600a91909155600b55565b6124ad613160565b6001600160a01b0381166119b15760405162461bcd60e51b815260206004820152601860248201527f4954424f776e61626c653a207a65726f206164647265737300000000000000006044820152606401610cb0565b6000336125186000546001600160a01b031690565b6001600160a01b0316148061253c57503360009081526002602052604090205460ff165b6125585760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b03166125805760405162461bcd60e51b8152600401610cb0906148d9565b604080516060810182526003546001600160a01b039081168083526004805483166020850181905260055484168587015260065495516373d0285560e11b8152918201929092526024810191909152604481018790529192169063e7a050aa906064016020604051808303816000875af1158015612602573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262691906147df565b91508282101561265d5760405162461bcd60e51b8152602060048201526002602482015261443160f01b6044820152606401610cb0565b602081810151604080516001600160a01b03909216825291810186905290810183905233907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79060600160405180910390a25092915050565b6126be613160565b6110ed838383613917565b336126dc6000546001600160a01b031690565b6001600160a01b0316148061270057503360009081526002602052604090205460ff165b61271c5760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b03166127445760405162461bcd60e51b8152600401610cb0906148d9565b8015610e3c57604080516060810182526003546001600160a01b0390811682526004805482166020840152600554821683850152600754935163285e212160e21b81523091810191909152919260009291169063a178848490602401602060405180830381865afa1580156127bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e191906147df565b905060006127ed610bdf565b6127f790436148f5565b600a80549192508190600061280b8361487a565b9091555050604080516001808252818301909252600091602080830190803683370190505090508581600081518110612846576128466147f8565b6020908102919091010152604080516001808252818301909252600091816020015b6040805160608082018352808252602082015260009181019190915281526020019060019003908161286857905050905060405180606001604052806128ac6134ab565b8152602001838152602001306001600160a01b0316815250816000815181106128d7576128d76147f8565b60200260200101819052506128eb816131ba565b505060408051600180825281830190925260009160208083019080368337019050509050846020015181600081518110612927576129276147f8565b6001600160a01b039283166020918202929092010152600754604051635dd6857960e01b81523060048201526000929190911690635dd6857990602401600060405180830381865afa158015612981573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129a99190810190614c87565b509050600081600183516129bd9190614b82565b815181106129cd576129cd6147f8565b6020908102919091018101516040805160608101825288815280840187815281830184905260008981526009865292909220815181559151805193955090939192612a1e9260018501920190613d54565b5060408281015180516002840180546001600160a01b03199081166001600160a01b0393841617825560208085015160038801805484169186169190911790559484015160048701805490921693169290921790915560608201516005850155608082015160068501805463ffffffff191663ffffffff90921691909117905560a0820151805192939192612ab99260078701920190613d54565b5060c08201518051612ad5916006840191602090910190613db5565b50505050602088810151604080516001600160a01b0390921682529181018990529081018690524360608201526080810187905260a081018a90523391507f17dfe68c8ee816770434a4224e165c9a95c518c75f02669e3379f365f469986d9060c00160405180910390a25050505050505050565b600033612b5f6000546001600160a01b031690565b6001600160a01b03161480612b8357503360009081526002602052604090205460ff165b612b9f5760405162461bcd60e51b8152600401610cb090614893565b6003546001600160a01b0316612bc75760405162461bcd60e51b8152600401610cb0906148d9565b604080516060810182526003546001600160a01b0390811682526004548116602083018190526005549091169282019290925290600090612c0790613739565b9050612c138185612503565b92506000612c1f610dc8565b9050600081516001600160401b03811115612c3c57612c3c613f40565b604051908082528060200260200182016040528015612c65578160200160208202803683370190505b509050612c758460200151613739565b612c7f9084614b82565b81600081518110612c9257612c926147f8565b602002602001018181525050336001600160a01b03167fe5b4fe1f78fdb60a80c1256020410f15f10c5d037dd186e02089696655ddfa39838388604051612cdb939291906149ef565b60405180910390a250505050919050565b612cf4613160565b600180546001600160a01b0383166001600160a01b03199091168117909155612d256000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b612d65613160565b61110682823361375f565b6060806000612d7d610dc8565b9050600081516001600160401b03811115612d9a57612d9a613f40565b604051908082528060200260200182016040528015612dc3578160200160208202803683370190505b506003549091506001600160a01b031663f3e73875612de0611b46565b6040518263ffffffff1660e01b8152600401612dfe91815260200190565b602060405180830381865afa158015612e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3f91906147df565b81600081518110612e5257612e526147f8565b602090810291909101015290939092509050565b6040516370a0823160e01b81526001600160a01b038281166004830152600091908416906370a0823190602401602060405180830381865afa158015612eb0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b91906147df565b6000612ee3600b54600a541190565b8015610c4d5750610c4d6113e7565b612efa613160565b6000612f0582613739565b905061110682823361375f565b612f1a613160565b816001600160a01b0316836001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f869190614b65565b6001600160a01b031614612fc25760405162461bcd60e51b815260206004820152600360248201526250433160e81b6044820152606401610cb0565b6001600160a01b038116158061304157506007546040516336b87bd760e11b81526001600160a01b03838116600483015290911690636d70f7ae90602401602060405180830381865afa15801561301d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130419190614b3d565b6130735760405162461bcd60e51b815260206004820152600360248201526228219960e91b6044820152606401610cb0565b60408051606080820183526001600160a01b038681168084528682166020808601829052928716948601859052600380546001600160a01b031990811684179091556004805482168317905560058054909116861790558551918252918101919091529283019190915233917fa064094fafea249409dec234759afc29f8418d4e18ef4bd31e763787f6e9daee91015b60405180910390a2505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b031633146119315760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cb0565b6007546040516306ec6e8160e11b81526001600160a01b0390911690630dd8dd02906131ea908490600401614dfc565b6000604051808303816000875af1158015613209573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111069190810190614e96565b6005546001600160a01b0316806132705760405162461bcd60e51b8152602060048201526003602482015262444c3160e81b6044820152606401610cb0565b600754604051631976849960e21b81523060048201526000916001600160a01b0316906365da126490602401602060405180830381865afa1580156132b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132dd9190614b65565b6001600160a01b0316146132f3576132f3611a84565b60075460408051808201825286815260208101869052905163eea9064b60e01b81526001600160a01b039092169163eea9064b91613338918591908790600401614f1b565b600060405180830381600087803b15801561335257600080fd5b505af1158015613366573d6000803e3d6000fd5b5050505050505050565b801561340857604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015282919085169063dd62ed3e90604401602060405180830381865afa1580156133c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e991906147df565b106133f357505050565b6134086001600160a01b038416836000613979565b61341c6001600160a01b0384168383613979565b604080516001600160a01b038481168252602082018490528516917feded619173dbb378903f97d44ecec898a1c4876f445ae551e063113aef58b4719101613103565b600854604051633ccc861d60e01b81526001600160a01b0390911690633ccc861d90613491908590859060040161515b565b600060405180830381600087803b158015611a6857600080fd5b60408051600180825281830190925260609160208083019080368337505060035482519293506001600160a01b0316918391506000906134ed576134ed6147f8565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b600080600760009054906101000a90046001600160a01b03166001600160a01b031663ca8aa7c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015613566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358a9190614b65565b90506000816001600160a01b03166394d7d00c8560400151602001516135ae6134ab565b87516040516001600160e01b031960e086901b1681526135d393929190600401615258565b600060405180830381865afa1580156135f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136189190810190615292565b9050670de0b6b3a76400006001600160401b03168160008151811061363f5761363f6147f8565b60200260200101516001600160401b0316856040015160c0015160008151811061366b5761366b6147f8565b602002602001015161367d9190615336565b6136879190615355565b949350505050565b6000670de0b6b3a76400006136a48385615336565b61159b9190615355565b600180546001600160a01b0319169055610e3c81613110565b6007546040516336a2fa1960e21b81523060048201526001600160a01b039091169063da8be864906024016000604051808303816000875af1158015613711573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e3c9190810190614e96565b60006001600160a01b038216156137585761375382613ac1565b6113df565b4792915050565b6001600160a01b0381166137a75760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610cb0565b60006137b284613739565b9050828110156137f95760405162461bcd60e51b8152602060048201526012602482015271496e73756666696369656e742066756e647360701b6044820152606401610cb0565b6001600160a01b0384166138b0576000826001600160a01b03168460405160006040518083038185875af1925050503d8060008114613854576040519150601f19603f3d011682016040523d82523d6000602084013e613859565b606091505b50509050806138aa5760405162461bcd60e51b815260206004820152601760248201527f4e6174697665207472616e73666572206661696c65642e0000000000000000006044820152606401610cb0565b506138c4565b6138c46001600160a01b0385168385613b2c565b836001600160a01b0316826001600160a01b03167f9207361cc2a04b9c7a06691df1eb87c6a63957ae88bf01d0d18c81e3d12720998560405161390991815260200190565b60405180910390a350505050565b600754604051630e4cc3f960e41b81526001600160a01b039091169063e4cc3f909061394b90869086908690600401615377565b600060405180830381600087803b15801561396557600080fd5b505af1158015610dbf573d6000803e3d6000fd5b8015806139f35750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156139cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f191906147df565b155b613a5e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610cb0565b6040516001600160a01b0383166024820152604481018290526110ed90849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613b5c565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613b08573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df91906147df565b6040516001600160a01b0383166024820152604481018290526110ed90849063a9059cbb60e01b90606401613a8a565b6000613bb1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613c319092919063ffffffff16565b9050805160001480613bd2575080806020019051810190613bd29190614b3d565b6110ed5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cb0565b6060613687848460008585600080866001600160a01b03168587604051613c5891906153af565b60006040518083038185875af1925050503d8060008114613c95576040519150601f19603f3d011682016040523d82523d6000602084013e613c9a565b606091505b5091509150613cab87838387613cb6565b979650505050505050565b60608315613d25578251600003613d1e576001600160a01b0385163b613d1e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb0565b5081613687565b6136878383815115613d3a5781518083602001fd5b8060405162461bcd60e51b8152600401610cb091906147cc565b828054828255906000526020600020908101928215613da9579160200282015b82811115613da957825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613d74565b5061176b929150613df0565b828054828255906000526020600020908101928215613da9579160200282015b82811115613da9578251825591602001919060010190613dd5565b5b8082111561176b5760008155600101613df1565b60008083601f840112613e1757600080fd5b5081356001600160401b03811115613e2e57600080fd5b6020830191508360208260051b8501011115613e4957600080fd5b9250929050565b60008060008060008060608789031215613e6957600080fd5b86356001600160401b0380821115613e8057600080fd5b613e8c8a838b01613e05565b90985096506020890135915080821115613ea557600080fd5b613eb18a838b01613e05565b90965094506040890135915080821115613eca57600080fd5b50613ed789828a01613e05565b979a9699509497509295939492505050565b600081518084526020808501945080840160005b83811015613f225781516001600160a01b031687529582019590820190600101613efd565b509495945050505050565b60208152600061159b6020830184613ee9565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613f7857613f78613f40565b60405290565b60405160e081016001600160401b0381118282101715613f7857613f78613f40565b604051601f8201601f191681016001600160401b0381118282101715613fc857613fc8613f40565b604052919050565b60006001600160401b03821115613fe957613fe9613f40565b5060051b60200190565b6001600160a01b0381168114610e3c57600080fd5b80356113e281613ff3565b600082601f83011261402457600080fd5b8135602061403961403483613fd0565b613fa0565b82815260059290921b8401810191818101908684111561405857600080fd5b8286015b8481101561407c57803561406f81613ff3565b835291830191830161405c565b509695505050505050565b600082601f83011261409857600080fd5b813560206140a861403483613fd0565b82815260059290921b840181019181810190868411156140c757600080fd5b8286015b8481101561407c57803583529183019183016140cb565b600060208083850312156140f557600080fd5b82356001600160401b038082111561410c57600080fd5b818501915085601f83011261412057600080fd5b813561412e61403482613fd0565b81815260059190911b8301840190848101908883111561414d57600080fd5b8585015b838110156141f5578035858111156141695760008081fd5b86016060818c03601f19018113156141815760008081fd5b614189613f56565b898301358881111561419b5760008081fd5b6141a98e8c83870101614013565b825250604080840135898111156141c05760008081fd5b6141ce8f8d83880101614087565b838d01525092820135926141e184613ff3565b810192909252508352918601918601614151565b5098975050505050505050565b60006020828403121561421457600080fd5b5035919050565b60006020828403121561422d57600080fd5b813561159b81613ff3565b60008060006060848603121561424d57600080fd5b83356001600160401b038082111561426457600080fd5b818601915086601f83011261427857600080fd5b813560208282111561428c5761428c613f40565b61429e601f8301601f19168201613fa0565b925081835288818386010111156142b457600080fd5b818185018285013760009183018101919091529097908601359650604090950135949350505050565b600080604083850312156142f057600080fd5b82356142fb81613ff3565b9150602083013561430b81613ff3565b809150509250929050565b60006101008284031215611e0657600080fd5b6000806040838503121561433c57600080fd5b82356001600160401b0381111561435257600080fd5b61435e85828601614316565b925050602083013561430b81613ff3565b6000806040838503121561438257600080fd5b50508035926020909101359150565b600080600080606085870312156143a757600080fd5b84356143b281613ff3565b93506020850135925060408501356001600160401b03808211156143d557600080fd5b818701915087601f8301126143e957600080fd5b8135818111156143f857600080fd5b88602082850101111561440a57600080fd5b95989497505060200194505050565b60008060006060848603121561442e57600080fd5b833561443981613ff3565b925060208401359150604084013561445081613ff3565b809150509250925092565b600081518084526020808501945080840160005b83811015613f225781518752958201959082019060010161446f565b600060018060a01b03808351168452806020840151166020850152806040840151166040850152506060820151606084015263ffffffff608083015116608084015260a082015160e060a08501526144e660e0850182613ee9565b905060c083015184820360c08601526144ff828261445b565b95945050505050565b828152604060208201526000613687604083018461448b565b60006020828403121561453357600080fd5b81356001600160401b0381111561454957600080fd5b61368784828501614316565b60008060006060848603121561456a57600080fd5b833561457581613ff3565b9250602084013561458581613ff3565b929592945050506040919091013590565b63ffffffff81168114610e3c57600080fd5b80356113e281614596565b8015158114610e3c57600080fd5b80356113e2816145b3565b6000806000606084860312156145e157600080fd5b83356001600160401b03808211156145f857600080fd5b9085019060e0828803121561460c57600080fd5b614614613f7e565b61461d83614008565b815261462b60208401614008565b602082015261463c60408401614008565b604082015260608301356060820152614657608084016145a8565b608082015260a08301358281111561466e57600080fd5b61467a89828601614013565b60a08301525060c08301358281111561469257600080fd5b61469e89828601614087565b60c083015250945060208601359150808211156146ba57600080fd5b506146c786828701614013565b9250506146d6604085016145c1565b90509250925092565b600080604083850312156146f257600080fd5b82356146fd81613ff3565b946020939093013593505050565b60408152600061471e6040830185613ee9565b82810360208401526144ff818561445b565b60008060006060848603121561474557600080fd5b833561475081613ff3565b9250602084013561476081613ff3565b9150604084013561445081613ff3565b60005b8381101561478b578181015183820152602001614773565b8381111561479a576000848401525b50505050565b600081518084526147b8816020860160208601614770565b601f01601f19169290920160200192915050565b60208152600061159b60208301846147a0565b6000602082840312156147f157600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261482557600080fd5b8301803591506001600160401b0382111561483f57600080fd5b602001915036819003821315613e4957600080fd5b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b60006001820161488c5761488c614864565b5060010190565b60208082526026908201527f45786563757461626c653a2063616c6c6572206973206e6f742074686520657860408201526532b1baba37b960d11b606082015260800190565b602080825260029082015261413360f01b604082015260600190565b6000821982111561490857614908614864565b500190565b6001600160a01b038316815260406020820181905260009061368790830184613ee9565b600082601f83011261494257600080fd5b8151602061495261403483613fd0565b82815260059290921b8401810191818101908684111561497157600080fd5b8286015b8481101561407c5780518352918301918301614975565b6000806040838503121561499f57600080fd5b82516001600160401b03808211156149b657600080fd5b6149c286838701614931565b935060208501519150808211156149d857600080fd5b506149e585828601614931565b9150509250929050565b606081526000614a026060830186613ee9565b8281036020840152614a14818661445b565b915050826040830152949350505050565b6000815480845260208085019450836000528060002060005b83811015613f225781546001600160a01b031687529582019560019182019101614a3e565b6000815480845260208085019450836000528060002060005b83811015613f2257815487529582019560019182019101614a7c565b60208152614ac160208201614ab484546001600160a01b031690565b6001600160a01b03169052565b6000614ad760018401546001600160a01b031690565b6001600160a01b039081166040840152600284015416606083015260038301546080830152600483015463ffffffff1660a083015260e060c0830152614b24610100830160058501614a25565b828103601f190160e08401526136878160068601614a63565b600060208284031215614b4f57600080fd5b815161159b816145b3565b80516113e281613ff3565b600060208284031215614b7757600080fd5b815161159b81613ff3565b600082821015614b9457614b94614864565b500390565b80516113e281614596565b600082601f830112614bb557600080fd5b81516020614bc561403483613fd0565b82815260059290921b84018101918181019086841115614be457600080fd5b8286015b8481101561407c578051614bfb81613ff3565b8352918301918301614be8565b600082601f830112614c1957600080fd5b81516020614c2961403483613fd0565b82815260059290921b84018101918181019086841115614c4857600080fd5b8286015b8481101561407c5780516001600160401b03811115614c6b5760008081fd5b614c798986838b0101614931565b845250918301918301614c4c565b60008060408385031215614c9a57600080fd5b82516001600160401b0380821115614cb157600080fd5b818501915085601f830112614cc557600080fd5b81516020614cd561403483613fd0565b82815260059290921b84018101918181019089841115614cf457600080fd5b8286015b84811015614dd557805186811115614d0f57600080fd5b870160e0818d03601f19011215614d2557600080fd5b614d2d613f7e565b614d38868301614b5a565b8152614d4660408301614b5a565b86820152614d5660608301614b5a565b604082015260808201516060820152614d7160a08301614b99565b608082015260c08083015189811115614d8a5760008081fd5b614d988f8983870101614ba4565b60a08401525060e083015189811115614db15760008081fd5b614dbf8f8983870101614931565b9183019190915250845250918301918301614cf8565b5091880151919650909350505080821115614def57600080fd5b506149e585828601614c08565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614e8857603f19898403018552815160608151818652614e4982870182613ee9565b915050888201518582038a870152614e61828261445b565b928901516001600160a01b0316958901959095525094870194925090860190600101614e23565b509098975050505050505050565b60006020808385031215614ea957600080fd5b82516001600160401b03811115614ebf57600080fd5b8301601f81018513614ed057600080fd5b8051614ede61403482613fd0565b81815260059190911b82018301908381019087831115614efd57600080fd5b928401925b82841015613cab57835182529284019290840190614f02565b60018060a01b0384168152606060208201526000835160406060840152614f4560a08401826147a0565b602095909501516080840152505060400152919050565b6000808335601e19843603018112614f7357600080fd5b83016020810192503590506001600160401b03811115614f9257600080fd5b803603821315613e4957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8035614fd581613ff3565b6001600160a01b03168252602090810135910152565b6000808335601e1984360301811261500257600080fd5b83016020810192503590506001600160401b0381111561502157600080fd5b8060051b3603821315613e4957600080fd5b8183526000602080850194508260005b85811015613f2257813561505681614596565b63ffffffff1687529582019590820190600101615043565b81835260006020808501808196508560051b810191508460005b878110156150be57828403895261509f8288614f5c565b6150aa868284614fa1565b9a87019a9550505090840190600101615088565b5091979650505050505050565b6000808335601e198436030181126150e257600080fd5b83016020810192503590506001600160401b0381111561510157600080fd5b8060061b3603821315613e4957600080fd5b8183526000602080850194508260005b85811015613f2257813561513681613ff3565b6001600160a01b03168752818301358388015260409687019690910190600101615123565b604081526000833561516c81614596565b63ffffffff166040830152615183602085016145a8565b63ffffffff16606083015261519b6040850185614f5c565b6101008060808601526151b361014086018385614fa1565b92506151c560a0860160608901614fca565b6151d260a0880188614feb565b9250603f19808786030160e08801526151ec858584615033565b94506151fb60c08a018a614feb565b9450915080878603018388015261521385858461506e565b945061522260e08a018a6150cb565b945092508087860301610120880152505061523e838383615113565b935050505061159b60208301846001600160a01b03169052565b6001600160a01b038416815260606020820181905260009061527c90830185613ee9565b905063ffffffff83166040830152949350505050565b600060208083850312156152a557600080fd5b82516001600160401b03808211156152bc57600080fd5b818501915085601f8301126152d057600080fd5b81516152de61403482613fd0565b81815260059190911b830184019084810190888311156152fd57600080fd5b938501935b8285101561532a578451848116811461531b5760008081fd5b82529385019390850190615302565b98975050505050505050565b600081600019048311821515161561535057615350614864565b500290565b60008261537257634e487b7160e01b600052601260045260246000fd5b500490565b60608152600061538a606083018661448b565b828103602084015261539c8186613ee9565b9150508215156040830152949350505050565b600082516153c1818460208701614770565b919091019291505056fea2646970667358221220647c62e02daa99450d6136695307a1edbcc346967a9a9cfaac199edb84ae84cf64736f6c634300080f0033
Verified Source Code Partial Match
Compiler: v0.8.15+commit.e14f2714
EVM: london
Optimization: Yes (200 runs)
ITBContract.sol 93 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.0;
import './utils/Withdrawable.sol';
import './utils/IWETH.sol';
/// @title ITBContract contract that implements common owner only functions accross all strategies
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract ITBContract is Withdrawable {
using SafeERC20 for IERC20;
event ApproveToken(address indexed token, address guy, uint256 wad);
address payable immutable public WNATIVE;
uint constant ONE = 1e18;
/// @param _executors Executor addresses
constructor(address[] memory _executors, address payable _wnative) Executable(_executors) {
WNATIVE = _wnative;
}
function _percentageAmount(uint _amount, uint _percentage) internal pure returns (uint) {
return _amount * _percentage / ONE;
}
/// @notice Set allowance for a given token, amount and spender
/// @param _token Token to spend
/// @param _guy Spender
/// @param _wad Max amount to spend
function _approveToken(address _token, address _guy, uint256 _wad) internal {
if (_wad != 0) {
if (IERC20(_token).allowance(address(this), _guy) >= _wad)
return;
IERC20(_token).safeApprove(_guy, 0);
}
IERC20(_token).safeApprove(_guy, _wad);
emit ApproveToken(_token, _guy, _wad);
}
/// @notice Check current allowance and, if necessary, set it to a new amount for a given token, amount and spender
/// @param _token Token to spend
/// @param _guy Spender
/// @param _amount New max amount to spend
function _checkAllowanceAndApprove(address _token, address _guy, uint256 _amount) internal {
if (IERC20(_token).allowance(address(this), _guy) < _amount)
_approveToken(_token, _guy, type(uint256).max);
}
/// @notice Only owner. Set allowance for a given token, amount and spender
/// @param _token Token to spend
/// @param _guy Spender
/// @param _wad Max amount to spend
function approveToken(address _token, address _guy, uint256 _wad) external onlyOwner {
_approveToken(_token, _guy, _wad);
}
/// @notice Only owner. Revoke allowance for a given token and spender
/// @param _token Token to spend
/// @param _guy Spender
function revokeToken(address _token, address _guy) external onlyOwner {
_approveToken(_token, _guy, 0);
}
/// @notice Only owner. Execute an arbitrary call
/// @param _to Target address
/// @param _value Value (i. e. msg.value)
/// @param _data Invocation data
function execute(address _to, uint256 _value, bytes calldata _data) external payable onlyOwner {
(bool success, bytes memory returnData) = _to.call{ value: _value }(_data);
require(success, string(returnData));
}
/// @notice Only owner. Execute multiple arbitrary calls in order
/// @param _tos Target address for each call
/// @param _values Value for each call (i. e. msg.value)
/// @param _datas Invocation data for each call
function batchExecute(address[] calldata _tos, uint256[] calldata _values, bytes[] calldata _datas) external payable onlyOwner {
require(_tos.length == _values.length && _tos.length == _datas.length, "Arguments length mismatch");
for (uint256 i = 0; i < _tos.length; i++) {
(bool success, bytes memory returnData) = _tos[i].call{ value: _values[i] }(_datas[i]);
require(success, string(returnData));
}
}
function wrapNative(uint256 _amount) public onlyExecutor {
IWETH(WNATIVE).deposit{ value: _amount }();
}
function unwrapNative(uint256 _amount) public onlyExecutor {
IWETH(WNATIVE).withdraw(_amount);
}
}
Executable.sol 40 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
/// @title Base contract that implements executor related functions
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract Executable is Ownable2Step {
mapping(address => bool) public executors;
event ExecutorUpdated(address indexed executor, bool enabled);
/// @param _executors Initial whitelisted executor addresses
constructor(address[] memory _executors) {
for (uint256 i = 0; i < _executors.length; i++) {
addExecutor(_executors[i]);
}
}
/// @notice Revert if call is not being made from the owner or an executor
modifier onlyExecutor() {
require(owner() == msg.sender || executors[msg.sender], "Executable: caller is not the executor");
_;
}
/// @notice Only owner. Add an executor
/// @param _executor New executor address
function addExecutor(address _executor) public onlyOwner {
emit ExecutorUpdated(_executor, true);
executors[_executor] = true;
}
/// @notice Only owner. Remove an executor
/// @param _executor Executor address to remove
function removeExecutor(address _executor) external onlyOwner {
emit ExecutorUpdated(_executor, false);
executors[_executor] = false;
}
}
IWETH.sol 25 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IWETH {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
event Approval(address indexed src, address indexed guy, uint256 wad);
event Transfer(address indexed src, address indexed dst, uint256 wad);
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function balanceOf(address) external view returns (uint256);
function allowance(address, address) external view returns (uint256);
fallback() external payable;
receive() external payable;
function deposit() external payable;
function withdraw(uint256 wad) external;
function totalSupply() external view returns (uint256);
function approve(address guy, uint256 wad) external returns (bool);
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(address src, address dst, uint256 wad) external returns (bool);
}
Ownable2StepWithShortcut.sol 11 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
abstract contract Ownable2StepWithShortcut is Ownable2Step {
function transferOwnership1Step(address newOwner) public onlyOwner {
require(newOwner != address(0), "ITBOwnable: zero address");
_transferOwnership(newOwner);
}
}
Withdrawable.sol 92 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import './Executable.sol';
/**
Ensures that any contract that inherits from this contract is able to
withdraw funds that are accidentally received or stuck.
*/
/// @title Base contract that implements withdrawal related functions
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract Withdrawable is Executable {
using SafeERC20 for IERC20;
address constant ETHER = address(0);
event LogWithdraw(
address indexed _to,
address indexed _asset_address,
uint256 amount
);
receive() external payable {}
/// @notice ERC20 or ETH balance of this contract given a token address
/// @param _asset_address Token address or address(0) for ETH
/// @return Balance
function _balance(address _asset_address) internal view returns (uint256) {
return _asset_address == ETHER ? address(this).balance : _erc20Balance(_asset_address);
}
function _erc20Balance(address _asset_address) internal view returns (uint256) {
return IERC20(_asset_address).balanceOf(address(this));
}
/// @notice ERC20 balance of given account
/// @param _asset_address Token address
/// @param _account Account address
/// @return Balance
function balanceOf(address _asset_address, address _account) public view returns (uint256) {
return IERC20(_asset_address).balanceOf(_account);
}
/// @notice Send the given amount of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
/// @param _to Receiver address
function _withdraw_to(address _asset_address, uint256 _amount, address payable _to) internal {
require(_to != address(0), 'Invalid address');
uint256 balance = _balance(_asset_address);
require(balance >= _amount, 'Insufficient funds');
if (_asset_address == ETHER) {
(bool success, ) = _to.call{value: _amount}(''); /* carry gas over so it works with contracts with custom fallback, we dont care about reentrancy on onlyOwner */
require(success, 'Native transfer failed.');
} else
IERC20(_asset_address).safeTransfer(_to, _amount);
emit LogWithdraw(_to, _asset_address, _amount);
}
/// @notice Only owner. Send the given amount of the given token or ETH to the caller
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
function withdraw(address _asset_address, uint256 _amount) external onlyOwner {
_withdraw_to(_asset_address, _amount, payable(msg.sender));
}
/// @notice Only owner. Send the given amount of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
/// @param _to Receiver address
function withdrawTo(address _asset_address, uint256 _amount, address payable _to) external onlyOwner {
_withdraw_to(_asset_address, _amount, _to);
}
/// @notice Only owner. Send its entire balance of the given token or ETH to the caller
/// @param _asset_address Token address or address(0) for ETH
function withdrawAll(address _asset_address) external onlyOwner {
uint256 balance = _balance(_asset_address);
_withdraw_to(_asset_address, balance, payable(msg.sender));
}
/// @notice Only owner. Send its entire balance of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _to Receiver address
function withdrawAllTo(address _asset_address, address payable _to) external onlyOwner {
uint256 balance = _balance(_asset_address);
_withdraw_to(_asset_address, balance, _to);
}
}
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);
}
}
Ownable2Step.sol 57 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides 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} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
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);
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Context.sol 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;
}
}
IAllocationManager.sol 8 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
interface IAllocationManager {
function getMaxMagnitude(address operator, address strategy) external view returns (uint64);
function getMaxMagnitudesAtBlock(address operator, address[] memory strategies, uint32 blockNumber) external view returns (uint64[] memory);
}
IDelegation.sol 56 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
interface IDelegation {
struct QueuedWithdrawalParams {
address[] strategies;
uint256[] shares;
address withdrawer;
}
struct Withdrawal {
address staker;
address delegatedTo;
address withdrawer;
uint256 nonce;
uint32 startBlock;
address[] strategies;
uint256[] scaledShares;
}
struct SignatureWithExpiry {
bytes signature;
uint expiry;
}
function queueWithdrawals(QueuedWithdrawalParams[] memory) external returns (bytes32[] memory shares);
function minWithdrawalDelayBlocks() external view returns (uint256);
function delegatedTo(address) external view returns (address);
function delegateTo(address, SignatureWithExpiry memory, bytes32) external;
function undelegate(address) external returns (bytes32[] memory);
function cumulativeWithdrawalsQueued(address) external view returns (uint);
function completeQueuedWithdrawal(Withdrawal memory, address[] memory, bool) external;
function calculateWithdrawalRoot(Withdrawal memory) external pure returns (bytes32);
function pendingWithdrawals(bytes32) external view returns (bool);
function delegationApprover(address operator) external view returns (address);
function getQueuedWithdrawals(address staker) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares);
function getWithdrawableShares(address staker, address[] memory strategies) external view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares);
function allocationManager() external view returns (address);
function isOperator(address operator) external view returns (bool);
function calculateDelegationApprovalDigestHash(address staker, address operator, address approver, bytes32 approverSalt, uint256 expiry) external view returns (bytes32);
}
ILiquidStaking.sol 14 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
interface ILiquidStaking {
function sharesToUnderlying(uint) external view returns (uint256 shares);
function shares(address) external view returns (uint256 shares);
function totalShares() external view returns (uint256);
function underlyingToken() external view returns (address);
}
IRewardsCoordinator.sol 345 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
/**
* @title Interface for the `IRewardsCoordinator` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Allows AVSs to make "Rewards Submissions", which get distributed amongst the AVSs' confirmed
* Operators and the Stakers delegated to those Operators.
* Calculations are performed based on the completed RewardsSubmission, with the results posted in
* a Merkle root against which Stakers & Operators can make claims.
*/
interface IRewardsCoordinator {
/// STRUCTS ///
/**
* @notice A linear combination of strategies and multipliers for AVSs to weigh
* EigenLayer strategies.
* @param strategy The EigenLayer strategy to be used for the rewards submission
* @param multiplier The weight of the strategy in the rewards submission
*/
struct StrategyAndMultiplier {
address strategy;
uint96 multiplier;
}
/**
* Sliding Window for valid RewardsSubmission startTimestamp
*
* Scenario A: GENESIS_REWARDS_TIMESTAMP IS WITHIN RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <--------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
*
*
* Scenario B: GENESIS_REWARDS_TIMESTAMP IS OUT OF RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <------------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
* @notice RewardsSubmission struct submitted by AVSs when making rewards for their operators and stakers
* RewardsSubmission can be for a time range within the valid window for startTimestamp and must be within max duration.
* See `createAVSRewardsSubmission()` for more details.
* @param strategiesAndMultipliers The strategies and their relative weights
* cannot have duplicate strategies and need to be sorted in ascending address order
* @param token The rewards token to be distributed
* @param amount The total amount of tokens to be distributed
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution
* could start in the past or in the future but within a valid range. See the diagram above.
* @param duration The duration of the submission range in seconds. Must be <= MAX_REWARDS_DURATION
*/
struct RewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
address token;
uint256 amount;
uint32 startTimestamp;
uint32 duration;
}
/**
* @notice A distribution root is a merkle root of the distribution of earnings for a given period.
* The RewardsCoordinator stores all historical distribution roots so that earners can claim their earnings against older roots
* if they wish but the merkle tree contains the cumulative earnings of all earners and tokens for a given period so earners (or their claimers if set)
* only need to claim against the latest root to claim all available earnings.
* @param root The merkle root of the distribution
* @param rewardsCalculationEndTimestamp The timestamp (seconds) until which rewards have been calculated
* @param activatedAt The timestamp (seconds) at which the root can be claimed against
*/
struct DistributionRoot {
bytes32 root;
uint32 rewardsCalculationEndTimestamp;
uint32 activatedAt;
bool disabled;
}
/**
* @notice Internal leaf in the merkle tree for the earner's account leaf
* @param earner The address of the earner
* @param earnerTokenRoot The merkle root of the earner's token subtree
* Each leaf in the earner's token subtree is a TokenTreeMerkleLeaf
*/
struct EarnerTreeMerkleLeaf {
address earner;
bytes32 earnerTokenRoot;
}
/**
* @notice The actual leaves in the distribution merkle tree specifying the token earnings
* for the respective earner's subtree. Each leaf is a claimable amount of a token for an earner.
* @param token The token for which the earnings are being claimed
* @param cumulativeEarnings The cumulative earnings of the earner for the token
*/
struct TokenTreeMerkleLeaf {
address token;
uint256 cumulativeEarnings;
}
/**
* @notice A claim against a distribution root called by an
* earners claimer (could be the earner themselves). Each token claim will claim the difference
* between the cumulativeEarnings of the earner and the cumulativeClaimed of the claimer.
* Each claim can specify which of the earner's earned tokens they want to claim.
* See `processClaim()` for more details.
* @param rootIndex The index of the root in the list of DistributionRoots
* @param earnerIndex The index of the earner's account root in the merkle tree
* @param earnerTreeProof The proof of the earner's EarnerTreeMerkleLeaf against the merkle root
* @param earnerLeaf The earner's EarnerTreeMerkleLeaf struct, providing the earner address and earnerTokenRoot
* @param tokenIndices The indices of the token leaves in the earner's subtree
* @param tokenTreeProofs The proofs of the token leaves against the earner's earnerTokenRoot
* @param tokenLeaves The token leaves to be claimed
* @dev The merkle tree is structured with the merkle root at the top and EarnerTreeMerkleLeaf as internal leaves
* in the tree. Each earner leaf has its own subtree with TokenTreeMerkleLeaf as leaves in the subtree.
* To prove a claim against a specified rootIndex(which specifies the distributionRoot being used),
* the claim will first verify inclusion of the earner leaf in the tree against _distributionRoots[rootIndex].root.
* Then for each token, it will verify inclusion of the token leaf in the earner's subtree against the earner's earnerTokenRoot.
*/
struct RewardsMerkleClaim {
uint32 rootIndex;
uint32 earnerIndex;
bytes earnerTreeProof;
EarnerTreeMerkleLeaf earnerLeaf;
uint32[] tokenIndices;
bytes[] tokenTreeProofs;
TokenTreeMerkleLeaf[] tokenLeaves;
}
/// EVENTS ///
/// @notice emitted when an AVS creates a valid RewardsSubmission
event AVSRewardsSubmissionCreated(
address indexed avs,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/// @notice emitted when a valid RewardsSubmission is created for all stakers by a valid submitter
event RewardsSubmissionForAllCreated(
address indexed submitter,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/// @notice emitted when a valid RewardsSubmission is created when rewardAllStakersAndOperators is called
event RewardsSubmissionForAllEarnersCreated(
address indexed tokenHopper,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/// @notice rewardsUpdater is responsible for submiting DistributionRoots, only owner can set rewardsUpdater
event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater);
event RewardsForAllSubmitterSet(
address indexed rewardsForAllSubmitter, bool indexed oldValue, bool indexed newValue
);
event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay);
event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips);
event ClaimerForSet(address indexed earner, address indexed oldClaimer, address indexed claimer);
/// @notice rootIndex is the specific array index of the newly created root in the storage array
event DistributionRootSubmitted(
uint32 indexed rootIndex,
bytes32 indexed root,
uint32 indexed rewardsCalculationEndTimestamp,
uint32 activatedAt
);
event DistributionRootDisabled(uint32 indexed rootIndex);
/// @notice root is one of the submitted distribution roots that was claimed against
event RewardsClaimed(
bytes32 root,
address indexed earner,
address indexed claimer,
address indexed recipient,
address token,
uint256 claimedAmount
);
/**
*
* VIEW FUNCTIONS
*
*/
/// @notice The address of the entity that can update the contract with new merkle roots
function rewardsUpdater() external view returns (address);
/**
* @notice The interval in seconds at which the calculation for a RewardsSubmission distribution is done.
* @dev Rewards Submission durations must be multiples of this interval.
*/
function CALCULATION_INTERVAL_SECONDS() external view returns (uint32);
/// @notice The maximum amount of time (seconds) that a RewardsSubmission can span over
function MAX_REWARDS_DURATION() external view returns (uint32);
/// @notice max amount of time (seconds) that a submission can start in the past
function MAX_RETROACTIVE_LENGTH() external view returns (uint32);
/// @notice max amount of time (seconds) that a submission can start in the future
function MAX_FUTURE_LENGTH() external view returns (uint32);
/// @notice absolute min timestamp (seconds) that a submission can start at
function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32);
/// @notice Delay in timestamp (seconds) before a posted root can be claimed against
function activationDelay() external view returns (uint32);
/// @notice Mapping: earner => the address of the entity who can call `processClaim` on behalf of the earner
function claimerFor(address earner) external view returns (address);
/// @notice Mapping: claimer => token => total amount claimed
function cumulativeClaimed(address claimer, address token) external view returns (uint256);
/// @notice the commission for all operators across all avss
function globalOperatorCommissionBips() external view returns (uint16);
/// @notice the commission for a specific operator for a specific avs
/// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release
function operatorCommissionBips(address operator, address avs) external view returns (uint16);
/// @notice return the hash of the earner's leaf
function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) external pure returns (bytes32);
/// @notice returns the hash of the earner's token leaf
function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) external pure returns (bytes32);
/// @notice returns 'true' if the claim would currently pass the check in `processClaims`
/// but will revert if not valid
function checkClaim(RewardsMerkleClaim calldata claim) external view returns (bool);
/// @notice The timestamp until which RewardsSubmissions have been calculated
function currRewardsCalculationEndTimestamp() external view returns (uint32);
/// @notice returns the number of distribution roots posted
function getDistributionRootsLength() external view returns (uint256);
/// @notice returns the distributionRoot at the specified index
function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory);
/// @notice returns the current distributionRoot
function getCurrentDistributionRoot() external view returns (DistributionRoot memory);
/// @notice loop through the distribution roots from reverse and get latest root that is not disabled and activated
/// i.e. a root that can be claimed against
function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory);
/// @notice loop through distribution roots from reverse and return index from hash
function getRootIndexFromHash(bytes32 rootHash) external view returns (uint32);
/**
*
* EXTERNAL FUNCTIONS
*
*/
/**
* @notice Creates a new rewards submission on behalf of an AVS, to be split amongst the
* set of stakers delegated to operators who are registered to the `avs`
* @param rewardsSubmissions The rewards submissions being created
* @dev Expected to be called by the ServiceManager of the AVS on behalf of which the submission is being made
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
* @dev The tokens are sent to the `RewardsCoordinator` contract
* @dev Strategies must be in ascending order of addresses to check for duplicates
* @dev This function will revert if the `rewardsSubmission` is malformed,
* e.g. if the `strategies` and `weights` arrays are of non-equal lengths
*/
function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external;
/**
* @notice similar to `createAVSRewardsSubmission` except the rewards are split amongst *all* stakers
* rather than just those delegated to operators who are registered to a single avs and is
* a permissioned call based on isRewardsForAllSubmitter mapping.
*/
function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmission) external;
/**
* @notice Creates a new rewards submission for all earners across all AVSs.
* Earners in this case indicating all operators and their delegated stakers. Undelegated stake
* is not rewarded from this RewardsSubmission. This interface is only callable
* by the token hopper contract from the Eigen Foundation
* @param rewardsSubmissions The rewards submissions being created
*/
function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) external;
/**
* @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]).
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for,
* they can simply claim against the latest root and the contract will calculate the difference between
* their cumulativeEarnings and cumulativeClaimed. This difference is then transferred to recipient address.
* @param claim The RewardsMerkleClaim to be processed.
* Contains the root index, earner, token leaves, and required proofs
* @param recipient The address recipient that receives the ERC20 rewards
* @dev only callable by the valid claimer, that is
* if claimerFor[claim.earner] is address(0) then only the earner can claim, otherwise only
* claimerFor[claim.earner] can claim the rewards.
*/
function processClaim(RewardsMerkleClaim calldata claim, address recipient) external;
/**
* @notice Creates a new distribution root. activatedAt is set to block.timestamp + activationDelay
* @param root The merkle root of the distribution
* @param rewardsCalculationEndTimestamp The timestamp (seconds) until which rewards have been calculated
* @dev Only callable by the rewardsUpdater
*/
function submitRoot(bytes32 root, uint32 rewardsCalculationEndTimestamp) external;
/**
* @notice allow the rewardsUpdater to disable/cancel a pending root submission in case of an error
* @param rootIndex The index of the root to be disabled
*/
function disableRoot(uint32 rootIndex) external;
/**
* @notice Sets the address of the entity that can call `processClaim` on behalf of the earner (msg.sender)
* @param claimer The address of the entity that can claim rewards on behalf of the earner
* @dev Only callable by the `earner`
*/
function setClaimerFor(address claimer) external;
/**
* @notice Sets the delay in timestamp before a posted root can be claimed against
* @param _activationDelay Delay in timestamp (seconds) before a posted root can be claimed against
* @dev Only callable by the contract owner
*/
function setActivationDelay(uint32 _activationDelay) external;
/**
* @notice Sets the global commission for all operators across all avss
* @param _globalCommissionBips The commission for all operators across all avss
* @dev Only callable by the contract owner
*/
function setGlobalOperatorCommission(uint16 _globalCommissionBips) external;
/**
* @notice Sets the permissioned `rewardsUpdater` address which can post new roots
* @dev Only callable by the contract owner
*/
function setRewardsUpdater(address _rewardsUpdater) external;
/**
* @notice Sets the permissioned `rewardsForAllSubmitter` address which can submit createRewardsForAllSubmission
* @dev Only callable by the contract owner
* @param _submitter The address of the rewardsForAllSubmitter
* @param _newValue The new value for isRewardsForAllSubmitter
*/
function setRewardsForAllSubmitter(address _submitter, bool _newValue) external;
}
IStrategyManager.sol 8 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
interface IStrategyManager {
function depositIntoStrategy(address strategy, address token, uint256 amount) external returns (uint256 shares);
}
PositionManager.sol 458 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
import '@itb/quant-common/contracts/solidity8/ITBContract.sol';
import './interfaces/IStrategyManager.sol';
import './interfaces/ILiquidStaking.sol';
import './interfaces/IDelegation.sol';
import './interfaces/IAllocationManager.sol';
import './interfaces/IRewardsCoordinator.sol';
/// @title PositionManager for EigenLayer
/// @author IntoTheBlock Corp
contract PositionManager is ITBContract {
uint64 constant WAD = 1e18;
struct PositionConfig {
address liquid_staking;
address underlying;
address delegate_to;
}
struct QueuedWithdrawal {
uint withdrawal_block;
address[] tokens;
IDelegation.Withdrawal withdrawal;
}
event Deposit(address indexed caller, address token, uint amount, uint lpt_change);
event StartWithdrawal(address indexed caller, address token, uint withdrawal_nonce, uint withdrawal_index, uint start_block, uint withdrawal_block, uint lpt_amount);
event Withdraw(address indexed caller, address token, uint withdrawal_nonce, uint withdrawal_index, uint amount, uint lpt_change);
event Assemble(address indexed caller, address[] tokens, uint[] amounts, uint lpt_change);
event Disassemble(address indexed caller, address[] tokens, uint[] amounts, uint lpt_change);
event UpdateStrategyManager(address indexed caller, address strategy_manager);
event UpdateDelegationManager(address indexed caller, address delegation_manager);
event UpdateRewardsCoordinator(address indexed caller, address rewards_coordinator);
event UpdatePositionConfig(address indexed caller, address liquid_staking, address underlying, address delegate_to);
PositionConfig public positionConfig;
IStrategyManager public strategyManager;
IDelegation public delegationManager;
IRewardsCoordinator public rewardsCoordinator;
mapping(uint => QueuedWithdrawal) public withdrawalQueue;
uint public cumulativeWithdrawalsQueued;
uint public indexNextWithdrawal;
function VERSION() external pure returns (string memory) {
return "1.0.0";
}
constructor(address[] memory _executors, address payable _wnative, address _strategy_manager, address _delegation_manager, address _rewards_coordinator, address _liquid_staking, address _underlying, address _delegate_to) ITBContract(_executors, _wnative) {
updateStrategyManager(_strategy_manager);
updateDelegationManager(_delegation_manager);
updateRewardsCoordinator(_rewards_coordinator);
updatePositionConfig(_liquid_staking, _underlying, _delegate_to);
if (_delegate_to != address(0))
delegate();
}
/// @notice Only owner. Updates the strategy manager, responsible of deposits
/// @param _strategy_manager Address of the strategy manager
function updateStrategyManager(address _strategy_manager) public onlyOwner {
strategyManager = IStrategyManager(_strategy_manager);
emit UpdateStrategyManager(msg.sender, _strategy_manager);
}
/// @notice Only owner. Updates the delegation manager, responsible of withdrawals and delegation
/// @param _delegation_manager Address of the delegation manager
function updateDelegationManager(address _delegation_manager) public onlyOwner {
delegationManager = IDelegation(_delegation_manager);
emit UpdateDelegationManager(msg.sender, _delegation_manager);
}
/// @notice Only owner. Updates the rewards coordinator
/// @param _rewards_coordinator Address of the rewards coordinator
function updateRewardsCoordinator(address _rewards_coordinator) public onlyOwner {
rewardsCoordinator = IRewardsCoordinator(_rewards_coordinator);
emit UpdateRewardsCoordinator(msg.sender, _rewards_coordinator);
}
/// @notice Only owner. Updates the position config
/// @param _liquid_staking Address of the liquid staking contract to deposit into
/// @param _underlying Address of the underlying token
/// @param _delegate_to Address of the operator to delegate to
function updatePositionConfig(address _liquid_staking, address _underlying, address _delegate_to) public onlyOwner {
require(ILiquidStaking(_liquid_staking).underlyingToken() == _underlying, 'PC1');
require(_delegate_to == address(0) || delegationManager.isOperator(_delegate_to), 'PC2');
positionConfig = PositionConfig(
_liquid_staking,
_underlying,
_delegate_to
);
emit UpdatePositionConfig(msg.sender, _liquid_staking, _underlying, _delegate_to);
}
modifier hasConfig() {
require(positionConfig.liquid_staking != address(0), 'A3'); // position_config is missing
_;
}
function _strategies() internal view returns (address[] memory strategies) {
strategies = new address[](1);
strategies[0] = positionConfig.liquid_staking;
}
/// @notice Returns the queued amount of shares for the given withdrawal after slashing
/// @param queued_withdrawal Queued withdrawal to check
/// @return Amount of shares after slashing
function _scaledSharesWithSlashing(QueuedWithdrawal memory queued_withdrawal) internal view returns (uint) {
address allocation_manager = delegationManager.allocationManager();
uint64[] memory magnitude_at_completion = IAllocationManager(allocation_manager).getMaxMagnitudesAtBlock(queued_withdrawal.withdrawal.delegatedTo, _strategies(), uint32(queued_withdrawal.withdrawal_block));
return queued_withdrawal.withdrawal.scaledShares[0] * magnitude_at_completion[0] / WAD;
}
/// @notice Get the withdrawal delay
/// @return Withdrawal delay in blocks
function getWithdrawalDelay() public view returns (uint) {
return delegationManager.minWithdrawalDelayBlocks();
}
/// @notice Get underlyings addresses
/// @return All underlying assets
function getPositionAssets() public view returns (address[] memory) {
address[] memory assets = new address[](1);
assets[0] = positionConfig.underlying;
return assets;
}
/// @notice Get underlyings addresses and amounts
/// @return assets all underlying assets
/// @return amounts amounts of all underlying assets
function getUnderlyings() external view returns (address[] memory assets, uint[] memory amounts) {
address[] memory tokens = getPositionAssets();
uint[] memory balances = new uint[](tokens.length);
balances[0] = ILiquidStaking(positionConfig.liquid_staking).sharesToUnderlying(getTotalLPT());
return (tokens, balances);
}
/// @notice Get the withdrawable and deposited shares
/// @return Amount of shares that can be withdrawn
/// @return Amount of shares that were originally deposited
function getLPTWithdrawableAndDeposited() public view returns (uint, uint) {
(uint[] memory withdrawable, uint[] memory deposited) = delegationManager.getWithdrawableShares(address(this), _strategies());
return (withdrawable[0], deposited[0]);
}
/// @notice Get the shares staked into the liquid staking contract
/// @return withdrawable Amount of shares that can be withdrawn
function getLPTStaked() public view returns (uint withdrawable) {
(withdrawable, ) = getLPTWithdrawableAndDeposited();
}
/// @notice Get the total shares deposited into the liquid staking contract
/// @return deposited Amount of shares that were originally deposited
function getLPTDeposited() public view returns (uint deposited) {
(, deposited) = getLPTWithdrawableAndDeposited();
}
/// @notice Get the total shares pending withdrawal accounting for slashing
/// @return amount_pending Total shares pending withdrawal accounting for slashing
function lptPendingOfWithdraw() public view returns (uint amount_pending) {
for (uint i = indexNextWithdrawal; i < cumulativeWithdrawalsQueued; i++)
amount_pending += _scaledSharesWithSlashing(withdrawalQueue[i]);
}
/// @notice Get total shares (active and pending withdrawal) accounting for slashing
/// @return Total shares accounting for slashing
function getTotalLPT() public view returns (uint) {
return getLPTStaked() + lptPendingOfWithdraw();
}
/// @notice Check if there are any withdrawals queued
/// @return True if there are withdrawals queued
function haveWithdrawalsQueued() public view returns (bool) {
return cumulativeWithdrawalsQueued > indexNextWithdrawal;
}
/// @notice Check if the given withdrawal index is pending
/// @param _withdrawal_index Index of the withdrawal to check
/// @return True if the withdrawal is pending
function withdrawalIsPending(uint _withdrawal_index) public view returns (bool) {
bytes32 root = delegationManager.calculateWithdrawalRoot(withdrawalQueue[_withdrawal_index].withdrawal);
return delegationManager.pendingWithdrawals(root);
}
/// @notice Check if the given withdrawal index is ready to be completed
/// @param _withdrawal_index Index of the withdrawal to check
/// @return True if the withdrawal is ready
function withdrawalIsReady(uint _withdrawal_index) public view returns (bool) {
QueuedWithdrawal memory w = withdrawalQueue[_withdrawal_index];
return withdrawalIsPending(_withdrawal_index) && block.number >= w.withdrawal_block;
}
/// @notice Check if the next queued withdrawal is ready to be completed
/// @return True if the next withdrawal is ready
function nextWithdrawalIsReady() public view returns (bool) {
return withdrawalIsReady(indexNextWithdrawal);
}
/// @notice Check if the next queued withdrawal, if any, is ready to be completed
/// @return True if the next withdrawal is ready
function canCompleteWithdrawals() public view returns (bool) {
return haveWithdrawalsQueued() && nextWithdrawalIsReady();
}
/// @notice Only executor. Delegate shares to the configured operator which doesnt have an approver
function delegate() public onlyExecutor hasConfig {
require(delegationManager.delegationApprover(positionConfig.delegate_to) == address(0), 'DL2');
_delegate(new bytes(0), 0, bytes32(0));
}
/// @notice Only owner. Delegate shares to the configured operator with a signature
/// @param _signature Signature to delegate
/// @param _expiry Expiry of the signature
/// @param _salt Salt to use for the signature
function delegateWithSignature(bytes memory _signature, uint _expiry, bytes32 _salt) public onlyOwner hasConfig {
_delegate(_signature, _expiry, _salt);
}
/// @notice Delegate shares to the configured operator
/// @dev If the shared are already delegated, undelegate first
function _delegate(bytes memory _signature, uint _expiry, bytes32 _salt) internal {
address delegate_to = positionConfig.delegate_to;
require(delegate_to != address(0), 'DL1');
if (delegationManager.delegatedTo(address(this)) != address(0))
undelegate();
delegationManager.delegateTo(delegate_to, IDelegation.SignatureWithExpiry(_signature, _expiry), _salt);
}
/// @notice Undelegate shares
function _undelegate() internal {
delegationManager.undelegate(address(this));
}
/// @notice Only owner. Undelegate shares without waiting for withdrawals
/// @dev In case owner wants to undelegate without waiting for withdrawals
function undelegateUnsafe() external onlyOwner {
_undelegate();
}
/// @notice Only executor. Undelegate shares
function undelegate() public onlyExecutor hasConfig {
uint lpt = getTotalLPT();
require(lpt == 0, 'U1');
_undelegate();
}
/// @notice Only executor. Deposits underlying into the liquid staking contract
/// @param _amount Amount of underlying to deposit
/// @param _min_lpt_out Minimum amount of shares expected from the deposit
/// @return lpt_out Amount of shares received from the deposit
function deposit(uint _amount, uint _min_lpt_out) public onlyExecutor hasConfig returns (uint lpt_out) {
PositionConfig memory c = positionConfig;
lpt_out = strategyManager.depositIntoStrategy(c.liquid_staking, c.underlying, _amount);
require(lpt_out >= _min_lpt_out, 'D1');
emit Deposit(msg.sender, c.underlying, _amount, lpt_out);
}
/// @notice Queue the given withdrawals
/// @param _withdrawal_params Array of withdrawal parameters to queue
function _queueWithdrawals(IDelegation.QueuedWithdrawalParams[] memory _withdrawal_params) internal {
delegationManager.queueWithdrawals(_withdrawal_params);
}
/// @notice Only owner. Queue the given withdrawals
/// @dev In case owner wants to manually queue withdrawals
/// @param _withdrawal_params Array of withdrawal parameters to queue
function queueWithdrawals(IDelegation.QueuedWithdrawalParams[] memory _withdrawal_params) external onlyOwner {
_queueWithdrawals(_withdrawal_params);
}
/// @notice Only executor. Starts a withdrawal for the given amount of shares
/// @param _shares_amount Shares amount to withdraw
function startWithdrawal(uint _shares_amount) public onlyExecutor hasConfig {
if (_shares_amount == 0)
return;
PositionConfig memory c = positionConfig;
uint nonce = delegationManager.cumulativeWithdrawalsQueued(address(this));
uint withdrawal_block = block.number + getWithdrawalDelay();
uint withdrawal_index = cumulativeWithdrawalsQueued;
cumulativeWithdrawalsQueued++;
{
uint[] memory shares = new uint[](1);
shares[0] = _shares_amount;
IDelegation.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegation.QueuedWithdrawalParams[](1);
queuedWithdrawalParams[0] = IDelegation.QueuedWithdrawalParams({
strategies: _strategies(),
shares: shares,
withdrawer: address(this)
});
_queueWithdrawals(queuedWithdrawalParams);
}
address[] memory tokens = new address[](1);
tokens[0] = c.underlying;
(IDelegation.Withdrawal[] memory pending_withdrawals, ) = delegationManager.getQueuedWithdrawals(address(this));
IDelegation.Withdrawal memory new_withdrawal = pending_withdrawals[pending_withdrawals.length - 1];
withdrawalQueue[withdrawal_index] = QueuedWithdrawal({
withdrawal_block: withdrawal_block,
tokens: tokens,
withdrawal: new_withdrawal
});
emit StartWithdrawal(msg.sender, c.underlying, nonce, withdrawal_index, block.number, withdrawal_block, _shares_amount);
}
/// @notice Completes the given queued withdrawal
/// @param _withdrawal Withdrawal to complete
/// @param _tokens Tokens to receive
/// @param _receive_as_tokens If true, the tokens will be received as tokens, otherwise as shares
function _completeQueuedWithdrawal(IDelegation.Withdrawal memory _withdrawal, address[] memory _tokens, bool _receive_as_tokens) internal {
delegationManager.completeQueuedWithdrawal(_withdrawal, _tokens, _receive_as_tokens);
}
/// @notice Only owner. Completes the given queued withdrawal
/// @param _withdrawal Withdrawal to complete
/// @param _tokens Tokens to receive
/// @param _receive_as_tokens If true, the tokens will be received as tokens, otherwise as shares
function completeQueuedWithdrawal(IDelegation.Withdrawal memory _withdrawal, address[] memory _tokens, bool _receive_as_tokens) external onlyOwner {
_completeQueuedWithdrawal(_withdrawal, _tokens, _receive_as_tokens);
}
/// @notice Only executor. Completes the pending withdrawal at the given index
/// @dev Should not be used under normal circumstances, will break withdrawal index flow
/// @param _withdrawal_index Index of the withdrawal to complete
/// @param _min_out Minimum amount of underlying expected from the withdrawal
/// @return lpt_burnt Amount of shares burnt
/// @return coin_out Amount of underlying received
function completeWithdrawal(uint _withdrawal_index, uint _min_out) public onlyExecutor hasConfig returns (uint lpt_burnt, uint coin_out) {
require(withdrawalIsReady(_withdrawal_index), 'W2');
QueuedWithdrawal memory w = withdrawalQueue[_withdrawal_index];
address underlying = w.tokens[0];
uint underlying_before = _balance(underlying);
_completeQueuedWithdrawal(w.withdrawal, w.tokens, true);
lpt_burnt = _scaledSharesWithSlashing(w);
coin_out = _balance(underlying) - underlying_before;
require(coin_out >= _min_out, 'W3');
emit Withdraw(msg.sender, underlying, w.withdrawal.nonce, _withdrawal_index, coin_out, lpt_burnt);
}
/// @notice Only executor. Completes the next pending withdrawal
/// @param _min_out Minimum amount of underlying expected from the withdrawal
/// @return lpt_burnt Shares burnt from completing the withdrawal
/// @return coin_out Collateral received after completing the withdrawal
function completeNextWithdrawal(uint _min_out) public onlyExecutor hasConfig returns (uint lpt_burnt, uint coin_out) {
uint i = indexNextWithdrawal;
indexNextWithdrawal++;
(lpt_burnt, coin_out) = completeWithdrawal(i, _min_out);
}
/// @notice Only executor. Completes all available pending withdrawals
/// @param _min_out Minimum total amount of underlying expected from the withdrawals
/// @return total_lpt_burnt Total shares burnt from completing the withdrawals
/// @return total_coin_out Total underlying out after completing the withdrawals
function completeNextWithdrawals(uint _min_out) public onlyExecutor hasConfig returns (uint total_lpt_burnt, uint total_coin_out) {
while (canCompleteWithdrawals()) {
(uint lpt_burnt, uint coin_out) = completeNextWithdrawal(0);
total_lpt_burnt += lpt_burnt;
total_coin_out += coin_out;
}
require(total_coin_out >= _min_out, 'W4');
}
/// @notice Only executor. Override withdrawal indexes
/// @dev Should not be used under normal circumstances
/// @param _cumulativeWithdrawalsQueued New cumulative withdrawals queued
/// @param _indexNextWithdrawal New index of the next withdrawal
function overrideWithdrawalIndexes(uint _cumulativeWithdrawalsQueued, uint _indexNextWithdrawal) external onlyExecutor {
cumulativeWithdrawalsQueued = _cumulativeWithdrawalsQueued;
indexNextWithdrawal = _indexNextWithdrawal;
}
/* Self service */
/// @notice Only executor. Deposits underlying into the liquid staking contract
/// @param _min_lpt_out Minimum amount of shares expected from the deposit
/// @return lpt_out Amount of shares received from the deposit
function assemble(uint _min_lpt_out) public onlyExecutor hasConfig returns (uint lpt_out) {
PositionConfig memory c = positionConfig;
uint underlying_amount = _balance(c.underlying);
lpt_out = deposit(underlying_amount, _min_lpt_out);
address[] memory tokens = getPositionAssets();
uint[] memory underlyings_change = new uint[](tokens.length);
underlyings_change[0] = underlying_amount - _balance(c.underlying);
emit Assemble(msg.sender, tokens, underlyings_change, lpt_out);
}
/// @notice Only executor. Starts a withdrawal if requested and completes all available pending withdrawals
/// @param _percentage Percentage of shares to start the withdrawal
/// @param _min_coin_out Minimum total amount of underlying expected from claims
/// @return coin_out Total underlying out after completing the withdrawals
function disassemble(uint _percentage, uint _min_coin_out) public onlyExecutor hasConfig returns (uint coin_out) {
require(_percentage <= ONE, 'P1');
uint lpt_burnt;
if (_percentage > 0) {
uint lpt_amount = _percentageAmount(getLPTDeposited(), _percentage);
startWithdrawal(lpt_amount);
}
(lpt_burnt, coin_out) = completeNextWithdrawals(_min_coin_out);
address[] memory tokens = getPositionAssets();
uint[] memory underlyings_change = new uint[](tokens.length);
underlyings_change[0] = coin_out;
emit Disassemble(msg.sender, tokens, underlyings_change, lpt_burnt);
}
/// @notice Only executor. Starts a withdrawal for all shares and completes all available pending withdrawals
/// @param _min_coin_out Minimum total underlying expected from completed withdrawals
/// @return Total underlying out after completing the withdrawals
function fullDisassemble(uint _min_coin_out) public onlyExecutor hasConfig returns (uint) {
return disassemble(ONE, _min_coin_out);
}
/* Rewards */
/// @notice Claim rewards from EigenLayer
/// @param _claim Merkle data to claim rewards
/// @param _recipient Address to receive the rewards
function _processClaim(IRewardsCoordinator.RewardsMerkleClaim calldata _claim, address _recipient) internal {
rewardsCoordinator.processClaim(_claim, _recipient);
}
/// @notice Only owner. Sets an address that can call `rewardsCoordinator.processClaim` on behalf of the position manager
/// @param _claimer Address of the claimer
function setRewardsClaimer(address _claimer) external onlyOwner {
rewardsCoordinator.setClaimerFor(_claimer);
}
/// @notice Only owner. Claim rewards from EigenLayer with a recipient address
/// @param _claim Merkle data to claim rewards
/// @param _recipient Address to receive the rewards
function processClaim(IRewardsCoordinator.RewardsMerkleClaim calldata _claim, address _recipient) external onlyOwner {
require(_recipient != address(0), 'C1');
_processClaim(_claim, _recipient);
}
/// @notice Only executor. Claim rewards from EigenLayer to the position manager
/// @param _claim Merkle data to claim rewards
function claimRewards(IRewardsCoordinator.RewardsMerkleClaim calldata _claim) external onlyExecutor {
_processClaim(_claim, address(this));
}
}
PositionManagerOwnable2StepWithShortcut.sol 9 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity 0.8.15;
import './PositionManager.sol';
import '@itb/quant-common/contracts/solidity8/utils/Ownable2StepWithShortcut.sol';
contract PositionManagerOwnable2StepWithShortcut is PositionManager, Ownable2StepWithShortcut {
constructor(address[] memory _executors, address payable _wnative, address _strategy_manager, address _delegation_manager, address _rewards_coordinator, address _liquid_staking, address _underlying, address _delegate_to) PositionManager(_executors, _wnative, _strategy_manager, _delegation_manager, _rewards_coordinator, _liquid_staking, _underlying, _delegate_to) {}
}
Read Contract
VERSION 0xffa1ad74 → string
WNATIVE 0xb381cf40 → address
balanceOf 0xf7888aec → uint256
canCompleteWithdrawals 0xf9f29356 → bool
cumulativeWithdrawalsQueued 0xf7c649dd → uint256
delegationManager 0xea4d3c9b → address
executors 0x9ac2a011 → bool
getLPTDeposited 0x72068dce → uint256
getLPTStaked 0xb7fcb831 → uint256
getLPTWithdrawableAndDeposited 0x4c7e972b → uint256, uint256
getPositionAssets 0x087ed837 → address[]
getTotalLPT 0x9b1209b5 → uint256
getUnderlyings 0xf65baefa → address[], uint256[]
getWithdrawalDelay 0x03160940 → uint256
haveWithdrawalsQueued 0x8b266206 → bool
indexNextWithdrawal 0xcdaf200f → uint256
lptPendingOfWithdraw 0x68dbd7a9 → uint256
nextWithdrawalIsReady 0x5c6b7a1d → bool
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
positionConfig 0xecf74777 → address, address, address
rewardsCoordinator 0x8a2fc4e3 → address
strategyManager 0x39b70e38 → address
withdrawalIsPending 0xb199329b → bool
withdrawalIsReady 0x62cef791 → bool
withdrawalQueue 0xc822adda → uint256, tuple
Write Contract 38 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
addExecutor 0x1f5a0bbe
address _executor
approveToken 0xda3e3397
address _token
address _guy
uint256 _wad
assemble 0xe6a6e7a2
uint256 _min_lpt_out
returns: uint256
batchExecute 0x077d97d7
address[] _tos
uint256[] _values
bytes[] _datas
claimRewards 0x99da3c03
tuple _claim
completeNextWithdrawal 0x1761b7ce
uint256 _min_out
returns: uint256, uint256
completeNextWithdrawals 0x1b51d9b5
uint256 _min_out
returns: uint256, uint256
completeQueuedWithdrawal 0x327cccc1
tuple _withdrawal
address[] _tokens
bool _receive_as_tokens
completeWithdrawal 0xd9ece259
uint256 _withdrawal_index
uint256 _min_out
returns: uint256, uint256
delegate 0xc89e4361
No parameters
delegateWithSignature 0x2b5af748
bytes _signature
uint256 _expiry
bytes32 _salt
deposit 0xe2bbb158
uint256 _amount
uint256 _min_lpt_out
returns: uint256
disassemble 0x6ed625ab
uint256 _percentage
uint256 _min_coin_out
returns: uint256
execute 0xb61d27f6
address _to
uint256 _value
bytes _data
fullDisassemble 0x54621b42
uint256 _min_coin_out
returns: uint256
overrideWithdrawalIndexes 0xda9d3be7
uint256 _cumulativeWithdrawalsQueued
uint256 _indexNextWithdrawal
processClaim 0x175fe91f
tuple _claim
address _recipient
queueWithdrawals 0xf16e1531
tuple[] _withdrawal_params
removeExecutor 0x24788429
address _executor
renounceOwnership 0x715018a6
No parameters
revokeToken 0x3419ba23
address _token
address _guy
setRewardsClaimer 0xb501d660
address _claimer
startWithdrawal 0xe69bb20d
uint256 _shares_amount
transferOwnership 0xf2fde38b
address newOwner
transferOwnership1Step 0xe1b97139
address newOwner
undelegate 0x92ab89bb
No parameters
undelegateUnsafe 0xb6234f9d
No parameters
unwrapNative 0x34b10a6d
uint256 _amount
updateDelegationManager 0xadb5d7bd
address _delegation_manager
updatePositionConfig 0xfdda34fe
address _liquid_staking
address _underlying
address _delegate_to
updateRewardsCoordinator 0x51fb9283
address _rewards_coordinator
updateStrategyManager 0xb1d4cfca
address _strategy_manager
withdraw 0xf3fef3a3
address _asset_address
uint256 _amount
withdrawAll 0xfa09e630
address _asset_address
withdrawAllTo 0xb6703fcd
address _asset_address
address _to
withdrawTo 0xc4e2c1e6
address _asset_address
uint256 _amount
address _to
wrapNative 0x9169d833
uint256 _amount
Recent Transactions
No transactions found for this address