Address Contract Partially Verified
Address
0xbc3Fc959FeF3F12a41738f406c02198cdeE7481F
Balance
0 ETH
Nonce
1
Code Size
15293 bytes
Creator
0x7fb85Bab...778d at tx 0xbaea2efa...eae612
Indexed Transactions
0 (1 on-chain, 1.6% indexed)
Contract Bytecode
15293 bytes
0x608060405260043610610062575f3560e01c80638cedca71116100415780638cedca71146100a1578063921daec0146100e4578063c579d490146100f7575f80fd5b80623316b6146100665780630c2c87501461007b578063422fa60c1461008e575b5f80fd5b6100796100743660046126b0565b610116565b005b6100796100893660046126fc565b61042a565b61007961009c366004612a1e565b610439565b3480156100ac575f80fd5b506100c873ccf3d848e08b94478ed8f46ffead3008faf581fd81565b6040516001600160a01b03909116815260200160405180910390f35b6100796100f2366004612b34565b6106f3565b348015610102575f80fd5b50610079610111366004612b8a565b6107bc565b6040517f93b188540000000000000000000000000000000000000000000000000000000081527f91bfbd870000000000000000000000000000000000000000000000000000000060048201525f9073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa15801561019e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101c29190612bd8565b9050336001600160a01b0382161461020d576040517fc45d9b2e0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b61021d60a0830160808401612bf3565b156102385761023361022e84612d98565b6108e5565b505050565b5f80826001600160a01b031663b0ade5d26040518163ffffffff1660e01b81526004015f60405180830381865afa158015610275573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261029c9190810190612ed1565b8060200190518101906102af9190612f03565b50915091506102c18561022e90612d98565b815f036102cf575050505050565b5f6102ef836102e46040880160208901613032565b876040013585610ac1565b90508435811115610336576040517fe0d316950000000000000000000000000000000000000000000000000000000081528535600482015260248101829052604401610204565b5f306001600160a01b031663a0e67e2b6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610372573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261039991908101906130b2565b905080516001036103e7576103e5815f815181106103b9576103b96130e4565b6020026020010151838860200160208101906103d59190613032565b6001600160a01b03169190610bcb565b505b610420730ed7f3223266ca1694f85c23abe06e614af3a4798361041060408a0160208b01613032565b6001600160a01b03169190610c57565b5050505050505050565b61043661022e82612d98565b50565b61047b6040518060c00160405280606081526020015f6001600160a01b031681526020016060815260200160608152602001606081526020015f151581525090565b8151602083015167ffffffffffffffff9091169015610529576040517fe7560f0a000000000000000000000000000000000000000000000000000000008152600481018290526024810185905273223c6ade533851df03219f6e3d8b763bd47f84cf9063e7560f0a90604401602060405180830381865afa158015610502573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052691906130f8565b90505b6040517fcfc0cc340000000000000000000000000000000000000000000000000000000081526004810182905273f52551f95ec4a2b4299dcc42fbbc576718dbf9339063cfc0cc34906024015f60405180830381865afa15801561058f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526105b69190810190613256565b9150505f806105dd838589898e731612fc28ee0ab882ec99842cde0fc77ff0691e90610d83565b915091508161061b576040517fdcc0991a00000000000000000000000000000000000000000000000000000000815260048101829052602401610204565b8260a0015161069e576040517fe33cace6000000000000000000000000000000000000000000000000000000008152600481018b9052731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace6906024015f604051808303815f87803b158015610687575f80fd5b505af1158015610699573d5f803e3d5ffd5b505050505b6040805160a08101909152835181525f90602081016106bd8b8d613349565b81526060808801516020830152868101516040830152608087015191015290506106e6816108e5565b5050505050505050505050565b5f6107016060840184613355565b905067ffffffffffffffff81111561071b5761071b612776565b604051908082528060200260200182016040528015610744578160200160208202803683370190505b50905081815f8151811061075a5761075a6130e4565b602090810291909101015260015b6107756060850185613355565b90508110156107b65761079161078a85612d98565b82846110a9565b8282815181106107a3576107a36130e4565b6020908102919091010152600101610768565b50505050565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610816573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061083a9190612bd8565b6001600160a01b03161461087a576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee036108d1576040516001600160a01b0383169082156108fc029083905f818181858888f193505050501580156107b6573d5f803e3d5ffd5b6102336001600160a01b038416838361120f565b5f73287778f121f134c66212fb16c9b53ec991d32f5b6001600160a01b03166393b1885483606001515f8151811061091f5761091f6130e4565b60200260200101516040518263ffffffff1660e01b815260040161095391906001600160e01b031991909116815260200190565b602060405180830381865afa15801561096e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109929190612bd8565b90505f82606001515167ffffffffffffffff8111156109b3576109b3612776565b6040519080825280602002602001820160405280156109dc578160200160208202803683370190505b5090506109e8826112a0565b156109fd576109f883838361130f565b610a3e565b5f5b836060015151811015610a3c57610a178482846110a9565b828281518110610a2957610a296130e4565b60209081029190910101526001016109ff565b505b82516040517f05fedae500000000000000000000000000000000000000000000000000000000815273ce7a977cac4a481bc84ac06b2da0df614e621cf3916305fedae591610a8f91906004016133c6565b5f604051808303815f87803b158015610aa6575f80fd5b505af1158015610ab8573d5f803e3d5ffd5b50505050505050565b5f45851115610ace574594505b81610ad93a876133ec565b610ae39190613403565b90506001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214610bc3575f610b1c856001600160a01b031661148a565b90506012811115610b5c576040517f1e3728a400000000000000000000000000000000000000000000000000000000815260048101829052602401610204565b835f03610b95576040517fb88ea7f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ba0816012613416565b610bab90600a613509565b610bb5838661151e565b610bbf9190613514565b9150505b949350505050565b5f5f198203610be157610bde8484611556565b91505b6001600160a01b03831615801590610c0257506001600160a01b0383163014155b8015610c2b57506001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b8015610c3657508115155b15610c5057610c506001600160a01b03851684308561160e565b5092915050565b5f5f198203610c6d57610c6a8430611556565b91505b6001600160a01b03831615801590610c8e57506001600160a01b0383163014155b8015610c9957508115155b15610c50576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610cdb57610cd66001600160a01b038516848461120f565b610c50565b5f836001600160a01b0316836040515f6040518083038185875af1925050503d805f8114610d24576040519150601f19603f3d011682016040523d82523d5f602084013e610d29565b606091505b5050905080610d7a5760405162461bcd60e51b815260206004820152600d60248201527f4574682073656e64206661696c000000000000000000000000000000000000006044820152606401610204565b50909392505050565b60408601515f9081908180805b83518110156110945773287778f121f134c66212fb16c9b53ec991d32f5b6001600160a01b03166393b18854858381518110610dce57610dce6130e4565b60200260200101516040518263ffffffff1660e01b8152600401610e0291906001600160e01b031991909116815260200190565b602060405180830381865afa158015610e1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e419190612bd8565b9150816001600160a01b03166391a973c68b8b84818110610e6457610e646130e4565b9050602002810190610e769190613533565b8e604001518581518110610e8c57610e8c6130e4565b60200260200101516040518463ffffffff1660e01b8152600401610eb293929190613576565b6020604051808303815f875af1158015610ece573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef291906135b2565b925082610f07575f9550935061109e92505050565b816001600160a01b031663ab9772ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f43573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f6791906135b2565b1561108c57816001600160a01b0316637c331ddb8c604001518381518110610f9157610f916130e4565b60200260200101516040518263ffffffff1660e01b8152600401610fb591906133c6565b5f60405180830381865afa158015610fcf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ff69190810190612ed1565b8b60400151828151811061100c5761100c6130e4565b60209081029190910101526040517ff14283c20000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063f14283c29061105e908b908f90600401613652565b5f604051808303815f87803b158015611075575f80fd5b505af1158015611087573d5f803e3d5ffd5b505050505b600101610d90565b6001955093505050505b965096945050505050565b5f8073287778f121f134c66212fb16c9b53ec991d32f5b6001600160a01b03166393b18854866060015186815181106110e4576110e46130e4565b60200260200101516040518263ffffffff1660e01b815260040161111891906001600160e01b031991909116815260200190565b602060405180830381865afa158015611133573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111579190612bd8565b905061120681638df50f7460e01b8760200151878151811061117b5761117b6130e4565b602002602001015188604001518960800151898151811061119e5761119e6130e4565b6020026020010151886040516024016111ba94939291906136eb565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915261165f565b95945050505050565b6040516001600160a01b0383166024820152604481018290526102339084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915261168f565b5f8060ff16826001600160a01b031663247492f86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113059190613756565b60ff161492915050565b5f61131930611775565b905061132581846117e2565b5f84306040516020016113399291906137bc565b60405160208183030381529060405290505f85602001515f81518110611361576113616130e4565b602002602001015180602001905181019061137c91906138f8565b60c08101839052604051909150611397908290602001613a0e565b60405160208183030381529060405286602001515f815181106113bc576113bc6130e4565b6020026020010181905250846001600160a01b0316638df50f7487602001515f815181106113ec576113ec6130e4565b6020026020010151886040015189608001515f8151811061140f5761140f6130e4565b6020026020010151886040518563ffffffff1660e01b815260040161143794939291906136eb565b6020604051808303815f875af1158015611453573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061147791906130f8565b506114828386611854565b505050505050565b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038316016114b857506012919050565b816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061151891906130f8565b92915050565b5f8161154561153585670de0b6b3a76400006118c2565b611540600286613514565b6118cd565b61154f9190613514565b9392505050565b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161158d57506001600160a01b03811631611518565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156115ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061154f91906130f8565b6040516001600160a01b03808516602483015283166044820152606481018290526107b69085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611254565b5f6001600160a01b038316611672575f80fd5b60205f835160208501866113885a03f45f51915080610c50575f80fd5b5f6116e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118d89092919063ffffffff16565b905080515f148061170357508080602001905181019061170391906135b2565b6102335760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610204565b5f61177f826118e6565b1561178b57505f919050565b6117948261197b565b156117a157506002919050565b7f15b0c1a13812f0fce8291b8e7786ece58e0daab08d489cdfe2899fdac4f660456001600160a01b0383163f036117da57506003919050565b506001919050565b5f8260038111156117f5576117f5613742565b036118075761180381611a22565b5050565b600282600381111561181b5761181b613742565b036118295761180381611c6c565b600382600381111561183d5761183d613742565b0361184b5761180381611d47565b61180381611e7e565b5f82600381111561186757611867613742565b036118755761180381611f46565b600282600381111561188957611889613742565b036118975761180381612018565b60038260038111156118ab576118ab613742565b036118b957611803816120c8565b611803816121da565b5f61154f82846133ec565b5f61154f8284613403565b6060610bc384845f85612589565b6040517f297103880000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201525f9073a26e15c895efc0616177b7c1e7270a4c7d51c99790632971038890602401602060405180830381865afa158015611957573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061151891906135b2565b6040517f6cfaf5e90000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201525f90734c8a1beb8a87765788946d6b19c6c6355194abeb90636cfaf5e990602401602060405180830381865afa1580156119ec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a109190613b02565b67ffffffffffffffff16151592915050565b5f306001600160a01b031663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a839190612bd8565b9050806001600160a01b038116611b7a57735a15566417e6c1c9546523066500bddbc53f88c76001600160a01b03166365688cc96040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611ae5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b099190612bd8565b6040517f7a9e5e4b0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201529091503090637a9e5e4b906024015f604051808303815f87803b158015611b63575f80fd5b505af1158015611b75573d5f803e3d5ffd5b505050505b6040517fb70096130000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152306024830152631cff79cd60e01b604483015282169063b700961390606401602060405180830381865afa158015611bea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c0e91906135b2565b610233576040517fcbeea68c0000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152306024830152631cff79cd60e01b604483015282169063cbeea68c90606401610a8f565b604051632520e7ff60e01b81526001600160a01b03821660048201523090632520e7ff90602401602060405180830381865afa158015611cae573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cd291906135b2565b610436576040517f5bfa1b680000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201523090635bfa1b68906024015b5f604051808303815f87803b158015611d2e575f80fd5b505af1158015611d40573d5f803e3d5ffd5b5050505050565b5f306001600160a01b0316637ceab3b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611da89190612bd8565b6040516350be256160e11b81523060048201526001600160a01b0384811660248301529192509082169063a17c4ac290604401602060405180830381865afa158015611df6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e1a91906135b2565b611803576040516331568f3d60e21b81526001600160a01b0383811660048301523060248301526001604483015282169063c55a3cf4906064015b5f604051808303815f87803b158015611e6c575f80fd5b505af1158015611482573d5f803e3d5ffd5b6040517f2d9ad53d0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201523090632d9ad53d90602401602060405180830381865afa158015611ed9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611efd91906135b2565b610436576040517f610b59250000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152309063610b592590602401611d17565b5f306001600160a01b031663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fa79190612bd8565b90506001600160a01b038116611fbb575050565b6040517f2bc3217d0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152306024830152631cff79cd60e01b6044830152829190821690632bc3217d90606401610a8f565b604051632520e7ff60e01b81526001600160a01b03821660048201523090632520e7ff90602401602060405180830381865afa15801561205a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061207e91906135b2565b15610436576040517fe6c09edf0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152309063e6c09edf90602401611d17565b5f306001600160a01b0316637ceab3b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612105573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121299190612bd8565b6040516350be256160e11b81523060048201526001600160a01b0384811660248301529192509082169063a17c4ac290604401602060405180830381865afa158015612177573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061219b91906135b2565b15611803576040516331568f3d60e21b81526001600160a01b0383811660048301523060248301525f604483015282169063c55a3cf490606401611e55565b604051636617c22960e11b815260016004820181905260026024830152905f90309063cc2f8452906044015f60405180830381865afa15801561221f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526122469190810190613b1d565b50905080515f03612275576040516311db1af760e11b81526001600160a01b0384166004820152602401610204565b826001600160a01b0316815f81518110612291576122916130e4565b60200260200101516001600160a01b0316036122da57604051637004e7ef60e11b8152600160048201526001600160a01b0384166024820152309063e009cfde90604401610a8f565b8051600103612307576040516311db1af760e11b81526001600160a01b0384166004820152602401610204565b826001600160a01b031681600181518110612324576123246130e4565b60200260200101516001600160a01b03160361239657306001600160a01b031663e009cfde825f8151811061235b5761235b6130e4565b6020026020010151856040518363ffffffff1660e01b8152600401610a8f9291906001600160a01b0392831681529116602082015260400190565b806001815181106123a9576123a96130e4565b6020908102919091010151604051636617c22960e11b81526001600160a01b038216600482015260086024820152909250309063cc2f8452906044015f60405180830381865afa1580156123ff573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526124269190810190613b1d565b5080519091501561256557826001600160a01b0316815f8151811061244d5761244d6130e4565b60200260200101516001600160a01b03160361249757604051637004e7ef60e11b81526001600160a01b03808416600483015284166024820152309063e009cfde90604401610a8f565b60015b815181101561256357836001600160a01b03168282815181106124bf576124bf6130e4565b60200260200101516001600160a01b03160361255b573063e009cfde836124e7600185613416565b815181106124f7576124f76130e4565b6020026020010151866040518363ffffffff1660e01b81526004016125329291906001600160a01b0392831681529116602082015260400190565b5f604051808303815f87803b158015612549575f80fd5b505af1158015610420573d5f803e3d5ffd5b60010161249a565b505b6040516311db1af760e11b81526001600160a01b0384166004820152602401610204565b606061259485612662565b6125ca576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80866001600160a01b031685876040516125e59190613b6c565b5f6040518083038185875af1925050503d805f811461261f576040519150601f19603f3d011682016040523d82523d5f602084013e612624565b606091505b50915091508115612638579150610bc39050565b8051156126485780518082602001fd5b8360405162461bcd60e51b815260040161020491906133c6565b5f813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610bc3575050151592915050565b5f60a082840312156126aa575f80fd5b50919050565b5f8060c083850312156126c1575f80fd5b823567ffffffffffffffff8111156126d7575f80fd5b6126e38582860161269a565b9250506126f3846020850161269a565b90509250929050565b5f6020828403121561270c575f80fd5b813567ffffffffffffffff811115612722575f80fd5b610bc38482850161269a565b5f8083601f84011261273e575f80fd5b50813567ffffffffffffffff811115612755575f80fd5b6020830191508360208260051b850101111561276f575f80fd5b9250929050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156127ad576127ad612776565b60405290565b60405160a0810167ffffffffffffffff811182821017156127ad576127ad612776565b6040516060810167ffffffffffffffff811182821017156127ad576127ad612776565b60405160c0810167ffffffffffffffff811182821017156127ad576127ad612776565b60405160e0810167ffffffffffffffff811182821017156127ad576127ad612776565b604051601f8201601f1916810167ffffffffffffffff8111828210171561286857612868612776565b604052919050565b67ffffffffffffffff81168114610436575f80fd5b8015158114610436575f80fd5b5f67ffffffffffffffff8211156128ab576128ab612776565b5060051b60200190565b5f67ffffffffffffffff8211156128ce576128ce612776565b50601f01601f191660200190565b5f6128ee6128e9846128b5565b61283f565b9050828152838383011115612901575f80fd5b828260208301375f602084830101529392505050565b5f6129246128e984612892565b8381529050602080820190600585901b840186811115612942575f80fd5b845b8181101561298e57803567ffffffffffffffff811115612962575f80fd5b8601601f81018913612972575f80fd5b6129808982358684016128dc565b855250928201928201612944565b505050509392505050565b5f82601f8301126129a8575f80fd5b61154f83833560208501612917565b5f82601f8301126129c6575f80fd5b813560206129d66128e983612892565b8083825260208201915060208460051b8701019350868411156129f7575f80fd5b602086015b84811015612a1357803583529183019183016129fc565b509695505050505050565b5f805f805f805f60a0888a031215612a34575f80fd5b87359650602088013567ffffffffffffffff80821115612a52575f80fd5b612a5e8b838c0161272e565b909850965060408a0135915080821115612a76575f80fd5b612a828b838c0161272e565b909650945060608a0135935060808a0135915080821115612aa1575f80fd5b908901906080828c031215612ab4575f80fd5b612abc61278a565b8235612ac781612870565b81526020830135612ad781612885565b6020820152604083013582811115612aed575f80fd5b612af98d828601612999565b604083015250606083013582811115612b10575f80fd5b612b1c8d8286016129b7565b60608301525080935050505092959891949750929550565b5f8060408385031215612b45575f80fd5b823567ffffffffffffffff811115612b5b575f80fd5b612b678582860161269a565b95602094909401359450505050565b6001600160a01b0381168114610436575f80fd5b5f805f60608486031215612b9c575f80fd5b8335612ba781612b76565b92506020840135612bb781612b76565b929592945050506040919091013590565b8051612bd381612b76565b919050565b5f60208284031215612be8575f80fd5b815161154f81612b76565b5f60208284031215612c03575f80fd5b813561154f81612885565b5f82601f830112612c1d575f80fd5b61154f838335602085016128dc565b6001600160e01b031981168114610436575f80fd5b5f82601f830112612c50575f80fd5b81356020612c606128e983612892565b8083825260208201915060208460051b870101935086841115612c81575f80fd5b602086015b84811015612a13578035612c9981612c2c565b8352918301918301612c86565b60ff81168114610436575f80fd5b5f82601f830112612cc3575f80fd5b81356020612cd36128e983612892565b828152600592831b8501820192828201919087851115612cf1575f80fd5b8387015b85811015612d8b57803567ffffffffffffffff811115612d13575f80fd5b8801603f81018a13612d23575f80fd5b858101356040612d356128e983612892565b82815291851b8301810191888101908d841115612d50575f80fd5b938201935b83851015612d7a5784359250612d6a83612ca6565b8282529389019390890190612d55565b885250505093850193508401612cf5565b5090979650505050505050565b5f60a08236031215612da8575f80fd5b612db06127b3565b823567ffffffffffffffff80821115612dc7575f80fd5b612dd336838701612c0e565b83526020850135915080821115612de8575f80fd5b612df436838701612999565b60208401526040850135915080821115612e0c575f80fd5b612e18368387016129b7565b60408401526060850135915080821115612e30575f80fd5b612e3c36838701612c41565b60608401526080850135915080821115612e54575f80fd5b50612e6136828601612cb4565b60808301525092915050565b5f5b83811015612e87578181015183820152602001612e6f565b50505f910152565b5f82601f830112612e9e575f80fd5b8151612eac6128e9826128b5565b818152846020838601011115612ec0575f80fd5b610bc3826020830160208701612e6d565b5f60208284031215612ee1575f80fd5b815167ffffffffffffffff811115612ef7575f80fd5b610bc384828501612e8f565b5f805f60608486031215612f15575f80fd5b8351925060208401519150604084015167ffffffffffffffff80821115612f3a575f80fd5b9085019060608288031215612f4d575f80fd5b612f556127d6565b8251612f6081612b76565b8152602083015182811115612f73575f80fd5b612f7f89828601612e8f565b602083015250604083015182811115612f96575f80fd5b929092019160c08389031215612faa575f80fd5b612fb26127f9565b8351612fbd81612b76565b81526020840151612fcd81612b76565b60208201526040840151612fe081612b76565b80604083015250606084015160608201526080840151608082015260a08401518381111561300c575f80fd5b6130188a828701612e8f565b60a083015250806040830152508093505050509250925092565b5f60208284031215613042575f80fd5b813561154f81612b76565b5f82601f83011261305c575f80fd5b8151602061306c6128e983612892565b8083825260208201915060208460051b87010193508684111561308d575f80fd5b602086015b84811015612a135780516130a581612b76565b8352918301918301613092565b5f602082840312156130c2575f80fd5b815167ffffffffffffffff8111156130d8575f80fd5b610bc38482850161304d565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613108575f80fd5b5051919050565b5f82601f83011261311e575f80fd5b8151602061312e6128e983612892565b8083825260208201915060208460051b87010193508684111561314f575f80fd5b602086015b84811015612a1357805161316781612c2c565b8352918301918301613154565b5f82601f830112613183575f80fd5b815160206131936128e983612892565b828152600592831b85018201928282019190878511156131b1575f80fd5b8387015b85811015612d8b57805167ffffffffffffffff8111156131d3575f80fd5b8801603f81018a136131e3575f80fd5b8581015160406131f56128e983612892565b82815291851b8301810191888101908d841115613210575f80fd5b938201935b8385101561323a578451925061322a83612ca6565b8282529389019390890190613215565b8852505050938501935084016131b5565b8051612bd381612885565b5f60208284031215613266575f80fd5b815167ffffffffffffffff8082111561327d575f80fd5b9083019060c08286031215613290575f80fd5b6132986127f9565b8251828111156132a6575f80fd5b6132b287828601612e8f565b8252506132c160208401612bc8565b60208201526040830151828111156132d7575f80fd5b6132e38782860161310f565b6040830152506060830151828111156132fa575f80fd5b6133068782860161310f565b60608301525060808301518281111561331d575f80fd5b61332987828601613174565b60808301525061333b60a0840161324b565b60a082015295945050505050565b5f61154f368484612917565b5f808335601e1984360301811261336a575f80fd5b83018035915067ffffffffffffffff821115613384575f80fd5b6020019150600581901b360382131561276f575f80fd5b5f81518084526133b2816020860160208601612e6d565b601f01601f19169290920160200192915050565b602081525f61154f602083018461339b565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417611518576115186133d8565b80820180821115611518576115186133d8565b81810381811115611518576115186133d8565b600181815b8085111561346357815f1904821115613449576134496133d8565b8085161561345657918102915b93841c939080029061342e565b509250929050565b5f8261347957506001611518565b8161348557505f611518565b816001811461349b57600281146134a5576134c1565b6001915050611518565b60ff8411156134b6576134b66133d8565b50506001821b611518565b5060208310610133831016604e8410600b84101617156134e4575081810a611518565b6134ee8383613429565b805f1904821115613501576135016133d8565b029392505050565b5f61154f838361346b565b5f8261352e57634e487b7160e01b5f52601260045260245ffd5b500490565b5f808335601e19843603018112613548575f80fd5b83018035915067ffffffffffffffff821115613562575f80fd5b60200191503681900382131561276f575f80fd5b60408152826040820152828460608301375f606084830101525f601f19601f85011682016060838203016020840152610bbf606082018561339b565b5f602082840312156135c2575f80fd5b815161154f81612885565b5f8282518085526020808601955060208260051b840101602086015f5b84811015612d8b57601f1986840301895261360683835161339b565b988401989250908301906001016135ea565b5f815180845260208085019450602084015f5b838110156136475781518752958201959082019060010161362b565b509495945050505050565b8281526040602082015267ffffffffffffffff82511660408201526020820151151560608201525f604083015160808084015261369260c08401826135cd565b90506060840151603f198483030160a08501526136af8282613618565b9695505050505050565b5f815180845260208085019450602084015f5b8381101561364757815160ff16875295820195908201906001016136cc565b608081525f6136fd608083018761339b565b828103602084015261370f8187613618565b9050828103604084015261372381866136b9565b905082810360608401526137378185613618565b979650505050505050565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215613766575f80fd5b815161154f81612ca6565b5f8282518085526020808601955060208260051b840101602086015f5b84811015612d8b57601f198684030189526137aa8383516136b9565b9884019892509083019060010161378e565b604081525f835160a060408401526137d760e084018261339b565b9050602080860151603f19808685030160608701526137f684836135cd565b935060408801519150808685030160808701526138138483613618565b6060890151878203830160a0890152805180835290850195505f9350908401905b8084101561385e5785516001600160e01b0319168252948401946001939093019290840190613834565b5060808901519450818782030160c088015261387a8186613771565b9550505050613893818501866001600160a01b03169052565b50509392505050565b5f82601f8301126138ab575f80fd5b815160206138bb6128e983612892565b8083825260208201915060208460051b8701019350868411156138dc575f80fd5b602086015b84811015612a1357805183529183019183016138e1565b5f60208284031215613908575f80fd5b815167ffffffffffffffff8082111561391f575f80fd5b9083019060e08286031215613932575f80fd5b61393a61281c565b825182811115613948575f80fd5b6139548782860161304d565b825250602083015182811115613968575f80fd5b6139748782860161389c565b60208301525060408301518281111561398b575f80fd5b6139978782860161389c565b6040830152506139a960608401612bc8565b60608201526139ba60808401612bc8565b608082015260a0830151828111156139d0575f80fd5b6139dc87828601612e8f565b60a08301525060c0830151828111156139f3575f80fd5b6139ff87828601612e8f565b60c08301525095945050505050565b6020808252825160e083830152805161010084018190525f929182019083906101208601905b80831015613a5d5783516001600160a01b03168252928401926001929092019190840190613a34565b50838701519350601f19925082868203016040870152613a7d8185613618565b93505050604085015181858403016060860152613a9a8382613618565b9250506060850151613ab760808601826001600160a01b03169052565b5060808501516001600160a01b03811660a08601525060a0850151818584030160c0860152613ae6838261339b565b92505060c0850151818584030160e08601526136af838261339b565b5f60208284031215613b12575f80fd5b815161154f81612870565b5f8060408385031215613b2e575f80fd5b825167ffffffffffffffff811115613b44575f80fd5b613b508582860161304d565b9250506020830151613b6181612b76565b809150509250929050565b5f8251613b7d818460208701612e6d565b919091019291505056fea2646970667358221220edfcca746cbbdd4fb3de47260f6ff4d0c3fda9a7863ba672133340550a5606c164736f6c63430008180033
Verified Source Code Partial Match
Compiler: v0.8.24+commit.e11b9ed9
EVM: cancun
Optimization: Yes (1000 runs)
RecipeExecutor.sol 2188 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.24;
library Address {
//insufficient balance
error InsufficientBalance(uint256 available, uint256 required);
//unable to send value, recipient may have reverted
error SendingValueFail();
//insufficient balance for call
error InsufficientBalanceForCall(uint256 available, uint256 required);
//call to non-contract
error NonContractCall();
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
uint256 balance = address(this).balance;
if (balance < amount) {
revert InsufficientBalance(balance, amount);
}
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success,) = recipient.call{ value: amount }("");
if (!(success)) {
revert SendingValueFail();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage)
internal
returns (bytes memory)
{
return _functionCallWithValue(target, data, 0, errorMessage);
}
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"
);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
uint256 balance = address(this).balance;
if (balance < value) {
revert InsufficientBalanceForCall(balance, value);
}
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint256 weiValue,
string memory errorMessage
) private returns (bytes memory) {
if (!(isContract(target))) {
revert NonContractCall();
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// 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
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint256 digits);
function totalSupply() external view returns (uint256 supply);
function balanceOf(address _owner) external view returns (uint256 balance);
function transfer(address _to, uint256 _value) external returns (bool success);
function transferFrom(address _from, address _to, uint256 _value)
external
returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
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 Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function safeApprove(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 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(token).code.length > 0;
}
}
contract MainnetActionsUtilAddresses {
address internal constant DFS_REG_CONTROLLER_ADDR = 0xF8f8B3C98Cf2E63Df3041b73f80F362a4cf3A576;
address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b;
address internal constant DFS_LOGGER_ADDR = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3;
address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90;
address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
address internal constant LSV_PROXY_REGISTRY_ADDRESS =
0xa8a3c86c4A2DcCf350E84D2b3c46BDeBc711C16e;
address internal constant TRANSIENT_STORAGE = 0x2F7Ef2ea5E8c97B8687CA703A0e50Aa5a49B7eb2;
address internal constant TRANSIENT_STORAGE_CANCUN = 0x0304E27cccE28bAB4d78C6cb7AfD4cd01c87c1e4;
}
contract ActionsUtilHelper is MainnetActionsUtilAddresses { }
contract MainnetAuthAddresses {
address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD;
address internal constant DSGUARD_FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; // USED IN ADMIN VAULT CONSTRUCTOR
address internal constant PROXY_AUTH_ADDRESS = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
address internal constant MODULE_AUTH_ADDRESS = 0x7407974DDBF539e552F1d051e44573090912CC3D;
}
contract AuthHelper is MainnetAuthAddresses { }
interface IAdminVault {
function owner() external view returns (address);
function admin() external view returns (address);
function changeOwner(address _owner) external;
function changeAdmin(address _admin) external;
}
contract AdminAuth is AuthHelper {
using SafeERC20 for IERC20;
IAdminVault public constant adminVault = IAdminVault(ADMIN_VAULT_ADDR);
error SenderNotOwner();
error SenderNotAdmin();
modifier onlyOwner() {
if (adminVault.owner() != msg.sender) {
revert SenderNotOwner();
}
_;
}
modifier onlyAdmin() {
if (adminVault.admin() != msg.sender) {
revert SenderNotAdmin();
}
_;
}
/// @notice withdraw stuck funds
function withdrawStuckFunds(address _token, address _receiver, uint256 _amount)
public
onlyOwner
{
if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
payable(_receiver).transfer(_amount);
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
}
interface IDFSRegistry {
function getAddr(bytes4 _id) external view returns (address);
function addNewContract(bytes32 _id, address _contractAddr, uint256 _waitPeriod) external;
function startContractChange(bytes32 _id, address _newContractAddr) external;
function approveContractChange(bytes32 _id) external;
function cancelContractChange(bytes32 _id) external;
function changeWaitPeriod(bytes32 _id, uint256 _newWaitPeriod) external;
}
contract DefisaverLogger {
event RecipeEvent(address indexed caller, string indexed logName);
event ActionDirectEvent(address indexed caller, string indexed logName, bytes data);
function logRecipeEvent(string memory _logName) public {
emit RecipeEvent(msg.sender, _logName);
}
function logActionDirectEvent(string memory _logName, bytes memory _data) public {
emit ActionDirectEvent(msg.sender, _logName, _data);
}
}
interface IDSProxy {
function execute(bytes memory _code, bytes memory _data)
external
payable
returns (address, bytes32);
function execute(address _target, bytes memory _data) external payable returns (bytes32);
function setCache(address _cacheAddr) external payable returns (bool);
function owner() external view returns (address);
function guard() external view returns (address);
}
interface IDSProxyFactory {
function isProxy(address _proxy) external view returns (bool);
function build(address owner) external returns (IDSProxy proxy);
function build() external returns (IDSProxy proxy);
}
interface IInstaList {
struct AccountLink {
address first;
address last;
uint64 count;
}
struct AccountList {
address prev;
address next;
}
struct UserLink {
uint64 first;
uint64 last;
uint64 count;
}
struct UserList {
uint64 prev;
uint64 next;
}
function accountAddr(uint64 _id) external view returns (address);
function accountID(address _addr) external view returns (uint64);
function accountLink(uint64 _id) external view returns (AccountLink memory);
function accountList(uint64 _id, address _user) external view returns (AccountList memory);
function userLink(address _user) external view returns (UserLink memory);
function userList(address _user, uint64 _id) external view returns (UserList memory);
}
interface ISafe {
enum Operation {
Call,
DelegateCall
}
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external;
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) external payable returns (bool success);
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Operation operation
) external returns (bool success);
function checkSignatures(bytes32 dataHash, bytes memory data, bytes memory signatures)
external
view;
function checkNSignatures(
address executor,
bytes32 dataHash,
bytes memory, /* data */
bytes memory signatures,
uint256 requiredSignatures
) external view;
function approveHash(bytes32 hashToApprove) external;
function domainSeparator() external view returns (bytes32);
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes32);
function nonce() external view returns (uint256);
function setFallbackHandler(address handler) external;
function getOwners() external view returns (address[] memory);
function isOwner(address owner) external view returns (bool);
function getThreshold() external view returns (uint256);
function enableModule(address module) external;
function isModuleEnabled(address module) external view returns (bool);
function disableModule(address prevModule, address module) external;
function getModulesPaginated(address start, uint256 pageSize)
external
view
returns (address[] memory array, address next);
}
contract MainnetDSAProxyFactoryAddresses {
address internal constant DSA_LIST_ADDR = 0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb;
}
contract DSAProxyFactoryHelper is MainnetDSAProxyFactoryAddresses { }
contract MainnetProxyFactoryAddresses {
address internal constant PROXY_FACTORY_ADDR = 0xA26e15C895EFc0616177B7c1e7270A4C7D51C997;
}
contract DSProxyFactoryHelper is MainnetProxyFactoryAddresses { }
contract MainnetSFProxyFactoryAddresses {
address internal constant SF_PROXY_FACTORY_ADDR = 0xF7B75183A2829843dB06266c114297dfbFaeE2b6;
address internal constant SF_PROXY_GUARD = 0xCe91349d2A4577BBd0fC91Fe6019600e047f2847;
bytes32 internal constant SF_PROXY_CODEHASH =
0x15b0c1a13812f0fce8291b8e7786ece58e0daab08d489cdfe2899fdac4f66045;
}
contract SFProxyFactoryHelper is MainnetSFProxyFactoryAddresses { }
enum WalletType {
DSPROXY,
SAFE,
DSAPROXY,
SFPROXY
}
contract SmartWalletUtils is DSProxyFactoryHelper, DSAProxyFactoryHelper, SFProxyFactoryHelper {
/// @notice Determine the type of wallet an address represents
function _getWalletType(address _wallet) internal view returns (WalletType) {
if (_isDSProxy(_wallet)) {
return WalletType.DSPROXY;
}
if (_isDSAProxy(_wallet)) {
return WalletType.DSAPROXY;
}
if (_isSFProxy(_wallet)) {
return WalletType.SFPROXY;
}
// Otherwise, we assume we are in context of Safe
return WalletType.SAFE;
}
/// @notice Check if the wallet is a DSProxy
function _isDSProxy(address _wallet) internal view returns (bool) {
return IDSProxyFactory(PROXY_FACTORY_ADDR).isProxy(_wallet);
}
/// @notice Check if the wallet is a DSA Proxy Account
function _isDSAProxy(address _wallet) internal view returns (bool) {
return IInstaList(DSA_LIST_ADDR).accountID(_wallet) != 0;
}
/// @notice Check if the wallet is a Summerfi account
function _isSFProxy(address _wallet) internal view returns (bool) {
return _wallet.codehash == SF_PROXY_CODEHASH;
}
/// @notice Fetch the owner of the smart wallet or the wallet itself
/// @dev For 1/1 Safe it returns the owner, otherwise it returns the wallet itself
/// @dev Only supports Safe and DSProxy wallets because SFProxy and DSAProxy are not part of automation
/// @param _wallet Address of the smart wallet
/// @return Address of the owner or wallet
function _fetchOwnerOrWallet(address _wallet) internal view returns (address) {
if (_isDSProxy(_wallet)) return IDSProxy(_wallet).owner();
// Otherwise, we assume we are in context of Safe
address[] memory owners = ISafe(_wallet).getOwners();
return owners.length == 1 ? owners[0] : _wallet;
}
}
abstract contract ActionBase is AdminAuth, ActionsUtilHelper, SmartWalletUtils {
event ActionEvent(string indexed logName, bytes data);
IDFSRegistry public constant registry = IDFSRegistry(REGISTRY_ADDR);
DefisaverLogger public constant logger = DefisaverLogger(DFS_LOGGER_ADDR);
//Wrong sub index value
error SubIndexValueError();
//Wrong return index value
error ReturnIndexValueError();
/// @dev Subscription params index range [128, 255]
uint8 public constant SUB_MIN_INDEX_VALUE = 128;
uint8 public constant SUB_MAX_INDEX_VALUE = 255;
/// @dev Return params index range [1, 127]
uint8 public constant RETURN_MIN_INDEX_VALUE = 1;
uint8 public constant RETURN_MAX_INDEX_VALUE = 127;
/// @dev If the input value should not be replaced
uint8 public constant NO_PARAM_MAPPING = 0;
/// @dev We need to parse Flash loan actions in a different way
enum ActionType {
FL_ACTION,
STANDARD_ACTION,
FEE_ACTION,
CHECK_ACTION,
CUSTOM_ACTION
}
/// @notice Parses inputs and runs the implemented action through a user wallet
/// @dev Is called by the RecipeExecutor chaining actions together
/// @param _callData Array of input values each value encoded as bytes
/// @param _subData Array of subscribed vales, replaces input values if specified
/// @param _paramMapping Array that specifies how return and subscribed values are mapped in input
/// @param _returnValues Returns values from actions before, which can be injected in inputs
/// @return Returns a bytes32 value through user wallet, each actions implements what that value is
function executeAction(
bytes memory _callData,
bytes32[] memory _subData,
uint8[] memory _paramMapping,
bytes32[] memory _returnValues
) public payable virtual returns (bytes32);
/// @notice Parses inputs and runs the single implemented action through a user wallet
/// @dev Used to save gas when executing a single action directly
function executeActionDirect(bytes memory _callData) public payable virtual;
/// @notice Returns the type of action we are implementing
function actionType() public pure virtual returns (uint8);
//////////////////////////// HELPER METHODS ////////////////////////////
/// @notice Given an uint256 input, injects return/sub values if specified
/// @param _param The original input value
/// @param _mapType Indicated the type of the input in paramMapping
/// @param _subData Array of subscription data we can replace the input value with
/// @param _returnValues Array of subscription data we can replace the input value with
function _parseParamUint(
uint256 _param,
uint8 _mapType,
bytes32[] memory _subData,
bytes32[] memory _returnValues
) internal pure returns (uint256) {
if (isReplaceable(_mapType)) {
if (isReturnInjection(_mapType)) {
_param = uint256(_returnValues[getReturnIndex(_mapType)]);
} else {
_param = uint256(_subData[getSubIndex(_mapType)]);
}
}
return _param;
}
/// @notice Given an addr input, injects return/sub values if specified
/// @param _param The original input value
/// @param _mapType Indicated the type of the input in paramMapping
/// @param _subData Array of subscription data we can replace the input value with
/// @param _returnValues Array of subscription data we can replace the input value with
function _parseParamAddr(
address _param,
uint8 _mapType,
bytes32[] memory _subData,
bytes32[] memory _returnValues
) internal view returns (address) {
if (isReplaceable(_mapType)) {
if (isReturnInjection(_mapType)) {
_param = address(bytes20((_returnValues[getReturnIndex(_mapType)])));
} else {
/// @dev The last two values are specially reserved for proxy addr and owner addr
if (_mapType == 254) return address(this); // wallet address
if (_mapType == 255) return _fetchOwnerOrWallet(address(this)); // owner if 1/1 wallet or the wallet itself
_param = address(uint160(uint256(_subData[getSubIndex(_mapType)])));
}
}
return _param;
}
/// @notice Given an bytes32 input, injects return/sub values if specified
/// @param _param The original input value
/// @param _mapType Indicated the type of the input in paramMapping
/// @param _subData Array of subscription data we can replace the input value with
/// @param _returnValues Array of subscription data we can replace the input value with
function _parseParamABytes32(
bytes32 _param,
uint8 _mapType,
bytes32[] memory _subData,
bytes32[] memory _returnValues
) internal pure returns (bytes32) {
if (isReplaceable(_mapType)) {
if (isReturnInjection(_mapType)) {
_param = (_returnValues[getReturnIndex(_mapType)]);
} else {
_param = _subData[getSubIndex(_mapType)];
}
}
return _param;
}
/// @notice Checks if the paramMapping value indicated that we need to inject values
/// @param _type Indicated the type of the input
function isReplaceable(uint8 _type) internal pure returns (bool) {
return _type != NO_PARAM_MAPPING;
}
/// @notice Checks if the paramMapping value is in the return value range
/// @param _type Indicated the type of the input
function isReturnInjection(uint8 _type) internal pure returns (bool) {
return (_type >= RETURN_MIN_INDEX_VALUE) && (_type <= RETURN_MAX_INDEX_VALUE);
}
/// @notice Transforms the paramMapping value to the index in return array value
/// @param _type Indicated the type of the input
function getReturnIndex(uint8 _type) internal pure returns (uint8) {
if (!(isReturnInjection(_type))) {
revert SubIndexValueError();
}
return (_type - RETURN_MIN_INDEX_VALUE);
}
/// @notice Transforms the paramMapping value to the index in sub array value
/// @param _type Indicated the type of the input
function getSubIndex(uint8 _type) internal pure returns (uint8) {
if (_type < SUB_MIN_INDEX_VALUE) {
revert ReturnIndexValueError();
}
return (_type - SUB_MIN_INDEX_VALUE);
}
}
interface IInstaAccount {
function isAuth(address _user) external view returns (bool);
function enable(address _user) external;
function disable(address _user) external;
function version() external view returns (uint256);
}
contract DSAProxyPermission is AuthHelper {
/// @notice Called in the context of DSA proxy account to authorize an address
/// @param _contractAddr Address which will be authorized
/// @dev Can't enable the same contract twice
function _giveDSAProxyPermission(address _contractAddr) internal {
if (!IInstaAccount(address(this)).isAuth(_contractAddr)) {
IInstaAccount(address(this)).enable(_contractAddr);
}
}
/// @notice Called in the context of DSA proxy account to remove authority of an address
/// @param _contractAddr Auth address which will be removed from auth list
/// @dev Can't remove a contract that is not authorized
function _removeDSAProxyPermission(address _contractAddr) internal {
if (IInstaAccount(address(this)).isAuth(_contractAddr)) {
IInstaAccount(address(this)).disable(_contractAddr);
}
}
}
interface IDSAuthority {
function canCall(address src, address dst, bytes4 sig) external view returns (bool);
}
interface IDSAuth {
function authority() external view returns (IDSAuthority);
function owner() external view returns (address);
function setOwner(address owner_) external;
function setAuthority(IDSAuthority authority_) external;
function isAuthorized(address src, bytes4 sig) external view returns (bool);
}
interface IDSGuard {
function canCall(address src_, address dst_, bytes4 sig) external view returns (bool);
function permit(bytes32 src, bytes32 dst, bytes32 sig) external;
function forbid(bytes32 src, bytes32 dst, bytes32 sig) external;
function permit(address src, address dst, bytes32 sig) external;
function forbid(address src, address dst, bytes32 sig) external;
}
interface IDSGuardFactory {
function newGuard() external returns (IDSGuard guard);
}
contract DSProxyPermission is AuthHelper {
bytes4 private constant EXECUTE_SELECTOR = bytes4(keccak256("execute(address,bytes)"));
/// @notice Called in the context of DSProxy to authorize an address
/// @param _contractAddr Address which will be authorized
function _giveProxyPermission(address _contractAddr) internal {
address currAuthority = address(IDSAuth(address(this)).authority());
IDSGuard guard = IDSGuard(currAuthority);
if (currAuthority == address(0)) {
guard = IDSGuardFactory(DSGUARD_FACTORY_ADDRESS).newGuard();
IDSAuth(address(this)).setAuthority(IDSAuthority(address(guard)));
}
if (!guard.canCall(_contractAddr, address(this), EXECUTE_SELECTOR)) {
guard.permit(_contractAddr, address(this), EXECUTE_SELECTOR);
}
}
/// @notice Called in the context of DSProxy to remove authority of an address
/// @param _contractAddr Auth address which will be removed from authority list
function _removeProxyPermission(address _contractAddr) internal {
address currAuthority = address(IDSAuth(address(this)).authority());
// if there is no authority, that means that contract doesn't have permission
if (currAuthority == address(0)) {
return;
}
IDSGuard guard = IDSGuard(currAuthority);
guard.forbid(_contractAddr, address(this), EXECUTE_SELECTOR);
}
}
contract SafeModulePermission {
address private constant SENTINEL_MODULES = address(0x1);
error ModuleNotFoundError(address moduleAddr);
/// @notice Called in the context of Safe to authorize module
/// @param _moduleAddr Address of module which will be authorized
/// @dev Can't enable the same module twice
function _enableModule(address _moduleAddr) internal {
if (!ISafe(address(this)).isModuleEnabled(_moduleAddr)) {
ISafe(address(this)).enableModule(_moduleAddr);
}
}
/// @notice Called in the context of Safe to remove authority of module
/// @param _moduleAddr Address of module which will be removed from authority list
/// @dev moduleAddr has to be one of the last 10 modules added
/// @dev modules are returned in order SM -> Mn -> M(n-1) -> ... -> M1 -> SM, without SM included
function _disableModule(address _moduleAddr) internal {
address startFrom = SENTINEL_MODULES;
// to save on gas, first check for last 2 modules added as they are most likely to be the ones to be removed
(address[] memory modules,) = ISafe(address(this)).getModulesPaginated(startFrom, 2);
// if no modules found, revert
if (modules.length == 0) {
revert ModuleNotFoundError(_moduleAddr);
}
// check for last module added
if (modules[0] == _moduleAddr) {
ISafe(address(this)).disableModule(SENTINEL_MODULES, _moduleAddr);
return;
}
// if there is only 1 module and it is not the one to be removed, revert
if (modules.length == 1) {
revert ModuleNotFoundError(_moduleAddr);
}
// check for second last module added
if (modules[1] == _moduleAddr) {
ISafe(address(this)).disableModule(modules[0], _moduleAddr);
return;
}
// if module not found in last 2 modules, fetch up to 8 more modules. Start searching from the second last module
startFrom = modules[1];
(modules,) = ISafe(address(this)).getModulesPaginated(startFrom, 8);
if (modules.length > 0) {
if (modules[0] == _moduleAddr) {
ISafe(address(this)).disableModule(startFrom, _moduleAddr);
return;
}
for (uint256 i = 1; i < modules.length; ++i) {
if (modules[i] == _moduleAddr) {
ISafe(address(this)).disableModule(modules[i - 1], _moduleAddr);
return;
}
}
}
// if module not found, revert
revert ModuleNotFoundError(_moduleAddr);
}
}
interface IAccountGuard {
function owners(address) external view returns (address);
function owner() external view returns (address);
function setWhitelist(address target, bool status) external;
function canCall(address proxy, address operator) external view returns (bool);
function permit(address caller, address target, bool allowance) external;
function isWhitelisted(address target) external view returns (bool);
function isWhitelistedSend(address target) external view returns (bool);
}
interface IAccountImplementation {
function execute(address _target, bytes memory _data)
external
payable
returns (bytes32 response);
function send(address _target, bytes memory _data) external payable;
function owner() external view returns (address owner);
function guard() external view returns (address);
}
contract SFProxyPermission {
/// @notice Gives permission to an address to call the Summerfi account
/// @param _caller Address to give permission to
function _giveSFProxyPermission(address _caller) internal {
address guard = IAccountImplementation(address(this)).guard();
if (!IAccountGuard(guard).canCall(address(this), _caller)) {
IAccountGuard(guard).permit(_caller, address(this), true);
}
}
/// @notice Removes permission from an address to call the Summerfi account
/// @param _caller Address to remove permission from
function _removeSFProxyPermission(address _caller) internal {
address guard = IAccountImplementation(address(this)).guard();
if (IAccountGuard(guard).canCall(address(this), _caller)) {
IAccountGuard(guard).permit(_caller, address(this), false);
}
}
}
contract Permission is
DSProxyPermission,
SafeModulePermission,
DSAProxyPermission,
SFProxyPermission
{
/// @notice Gives permission to Auth contract used by dfs automation
function _givePermissionToAuthContract(bool _isDSProxyWallet) internal {
_isDSProxyWallet
? _giveProxyPermission(PROXY_AUTH_ADDRESS)
: _enableModule(MODULE_AUTH_ADDRESS);
}
/// @notice Removes permission for Auth contract used by dfs automation
function _removePermissionFromAuthContract(bool _isDSProxyWallet) internal {
_isDSProxyWallet
? _removeProxyPermission(PROXY_AUTH_ADDRESS)
: _disableModule(MODULE_AUTH_ADDRESS);
}
/// @notice Gives permission to an arbitrary contract
/// @dev Defaults to Safe Smart Wallet if wallet type is not found
/// @param _walletType Type of smart wallet
/// @param _to Address of the contract to give permission to
function _givePermissionTo(WalletType _walletType, address _to) internal {
if (_walletType == WalletType.DSPROXY) {
_giveProxyPermission(_to);
} else if (_walletType == WalletType.DSAPROXY) {
_giveDSAProxyPermission(_to);
} else if (_walletType == WalletType.SFPROXY) {
_giveSFProxyPermission(_to);
} else {
_enableModule(_to);
}
}
/// @notice Removes permission for an arbitrary contract
/// @dev Defaults to Safe Smart Wallet if wallet type is not found
/// @param _walletType Type of smart wallet
/// @param _from Address of the contract to remove permission from
function _removePermissionFrom(WalletType _walletType, address _from) internal {
if (_walletType == WalletType.DSPROXY) {
_removeProxyPermission(_from);
} else if (_walletType == WalletType.DSAPROXY) {
_removeDSAProxyPermission(_from);
} else if (_walletType == WalletType.SFPROXY) {
_removeSFProxyPermission(_from);
} else {
_disableModule(_from);
}
}
}
contract MainnetCoreAddresses {
address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b;
address internal constant DEFISAVER_LOGGER = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3;
address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
address internal constant MODULE_AUTH_ADDR = 0x7407974DDBF539e552F1d051e44573090912CC3D;
address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90;
address internal constant BUNDLE_STORAGE_ADDR = 0x223c6aDE533851Df03219f6E3D8B763Bd47f84cf;
address internal constant STRATEGY_STORAGE_ADDR = 0xF52551F95ec4A2B4299DcC42fbbc576718Dbf933;
address internal constant BYTES_TRANSIENT_STORAGE = 0xB3FE6f712c8B8c64CD2780ce714A36e7640DDf0f;
}
contract CoreHelper is MainnetCoreAddresses { }
contract StrategyModel {
/// @dev Group of strategies bundled together so user can sub to multiple strategies at once
/// @param creator Address of the user who created the bundle
/// @param strategyIds Array of strategy ids stored in StrategyStorage
struct StrategyBundle {
address creator;
uint64[] strategyIds;
}
/// @dev Template/Class which defines a Strategy
/// @param name Name of the strategy useful for logging what strategy is executing
/// @param creator Address of the user which created the strategy
/// @param triggerIds Array of identifiers for trigger - bytes4(keccak256(TriggerName))
/// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName))
/// @param paramMapping Describes how inputs to functions are piped from return/subbed values
/// @param continuous If the action is repeated (continuos) or one time
struct Strategy {
string name;
address creator;
bytes4[] triggerIds;
bytes4[] actionIds;
uint8[][] paramMapping;
bool continuous;
}
/// @dev List of actions grouped as a recipe
/// @param name Name of the recipe useful for logging what recipe is executing
/// @param callData Array of calldata inputs to each action
/// @param subData Used only as part of strategy, subData injected from StrategySub.subData
/// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName))
/// @param paramMapping Describes how inputs to functions are piped from return/subbed values
struct Recipe {
string name;
bytes[] callData;
bytes32[] subData;
bytes4[] actionIds;
uint8[][] paramMapping;
}
/// @dev Actual data of the sub we store on-chain
/// @dev In order to save on gas we store a keccak256(StrategySub) and verify later on
/// @param walletAddr Address of the users smart wallet/proxy
/// @param isEnabled Toggle if the subscription is active
/// @param strategySubHash Hash of the StrategySub data the user inputted
struct StoredSubData {
bytes20 walletAddr; // address but put in bytes20 for gas savings
bool isEnabled;
bytes32 strategySubHash;
}
/// @dev Instance of a strategy, user supplied data
/// @param strategyOrBundleId Id of the strategy or bundle, depending on the isBundle bool
/// @param isBundle If true the id points to bundle, if false points directly to strategyId
/// @param triggerData User supplied data needed for checking trigger conditions
/// @param subData User supplied data used in recipe
struct StrategySub {
uint64 strategyOrBundleId;
bool isBundle;
bytes[] triggerData;
bytes32[] subData;
}
/// @dev Data needed when signing relay transaction
/// @param maxTxCostInFeeToken Max tx cost user is willing to pay in fee token
/// @param feeToken Address of the token user is willing to pay fee in
/// @param tokenPriceInEth Price of the token in ETH
/// @param deadline Deadline for the relay transaction to be executed
/// @param shouldTakeFeeFromPosition Flag to indicate if fee should be taken from position, otherwise from EOA/wallet
struct TxSaverSignedData {
uint256 maxTxCostInFeeToken;
address feeToken;
uint256 tokenPriceInEth;
uint256 deadline;
bool shouldTakeFeeFromPosition;
}
}
contract DFSExchangeData {
struct OffchainData {
address wrapper; // dfs wrapper address for the aggregator (must be in WrapperExchangeRegistry)
address exchangeAddr; // exchange address we are calling to execute the order (must be in ExchangeAggregatorRegistry)
address allowanceTarget; // exchange aggregator contract we give allowance to
uint256 price; // expected price that the aggregator sent us
uint256 protocolFee; // deprecated (used as a separate fee amount for 0x v1)
bytes callData; // 0ff-chain calldata the aggregator gives to perform the swap
}
struct ExchangeData {
address srcAddr; // source token address (which we're selling)
address destAddr; // destination token address (which we're buying)
uint256 srcAmount; // amount of source token in token decimals
uint256 destAmount; // amount of bought token in token decimals
uint256 minPrice; // minPrice we are expecting (checked in DFSExchangeCore)
uint256 dfsFeeDivider; // service fee divider
address user; // currently deprecated (used to check custom fees for the user)
address wrapper; // on-chain wrapper address (must be in WrapperExchangeRegistry)
bytes wrapperData; // on-chain additional data for on-chain (uniswap route for example)
OffchainData offchainData; // offchain aggregator order
}
struct InjectedExchangeData {
address wrapper; // on-chain wrapper address (must be in WrapperExchangeRegistry)
bytes wrapperData; // on-chain additional data for on-chain (uniswap route for example)
OffchainData offchainData; // offchain aggregator order
}
}
interface IActionBase {
function executeAction(
bytes memory _callData,
bytes32[] memory _subData,
uint8[] memory _paramMapping,
bytes32[] memory _returnValues
) external payable returns (bytes32);
function executeActionDirect(bytes memory _callData) external payable;
function actionType() external pure returns (uint8);
}
interface IBundleStorage {
function openToPublic() external view returns (bool);
function createBundle(uint64[] memory _strategyIds) external returns (uint256);
function changeEditPermission(bool _openToPublic) external;
function getStrategyId(uint256 _bundleId, uint256 _strategyIndex)
external
view
returns (uint256);
function getBundle(uint256 _bundleId)
external
view
returns (StrategyModel.StrategyBundle memory);
function getBundleCount() external view returns (uint256);
function getPaginatedBundles(uint256 _page, uint256 _perPage)
external
view
returns (StrategyModel.StrategyBundle[] memory);
}
interface IRecipeExecutor {
function executeRecipe(StrategyModel.Recipe calldata _currRecipe) external payable;
function executeRecipeFromTxSaver(
StrategyModel.Recipe calldata _currRecipe,
StrategyModel.TxSaverSignedData calldata _txSaverData
) external payable;
function executeRecipeFromStrategy(
uint256 _subId,
bytes[] calldata _actionCallData,
bytes[] calldata _triggerCallData,
uint256 _strategyIndex,
StrategyModel.StrategySub memory _sub
) external payable;
function executeActionsFromFL(StrategyModel.Recipe calldata _currRecipe, bytes32 _flAmount)
external
payable;
}
interface IStrategyStorage {
function openToPublic() external view returns (bool);
function createStrategy(
string memory _name,
bytes4[] memory _triggerIds,
bytes4[] memory _actionIds,
uint8[][] memory _paramMapping,
bool _continuous
) external returns (uint256);
function changeEditPermission(bool _openToPublic) external;
function getStrategy(uint256 _strategyId) external view returns (StrategyModel.Strategy memory);
function getStrategyCount() external view returns (uint256);
function getPaginatedStrategies(uint256 _page, uint256 _perPage)
external
view
returns (StrategyModel.Strategy[] memory);
}
interface ISubStorage {
function subscribeToStrategy(StrategyModel.StrategySub memory _sub) external returns (uint256);
function updateSubData(uint256 _subId, StrategyModel.StrategySub calldata _sub) external;
function activateSub(uint256 _subId) external;
function deactivateSub(uint256 _subId) external;
function getSub(uint256 _subId) external view returns (StrategyModel.StoredSubData memory);
function getSubsCount() external view returns (uint256);
}
interface ITrigger {
function isTriggered(bytes memory, bytes memory) external returns (bool);
function isChangeable() external view returns (bool);
function changedSubData(bytes memory) external view returns (bytes memory);
}
interface ITxSaverBytesTransientStorage {
function getFeeType() external view returns (uint256);
function getBytesTransiently() external view returns (bytes memory result);
}
interface IFlashLoanBase {
struct FlashLoanParams {
address[] tokens;
uint256[] amounts;
uint256[] modes;
address onBehalfOf;
address flParamGetterAddr;
bytes flParamGetterData;
bytes recipeData;
}
}
contract DSMath {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x + y;
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x - y;
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x * y;
}
function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x / y;
}
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x <= y ? x : y;
}
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
return x >= y ? x : y;
}
function imin(int256 x, int256 y) internal pure returns (int256 z) {
return x <= y ? x : y;
}
function imax(int256 x, int256 y) internal pure returns (int256 z) {
return x >= y ? x : y;
}
uint256 constant WAD = 10 ** 18;
uint256 constant RAY = 10 ** 27;
function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
contract MainnetUtilAddresses {
address internal refillCaller = 0x8973f5e6142ed2e2F50EEE8Bb34a47C2DAa6624a;
address internal constant FEE_RECIPIENT_ADDR = 0x39C4a92Dc506300c3Ea4c67ca4CA611102ee6F2A;
address internal constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
address internal constant UNI_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address internal constant MKR_PROXY_REGISTRY = 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4;
address internal constant AAVE_MARKET = 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5;
address internal constant AAVE_V3_MARKET = 0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e;
address internal constant SPARK_MARKET = 0x02C3eA4e34C0cBd694D2adFa2c690EECbC1793eE;
address internal constant DFS_PROXY_REGISTRY_ADDR = 0x29474FdaC7142f9aB7773B8e38264FA15E3805ed;
address internal constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant WSTETH_ADDR = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
address internal constant STETH_ADDR = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
a...
// [truncated — 82536 bytes total]
Read Contract
adminVault 0x8cedca71 → address
Write Contract 5 functions
These functions modify contract state and require a wallet transaction to execute.
executeActionsFromFL 0x2aeae6ec
tuple _currRecipe
bytes32 _flAmount
executeRecipe 0xe6e3534d
tuple _currRecipe
executeRecipeFromStrategy 0x6a90acf4
uint256 _subId
bytes[] _actionCallData
bytes[] _triggerCallData
uint256 _strategyIndex
tuple _sub
executeRecipeFromTxSaver 0x5dfbd566
tuple _currRecipe
tuple _txSaverData
withdrawStuckFunds 0xc579d490
address _token
address _receiver
uint256 _amount
Recent Transactions
This address has 1 on-chain transactions, but only 1.6% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →