Address Contract Verified
Address
0xdad2DFF89e9B4cb131F4922aC0Fab21270b59c87
Balance
0 ETH
Nonce
3
Code Size
21273 bytes
Creator
0xba5Ed099...a5Ed at tx 0x129d21f5...8df24e
Indexed Transactions
0
Contract Bytecode
21273 bytes
0x60806040523480156200001157600080fd5b5060043610620000b75760003560e01c8063a59a9973116200007a578063a59a99731462000182578063a840332714620001aa578063aced166114620001c1578063e436a60b14620001d5578063ed27f7c914620001fd578063f887ea40146200021157600080fd5b80630d00442414620000bc578063316b373914620000e8578063363bf964146200012d5780635001f3b5146200014657806388a8d602146200016e575b600080fd5b620000d3620000cd36600462000845565b62000239565b60405190151581526020015b60405180910390f35b62000114620000f936600462000845565b6003602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001620000df565b620001446200013e3660046200086c565b620002c9565b005b620001147f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60005462000114906001600160a01b031681565b620001147f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e281565b62000114620001bb36600462000845565b6200037e565b60025462000114906001600160a01b031681565b620001147f000000000000000000000000c0a7c631f50abaaab9942839720803e16a24172d81565b60015462000114906001600160a01b031681565b620001147f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b600080826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200027b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a19190620008be565b6001600160a01b03908116600090815260036020526040902054811693169290921492915050565b6000546001600160a01b03163314620003175760405162461bcd60e51b815260206004820152600b60248201526a085b585b9859d95b595b9d60aa1b60448201526064015b60405180910390fd5b6001600160a01b0383166200033f576040516303988b8160e61b815260040160405180910390fd5b600080546001600160a01b039485166001600160a01b031991821617909155600180549385169382169390931790925560028054919093169116179055565b600080546001600160a01b03163314620003c95760405162461bcd60e51b815260206004820152600b60248201526a085b585b9859d95b595b9d60aa1b60448201526064016200030e565b6001600160a01b03828116600090815260036020526040902054161562000422576001600160a01b03828116600090815260036020526040908190205490516329ab51bf60e01b8152911660048201526024016200030e565b6000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000463573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200048d91908101906200091a565b6040516020016200049f9190620009d3565b6040516020818303038152906040529050600083827f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e27f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615647f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260405162000525906200081e565b6200053595949392919062000a16565b604051809103906000f08015801562000552573d6000803e3d6000fd5b5060015460405163352f8d5160e11b81526001600160a01b039182166004820152919250821690636a5f1aa290602401600060405180830381600087803b1580156200059d57600080fd5b505af1158015620005b2573d6000803e3d6000fd5b5050600254604051633a43a3f360e11b81526001600160a01b039182166004820152908416925063748747e69150602401600060405180830381600087803b158015620005fe57600080fd5b505af115801562000613573d6000803e3d6000fd5b5050600054604051630f629b7960e41b81526001600160a01b039182166004820152908416925063f629b7909150602401600060405180830381600087803b1580156200065f57600080fd5b505af115801562000674573d6000803e3d6000fd5b5050604051630d768ce560e21b81526001600160a01b037f000000000000000000000000c0a7c631f50abaaab9942839720803e16a24172d81166004830152841692506335da33949150602401600060405180830381600087803b158015620006dc57600080fd5b505af1158015620006f1573d6000803e3d6000fd5b505060405163aa290e6d60e01b81526107d060048201526001600160a01b038416925063aa290e6d9150602401600060405180830381600087803b1580156200073957600080fd5b505af11580156200074e573d6000803e3d6000fd5b5050604051636fb4d91560e11b81526203f48060048201526001600160a01b038416925063df69b22a9150602401600060405180830381600087803b1580156200079757600080fd5b505af1158015620007ac573d6000803e3d6000fd5b50506040516001600160a01b038088169350841691507f0af7b0321568b9f79652baf50d0aa93f58f651114afc2d87fece680a6bbddd4990600090a36001600160a01b03938416600090815260036020526040902080546001600160a01b031916948216949094179093555090919050565b6148728062000a7283390190565b6001600160a01b03811681146200084257600080fd5b50565b6000602082840312156200085857600080fd5b813562000865816200082c565b9392505050565b6000806000606084860312156200088257600080fd5b83356200088f816200082c565b92506020840135620008a1816200082c565b91506040840135620008b3816200082c565b809150509250925092565b600060208284031215620008d157600080fd5b815162000865816200082c565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000911578181015183820152602001620008f7565b50506000910152565b6000602082840312156200092d57600080fd5b815167ffffffffffffffff808211156200094657600080fd5b818401915084601f8301126200095b57600080fd5b815181811115620009705762000970620008de565b604051601f8201601f19908116603f011681019083821181831017156200099b576200099b620008de565b81604052828152876020848701011115620009b557600080fd5b620009c8836020830160208801620008f4565b979650505050505050565b67020b0bb32902b19960c51b815260008251620009f8816008850160208701620008f4565b66102632b73232b960c91b6008939091019283015250600f01919050565b600060018060a01b03808816835260a0602084015286518060a085015262000a468160c0860160208b01620008f4565b95811660408401529384166060830152509116608082015260c0601f909201601f191601019291505056fe610140604052600080546227100162ffffff19909116179055600480546001600160a01b031990811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2179091556005805490911673e592427a0aece92de3edee1f18e0157c058615641790553480156200006d57600080fd5b5060405162004872380380620048728339810160408190526200009091620007ae565b6001600160a01b0385166080523060a052604051859085908290829082908290829082906200010590620000d190849084903390819081906024016200089b565b60408051601f198184030181529190526020810180516001600160e01b03908116634b839d7360e11b179091526200035016565b505073f0c3ff22876d34f1a7dc342385ea17fcf66376d17f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5550506002805460ff19166001179055505050506001600160a01b0384811660e08190526040516335ea6a7560e01b8152918816600483015291506335ea6a75906024016101e060405180830381865afa158015620001a0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c691906200097c565b61010001516001600160a01b0316610120819052620002165760405162461bcd60e51b815260206004820152600760248201526610b0aa37b5b2b760c91b60448201526064015b60405180910390fd5b610120516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000258573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200027e919062000ac0565b60ff1660c08181525050610120516001600160a01b03166375d264136040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002ca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f0919062000ae5565b6001600160a01b039081166101005260e05160805162000315921690600019620003e4565b6000600355600580546001600160a01b039384166001600160a01b031991821617909155600480549290931691161790555062000b47915050565b606060008073f0c3ff22876d34f1a7dc342385ea17fcf66376d16001600160a01b03168460405162000383919062000b05565b600060405180830381855af49150503d8060008114620003c0576040519150601f19603f3d011682016040523d82523d6000602084013e620003c5565b606091505b509150915081620003dd576040513d806000833e8082fd5b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200043e9085908390620004b016565b620004aa57604080516001600160a01b038516602482015260006044808301919091528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200049e9186916200056116565b620004aa848262000561565b50505050565b6000806000846001600160a01b031684604051620004cf919062000b05565b6000604051808303816000865af19150503d80600081146200050e576040519150601f19603f3d011682016040523d82523d6000602084013e62000513565b606091505b5091509150818015620005415750805115806200054157508080602001905181019062000541919062000b23565b80156200055857506000856001600160a01b03163b115b95945050505050565b6000620005786001600160a01b03841683620005d0565b90508051600014158015620005a05750808060200190518101906200059e919062000b23565b155b15620005cb57604051635274afe760e01b81526001600160a01b03841660048201526024016200020d565b505050565b6060620003dd8383600084600080856001600160a01b03168486604051620005f9919062000b05565b60006040518083038185875af1925050503d806000811462000638576040519150601f19603f3d011682016040523d82523d6000602084013e6200063d565b606091505b509092509050620006508683836200065a565b9695505050505050565b60608262000673576200066d82620006be565b620003dd565b81511580156200068b57506001600160a01b0384163b155b15620006b657604051639996b31560e01b81526001600160a01b03851660048201526024016200020d565b5080620003dd565b805115620006cf5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b6001600160a01b0381168114620006e857600080fd5b80516200070e81620006eb565b919050565b634e487b7160e01b600052604160045260246000fd5b6040516101e081016001600160401b03811182821017156200074f576200074f62000713565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000780576200078062000713565b604052919050565b60005b83811015620007a55781810151838201526020016200078b565b50506000910152565b600080600080600060a08688031215620007c757600080fd5b8551620007d481620006eb565b60208701519095506001600160401b0380821115620007f257600080fd5b818801915088601f8301126200080757600080fd5b8151818111156200081c576200081c62000713565b62000831601f8201601f191660200162000755565b91508082528960208285010111156200084957600080fd5b6200085c81602084016020860162000788565b5094506200086f90506040870162000701565b92506200087f6060870162000701565b91506200088f6080870162000701565b90509295509295909350565b600060018060a01b03808816835260a0602084015286518060a0850152620008cb8160c0860160208b0162000788565b95811660408401529384166060830152509116608082015260c0601f909201601f1916010192915050565b6000602082840312156200090957600080fd5b604051602081016001600160401b03811182821017156200092e576200092e62000713565b6040529151825250919050565b80516001600160801b03811681146200070e57600080fd5b805164ffffffffff811681146200070e57600080fd5b805161ffff811681146200070e57600080fd5b60006101e082840312156200099057600080fd5b6200099a62000729565b620009a68484620008f6565b8152620009b6602084016200093b565b6020820152620009c9604084016200093b565b6040820152620009dc606084016200093b565b6060820152620009ef608084016200093b565b608082015262000a0260a084016200093b565b60a082015262000a1560c0840162000953565b60c082015262000a2860e0840162000969565b60e082015261010062000a3d81850162000701565b9082015261012062000a5184820162000701565b9082015261014062000a6584820162000701565b9082015261016062000a7984820162000701565b9082015261018062000a8d8482016200093b565b908201526101a062000aa18482016200093b565b908201526101c062000ab58482016200093b565b908201529392505050565b60006020828403121562000ad357600080fd5b815160ff81168114620003dd57600080fd5b60006020828403121562000af857600080fd5b8151620003dd81620006eb565b6000825162000b1981846020870162000788565b9190910192915050565b60006020828403121562000b3657600080fd5b81518015158114620003dd57600080fd5b60805160a05160c05160e0516101005161012051613bb562000cbd600039600081816105b8015281816107b901528181610f9101528181611d4801528181611ec8015281816122a7015261241b0152600081816104de0152611da20152600081816105f20152818161086a01528181610b1101528181610e4a0152818161225701526126350152600061214501526000818161091b015281816109da01528181610a5f01528181610b9e01528181610c4701528181610d250152818161128b0152818161130e0152818161143f015281816114c0015281816115400152818161172201528181611779015281816118040152818161189e01528181611add01528181611b6001528181611c67015281816124b60152818161266801526127a801526000818161083b01528181610ae201528181610e1c01528181610f1c015281816113c50152818161191101528181611e8d01528181611ffc01528181612281015281816125f9015261289d0152613bb56000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c8063797bf3431161019d578063ac00ff26116100e9578063d19a3bb8116100a2578063f887ea401161007c578063f887ea401461074b578063fc7f71b61461075e578063fde813a814610771578063ff9913e814610784576102f1565b8063d19a3bb8146106d9578063d6968601146106f4578063f3ce280a14610707576102f1565b8063ac00ff261461063a578063b460af941461064d578063b4a8d1b614610660578063b8c6f57914610690578063ba087652146106a3578063babcc539146106b6576102f1565b80639d7fb70c11610156578063a318c1a411610130578063a318c1a4146105da578063a59a9973146105ed578063a9059cbb14610614578063a98f929614610627576102f1565b80639d7fb70c1461058d5780639f40a7b3146105a0578063a0c1f15e146105b3576102f1565b8063797bf343146105265780637d9699321461052e5780637d9f6db51461054157806394bf804d14610554578063950b3d73146105675780639c52a7f11461057a576102f1565b806346aa2f121161025c5780635d265d3f116102155780636718835f116101ef5780636718835f146104cc5780636bb65f53146104d95780636e553f65146105005780637570594914610513576102f1565b80635d265d3f1461048e5780635d6297b1146104a45780635e311fa5146104ac576102f1565b806346aa2f121461041757806349317f1d1461042a5780634a5d0943146104325780635001f3b514610443578063503160d91461046e57806351fb012d14610481576102f1565b8063227b9f5a116102ae578063227b9f5a1461039157806323b872dd146103a45780632606a10b146103c75780632e3ecf2c146103e4578063372500ab146103f75780633d6cb57514610404576102f1565b806304bd46291461032c578063052d9e7e1461035257806318144367146103655780631aa1f9381461036e5780631e17d967146103815780632036181414610389575b73f0c3ff22876d34f1a7dc342385ea17fcf66376d13660008037600080366000845af43d6000803e808015610325573d6000f35b3d6000fd5b005b61033f61033a36600461320a565b610797565b6040519081526020015b60405180910390f35b61032a610360366004613235565b610906565b61033f60035481565b61032a61037c366004613252565b6109c5565b61032a610a4a565b61033f610acb565b61032a61039f366004613252565b610b89565b6103b76103b236600461327e565b610c1c565b6040519015158152602001610349565b6103cf610cbf565b60408051928352602083019190915201610349565b61032a6103f23660046132bf565b610d10565b600a546103b79060ff1681565b61032a610412366004613312565b610de5565b61033f61042536600461320a565b610df9565b61033f611048565b600054610100900461ffff1661033f565b600454610456906001600160a01b031681565b6040516001600160a01b039091168152602001610349565b61032a61047c366004613312565b611068565b6002546103b79060ff1681565b610496611079565b60405161034992919061337b565b6103b76110b7565b61033f6104ba36600461320a565b60086020526000908152604090205481565b6000546103b79060ff1681565b6104567f000000000000000000000000000000000000000000000000000000000000000081565b61033f61050e366004613396565b611284565b61032a6105213660046133c6565b6112f9565b61033f6113ad565b6000546301000000900461ffff1661033f565b600754610456906001600160a01b031681565b61033f610562366004613396565b611438565b61032a610575366004613312565b6114ab565b61032a61058836600461320a565b61152b565b61032a61059b366004613312565b6115f8565b61033f6105ae3660046133f8565b611609565b6104567f000000000000000000000000000000000000000000000000000000000000000081565b61033f6105e83660046133f8565b611685565b6104567f000000000000000000000000000000000000000000000000000000000000000081565b6103b7610622366004613252565b6116ff565b61032a610635366004613235565b611764565b61032a610648366004613235565b6117ef565b61033f61065b366004613440565b61187a565b61068361066e36600461320a565b60096020526000908152604090205460ff1681565b604051610349919061348d565b61032a61069e36600461320a565b611889565b61033f6106b1366004613440565b611ab8565b6103b76106c436600461320a565b60016020526000908152604090205460ff1681565b61045673f0c3ff22876d34f1a7dc342385ea17fcf66376d181565b61032a610702366004613312565b611ac8565b6107376107153660046134b5565b600660209081526000928352604080842090915290825290205462ffffff1681565b60405162ffffff9091168152602001610349565b600554610456906001600160a01b031681565b61033f61076c36600461320a565b611b48565b61032a61077f366004613312565b611c41565b61032a61079236600461320a565b611c52565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610800573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082491906134e3565b6040516335ea6a7560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192506108e3917f000000000000000000000000000000000000000000000000000000000000000016906335ea6a75906024016101e060405180830381865afa1580156108b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d69190613601565b51516001603c1b16151590565b156108ec575060005b806108f56113ad565b6108ff919061373a565b9392505050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561096557600080fd5b505afa158015610979573d6000803e3d6000fd5b50506002805460ff19168415159081179091556040519081527f9bea0dd3cae4438dc4c54c3110002aedc380f4075b6edae73ae0536105a2008a9250602001905060405180910390a150565b60405163d43fdcf760e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d43fdcf79060240160006040518083038186803b158015610a2457600080fd5b505afa158015610a38573d6000803e3d6000fd5b50505050610a468282611d1c565b5050565b60405163d43fdcf760e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d43fdcf79060240160006040518083038186803b158015610aa957600080fd5b505afa158015610abd573d6000803e3d6000fd5b50505050610ac9612037565b565b6040516335ea6a7560e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600091610b84917f000000000000000000000000000000000000000000000000000000000000000016906335ea6a75906024016101e060405180830381865afa158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190613601565b5151612132565b905090565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610be857600080fd5b505afa158015610bfc573d6000803e3d6000fd5b5050506001600160a01b0390921660009081526008602052604090205550565b6040516001600160a01b038481166024830152838116604483015260648201839052600091610ca4917f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612175565b806020019051810190610cb7919061374d565b949350505050565b6000806040805160048152602481019091526020810180516001600160e01b0316632606a10b60e01b179052610cf490612175565b806020019051810190610d07919061376a565b90925090509091565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610d6f57600080fd5b505afa158015610d83573d6000803e3d6000fd5b5050506001600160a01b0380851660008181526006602081815260408084209589168452948152848320805462ffffff1990811662ffffff8a16908117909255928252858420948452939052929020805490921617905550505050565b505050565b610ded612203565b610df68161223a565b50565b600080610e058361238d565b6040516335ea6a7560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906335ea6a75906024016101e060405180830381865afa158015610e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb69190613601565b515190506001603c1b8116151580610ed75750670200000000000000811615155b15610ee6575060009392505050565b6000610ef182612132565b905080600003610f045750909392505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8f91906134e3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101191906134e3565b61101b919061373a565b90508082116110305750600095945050505050565b80820361103d85826123cf565b979650505050505050565b6000611052612203565b61105a6123e5565b905061106581612498565b90565b611070612203565b610df6816125e2565b60006060611085612664565b6040805160048152602481019091526020810180516001600160e01b031663440368a360e01b17905290939092509050565b6000466001146110c75750600090565b60405163091030c360e01b8152306004820152600090734da27a545c0c5b758a6ba100e3a049001de870f59063091030c3906024016040805180830381865afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061378e565b5164ffffffffff169050600081900361115757600091505090565b6000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663616e0bf96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cf91906134e3565b90506000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663359c4a966040518163ffffffff1660e01b8152600401602060405180830381865afa158015611225573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124991906134e3565b9050611255828461373a565b421061127a5780611266838561373a565b61127090426137f7565b1115935050505090565b6000935050505090565b60006112dd7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e553f658585604051602401610c729291909182526001600160a01b0316602082015260400190565b8060200190518101906112f091906134e3565b90505b92915050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561135857600080fd5b505afa15801561136c573d6000803e3d6000fd5b5050506001600160a01b0383166000908152600960205260409020805483925060ff191660018360028111156113a4576113a4613477565b02179055505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611414573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8491906134e3565b60006114917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166394bf804d8585604051602401610c729291909182526001600160a01b0316602082015260400190565b8060200190518101906114a491906134e3565b90506112f3565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561150a57600080fd5b505afa15801561151e573d6000803e3d6000fd5b50505050610df681612700565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561158a57600080fd5b505afa15801561159e573d6000803e3d6000fd5b505050506001600160a01b0381166000818152600160209081526040808320805460ff19169055519182527ff93f9a76c1bf3444d22400a00cb9fe990e6abe9dbb333fda48859cfee864543d91015b60405180910390a250565b611600612203565b610df68161279b565b6000604051602481018690526001600160a01b03808616604483015284166064820152608481018390526116699060a40160408051601f198184030181529190526020810180516001600160e01b0316639f40a7b360e01b179052612175565b80602001905181019061167c91906134e3565b95945050505050565b6000604051602481018690526001600160a01b03808616604483015284166064820152608481018390526116e59060a40160408051601f198184030181529190526020810180516001600160e01b03166328c6306960e21b179052612175565b8060200190518101906116f891906134e3565b9050610cb7565b6040516001600160a01b03838116602483015260448201839052600091611751917f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90606401610c72565b8060200190518101906114a4919061374d565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156117c357600080fd5b505afa1580156117d7573d6000803e3d6000fd5b5050600a805460ff1916931515939093179092555050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561184e57600080fd5b505afa158015611862573d6000803e3d6000fd5b50506000805460ff1916931515939093179092555050565b6000610cb78484846000611685565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156118e857600080fd5b505afa1580156118fc573d6000803e3d6000fd5b505050506001600160a01b03811615611a96577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316631f1fcd516040518163ffffffff1660e01b8152600401602060405180830381865afa158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b919061380a565b6001600160a01b0316146119e35760405162461bcd60e51b815260206004820152600a6024820152691ddc9bdb99c81dd85b9d60b21b60448201526064015b60405180910390fd5b306001600160a01b0316816001600160a01b031663f7260d3e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f919061380a565b6001600160a01b031614611a965760405162461bcd60e51b815260206004820152600e60248201526d3bb937b733903932b1b2b4bb32b960911b60448201526064016119da565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6000610cb7848484612710611609565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015611b2757600080fd5b505afa158015611b3b573d6000803e3d6000fd5b50505050610df681612838565b60405163d43fdcf760e01b81523360048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d43fdcf79060240160006040518083038186803b158015611baa57600080fd5b505afa158015611bbe573d6000803e3d6000fd5b5060029250611bcb915050565b6001600160a01b03831660009081526009602052604090205460ff166002811115611bf857611bf8613477565b14611c305760405162461bcd60e51b815260206004820152600860248201526710b0bab1ba34b7b760c11b60448201526064016119da565b611c3982612899565b90505b919050565b611c49612203565b610df681610ded565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015611cb157600080fd5b505afa158015611cc5573d6000803e3d6000fd5b505050506001600160a01b038116600081815260016020818152604092839020805460ff19168317905591519081527ff93f9a76c1bf3444d22400a00cb9fe990e6abe9dbb333fda48859cfee864543d91016115ed565b611d24612037565b604080516001808252818301909252600091602080830190803683370190505090507f000000000000000000000000000000000000000000000000000000000000000081600081518110611d7a57611d7a613827565b6001600160a01b039283166020918202929092010152604051635fc87b1d60e11b81526000917f0000000000000000000000000000000000000000000000000000000000000000169063bf90f63a90611dd790859060040161383d565b6000604051808303816000875af1158015611df6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e1e919081019061391d565b509050611e29612aa0565b6000805b825181101561202f57828181518110611e4857611e48613827565b6020026020010151915060006001600160a01b0316866001600160a01b031614158015611e875750856001600160a01b0316826001600160a01b031614155b612027577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480611efc57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b61202757734da27a545c0c5b758a6ba100e3a049001de870f4196001600160a01b03831601611f3d57737fc66500c84a76ad7e9c93437bfc5ac33e2ddae991505b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b815230600482015260ff90911692906370a0823190602401602060405180830381865afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba91906134e3565b6001600160a01b038516600090815260086020526040902054909150811115612024576001826002811115611ff157611ff1613477565b0361202457612022847f0000000000000000000000000000000000000000000000000000000000000000838a612b89565b505b50505b600101611e2d565b505050505050565b61203f6110b7565b61204557565b6040516370a0823160e01b8152306004820152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190602401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906134e3565b90508015610df6576040516301e9a69560e41b815230600482015260248101829052734da27a545c0c5b758a6ba100e3a049001de870f590631e9a6950906044015b600060405180830381600087803b15801561211757600080fd5b505af115801561212b573d6000803e3d6000fd5b5050505050565b6000640fffffffff607483901c1661216b7f0000000000000000000000000000000000000000000000000000000000000000600a613ac6565b6108ff9082613ad2565b606060008073f0c3ff22876d34f1a7dc342385ea17fcf66376d16001600160a01b0316846040516121a69190613ae9565b600060405180830381855af49150503d80600081146121e1576040519150601f19603f3d011682016040523d82523d6000602084013e6121e6565b606091505b5091509150816108ff576040513d806000833e8082fd5b50505050565b333014610ac95760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b60448201526064016119da565b6040516370a0823160e01b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916369328dec917f000000000000000000000000000000000000000000000000000000000000000091612318917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156122ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231291906134e3565b856123cf565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201523060448201526064016020604051808303816000875af1158015612369573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4691906134e3565b60025460009060ff1615806123ba57506001600160a01b03821660009081526001602052604090205460ff165b156123c757600019611c39565b506000919050565b60008183106123de57816112f0565b5090919050565b600a5460009060ff16156123fe576123fe600080611d1c565b6124066113ad565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561246a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248e91906134e3565b610b84919061373a565b60005460ff166124b257506000805460ff19166001179055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015612512573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253691906134e3565b9050808211156125aa576000546127109061255a90610100900461ffff1683613ad2565b6125649190613b05565b61256e82846137f7565b1115610a465760405162461bcd60e51b815260206004820152600b60248201526a6865616c7468436865636b60a81b60448201526064016119da565b81811115610a4657600054612710906125ce906301000000900461ffff1683613ad2565b6125d89190613b05565b61256e83836137f7565b60405163617ba03760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201839052306044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169063617ba037906084016120fd565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e8919061374d565b158015610b84575060006126fa6113ad565b11905090565b6000811161273f5760405162461bcd60e51b815260206004820152600c60248201526b085e995c9bc81c1c9bd99a5d60a21b60448201526064016119da565b61ffff81111561277d5760405162461bcd60e51b8152602060048201526009602482015268042e8dede40d0d2ced60bb1b60448201526064016119da565b6000805461ffff9092166101000262ffff0019909216919091179055565b60008111801561282a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015612804573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612828919061374d565b155b15610df657610df6816125e2565b61271081106128775760405162461bcd60e51b815260206004820152600b60248201526a085b1bdcdcc81b1a5b5a5d60aa1b60448201526064016119da565b6000805461ffff90921663010000000264ffff00000019909216919091179055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361290a5760405162461bcd60e51b815260206004820152600b60248201526a63616e6e6f74206b69636b60a81b60448201526064016119da565b6007546001600160a01b031661294f5760405162461bcd60e51b815260206004820152600a60248201526937379030bab1ba34b7b760b11b60448201526064016119da565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ba91906134e3565b6001600160a01b0384166000908152600860205260409020549091508111612a165760405162461bcd60e51b815260206004820152600f60248201526e62616c616e636520746f6f206c6f7760881b60448201526064016119da565b600754612a30906001600160a01b03858116911683612e3d565b6007546040516396c5517560e01b81526001600160a01b038581166004830152909116906396c55175906024016020604051808303816000875af1158015612a7c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ff91906134e3565b46600114612aaa57565b6040516370a0823160e01b8152306004820152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190602401602060405180830381865afa158015612afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2091906134e3565b1115610ac957734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612b7557600080fd5b505af11580156121fd573d6000803e3d6000fd5b60008215801590612b9c57506003548310155b15610cb757600554612bb8906001600160a01b03168685612e9c565b6004546001600160a01b0386811691161480612be157506004546001600160a01b038581169116145b15612cfb5760408051610100810182526001600160a01b0387811680835287821660208085018281526000938452600682528684209284529190528482205462ffffff9081168587019081523060608701908152426080880190815260a088018c815260c089018c815260e08a019788526005549a5163414bf38960e01b81528a518a16600482015296518916602488015293519094166044860152905186166064850152516084840152905160a48301525160c48201529051821660e48201529192169063414bf38990610104016020604051808303816000875af1158015612ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf391906134e3565b915050610cb7565b6001600160a01b038581166000908152600660208181526040808420600454808716865290835281852054938352818520958a1685529482528084205490516bffffffffffffffffffffffff1960608c811b8216948301949094526001600160e81b031960e895861b8116603484015296841b811660378301529190931b909416604b83015287901b909216604e8301529060620160408051601f1981840301815260055460a08401835281845230602085015242848401526060840188905260808401879052915163c04b8d5960e01b81529093506001600160a01b039091169163c04b8d5991612df09190600401613b27565b6020604051808303816000875af1158015612e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3391906134e3565b9695505050505050565b6040516001600160a01b03838116602483015260448201839052610de091859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612f3e565b604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015282919084169063dd62ed3e90604401602060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0f91906134e3565b1015610de057612f2a6001600160a01b038316846000612fa1565b610de06001600160a01b0383168483612fa1565b6000612f536001600160a01b03841683613031565b90508051600014158015612f78575080806020019051810190612f76919061374d565b155b15610de057604051635274afe760e01b81526001600160a01b03841660048201526024016119da565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052612ff2848261303f565b6121fd576040516001600160a01b0384811660248301526000604483015261302791869182169063095ea7b390606401612e6a565b6121fd8482612f3e565b60606112f0838360006130e2565b6000806000846001600160a01b03168460405161305c9190613ae9565b6000604051808303816000865af19150503d8060008114613099576040519150601f19603f3d011682016040523d82523d6000602084013e61309e565b606091505b50915091508180156130c85750805115806130c85750808060200190518101906130c8919061374d565b801561167c5750505050506001600160a01b03163b151590565b6060814710156131075760405163cd78605960e01b81523060048201526024016119da565b600080856001600160a01b031684866040516131239190613ae9565b60006040518083038185875af1925050503d8060008114613160576040519150601f19603f3d011682016040523d82523d6000602084013e613165565b606091505b5091509150612e3386838360608261318557613180826131cc565b6108ff565b815115801561319c57506001600160a01b0384163b155b156131c557604051639996b31560e01b81526001600160a01b03851660048201526024016119da565b50806108ff565b8051156131dc5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610df657600080fd5b60006020828403121561321c57600080fd5b81356108ff816131f5565b8015158114610df657600080fd5b60006020828403121561324757600080fd5b81356108ff81613227565b6000806040838503121561326557600080fd5b8235613270816131f5565b946020939093013593505050565b60008060006060848603121561329357600080fd5b833561329e816131f5565b925060208401356132ae816131f5565b929592945050506040919091013590565b6000806000606084860312156132d457600080fd5b83356132df816131f5565b925060208401356132ef816131f5565b9150604084013562ffffff8116811461330757600080fd5b809150509250925092565b60006020828403121561332457600080fd5b5035919050565b60005b8381101561334657818101518382015260200161332e565b50506000910152565b6000815180845261336781602086016020860161332b565b601f01601f19169290920160200192915050565b8215158152604060208201526000610cb7604083018461334f565b600080604083850312156133a957600080fd5b8235915060208301356133bb816131f5565b809150509250929050565b600080604083850312156133d957600080fd5b82356133e4816131f5565b91506020830135600381106133bb57600080fd5b6000806000806080858703121561340e57600080fd5b843593506020850135613420816131f5565b92506040850135613430816131f5565b9396929550929360600135925050565b60008060006060848603121561345557600080fd5b833592506020840135613467816131f5565b91506040840135613307816131f5565b634e487b7160e01b600052602160045260246000fd5b60208101600383106134af57634e487b7160e01b600052602160045260246000fd5b91905290565b600080604083850312156134c857600080fd5b82356134d3816131f5565b915060208301356133bb816131f5565b6000602082840312156134f557600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613536576135366134fc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613565576135656134fc565b604052919050565b60006020828403121561357f57600080fd5b6040516020810181811067ffffffffffffffff821117156135a2576135a26134fc565b6040529151825250919050565b80516fffffffffffffffffffffffffffffffff81168114611c3c57600080fd5b805164ffffffffff81168114611c3c57600080fd5b805161ffff81168114611c3c57600080fd5b8051611c3c816131f5565b60006101e0828403121561361457600080fd5b61361c613512565b613626848461356d565b8152613634602084016135af565b6020820152613645604084016135af565b6040820152613656606084016135af565b6060820152613667608084016135af565b608082015261367860a084016135af565b60a082015261368960c084016135cf565b60c082015261369a60e084016135e4565b60e08201526101006136ad8185016135f6565b908201526101206136bf8482016135f6565b908201526101406136d18482016135f6565b908201526101606136e38482016135f6565b908201526101806136f58482016135af565b908201526101a06137078482016135af565b908201526101c06137198482016135af565b908201529392505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156112f3576112f3613724565b60006020828403121561375f57600080fd5b81516108ff81613227565b6000806040838503121561377d57600080fd5b505080516020909101519092909150565b6000604082840312156137a057600080fd5b6040516040810181811067ffffffffffffffff821117156137c3576137c36134fc565b6040526137cf836135cf565b815260208301516001600160d81b03811681146137eb57600080fd5b60208201529392505050565b818103818111156112f3576112f3613724565b60006020828403121561381c57600080fd5b81516108ff816131f5565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b8181101561387e5783516001600160a01b031683529284019291840191600101613859565b50909695505050505050565b600067ffffffffffffffff8211156138a4576138a46134fc565b5060051b60200190565b600082601f8301126138bf57600080fd5b815160206138d46138cf8361388a565b61353c565b8083825260208201915060208460051b8701019350868411156138f657600080fd5b602086015b8481101561391257805183529183019183016138fb565b509695505050505050565b6000806040838503121561393057600080fd5b825167ffffffffffffffff8082111561394857600080fd5b818501915085601f83011261395c57600080fd5b8151602061396c6138cf8361388a565b82815260059290921b8401810191818101908984111561398b57600080fd5b948201945b838610156139b25785516139a3816131f5565b82529482019490820190613990565b918801519196509093505050808211156139cb57600080fd5b506139d8858286016138ae565b9150509250929050565b600181815b80851115613a1d578160001904821115613a0357613a03613724565b80851615613a1057918102915b93841c93908002906139e7565b509250929050565b600082613a34575060016112f3565b81613a41575060006112f3565b8160018114613a575760028114613a6157613a7d565b60019150506112f3565b60ff841115613a7257613a72613724565b50506001821b6112f3565b5060208310610133831016604e8410600b8410161715613aa0575081810a6112f3565b613aaa83836139e2565b8060001904821115613abe57613abe613724565b029392505050565b60006112f08383613a25565b80820281158282048414176112f3576112f3613724565b60008251613afb81846020870161332b565b9190910192915050565b600082613b2257634e487b7160e01b600052601260045260246000fd5b500490565b602081526000825160a06020840152613b4360c084018261334f565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a0840152809150509291505056fea26469706673582212203074ef0c7444e9952fb9840069c7bb96aee3fd5ca782117da3d8a1a0d4fecf5a64736f6c63430008160033a2646970667358221220f30477ab3edfbac81c3cc155d3f5ab3721bf6a5788e2d7857c30f5c26aa947a364736f6c63430008160033
Verified Source Code Full Match
Compiler: v0.8.22+commit.4fc1097e
EVM: paris
Optimization: Yes (200 runs)
IERC4626.sol 230 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
draft-IERC6093.sol 161 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
ERC20.sol 316 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @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);
}
SafeERC20.sol 118 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev 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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that 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;
}
}
Address.sol 159 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
Math.sol 415 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
ZircuitBaseStrategy.sol 86 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { BaseHooks } from "./periphery/Bases/Hooks/BaseHooks.sol";
/**
* @title Zircuit Base Strategy
* @author Zircuit Labs
* @notice
* This contract extends the BaseStrategy to provide a common
* base for all strategies in the Zircuit ecosystem. It includes both
* Yearn health checks and permissioning and statistical tracking features
* needed by the vaults.
*/
abstract contract ZircuitBaseStrategy is BaseHooks {
/*//////////////////////////////////////////////////////////////
STATE
//////////////////////////////////////////////////////////////*/
mapping(address => bool) public isAllowed;
bool public whitelistEnabled;
event WhitelistUpdated(address indexed user, bool allowed);
event WhitelistEnabled(bool enabled);
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address _asset, string memory _name) BaseHooks(_asset, _name) {
whitelistEnabled = true;
}
/*//////////////////////////////////////////////////////////////
MANAGEMENT
//////////////////////////////////////////////////////////////*/
/**
* @notice Allows a user to deposit into the strategy.
* @dev Can only be called by the management role.
* @param user The address of the user to allow.
*/
function allow(address user) external onlyManagement {
isAllowed[user] = true;
emit WhitelistUpdated(user, true);
}
/**
* @notice Denies a user from depositing into the strategy.
* @dev Can only be called by the management role.
* @param user The address of the user to deny.
*/
function deny(address user) external onlyManagement {
isAllowed[user] = false;
emit WhitelistUpdated(user, false);
}
/**
* @notice Enables or disables the whitelist for deposits.
* @dev Can only be called by the management role.
* @param _enabled The new status for the whitelist.
*/
function setWhitelistEnabled(bool _enabled) external onlyManagement {
whitelistEnabled = _enabled;
emit WhitelistEnabled(_enabled);
}
/*//////////////////////////////////////////////////////////////
OVERRIDDEN PUBLIC FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Gets the max amount of `asset` that an address can deposit.
* @dev Overrides the BaseStrategy function to enforce a whitelist.
* Only whitelisted users can deposit.
* @param _owner The address that is depositing into the strategy.
* @return The available amount the `_owner` can deposit in terms of `asset`.
*/
function availableDepositLimit(
address _owner
) public view virtual override returns (uint256) {
if (!whitelistEnabled || isAllowed[_owner]) {
return super.availableDepositLimit(_owner);
}
return 0;
}
}
AaveV3Lender.sol 552 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.22;
import { ZircuitBaseStrategy } from "../ZircuitBaseStrategy.sol";
import { ERC20 } from "../tokenized-strategy/BaseStrategy.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IAToken } from "./interfaces/V3/IAtoken.sol";
import { IStakedAave } from "./interfaces/V3/IStakedAave.sol";
import { IPool } from "./interfaces/V3/IPool.sol";
import { IRewardsController } from "./interfaces/V3/IRewardsController.sol";
// Swappers
import { UniswapV3Swapper } from "../periphery/swappers/UniswapV3Swapper.sol";
interface IAuction {
function want() external view returns (address);
function receiver() external view returns (address);
function kick(address _token) external returns (uint256);
}
contract AaveV3Lender is ZircuitBaseStrategy, UniswapV3Swapper {
using SafeERC20 for ERC20;
enum SwapType {
NULL,
UNISWAP_V3,
AUCTION
}
address public auction;
// Mapping to be set by management for any reward tokens.
// This can be used to set different mins for different tokens
// or to set to uin256.max if selling a reward token is reverting
// to allow for reports to still work properly.
mapping(address => uint256) public minAmountToSellMapping;
mapping(address => SwapType) public swapType;
IStakedAave internal constant stkAave =
IStakedAave(0x4da27a545c0c5B758a6BA100e3a049001de870f5);
address internal constant AAVE =
address(0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9);
// To get the Supply cap of an asset.
uint256 internal constant SUPPLY_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore
uint256 internal constant SUPPLY_CAP_START_BIT_POSITION = 116;
uint256 internal immutable decimals;
// The pool to deposit and withdraw through.
IPool public immutable lendingPool;
// The a Token specific rewards contract for claiming rewards.
IRewardsController public immutable rewardsController;
// The token that we get in return for deposits.
IAToken public immutable aToken;
// Bool to decide to try and claim rewards. Defaults to False.
bool public claimRewards;
constructor(
address _asset,
string memory _name,
address _lendingPool,
address _router,
address _base
) ZircuitBaseStrategy(_asset, _name) {
lendingPool = IPool(_lendingPool);
// Set the aToken based on the asset we are using.
aToken = IAToken(lendingPool.getReserveData(_asset).aTokenAddress);
// Make sure its a real token.
require(address(aToken) != address(0), "!aToken");
// Get aToken decimals for supply caps.
decimals = ERC20(address(aToken)).decimals();
// Set the rewards controller
rewardsController = aToken.getIncentivesController();
// Make approve the lending pool for cheaper deposits.
asset.forceApprove(address(lendingPool), type(uint256).max);
// Set uni swapper values
// We will use the minAmountToSell mapping instead.
minAmountToSell = 0;
router = _router;
base = _base;
}
/**
* @notice Set the uni fees for swaps.
* @dev External function available to management to set
* the fees used in the `UniswapV3Swapper.
*
* Any incentivized tokens will need a fee to be set for each
* reward token that it wishes to swap on reports.
*
* @param _token0 The first token of the pair.
* @param _token1 The second token of the pair.
* @param _fee The fee to be used for the pair.
*/
function setUniFees(
address _token0,
address _token1,
uint24 _fee
) external onlyManagement {
_setUniFees(_token0, _token1, _fee);
}
/*//////////////////////////////////////////////////////////////
NEEDED TO BE OVERRIDDEN BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Should deploy up to '_amount' of 'asset' in the yield source.
*
* This function is called at the end of a {deposit} or {mint}
* call. Meaning that unless a whitelist is implemented it will
* be entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* @param _amount The amount of 'asset' that the strategy should attempt
* to deposit in the yield source.
*/
function _deployFunds(uint256 _amount) internal override {
lendingPool.supply(address(asset), _amount, address(this), 0);
}
/**
* @dev Will attempt to free the '_amount' of 'asset'.
*
* The amount of 'asset' that is already loose has already
* been accounted for.
*
* This function is called during {withdraw} and {redeem} calls.
* Meaning that unless a whitelist is implemented it will be
* entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* Should not rely on asset.balanceOf(address(this)) calls other than
* for diff accounting purposes.
*
* Any difference between `_amount` and what is actually freed will be
* counted as a loss and passed on to the withdrawer. This means
* care should be taken in times of illiquidity. It may be better to revert
* if withdraws are simply illiquid so not to realize incorrect losses.
*
* Any difference between `_amount` and what is actually freed will be
* counted as a loss and passed on to the withdrawer. This means
* care should be taken in times of illiquidity. It may be better to revert
* if withdraws are simply illiquid so not to realize incorrect losses.
*
* @param _amount, The amount of 'asset' to be freed.
*/
function _freeFunds(uint256 _amount) internal override {
lendingPool.withdraw(
address(asset),
Math.min(aToken.balanceOf(address(this)), _amount),
address(this)
);
}
/**
* @dev Internal function to harvest all rewards, redeploy any idle
* funds and return an accurate accounting of all funds currently
* held by the Strategy.
*
* This should do any needed harvesting, rewards selling, accrual,
* redepositing etc. to get the most accurate view of current assets.
*
* NOTE: All applicable assets including loose assets should be
* accounted for in this function.
*
* Care should be taken when relying on oracles or swap values rather
* than actual amounts as all Strategy profit/loss accounting will
* be done based on this returned value.
*
* This can still be called post a shutdown, a strategist can check
* `TokenizedStrategy.isShutdown()` to decide if funds should be
* redeployed or simply realize any profits/losses.
*
* @return _totalAssets A trusted and accurate account for the total
* amount of 'asset' the strategy currently holds including idle funds.
*/
function _harvestAndReport()
internal
override
returns (uint256 _totalAssets)
{
if (claimRewards) {
// Claim and sell any rewards to `asset`.
_claimAndSellRewards(address(0), 0);
}
_totalAssets = aToken.balanceOf(address(this)) + balanceOfAsset();
}
function balanceOfAsset() public view returns (uint256) {
return asset.balanceOf(address(this));
}
function claimAndSellRewards(
address _rewardToken,
uint256 _minAmountOut
) external onlyKeepers {
_claimAndSellRewards(_rewardToken, _minAmountOut);
}
/**
* @notice Used to claim any pending rewards and sell them to asset.
*/
function _claimAndSellRewards(
address _rewardToken,
uint256 _minAmountOut
) internal {
// Claim any pending stkAave.
_redeemAave();
//claim all rewards
address[] memory assets = new address[](1);
assets[0] = address(aToken);
(address[] memory rewardsList, ) = rewardsController
.claimAllRewardsToSelf(assets);
// Start cooldown on any new stkAave.
_harvestStkAave();
// Handle rewards by swapping to asset
address token;
for (uint256 i = 0; i < rewardsList.length; ++i) {
token = rewardsList[i];
// If a reward token is specified, only sell that token
if (_rewardToken != address(0) && token != _rewardToken) {
continue;
}
// Ignore underlying and aToken as rewards
if (token == address(asset) || token == address(aToken)) {
continue;
} else if (token == address(stkAave)) {
// Convert stkAAVE into AAVE if available via redeem path
token = AAVE;
}
SwapType _swapType = swapType[token];
uint256 balance = ERC20(token).balanceOf(address(this));
if (balance > minAmountToSellMapping[token]) {
if (_swapType == SwapType.UNISWAP_V3) {
_swapFrom(token, address(asset), balance, _minAmountOut);
}
}
}
}
function _tend(uint256 _totalIdle) internal override {
if (_totalIdle > 0 && !TokenizedStrategy.isShutdown()) {
_deployFunds(_totalIdle);
}
}
function _tendTrigger() internal view override returns (bool) {
return !TokenizedStrategy.isShutdown() && balanceOfAsset() > 0;
}
function _redeemAave() internal {
if (!checkCooldown()) {
return;
}
uint256 stkAaveBalance = ERC20(address(stkAave)).balanceOf(
address(this)
);
if (stkAaveBalance > 0) {
stkAave.redeem(address(this), stkAaveBalance);
}
}
function checkCooldown() public view returns (bool) {
if (block.chainid != 1) return false;
uint256 cooldownStartTimestamp = IStakedAave(stkAave)
.stakersCooldowns(address(this))
.timestamp;
if (cooldownStartTimestamp == 0) return false;
uint256 cooldownSeconds = IStakedAave(stkAave).getCooldownSeconds();
uint256 UNSTAKE_WINDOW = IStakedAave(stkAave).UNSTAKE_WINDOW();
if (block.timestamp >= cooldownStartTimestamp + cooldownSeconds) {
return
block.timestamp - (cooldownStartTimestamp + cooldownSeconds) <=
UNSTAKE_WINDOW;
} else {
return false;
}
}
function _harvestStkAave() internal {
if (block.chainid != 1) return;
// request start of cooldown period
if (ERC20(address(stkAave)).balanceOf(address(this)) > 0) {
stkAave.cooldown();
}
}
function manualRedeemAave() external onlyKeepers {
_redeemAave();
}
/**
* @notice Gets the max amount of `asset` that an address can deposit.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any deposit or mints to enforce
* any limits desired by the strategist. This can be used for either a
* traditional deposit limit or for implementing a whitelist etc.
*
* EX:
* if(isAllowed[_owner]) return super.availableDepositLimit(_owner);
*
* This does not need to take into account any conversion rates
* from shares to assets. But should know that any non max uint256
* amounts may be converted to shares. So it is recommended to keep
* custom amounts low enough as not to cause overflow when multiplied
* by `totalSupply`.
*
* @param . The address that is depositing into the strategy.
* @return . The available amount the `_owner` can deposit in terms of `asset`
*/
function availableDepositLimit(
address _owner
) public view override returns (uint256) {
// Get the limit from the permissioning layer.
uint256 permissionedLimit = super.availableDepositLimit(_owner);
// Get the data configuration bitmap.
uint256 _data = lendingPool
.getReserveData(address(asset))
.configuration
.data;
// Cannot deposit when paused or frozen.
if (_isPaused(_data) || _isFrozen(_data)) return 0;
uint256 supplyCap = _getSupplyCap(_data);
// If we have no supply cap, the only limit is the permissioning.
if (supplyCap == 0) return permissionedLimit;
// Supply plus any already idle funds.
uint256 supply = aToken.totalSupply() + asset.balanceOf(address(this));
// If we already hit the cap, no deposits allowed.
if (supplyCap <= supply) return 0;
// The protocol limit is the remaining room in the supply cap.
uint256 protocolLimit;
unchecked {
protocolLimit = supplyCap - supply;
}
// The final limit is the minimum of the two.
return Math.min(permissionedLimit, protocolLimit);
}
/**
* @notice Gets the supply cap of the reserve
* @return The supply cap
*/
function getSupplyCap() public view returns (uint256) {
return
_getSupplyCap(
lendingPool.getReserveData(address(asset)).configuration.data
);
}
/**
* @dev Given the data configuration returns the supply cap.
*/
function _getSupplyCap(uint256 _data) internal view returns (uint256) {
// Get out the supply cap for the asset.
uint256 cap = (_data & ~SUPPLY_CAP_MASK) >>
SUPPLY_CAP_START_BIT_POSITION;
// Adjust to the correct decimals.
return cap * (10 ** decimals);
}
/**
* @dev Paused flag is at the 60th bit
*/
function _isPaused(uint256 _data) internal pure returns (bool) {
// Create a mask with only the 60th bit set
uint256 mask = 1 << 60; // Bitwise left shift by 59 positions
// Perform bitwise AND operation to check if the 60th bit is 0.
return (_data & mask) != 0;
}
/**
* @dev Frozen flag is at the 57th bit.
*/
function _isFrozen(uint256 _data) internal pure returns (bool) {
// Create a mask with only the 57th bit set
uint256 mask = 1 << 57; // Bitwise left shift by 56 positions
// Perform bitwise AND operation to check if the 57th bit 0.
return (_data & mask) != 0;
}
/**
* @notice Gets the max amount of `asset` that can be withdrawn.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any withdraw or redeem to enforce
* any limits desired by the strategist. This can be used for illiquid
* or sandwichable strategies. It should never be lower than `totalIdle`.
*
* EX:
* return TokenIzedStrategy.totalIdle();
*
* This does not need to take into account the `_owner`'s share balance
* or conversion rates from shares to assets.
*
* @param . The address that is withdrawing from the strategy.
* @return . The available amount that can be withdrawn in terms of `asset`
*/
function availableWithdrawLimit(
address /*_owner*/
) public view override returns (uint256) {
uint256 liquidity = aToken.balanceOf(address(this));
// IF pool is paused
if (
_isPaused(
lendingPool.getReserveData(address(asset)).configuration.data
)
) {
liquidity = 0;
}
return balanceOfAsset() + liquidity;
}
/**
* @notice Set the `minAmountToSellMapping` for a specific `_token`.
* @dev This can be used by management to adjust wether or not the
* _claimAndSellRewards() function will attempt to sell a specific
* reward token. This can be used if liquidity is to low, amounts
* are to low or any other reason that may cause reverts.
*
* @param _token The address of the token to adjust.
* @param _amount Min required amount to sell.
*/
function setMinAmountToSellMapping(
address _token,
uint256 _amount
) external onlyManagement {
minAmountToSellMapping[_token] = _amount;
}
/**
* @notice Set wether or not the strategy should claim and sell rewards.
* @param _bool Wether or not rewards should be claimed and sold automatically
*/
function setClaimRewards(bool _bool) external onlyManagement {
claimRewards = _bool;
}
///////////// DUTCH AUCTION FUNCTIONS \\\\\\\\\\\\\\\\\\
function setAuction(address _auction) external onlyManagement {
if (_auction != address(0)) {
require(IAuction(_auction).want() == address(asset), "wrong want");
require(
IAuction(_auction).receiver() == address(this),
"wrong receiver"
);
}
auction = _auction;
}
/**
* @notice Set the swap type for a specific token.
* @param _from The address of the token to set the swap type for.
* @param _swapType The swap type to set.
*/
function setSwapType(
address _from,
SwapType _swapType
) external onlyManagement {
swapType[_from] = _swapType;
}
/**
* @dev Kick an auction for a given token.
* @param _from The token that was being sold.
*/
function _kickAuction(address _from) internal returns (uint256) {
require(_from != address(asset), "cannot kick");
require(auction != address(0), "no auction");
uint256 _balance = ERC20(_from).balanceOf(address(this));
require(_balance > minAmountToSellMapping[_from], "balance too low");
ERC20(_from).safeTransfer(auction, _balance);
return IAuction(auction).kick(_from);
}
function kickAuction(
address _token
) external onlyKeepers returns (uint256) {
require(swapType[_token] == SwapType.AUCTION, "!auction");
return _kickAuction(_token);
}
/**
* @dev Optional function for a strategist to override that will
* allow management to manually withdraw deployed funds from the
* yield source if a strategy is shutdown.
*
* This should attempt to free `_amount`, noting that `_amount` may
* be more than is currently deployed.
*
* NOTE: This will not realize any profits or losses. A separate
* {report} will be needed in order to record any profit/loss. If
* a report may need to be called after a shutdown it is important
* to check if the strategy is shutdown during {_harvestAndReport}
* so that it does not simply re-deploy all funds that had been freed.
*
* EX:
* if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {
* depositFunds...
* }
*
* @param _amount The amount of asset to attempt to free.
*/
function _emergencyWithdraw(uint256 _amount) internal override {
_freeFunds(_amount);
}
}
AaveV3LenderFactory.sol 102 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.22;
import { AaveV3Lender, ERC20 } from "./AaveV3Lender.sol";
import { IStrategy } from "../tokenized-strategy/interfaces/IStrategy.sol";
contract AaveV3LenderFactory {
/// @notice Revert message for when a strategy has already been deployed.
error AlreadyDeployed(address _strategy);
error AddressCannotBeZero();
event NewAaveV3Lender(address indexed strategy, address indexed asset);
address public immutable sms;
address public immutable lendingPool;
address public immutable router;
address public immutable base;
address public management;
address public performanceFeeRecipient;
address public keeper;
/// @notice Track the deployments. asset => pool => strategy
mapping(address => address) public deployments;
constructor(
address _management,
address _performanceFeeRecipient,
address _keeper,
address _sms,
address _lendingPool,
address _router,
address _base
) {
if (_management == address(0)) revert AddressCannotBeZero();
management = _management;
performanceFeeRecipient = _performanceFeeRecipient;
keeper = _keeper;
sms = _sms;
lendingPool = _lendingPool;
router = _router;
base = _base;
}
/**
* @notice Deploy a new Aave V3 Lender.
* @param _asset The underlying asset for the lender to use.
* @return . The address of the new lender.
*/
function newAaveV3Lender(address _asset) external returns (address) {
require(msg.sender == management, "!management");
if (deployments[_asset] != address(0))
revert AlreadyDeployed(deployments[_asset]);
string memory _name = string(
abi.encodePacked("Aave V3 ", ERC20(_asset).symbol(), " Lender")
);
// We need to use the custom interface with the
// tokenized strategies available setters.
IStrategy newStrategy = IStrategy(
address(new AaveV3Lender(_asset, _name, lendingPool, router, base))
);
newStrategy.setPerformanceFeeRecipient(performanceFeeRecipient);
newStrategy.setKeeper(keeper);
newStrategy.setPendingManagement(management);
newStrategy.setEmergencyAdmin(sms);
newStrategy.setPerformanceFee(2000);
newStrategy.setProfitMaxUnlockTime(60 * 60 * 24 * 3);
emit NewAaveV3Lender(address(newStrategy), _asset);
deployments[_asset] = address(newStrategy);
return address(newStrategy);
}
function setAddresses(
address _management,
address _performanceFeeRecipient,
address _keeper
) external {
require(msg.sender == management, "!management");
if (_management == address(0)) revert AddressCannotBeZero();
management = _management;
performanceFeeRecipient = _performanceFeeRecipient;
keeper = _keeper;
}
function isDeployedStrategy(
address _strategy
) external view returns (bool) {
address _asset = IStrategy(_strategy).asset();
return deployments[_asset] == _strategy;
}
}
DataTypes.sol 330 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library DataTypes {
/**
* This exists specifically to maintain the `getReserveData()` interface, since the new, internal
* `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.
*/
struct ReserveDataLegacy {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
// DEPRECATED on v3.2.0
uint128 currentStableBorrowRate;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//aToken address
address aTokenAddress;
// DEPRECATED on v3.2.0
address stableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
}
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
/// @notice reused `__deprecatedStableBorrowRate` storage from pre 3.2
// the current accumulate deficit in underlying tokens
uint128 deficit;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
uint40 liquidationGracePeriodUntil;
//aToken address
address aTokenAddress;
// DEPRECATED on v3.2.0
address __deprecatedStableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
//the amount of underlying accounted for by the protocol
uint128 virtualUnderlyingBalance;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: DEPRECATED: stable rate borrowing enabled
//bit 60: asset is paused
//bit 61: borrowing in isolation mode is enabled
//bit 62: siloed borrowing enabled
//bit 63: flashloaning enabled
//bit 64-79: reserve factor
//bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap
//bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap
//bit 152-167: liquidation protocol fee
//bit 168-175: DEPRECATED: eMode category
//bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
//bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
//bit 252: virtual accounting is enabled for the reserve
//bit 253-255 unused
uint256 data;
}
struct UserConfigurationMap {
/**
* @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.
* The first bit indicates if an asset is used as collateral by the user, the second whether an
* asset is borrowed by the user.
*/
uint256 data;
}
// DEPRECATED: kept for backwards compatibility, might be removed in a future version
struct EModeCategoryLegacy {
// each eMode category has a custom ltv and liquidation threshold
uint16 ltv;
uint16 liquidationThreshold;
uint16 liquidationBonus;
// DEPRECATED
address priceSource;
string label;
}
struct CollateralConfig {
uint16 ltv;
uint16 liquidationThreshold;
uint16 liquidationBonus;
}
struct EModeCategoryBaseConfiguration {
uint16 ltv;
uint16 liquidationThreshold;
uint16 liquidationBonus;
string label;
}
struct EModeCategory {
// each eMode category has a custom ltv and liquidation threshold
uint16 ltv;
uint16 liquidationThreshold;
uint16 liquidationBonus;
uint128 collateralBitmap;
string label;
uint128 borrowableBitmap;
}
enum InterestRateMode {
NONE,
__DEPRECATED,
VARIABLE
}
struct ReserveCache {
uint256 currScaledVariableDebt;
uint256 nextScaledVariableDebt;
uint256 currLiquidityIndex;
uint256 nextLiquidityIndex;
uint256 currVariableBorrowIndex;
uint256 nextVariableBorrowIndex;
uint256 currLiquidityRate;
uint256 currVariableBorrowRate;
uint256 reserveFactor;
ReserveConfigurationMap reserveConfiguration;
address aTokenAddress;
address variableDebtTokenAddress;
uint40 reserveLastUpdateTimestamp;
}
struct ExecuteLiquidationCallParams {
uint256 reservesCount;
uint256 debtToCover;
address collateralAsset;
address debtAsset;
address user;
bool receiveAToken;
address priceOracle;
uint8 userEModeCategory;
address priceOracleSentinel;
}
struct ExecuteSupplyParams {
address asset;
uint256 amount;
address onBehalfOf;
uint16 referralCode;
}
struct ExecuteBorrowParams {
address asset;
address user;
address onBehalfOf;
uint256 amount;
InterestRateMode interestRateMode;
uint16 referralCode;
bool releaseUnderlying;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address priceOracleSentinel;
}
struct ExecuteRepayParams {
address asset;
uint256 amount;
InterestRateMode interestRateMode;
address onBehalfOf;
bool useATokens;
}
struct ExecuteWithdrawParams {
address asset;
uint256 amount;
address to;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
}
struct ExecuteEliminateDeficitParams {
address asset;
uint256 amount;
}
struct ExecuteSetUserEModeParams {
uint256 reservesCount;
address oracle;
uint8 categoryId;
}
struct FinalizeTransferParams {
address asset;
address from;
address to;
uint256 amount;
uint256 balanceFromBefore;
uint256 balanceToBefore;
uint256 reservesCount;
address oracle;
uint8 fromEModeCategory;
}
struct FlashloanParams {
address receiverAddress;
address[] assets;
uint256[] amounts;
uint256[] interestRateModes;
address onBehalfOf;
bytes params;
uint16 referralCode;
uint256 flashLoanPremiumToProtocol;
uint256 flashLoanPremiumTotal;
uint256 reservesCount;
address addressesProvider;
address pool;
uint8 userEModeCategory;
bool isAuthorizedFlashBorrower;
}
struct FlashloanSimpleParams {
address receiverAddress;
address asset;
uint256 amount;
bytes params;
uint16 referralCode;
uint256 flashLoanPremiumToProtocol;
uint256 flashLoanPremiumTotal;
}
struct FlashLoanRepaymentParams {
uint256 amount;
uint256 totalPremium;
uint256 flashLoanPremiumToProtocol;
address asset;
address receiverAddress;
uint16 referralCode;
}
struct CalculateUserAccountDataParams {
UserConfigurationMap userConfig;
uint256 reservesCount;
address user;
address oracle;
uint8 userEModeCategory;
}
struct ValidateBorrowParams {
ReserveCache reserveCache;
UserConfigurationMap userConfig;
address asset;
address userAddress;
uint256 amount;
InterestRateMode interestRateMode;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address priceOracleSentinel;
bool isolationModeActive;
address isolationModeCollateralAddress;
uint256 isolationModeDebtCeiling;
}
struct ValidateLiquidationCallParams {
ReserveCache debtReserveCache;
uint256 totalDebt;
uint256 healthFactor;
address priceOracleSentinel;
}
struct CalculateInterestRatesParams {
uint256 unbacked;
uint256 liquidityAdded;
uint256 liquidityTaken;
uint256 totalDebt;
uint256 reserveFactor;
address reserve;
bool usingVirtualBalance;
uint256 virtualUnderlyingBalance;
}
struct InitReserveParams {
address asset;
address aTokenAddress;
address variableDebtAddress;
address interestRateStrategyAddress;
uint16 reservesCount;
uint16 maxNumberReserves;
}
}
IAtoken.sol 211 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.6.12;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IScaledBalanceToken } from "./IScaledBalanceToken.sol";
import { IRewardsController } from "./IRewardsController.sol";
import { IPool } from "./IPool.sol";
/**
* @title IInitializableAToken
* @author Aave
* @notice Interface for the initialize function on AToken
**/
interface IInitializableAToken {
/**
* @dev Emitted when an aToken is initialized
* @param underlyingAsset The address of the underlying asset
* @param pool The address of the associated pool
* @param treasury The address of the treasury
* @param incentivesController The address of the incentives controller for this aToken
* @param aTokenDecimals The decimals of the underlying
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
* @param params A set of encoded parameters for additional initialization
**/
event Initialized(
address indexed underlyingAsset,
address indexed pool,
address treasury,
address incentivesController,
uint8 aTokenDecimals,
string aTokenName,
string aTokenSymbol,
bytes params
);
/**
* @notice Initializes the aToken
* @param pool The pool contract that is initializing this contract
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
* @param params A set of encoded parameters for additional initialization
*/
function initialize(
IPool pool,
address treasury,
address underlyingAsset,
IRewardsController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external;
}
/**
* @title IAToken
* @author Aave
* @notice Defines the basic interface for an AToken.
**/
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted during the transfer action
* @param from The user whose tokens are being transferred
* @param to The recipient
* @param value The amount being transferred
* @param index The next liquidity index of the reserve
**/
event BalanceTransfer(
address indexed from,
address indexed to,
uint256 value,
uint256 index
);
/**
* @notice Mints `amount` aTokens to `user`
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted aTokens
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
* @return `true` if the the previous balance of the user was 0
*/
function mint(
address caller,
address onBehalfOf,
uint256 amount,
uint256 index
) external returns (bool);
/**
* @notice Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @dev In some instances, the mint event could be emitted from a burn transaction
* if the amount to burn is less than the interest that the user accrued
* @param from The address from which the aTokens will be burned
* @param receiverOfUnderlying The address that will receive the underlying
* @param amount The amount being burned
* @param index The next liquidity index of the reserve
**/
function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external;
/**
* @notice Mints aTokens to the reserve treasury
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
*/
function mintToTreasury(uint256 amount, uint256 index) external;
/**
* @notice Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* @param from The address getting liquidated, current owner of the aTokens
* @param to The recipient
* @param value The amount of tokens getting transferred
**/
function transferOnLiquidation(
address from,
address to,
uint256 value
) external;
/**
* @notice Transfers the underlying asset to `target`.
* @dev Used by the Pool to transfer assets in borrow(), withdraw() and flashLoan()
* @param user The recipient of the underlying
* @param amount The amount getting transferred
**/
function transferUnderlyingTo(address user, uint256 amount) external;
/**
* @notice Handles the underlying received by the aToken after the transfer has been completed.
* @dev The default implementation is empty as with standard ERC20 tokens, nothing needs to be done after the
* transfer is concluded. However in the future there may be aTokens that allow for example to stake the underlying
* to receive LM rewards. In that case, `handleRepayment()` would perform the staking of the underlying asset.
* @param user The user executing the repayment
* @param amount The amount getting repaid
**/
function handleRepayment(address user, uint256 amount) external;
/**
* @notice Allow passing a signed message to approve spending
* @dev implements the permit function as for
* https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner The owner of the funds
* @param spender The spender
* @param value The amount
* @param deadline The deadline timestamp, type(uint256).max for max deadline
* @param v Signature param
* @param s Signature param
* @param r Signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController()
external
view
returns (IRewardsController);
/**
* @notice Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @return The address of the underlying asset
**/
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
/**
* @notice Returns the address of the Aave treasury, receiving the fees on this aToken.
* @return Address of the Aave treasury
**/
function RESERVE_TREASURY_ADDRESS() external view returns (address);
/**
* @notice Get the domain separator for the token
* @dev Return cached value if chainId matches cache, otherwise recomputes separator
* @return The domain separator of the token at current chain
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the nonce for owner.
* @param owner The address of the owner
* @return The nonce of the owner
**/
function nonces(address owner) external view returns (uint256);
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
}
IPool.sol 946 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol";
import { DataTypes } from "./DataTypes.sol";
/**
* @title IPool
* @author Aave
* @notice Defines the basic interface for an Aave Pool.
*/
interface IPool {
/**
* @dev Emitted on mintUnbacked()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the supply
* @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens
* @param amount The amount of supplied assets
* @param referralCode The referral code used
*/
event MintUnbacked(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referralCode
);
/**
* @dev Emitted on backUnbacked()
* @param reserve The address of the underlying asset of the reserve
* @param backer The address paying for the backing
* @param amount The amount added as backing
* @param fee The amount paid in fees
*/
event BackUnbacked(
address indexed reserve,
address indexed backer,
uint256 amount,
uint256 fee
);
/**
* @dev Emitted on supply()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the supply
* @param onBehalfOf The beneficiary of the supply, receiving the aTokens
* @param amount The amount supplied
* @param referralCode The referral code used
*/
event Supply(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referralCode
);
/**
* @dev Emitted on withdraw()
* @param reserve The address of the underlying asset being withdrawn
* @param user The address initiating the withdrawal, owner of aTokens
* @param to The address that will receive the underlying
* @param amount The amount to be withdrawn
*/
event Withdraw(
address indexed reserve,
address indexed user,
address indexed to,
uint256 amount
);
/**
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
* @param reserve The address of the underlying asset being borrowed
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
* initiator of the transaction on flashLoan()
* @param onBehalfOf The address that will be getting the debt
* @param amount The amount borrowed out
* @param interestRateMode The rate mode: 2 for Variable, 1 is deprecated (changed on v3.2.0)
* @param borrowRate The numeric rate at which the user has borrowed, expressed in ray
* @param referralCode The referral code used
*/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
DataTypes.InterestRateMode interestRateMode,
uint256 borrowRate,
uint16 indexed referralCode
);
/**
* @dev Emitted on repay()
* @param reserve The address of the underlying asset of the reserve
* @param user The beneficiary of the repayment, getting his debt reduced
* @param repayer The address of the user initiating the repay(), providing the funds
* @param amount The amount repaid
* @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly
*/
event Repay(
address indexed reserve,
address indexed user,
address indexed repayer,
uint256 amount,
bool useATokens
);
/**
* @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets
* @param asset The address of the underlying asset of the reserve
* @param totalDebt The total isolation mode debt for the reserve
*/
event IsolationModeTotalDebtUpdated(
address indexed asset,
uint256 totalDebt
);
/**
* @dev Emitted when the user selects a certain asset category for eMode
* @param user The address of the user
* @param categoryId The category id
*/
event UserEModeSet(address indexed user, uint8 categoryId);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*/
event ReserveUsedAsCollateralEnabled(
address indexed reserve,
address indexed user
);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*/
event ReserveUsedAsCollateralDisabled(
address indexed reserve,
address indexed user
);
/**
* @dev Emitted on flashLoan()
* @param target The address of the flash loan receiver contract
* @param initiator The address initiating the flash loan
* @param asset The address of the asset being flash borrowed
* @param amount The amount flash borrowed
* @param interestRateMode The flashloan mode: 0 for regular flashloan,
* 1 for Stable (Deprecated on v3.2.0), 2 for Variable
* @param premium The fee flash borrowed
* @param referralCode The referral code used
*/
event FlashLoan(
address indexed target,
address initiator,
address indexed asset,
uint256 amount,
DataTypes.InterestRateMode interestRateMode,
uint256 premium,
uint16 indexed referralCode
);
/**
* @dev Emitted when a borrower is liquidated.
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param liquidatedCollateralAmount The amount of collateral received by the liquidator
* @param liquidator The address of the liquidator
* @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*/
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the state of a reserve is updated.
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The next liquidity rate
* @param stableBorrowRate The next stable borrow rate @note deprecated on v3.2.0
* @param variableBorrowRate The next variable borrow rate
* @param liquidityIndex The next liquidity index
* @param variableBorrowIndex The next variable borrow index
*/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Emitted when the deficit of a reserve is covered.
* @param reserve The address of the underlying asset of the reserve
* @param caller The caller that triggered the DeficitCovered event
* @param amountCovered The amount of deficit covered
*/
event DeficitCovered(
address indexed reserve,
address caller,
uint256 amountCovered
);
/**
* @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.
* @param reserve The address of the reserve
* @param amountMinted The amount minted to the treasury
*/
event MintedToTreasury(address indexed reserve, uint256 amountMinted);
/**
* @dev Emitted when deficit is realized on a liquidation.
* @param user The user address where the bad debt will be burned
* @param debtAsset The address of the underlying borrowed asset to be burned
* @param amountCreated The amount of deficit created
*/
event DeficitCreated(
address indexed user,
address indexed debtAsset,
uint256 amountCreated
);
/**
* @notice Mints an `amount` of aTokens to the `onBehalfOf`
* @param asset The address of the underlying asset to mint
* @param amount The amount to mint
* @param onBehalfOf The address that will receive the aTokens
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function mintUnbacked(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Back the current unbacked underlying with `amount` and pay `fee`.
* @param asset The address of the underlying asset to back
* @param amount The amount to back
* @param fee The amount paid in fees
* @return The backed amount
*/
function backUnbacked(
address asset,
uint256 amount,
uint256 fee
) external returns (uint256);
/**
* @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User supplies 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function supply(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Supply with transfer approval of asset to be supplied done via permit function
* see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param deadline The deadline timestamp that the permit is valid
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param permitV The V parameter of ERC712 permit sig
* @param permitR The R parameter of ERC712 permit sig
* @param permitS The S parameter of ERC712 permit sig
*/
function supplyWithPermit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external;
/**
* @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to The address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
*/
function withdraw(
address asset,
uint256 amount,
address to
) external returns (uint256);
/**
* @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already supplied enough collateral, or he was given enough allowance by a credit delegator on the VariableDebtToken
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 variable debt tokens
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
*/
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0
* @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @return The final amount repaid
*/
function repay(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf
) external returns (uint256);
/**
* @notice Repay with transfer approval of asset to be repaid done via permit function
* see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @param deadline The deadline timestamp that the permit is valid
* @param permitV The V parameter of ERC712 permit sig
* @param permitR The R parameter of ERC712 permit sig
* @param permitS The S parameter of ERC712 permit sig
* @return The final amount repaid
*/
function repayWithPermit(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external returns (uint256);
/**
* @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the
* equivalent debt tokens
* - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable debt tokens
* @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken
* balance is not enough to cover the whole debt
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode DEPRECATED in v3.2.0
* @return The final amount repaid
*/
function repayWithATokens(
address asset,
uint256 amount,
uint256 interestRateMode
) external returns (uint256);
/**
* @notice Allows suppliers to enable/disable a specific supplied asset as collateral
* @param asset The address of the underlying asset supplied
* @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise
*/
function setUserUseReserveAsCollateral(
address asset,
bool useAsCollateral
) external;
/**
* @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
/**
* @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://docs.aave.com/developers/
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts of the assets being flash-borrowed
* @param interestRateModes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Deprecated on v3.2.0
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using 2 on `modes`
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata interestRateModes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://docs.aave.com/developers/
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
* @param asset The address of the asset being flash-borrowed
* @param amount The amount of the asset being flash-borrowed
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Returns the user account data across all the reserves
* @param user The address of the user
* @return totalCollateralBase The total collateral of the user in the base currency used by the price feed
* @return totalDebtBase The total debt of the user in the base currency used by the price feed
* @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed
* @return currentLiquidationThreshold The liquidation threshold of the user
* @return ltv The loan to value of The user
* @return healthFactor The current health factor of the user
*/
function getUserAccountData(
address user
)
external
view
returns (
uint256 totalCollateralBase,
uint256 totalDebtBase,
uint256 availableBorrowsBase,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
/**
* @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an
* interest rate strategy
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param aTokenAddress The address of the aToken that will be assigned to the reserve
* @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve
* @param interestRateStrategyAddress The address of the interest rate strategy contract
*/
function initReserve(
address asset,
address aTokenAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
/**
* @notice Drop a reserve
* @dev Only callable by the PoolConfigurator contract
* @dev Does not reset eMode flags, which must be considered when reusing the same reserve id for a different reserve.
* @param asset The address of the underlying asset of the reserve
*/
function dropReserve(address asset) external;
/**
* @notice Updates the address of the interest rate strategy contract
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param rateStrategyAddress The address of the interest rate strategy contract
*/
function setReserveInterestRateStrategyAddress(
address asset,
address rateStrategyAddress
) external;
/**
* @notice Accumulates interest to all indexes of the reserve
* @dev Only callable by the PoolConfigurator contract
* @dev To be used when required by the configurator, for example when updating interest rates strategy data
* @param asset The address of the underlying asset of the reserve
*/
function syncIndexesState(address asset) external;
/**
* @notice Updates interest rates on the reserve data
* @dev Only callable by the PoolConfigurator contract
* @dev To be used when required by the configurator, for example when updating interest rates strategy data
* @param asset The address of the underlying asset of the reserve
*/
function syncRatesState(address asset) external;
/**
* @notice Sets the configuration bitmap of the reserve as a whole
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param configuration The new configuration bitmap
*/
function setConfiguration(
address asset,
DataTypes.ReserveConfigurationMap calldata configuration
) external;
/**
* @notice Returns the configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
*/
function getConfiguration(
address asset
) external view returns (DataTypes.ReserveConfigurationMap memory);
/**
* @notice Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
*/
function getUserConfiguration(
address user
) external view returns (DataTypes.UserConfigurationMap memory);
/**
* @notice Returns the normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(
address asset
) external view returns (uint256);
/**
* @notice Returns the normalized variable debt per unit of asset
* @dev WARNING: This function is intended to be used primarily by the protocol itself to get a
* "dynamic" variable index based on time, current stored index and virtual rate at the current
* moment (approx. a borrower would get if opening a position). This means that is always used in
* combination with variable debt supply/balances.
* If using this function externally, consider that is possible to have an increasing normalized
* variable debt that is not equivalent to how the variable debt index would be updated in storage
* (e.g. only updates with non-zero variable debt supply)
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(
address asset
) external view returns (uint256);
/**
* @notice Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state and configuration data of the reserve
*/
function getReserveData(
address asset
) external view returns (DataTypes.ReserveDataLegacy memory);
/**
* @notice Returns the virtual underlying balance of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve virtual underlying balance
*/
function getVirtualUnderlyingBalance(
address asset
) external view returns (uint128);
/**
* @notice Validates and finalizes an aToken transfer
* @dev Only callable by the overlying aToken of the `asset`
* @param asset The address of the underlying asset of the aToken
* @param from The user from which the aTokens are transferred
* @param to The user receiving the aTokens
* @param amount The amount being transferred/withdrawn
* @param balanceFromBefore The aToken balance of the `from` user before the transfer
* @param balanceToBefore The aToken balance of the `to` user before the transfer
*/
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) external;
/**
* @notice Returns the list of the underlying assets of all the initialized reserves
* @dev It does not include dropped reserves
* @return The addresses of the underlying assets of the initialized reserves
*/
function getReservesList() external view returns (address[] memory);
/**
* @notice Returns the number of initialized reserves
* @dev It includes dropped reserves
* @return The count
*/
function getReservesCount() external view returns (uint256);
/**
* @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct
* @param id The id of the reserve as stored in the DataTypes.ReserveData struct
* @return The address of the reserve associated with id
*/
function getReserveAddressById(uint16 id) external view returns (address);
/**
* @notice Returns the PoolAddressesProvider connected to this contract
* @return The address of the PoolAddressesProvider
*/
function ADDRESSES_PROVIDER()
external
view
returns (IPoolAddressesProvider);
/**
* @notice Updates the protocol fee on the bridging
* @param bridgeProtocolFee The part of the premium sent to the protocol treasury
*/
function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;
/**
* @notice Updates flash loan premiums. Flash loan premium consists of two parts:
* - A part is sent to aToken holders as extra, one time accumulated interest
* - A part is collected by the protocol treasury
* @dev The total premium is calculated on the total borrowed amount
* @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`
* @dev Only callable by the PoolConfigurator contract
* @param flashLoanPremiumTotal The total premium, expressed in bps
* @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps
*/
function updateFlashloanPremiums(
uint128 flashLoanPremiumTotal,
uint128 flashLoanPremiumToProtocol
) external;
/**
* @notice Configures a new or alters an existing collateral configuration of an eMode.
* @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.
* The category 0 is reserved as it's the default for volatile assets
* @param id The id of the category
* @param config The configuration of the category
*/
function configureEModeCategory(
uint8 id,
DataTypes.EModeCategoryBaseConfiguration memory config
) external;
/**
* @notice Replaces the current eMode collateralBitmap.
* @param id The id of the category
* @param collateralBitmap The collateralBitmap of the category
*/
function configureEModeCategoryCollateralBitmap(
uint8 id,
uint128 collateralBitmap
) external;
/**
* @notice Replaces the current eMode borrowableBitmap.
* @param id The id of the category
* @param borrowableBitmap The borrowableBitmap of the category
*/
function configureEModeCategoryBorrowableBitmap(
uint8 id,
uint128 borrowableBitmap
) external;
/**
* @notice Returns the data of an eMode category
* @dev DEPRECATED use independent getters instead
* @param id The id of the category
* @return The configuration data of the category
*/
function getEModeCategoryData(
uint8 id
) external view returns (DataTypes.EModeCategoryLegacy memory);
/**
* @notice Returns the label of an eMode category
* @param id The id of the category
* @return The label of the category
*/
function getEModeCategoryLabel(
uint8 id
) external view returns (string memory);
/**
* @notice Returns the collateral config of an eMode category
* @param id The id of the category
* @return The ltv,lt,lb of the category
*/
function getEModeCategoryCollateralConfig(
uint8 id
) external view returns (DataTypes.CollateralConfig memory);
/**
* @notice Returns the collateralBitmap of an eMode category
* @param id The id of the category
* @return The collateralBitmap of the category
*/
function getEModeCategoryCollateralBitmap(
uint8 id
) external view returns (uint128);
/**
* @notice Returns the borrowableBitmap of an eMode category
* @param id The id of the category
* @return The borrowableBitmap of the category
*/
function getEModeCategoryBorrowableBitmap(
uint8 id
) external view returns (uint128);
/**
* @notice Allows a user to use the protocol in eMode
* @param categoryId The id of the category
*/
function setUserEMode(uint8 categoryId) external;
/**
* @notice Returns the eMode the user is using
* @param user The address of the user
* @return The eMode id
*/
function getUserEMode(address user) external view returns (uint256);
/**
* @notice Resets the isolation mode total debt of the given asset to zero
* @dev It requires the given asset has zero debt ceiling
* @param asset The address of the underlying asset to reset the isolationModeTotalDebt
*/
function resetIsolationModeTotalDebt(address asset) external;
/**
* @notice Sets the liquidation grace period of the given asset
* @dev To enable a liquidation grace period, a timestamp in the future should be set,
* To disable a liquidation grace period, any timestamp in the past works, like 0
* @param asset The address of the underlying asset to set the liquidationGracePeriod
* @param until Timestamp when the liquidation grace period will end
**/
function setLiquidationGracePeriod(address asset, uint40 until) external;
/**
* @notice Returns the liquidation grace period of the given asset
* @param asset The address of the underlying asset
* @return Timestamp when the liquidation grace period will end
**/
function getLiquidationGracePeriod(
address asset
) external view returns (uint40);
/**
* @notice Returns the total fee on flash loans
* @return The total fee on flashloans
*/
function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
/**
* @notice Returns the part of the bridge fees sent to protocol
* @return The bridge fee sent to the protocol treasury
*/
function BRIDGE_PROTOCOL_FEE() external view returns (uint256);
/**
* @notice Returns the part of the flashloan fees sent to protocol
* @return The flashloan fee sent to the protocol treasury
*/
function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);
/**
* @notice Returns the maximum number of reserves supported to be listed in this Pool
* @return The maximum number of reserves supported
*/
function MAX_NUMBER_RESERVES() external view returns (uint16);
/**
* @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
* @param assets The list of reserves for which the minting needs to be executed
*/
function mintToTreasury(address[] calldata assets) external;
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
/**
* @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User supplies 100 USDC and gets in return 100 aUSDC
* @dev Deprecated: Use the `supply` function instead
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice It covers the deficit of a specified reserve by burning:
* - the equivalent aToken `amount` for assets with virtual accounting enabled
* - the equivalent `amount` of underlying for assets with virtual accounting disabled (e.g. GHO)
* @dev The deficit of a reserve can occur due to situations where borrowed assets are not repaid, leading to bad debt.
* @param asset The address of the underlying asset to cover the deficit.
* @param amount The amount to be covered, in aToken or underlying on non-virtual accounted assets
*/
function eliminateReserveDeficit(address asset, uint256 amount) external;
/**
* @notice Returns the current deficit of a reserve.
* @param asset The address of the underlying asset of the reserve
* @return The current deficit of the reserve
*/
function getReserveDeficit(address asset) external view returns (uint256);
/**
* @notice Returns the aToken address of a reserve.
* @param asset The address of the underlying asset of the reserve
* @return The address of the aToken
*/
function getReserveAToken(address asset) external view returns (address);
/**
* @notice Returns the variableDebtToken address of a reserve.
* @param asset The address of the underlying asset of the reserve
* @return The address of the variableDebtToken
*/
function getReserveVariableDebtToken(
address asset
) external view returns (address);
/**
* @notice Gets the address of the external FlashLoanLogic
*/
function getFlashLoanLogic() external view returns (address);
/**
* @notice Gets the address of the external BorrowLogic
*/
function getBorrowLogic() external view returns (address);
/**
* @notice Gets the address of the external BridgeLogic
*/
function getBridgeLogic() external view returns (address);
/**
* @notice Gets the address of the external EModeLogic
*/
function getEModeLogic() external view returns (address);
/**
* @notice Gets the address of the external LiquidationLogic
*/
function getLiquidationLogic() external view returns (address);
/**
* @notice Gets the address of the external PoolLogic
*/
function getPoolLogic() external view returns (address);
/**
* @notice Gets the address of the external SupplyLogic
*/
function getSupplyLogic() external view returns (address);
}
IPoolAddressesProvider.sol 252 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.6.12;
/**
* @title IPoolAddressesProvider
* @author Aave
* @notice Defines the basic interface for a Pool Addresses Provider.
**/
interface IPoolAddressesProvider {
/**
* @dev Emitted when the market identifier is updated.
* @param oldMarketId The old id of the market
* @param newMarketId The new id of the market
*/
event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);
/**
* @dev Emitted when the pool is updated.
* @param oldAddress The old address of the Pool
* @param newAddress The new address of the Pool
*/
event PoolUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the pool configurator is updated.
* @param oldAddress The old address of the PoolConfigurator
* @param newAddress The new address of the PoolConfigurator
*/
event PoolConfiguratorUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the price oracle is updated.
* @param oldAddress The old address of the PriceOracle
* @param newAddress The new address of the PriceOracle
*/
event PriceOracleUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the ACL manager is updated.
* @param oldAddress The old address of the ACLManager
* @param newAddress The new address of the ACLManager
*/
event ACLManagerUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the ACL admin is updated.
* @param oldAddress The old address of the ACLAdmin
* @param newAddress The new address of the ACLAdmin
*/
event ACLAdminUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the price oracle sentinel is updated.
* @param oldAddress The old address of the PriceOracleSentinel
* @param newAddress The new address of the PriceOracleSentinel
*/
event PriceOracleSentinelUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the pool data provider is updated.
* @param oldAddress The old address of the PoolDataProvider
* @param newAddress The new address of the PoolDataProvider
*/
event PoolDataProviderUpdated(
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when a new proxy is created.
* @param id The identifier of the proxy
* @param proxyAddress The address of the created proxy contract
* @param implementationAddress The address of the implementation contract
*/
event ProxyCreated(
bytes32 indexed id,
address indexed proxyAddress,
address indexed implementationAddress
);
/**
* @dev Emitted when a new non-proxied contract address is registered.
* @param id The identifier of the contract
* @param oldAddress The address of the old contract
* @param newAddress The address of the new contract
*/
event AddressSet(
bytes32 indexed id,
address indexed oldAddress,
address indexed newAddress
);
/**
* @dev Emitted when the implementation of the proxy registered with id is updated
* @param id The identifier of the contract
* @param proxyAddress The address of the proxy contract
* @param oldImplementationAddress The address of the old implementation contract
* @param newImplementationAddress The address of the new implementation contract
*/
event AddressSetAsProxy(
bytes32 indexed id,
address indexed proxyAddress,
address oldImplementationAddress,
address indexed newImplementationAddress
);
/**
* @notice Returns the id of the Aave market to which this contract points to.
* @return The market id
**/
function getMarketId() external view returns (string memory);
/**
* @notice Associates an id with a specific PoolAddressesProvider.
* @dev This can be used to create an onchain registry of PoolAddressesProviders to
* identify and validate multiple Aave markets.
* @param newMarketId The market id
*/
function setMarketId(string calldata newMarketId) external;
/**
* @notice Returns an address by its identifier.
* @dev The returned address might be an EOA or a contract, potentially proxied
* @dev It returns ZERO if there is no registered address with the given id
* @param id The id
* @return The address of the registered for the specified id
*/
function getAddress(bytes32 id) external view returns (address);
/**
* @notice General function to update the implementation of a proxy registered with
* certain `id`. If there is no proxy registered, it will instantiate one and
* set as implementation the `newImplementationAddress`.
* @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
* setter function, in order to avoid unexpected consequences
* @param id The id
* @param newImplementationAddress The address of the new implementation
*/
function setAddressAsProxy(
bytes32 id,
address newImplementationAddress
) external;
/**
* @notice Sets an address for an id replacing the address saved in the addresses map.
* @dev IMPORTANT Use this function carefully, as it will do a hard replacement
* @param id The id
* @param newAddress The address to set
*/
function setAddress(bytes32 id, address newAddress) external;
/**
* @notice Returns the address of the Pool proxy.
* @return The Pool proxy address
**/
function getPool() external view returns (address);
/**
* @notice Updates the implementation of the Pool, or creates a proxy
* setting the new `pool` implementation when the function is called for the first time.
* @param newPoolImpl The new Pool implementation
**/
function setPoolImpl(address newPoolImpl) external;
/**
* @notice Returns the address of the PoolConfigurator proxy.
* @return The PoolConfigurator proxy address
**/
function getPoolConfigurator() external view returns (address);
/**
* @notice Updates the implementation of the PoolConfigurator, or creates a proxy
* setting the new `PoolConfigurator` implementation when the function is called for the first time.
* @param newPoolConfiguratorImpl The new PoolConfigurator implementation
**/
function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;
/**
* @notice Returns the address of the price oracle.
* @return The address of the PriceOracle
*/
function getPriceOracle() external view returns (address);
/**
* @notice Updates the address of the price oracle.
* @param newPriceOracle The address of the new PriceOracle
*/
function setPriceOracle(address newPriceOracle) external;
/**
* @notice Returns the address of the ACL manager.
* @return The address of the ACLManager
*/
function getACLManager() external view returns (address);
/**
* @notice Updates the address of the ACL manager.
* @param newAclManager The address of the new ACLManager
**/
function setACLManager(address newAclManager) external;
/**
* @notice Returns the address of the ACL admin.
* @return The address of the ACL admin
*/
function getACLAdmin() external view returns (address);
/**
* @notice Updates the address of the ACL admin.
* @param newAclAdmin The address of the new ACL admin
*/
function setACLAdmin(address newAclAdmin) external;
/**
* @notice Returns the address of the price oracle sentinel.
* @return The address of the PriceOracleSentinel
*/
function getPriceOracleSentinel() external view returns (address);
/**
* @notice Updates the address of the price oracle sentinel.
* @param newPriceOracleSentinel The address of the new PriceOracleSentinel
**/
function setPriceOracleSentinel(address newPriceOracleSentinel) external;
/**
* @notice Returns the address of the data provider.
* @return The address of the DataProvider
*/
function getPoolDataProvider() external view returns (address);
/**
* @notice Updates the address of the data provider.
* @param newDataProvider The address of the new DataProvider
**/
function setPoolDataProvider(address newDataProvider) external;
}
IRewardsController.sol 370 lines
// SPDX-License-Identifier: agpl-3.0
pragma solidity >=0.6.12;
/**
* @title IRewardsDistributor
* @author Aave
* @notice Defines the basic interface for a Rewards Distributor.
*/
interface IRewardsDistributor {
/**
* @dev Emitted when the configuration of the rewards of an asset is updated.
* @param asset The address of the incentivized asset
* @param reward The address of the reward token
* @param oldEmission The old emissions per second value of the reward distribution
* @param newEmission The new emissions per second value of the reward distribution
* @param oldDistributionEnd The old end timestamp of the reward distribution
* @param newDistributionEnd The new end timestamp of the reward distribution
* @param assetIndex The index of the asset distribution
*/
event AssetConfigUpdated(
address indexed asset,
address indexed reward,
uint256 oldEmission,
uint256 newEmission,
uint256 oldDistributionEnd,
uint256 newDistributionEnd,
uint256 assetIndex
);
/**
* @dev Emitted when rewards of an asset are accrued on behalf of a user.
* @param asset The address of the incentivized asset
* @param reward The address of the reward token
* @param user The address of the user that rewards are accrued on behalf of
* @param assetIndex The index of the asset distribution
* @param userIndex The index of the asset distribution on behalf of the user
* @param rewardsAccrued The amount of rewards accrued
*/
event Accrued(
address indexed asset,
address indexed reward,
address indexed user,
uint256 assetIndex,
uint256 userIndex,
uint256 rewardsAccrued
);
/**
* @dev Emitted when the emission manager address is updated.
* @param oldEmissionManager The address of the old emission manager
* @param newEmissionManager The address of the new emission manager
*/
event EmissionManagerUpdated(
address indexed oldEmissionManager,
address indexed newEmissionManager
);
/**
* @dev Sets the end date for the distribution
* @param asset The asset to incentivize
* @param reward The reward token that incentives the asset
* @param newDistributionEnd The end date of the incentivization, in unix time format
**/
function setDistributionEnd(
address asset,
address reward,
uint32 newDistributionEnd
) external;
/**
* @dev Sets the emission per second of a set of reward distributions
* @param asset The asset is being incentivized
* @param rewards List of reward addresses are being distributed
* @param newEmissionsPerSecond List of new reward emissions per second
*/
function setEmissionPerSecond(
address asset,
address[] calldata rewards,
uint88[] calldata newEmissionsPerSecond
) external;
/**
* @dev Gets the end date for the distribution
* @param asset The incentivized asset
* @param reward The reward token of the incentivized asset
* @return The timestamp with the end of the distribution, in unix time format
**/
function getDistributionEnd(
address asset,
address reward
) external view returns (uint256);
/**
* @dev Returns the index of a user on a reward distribution
* @param user Address of the user
* @param asset The incentivized asset
* @param reward The reward token of the incentivized asset
* @return The current user asset index, not including new distributions
**/
function getUserAssetIndex(
address user,
address asset,
address reward
) external view returns (uint256);
/**
* @dev Returns the configuration of the distribution reward for a certain asset
* @param asset The incentivized asset
* @param reward The reward token of the incentivized asset
* @return The index of the asset distribution
* @return The emission per second of the reward distribution
* @return The timestamp of the last update of the index
* @return The timestamp of the distribution end
**/
function getRewardsData(
address asset,
address reward
) external view returns (uint256, uint256, uint256, uint256);
/**
* @dev Returns the list of available reward token addresses of an incentivized asset
* @param asset The incentivized asset
* @return List of rewards addresses of the input asset
**/
function getRewardsByAsset(
address asset
) external view returns (address[] memory);
/**
* @dev Returns the list of available reward addresses
* @return List of rewards supported in this contract
**/
function getRewardsList() external view returns (address[] memory);
/**
* @dev Returns the accrued rewards balance of a user, not including virtually accrued rewards since last distribution.
* @param user The address of the user
* @param reward The address of the reward token
* @return Unclaimed rewards, not including new distributions
**/
function getUserAccruedRewards(
address user,
address reward
) external view returns (uint256);
/**
* @dev Returns a single rewards balance of a user, including virtually accrued and unrealized claimable rewards.
* @param assets List of incentivized assets to check eligible distributions
* @param user The address of the user
* @param reward The address of the reward token
* @return The rewards amount
**/
function getUserRewards(
address[] calldata assets,
address user,
address reward
) external view returns (uint256);
/**
* @dev Returns a list all rewards of a user, including already accrued and unrealized claimable rewards
* @param assets List of incentivized assets to check eligible distributions
* @param user The address of the user
* @return The list of reward addresses
* @return The list of unclaimed amount of rewards
**/
function getAllUserRewards(
address[] calldata assets,
address user
) external view returns (address[] memory, uint256[] memory);
/**
* @dev Returns the decimals of an asset to calculate the distribution delta
* @param asset The address to retrieve decimals
* @return The decimals of an underlying asset
*/
function getAssetDecimals(address asset) external view returns (uint8);
/**
* @dev Returns the address of the emission manager
* @return The address of the EmissionManager
*/
function getEmissionManager() external view returns (address);
/**
* @dev Updates the address of the emission manager
* @param emissionManager The address of the new EmissionManager
*/
function setEmissionManager(address emissionManager) external;
}
/**
* @title IRewardsController
* @author Aave
* @notice Defines the basic interface for a Rewards Controller.
*/
interface IRewardsController is IRewardsDistributor {
/**
* @dev Emitted when a new address is whitelisted as claimer of rewards on behalf of a user
* @param user The address of the user
* @param claimer The address of the claimer
*/
event ClaimerSet(address indexed user, address indexed claimer);
/**
* @dev Emitted when rewards are claimed
* @param user The address of the user rewards has been claimed on behalf of
* @param reward The address of the token reward is claimed
* @param to The address of the receiver of the rewards
* @param claimer The address of the claimer
* @param amount The amount of rewards claimed
*/
event RewardsClaimed(
address indexed user,
address indexed reward,
address indexed to,
address claimer,
uint256 amount
);
/**
* @dev Emitted when a transfer strategy is installed for the reward distribution
* @param reward The address of the token reward
* @param transferStrategy The address of TransferStrategy contract
*/
event TransferStrategyInstalled(
address indexed reward,
address indexed transferStrategy
);
/**
* @dev Emitted when the reward oracle is updated
* @param reward The address of the token reward
* @param rewardOracle The address of oracle
*/
event RewardOracleUpdated(
address indexed reward,
address indexed rewardOracle
);
/**
* @dev Whitelists an address to claim the rewards on behalf of another address
* @param user The address of the user
* @param claimer The address of the claimer
*/
function setClaimer(address user, address claimer) external;
/**
* @dev Get the price aggregator oracle address
* @param reward The address of the reward
* @return The price oracle of the reward
*/
function getRewardOracle(address reward) external view returns (address);
/**
* @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
* @param user The address of the user
* @return The claimer address
*/
function getClaimer(address user) external view returns (address);
/**
* @dev Returns the Transfer Strategy implementation contract address being used for a reward address
* @param reward The address of the reward
* @return The address of the TransferStrategy contract
*/
function getTransferStrategy(
address reward
) external view returns (address);
/**
* @dev Called by the corresponding asset on any update that affects the rewards distribution
* @param user The address of the user
* @param userBalance The user balance of the asset
* @param totalSupply The total supply of the asset
**/
function handleAction(
address user,
uint256 userBalance,
uint256 totalSupply
) external;
/**
* @dev Claims reward for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
* @param assets List of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param to The address that will be receiving the rewards
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewards(
address[] calldata assets,
uint256 amount,
address to,
address reward
) external returns (uint256);
/**
* @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The
* caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param user The address to check and claim rewards
* @param to The address that will be receiving the rewards
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to,
address reward
) external returns (uint256);
/**
* @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewardsToSelf(
address[] calldata assets,
uint256 amount,
address reward
) external returns (uint256);
/**
* @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param to The address that will be receiving the rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList"
**/
function claimAllRewards(
address[] calldata assets,
address to
)
external
returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
/**
* @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The caller must
* be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param user The address to check and claim rewards
* @param to The address that will be receiving the rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
**/
function claimAllRewardsOnBehalf(
address[] calldata assets,
address user,
address to
)
external
returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
/**
* @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
**/
function claimAllRewardsToSelf(
address[] calldata assets
)
external
returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
}
IScaledBalanceToken.sol 73 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.6.12;
/**
* @title IScaledBalanceToken
* @author Aave
* @notice Defines the basic interface for a scaledbalance token.
**/
interface IScaledBalanceToken {
/**
* @dev Emitted after the mint action
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted scaled balance tokens
* @param value The amount being minted (user entered amount + balance increase from interest)
* @param balanceIncrease The increase in balance since the last action of the user
* @param index The next liquidity index of the reserve
**/
event Mint(
address indexed caller,
address indexed onBehalfOf,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @dev Emitted after scaled balance tokens are burned
* @param from The address from which the scaled tokens will be burned
* @param target The address that will receive the underlying, if any
* @param value The amount being burned (user entered amount - balance increase from interest)
* @param balanceIncrease The increase in balance since the last action of the user
* @param index The next liquidity index of the reserve
**/
event Burn(
address indexed from,
address indexed target,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @notice Returns the scaled balance of the user.
* @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
* at the moment of the update
* @param user The user whose balance is calculated
* @return The scaled balance of the user
**/
function scaledBalanceOf(address user) external view returns (uint256);
/**
* @notice Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user
* @return The scaled balance of the user
* @return The scaled total supply
**/
function getScaledUserBalanceAndSupply(
address user
) external view returns (uint256, uint256);
/**
* @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
* @return The scaled total supply
**/
function scaledTotalSupply() external view returns (uint256);
/**
* @notice Returns last index interest was accrued to the user's balance
* @param user The address of the user
* @return The last index interest was accrued to the user's balance, expressed in ray
**/
function getPreviousIndex(address user) external view returns (uint256);
}
IStakedAave.sol 27 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.6.12;
interface IStakedAave {
struct CooldownSnapshot {
uint40 timestamp;
uint216 amount;
}
function stake(address to, uint256 amount) external;
function redeem(address to, uint256 amount) external;
function cooldown() external;
function claimRewards(address to, uint256 amount) external;
function getTotalRewardsBalance(address) external view returns (uint256);
function getCooldownSeconds() external view returns (uint256);
function stakersCooldowns(
address
) external view returns (CooldownSnapshot memory);
function UNSTAKE_WINDOW() external view returns (uint256);
}
BaseHealthCheck.sol 164 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import {
BaseStrategy,
ERC20
} from "../../../tokenized-strategy/BaseStrategy.sol";
/**
* @title Base Health Check
* @author Yearn.finance
* @notice This contract can be inherited by any Yearn
* V3 strategy wishing to implement a health check during
* the `report` function in order to prevent any unexpected
* behavior from being permanently recorded as well as the
* `checkHealth` modifier.
*
* A strategist simply needs to inherit this contract. Set
* the limit ratios to the desired amounts and then
* override `_harvestAndReport()` just as they otherwise
* would. If the profit or loss that would be recorded is
* outside the acceptable bounds the tx will revert.
*
* The healthcheck does not prevent a strategy from reporting
* losses, but rather can make sure manual intervention is
* needed before reporting an unexpected loss or profit.
*/
abstract contract BaseHealthCheck is BaseStrategy {
// Can be used to determine if a healthcheck should be called.
// Defaults to true;
bool public doHealthCheck = true;
uint256 internal constant MAX_BPS = 10_000;
// Default profit limit to 100%.
uint16 private _profitLimitRatio = uint16(MAX_BPS);
// Defaults loss limit to 0.
uint16 private _lossLimitRatio;
constructor(
address _asset,
string memory _name
) BaseStrategy(_asset, _name) {}
/**
* @notice Returns the current profit limit ratio.
* @dev Use a getter function to keep the variable private.
* @return . The current profit limit ratio.
*/
function profitLimitRatio() public view returns (uint256) {
return _profitLimitRatio;
}
/**
* @notice Returns the current loss limit ratio.
* @dev Use a getter function to keep the variable private.
* @return . The current loss limit ratio.
*/
function lossLimitRatio() public view returns (uint256) {
return _lossLimitRatio;
}
/**
* @notice Set the `profitLimitRatio`.
* @dev Denominated in basis points. I.E. 1_000 == 10%.
* @param _newProfitLimitRatio The mew profit limit ratio.
*/
function setProfitLimitRatio(
uint256 _newProfitLimitRatio
) external onlyManagement {
_setProfitLimitRatio(_newProfitLimitRatio);
}
/**
* @dev Internally set the profit limit ratio. Denominated
* in basis points. I.E. 1_000 == 10%.
* @param _newProfitLimitRatio The mew profit limit ratio.
*/
function _setProfitLimitRatio(uint256 _newProfitLimitRatio) internal {
require(_newProfitLimitRatio > 0, "!zero profit");
require(_newProfitLimitRatio <= type(uint16).max, "!too high");
_profitLimitRatio = uint16(_newProfitLimitRatio);
}
/**
* @notice Set the `lossLimitRatio`.
* @dev Denominated in basis points. I.E. 1_000 == 10%.
* @param _newLossLimitRatio The new loss limit ratio.
*/
function setLossLimitRatio(
uint256 _newLossLimitRatio
) external onlyManagement {
_setLossLimitRatio(_newLossLimitRatio);
}
/**
* @dev Internally set the loss limit ratio. Denominated
* in basis points. I.E. 1_000 == 10%.
* @param _newLossLimitRatio The new loss limit ratio.
*/
function _setLossLimitRatio(uint256 _newLossLimitRatio) internal {
require(_newLossLimitRatio < MAX_BPS, "!loss limit");
_lossLimitRatio = uint16(_newLossLimitRatio);
}
/**
* @notice Turns the healthcheck on and off.
* @dev If turned off the next report will auto turn it back on.
* @param _doHealthCheck Bool if healthCheck should be done.
*/
function setDoHealthCheck(bool _doHealthCheck) public onlyManagement {
doHealthCheck = _doHealthCheck;
}
/**
* @notice OVerrides the default {harvestAndReport} to include a healthcheck.
* @return _totalAssets New totalAssets post report.
*/
function harvestAndReport()
external
override
onlySelf
returns (uint256 _totalAssets)
{
// Let the strategy report.
_totalAssets = _harvestAndReport();
// Run the healthcheck on the amount returned.
_executeHealthCheck(_totalAssets);
}
/**
* @dev To be called during a report to make sure the profit
* or loss being recorded is within the acceptable bound.
*
* @param _newTotalAssets The amount that will be reported.
*/
function _executeHealthCheck(uint256 _newTotalAssets) internal virtual {
if (!doHealthCheck) {
doHealthCheck = true;
return;
}
// Get the current total assets from the implementation.
uint256 currentTotalAssets = TokenizedStrategy.totalAssets();
if (_newTotalAssets > currentTotalAssets) {
require(
((_newTotalAssets - currentTotalAssets) <=
(currentTotalAssets * uint256(_profitLimitRatio)) /
MAX_BPS),
"healthCheck"
);
} else if (currentTotalAssets > _newTotalAssets) {
require(
(currentTotalAssets - _newTotalAssets <=
((currentTotalAssets * uint256(_lossLimitRatio)) /
MAX_BPS)),
"healthCheck"
);
}
}
}
BaseHooks.sol 157 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { Hooks } from "./Hooks.sol";
import { BaseHealthCheck, ERC20 } from "../HealthCheck/BaseHealthCheck.sol";
/**
* @title Base Hooks
* @author Yearn.finance
* @notice This contract can be inherited by any Yearn
* strategy wishing to implement pre or post deposit, withdraw
* or transfer hooks in their strategy.
*/
abstract contract BaseHooks is BaseHealthCheck, Hooks {
constructor(
address _asset,
string memory _name
) BaseHealthCheck(_asset, _name) {}
// Deposit
function deposit(
uint256 assets,
address receiver
) external virtual returns (uint256 shares) {
_preDepositHook(assets, shares, receiver);
shares = abi.decode(
_delegateCall(
abi.encodeCall(TokenizedStrategy.deposit, (assets, receiver))
),
(uint256)
);
_postDepositHook(assets, shares, receiver);
}
// Mint
function mint(
uint256 shares,
address receiver
) external virtual returns (uint256 assets) {
_preDepositHook(assets, shares, receiver);
assets = abi.decode(
_delegateCall(
abi.encodeCall(TokenizedStrategy.mint, (shares, receiver))
),
(uint256)
);
_postDepositHook(assets, shares, receiver);
}
// Withdraw
function withdraw(
uint256 assets,
address receiver,
address owner
) external virtual returns (uint256 shares) {
return withdraw(assets, receiver, owner, 0);
}
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxLoss
) public virtual returns (uint256 shares) {
_preWithdrawHook(assets, shares, receiver, owner, maxLoss);
shares = abi.decode(
_delegateCall(
// Have to use encodeWithSignature due to overloading parameters.
abi.encodeWithSignature(
"withdraw(uint256,address,address,uint256)",
assets,
receiver,
owner,
maxLoss
)
),
(uint256)
);
_postWithdrawHook(assets, shares, receiver, owner, maxLoss);
}
// Redeem
function redeem(
uint256 shares,
address receiver,
address owner
) external virtual returns (uint256) {
// We default to not limiting a potential loss.
return redeem(shares, receiver, owner, MAX_BPS);
}
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) public returns (uint256 assets) {
_preWithdrawHook(assets, shares, receiver, owner, maxLoss);
assets = abi.decode(
_delegateCall(
// Have to use encodeWithSignature due to overloading parameters.
abi.encodeWithSignature(
"redeem(uint256,address,address,uint256)",
shares,
receiver,
owner,
maxLoss
)
),
(uint256)
);
_postWithdrawHook(assets, shares, receiver, owner, maxLoss);
}
// Transfer
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool success) {
_preTransferHook(from, to, amount);
success = abi.decode(
_delegateCall(
abi.encodeCall(
TokenizedStrategy.transferFrom,
(from, to, amount)
)
),
(bool)
);
_postTransferHook(from, to, amount, success);
}
// Transfer from
function transfer(
address to,
uint256 amount
) external virtual returns (bool success) {
_preTransferHook(msg.sender, to, amount);
success = abi.decode(
_delegateCall(
abi.encodeCall(TokenizedStrategy.transfer, (to, amount))
),
(bool)
);
_postTransferHook(msg.sender, to, amount, success);
}
function report() external virtual returns (uint256 profit, uint256 loss) {
_preReportHook();
(profit, loss) = abi.decode(
_delegateCall(abi.encodeCall(TokenizedStrategy.report, ())),
(uint256, uint256)
);
_postReportHook(profit, loss);
}
}
Hooks.sol 57 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
contract DepositHooks {
function _preDepositHook(
uint256 assets,
uint256 shares,
address receiver
) internal virtual {}
function _postDepositHook(
uint256 assets,
uint256 shares,
address receiver
) internal virtual {}
}
contract WithdrawHooks {
function _preWithdrawHook(
uint256 assets,
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) internal virtual {}
function _postWithdrawHook(
uint256 assets,
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) internal virtual {}
}
contract TransferHooks {
function _preTransferHook(
address from,
address to,
uint256 amount
) internal virtual {}
function _postTransferHook(
address from,
address to,
uint256 amount,
bool success
) internal virtual {}
}
contract ReportHooks {
function _preReportHook() internal virtual {}
function _postReportHook(uint256 profit, uint256 loss) internal virtual {}
}
contract Hooks is DepositHooks, WithdrawHooks, TransferHooks, ReportHooks {}
ISwapRouter.sol 79 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;
import "./IUniswapV3SwapCallback.sol";
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(
ExactOutputSingleParams calldata params
) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(
ExactOutputParams calldata params
) external payable returns (uint256 amountIn);
// Taken from https://soliditydeveloper.com/uniswap3
// Manually added to the interface
function refundETH() external payable;
}
IUniswapV3SwapCallback.sol 21 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}
UniswapV3Swapper.sol 197 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ISwapRouter } from "../interfaces/Uniswap/V3/ISwapRouter.sol";
/**
* @title UniswapV3Swapper
* @author Yearn.finance
* @dev This is a simple contract that can be inherited by any tokenized
* strategy that would like to use Uniswap V3 for swaps. It hold all needed
* logic to perform both exact input and exact output swaps.
*
* The global address variables default to the ETH mainnet addresses but
* remain settable by the inheriting contract to allow for customization
* based on needs or chain its used on.
*
* The only variables that are required to be set are the specific fees
* for each token pair. The inheriting contract can use the {_setUniFees}
* function to easily set this for any token pairs needed.
*/
contract UniswapV3Swapper {
using SafeERC20 for ERC20;
// Optional Variable to be set to not sell dust.
uint256 public minAmountToSell;
// Defaults to WETH on mainnet.
address public base = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// Defaults to Uniswap V3 router on mainnet.
address public router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
// Fees for the Uni V3 pools. Each fee should get set each way in
// the mapping so no matter the direction the correct fee will get
// returned for any two tokens.
mapping(address => mapping(address => uint24)) public uniFees;
/**
* @dev All fess will default to 0 on creation. A strategist will need
* To set the mapping for the tokens expected to swap. This function
* is to help set the mapping. It can be called internally during
* initialization, through permissioned functions etc.
*/
function _setUniFees(
address _token0,
address _token1,
uint24 _fee
) internal virtual {
uniFees[_token0][_token1] = _fee;
uniFees[_token1][_token0] = _fee;
}
/**
* @dev Used to swap a specific amount of `_from` to `_to`.
* This will check and handle all allowances as well as not swapping
* unless `_amountIn` is greater than the set `_minAmountOut`
*
* If one of the tokens matches with the `base` token it will do only
* one jump, otherwise will do two jumps.
*
* The corresponding uniFees for each token pair will need to be set
* other wise this function will revert.
*
* @param _from The token we are swapping from.
* @param _to The token we are swapping to.
* @param _amountIn The amount of `_from` we will swap.
* @param _minAmountOut The min of `_to` to get out.
* @return _amountOut The actual amount of `_to` that was swapped to
*/
function _swapFrom(
address _from,
address _to,
uint256 _amountIn,
uint256 _minAmountOut
) internal virtual returns (uint256 _amountOut) {
if (_amountIn != 0 && _amountIn >= minAmountToSell) {
_checkAllowance(router, _from, _amountIn);
if (_from == base || _to == base) {
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams(
_from, // tokenIn
_to, // tokenOut
uniFees[_from][_to], // from-to fee
address(this), // recipient
block.timestamp, // deadline
_amountIn, // amountIn
_minAmountOut, // amountOut
0 // sqrtPriceLimitX96
);
_amountOut = ISwapRouter(router).exactInputSingle(params);
} else {
bytes memory path = abi.encodePacked(
_from, // tokenIn
uniFees[_from][base], // from-base fee
base, // base token
uniFees[base][_to], // base-to fee
_to // tokenOut
);
_amountOut = ISwapRouter(router).exactInput(
ISwapRouter.ExactInputParams(
path,
address(this),
block.timestamp,
_amountIn,
_minAmountOut
)
);
}
}
}
/**
* @dev Used to swap a specific amount of `_to` from `_from` unless
* it takes more than `_maxAmountFrom`.
*
* This will check and handle all allowances as well as not swapping
* unless `_maxAmountFrom` is greater than the set `minAmountToSell`
*
* If one of the tokens matches with the `base` token it will do only
* one jump, otherwise will do two jumps.
*
* The corresponding uniFees for each token pair will need to be set
* other wise this function will revert.
*
* @param _from The token we are swapping from.
* @param _to The token we are swapping to.
* @param _amountTo The amount of `_to` we need out.
* @param _maxAmountFrom The max of `_from` we will swap.
* @return _amountIn The actual amount of `_from` swapped.
*/
function _swapTo(
address _from,
address _to,
uint256 _amountTo,
uint256 _maxAmountFrom
) internal virtual returns (uint256 _amountIn) {
if (_maxAmountFrom != 0 && _maxAmountFrom >= minAmountToSell) {
_checkAllowance(router, _from, _maxAmountFrom);
if (_from == base || _to == base) {
ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter
.ExactOutputSingleParams(
_from, // tokenIn
_to, // tokenOut
uniFees[_from][_to], // from-to fee
address(this), // recipient
block.timestamp, // deadline
_amountTo, // amountOut
_maxAmountFrom, // maxAmountIn
0 // sqrtPriceLimitX96
);
_amountIn = ISwapRouter(router).exactOutputSingle(params);
} else {
bytes memory path = abi.encodePacked(
_to,
uniFees[base][_to], // base-to fee
base,
uniFees[_from][base], // from-base fee
_from
);
_amountIn = ISwapRouter(router).exactOutput(
ISwapRouter.ExactOutputParams(
path,
address(this),
block.timestamp,
_amountTo, // How much we want out
_maxAmountFrom
)
);
}
}
}
/**
* @dev Internal safe function to make sure the contract you want to
* interact with has enough allowance to pull the desired tokens.
*
* @param _contract The address of the contract that will move the token.
* @param _token The ERC-20 token that will be getting spent.
* @param _amount The amount of `_token` to be spent.
*/
function _checkAllowance(
address _contract,
address _token,
uint256 _amount
) internal virtual {
if (ERC20(_token).allowance(address(this), _contract) < _amount) {
ERC20(_token).forceApprove(_contract, 0);
ERC20(_token).forceApprove(_contract, _amount);
}
}
}
BaseStrategy.sol 513 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// TokenizedStrategy interface used for internal view delegateCalls.
import { ITokenizedStrategy } from "./interfaces/ITokenizedStrategy.sol";
/**
* @title YearnV3 Base Strategy
* @author yearn.finance
* @notice
* BaseStrategy implements all of the required functionality to
* seamlessly integrate with the `TokenizedStrategy` implementation contract
* allowing anyone to easily build a fully permissionless ERC-4626 compliant
* Vault by inheriting this contract and overriding three simple functions.
* It utilizes an immutable proxy pattern that allows the BaseStrategy
* to remain simple and small. All standard logic is held within the
* `TokenizedStrategy` and is reused over any n strategies all using the
* `fallback` function to delegatecall the implementation so that strategists
* can only be concerned with writing their strategy specific code.
*
* This contract should be inherited and the three main abstract methods
* `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt
* the Strategy to the particular needs it has to generate yield. There are
* other optional methods that can be implemented to further customize
* the strategy if desired.
*
* All default storage for the strategy is controlled and updated by the
* `TokenizedStrategy`. The implementation holds a storage struct that
* contains all needed global variables in a manual storage slot. This
* means strategists can feel free to implement their own custom storage
* variables as they need with no concern of collisions. All global variables
* can be viewed within the Strategy by a simple call using the
* `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();.
*/
abstract contract BaseStrategy {
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @dev Used on TokenizedStrategy callback functions to make sure it is post
* a delegateCall from this address to the TokenizedStrategy.
*/
modifier onlySelf() {
_onlySelf();
_;
}
/**
* @dev Use to assure that the call is coming from the strategies management.
*/
modifier onlyManagement() {
TokenizedStrategy.requireManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the keeper.
*/
modifier onlyKeepers() {
TokenizedStrategy.requireKeeperOrManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the emergency admin.
*/
modifier onlyEmergencyAuthorized() {
TokenizedStrategy.requireEmergencyAuthorized(msg.sender);
_;
}
/**
* @dev Require that the msg.sender is this address.
*/
function _onlySelf() internal view {
require(msg.sender == address(this), "!self");
}
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @dev This is the address of the TokenizedStrategy implementation
* contract that will be used by all strategies to handle the
* accounting, logic, storage etc.
*
* Any external calls to the that don't hit one of the functions
* defined in this base or the strategy will end up being forwarded
* through the fallback function, which will delegateCall this address.
*
* This address should be the same for every strategy, never be adjusted
* and always be checked before any integration with the Strategy.
*/
address public constant tokenizedStrategyAddress =
0xf0C3fF22876D34F1a7Dc342385Ea17fCf66376d1;
/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/
/**
* @dev Underlying asset the Strategy is earning yield on.
* Stored here for cheap retrievals within the strategy.
*/
ERC20 internal immutable asset;
/**
* @dev This variable is set to address(this) during initialization of each strategy.
*
* This can be used to retrieve storage data within the strategy
* contract as if it were a linked library.
*
* i.e. uint256 totalAssets = TokenizedStrategy.totalAssets()
*
* Using address(this) will mean any calls using this variable will lead
* to a call to itself. Which will hit the fallback function and
* delegateCall that to the actual TokenizedStrategy.
*/
ITokenizedStrategy internal immutable TokenizedStrategy;
/**
* @notice Used to initialize the strategy on deployment.
*
* This will set the `TokenizedStrategy` variable for easy
* internal view calls to the implementation. As well as
* initializing the default storage variables based on the
* parameters and using the deployer for the permissioned roles.
*
* @param _asset Address of the underlying asset.
* @param _name Name the strategy will use.
*/
constructor(address _asset, string memory _name) {
asset = ERC20(_asset);
// Set instance of the implementation for internal use.
TokenizedStrategy = ITokenizedStrategy(address(this));
// Initialize the strategy's storage variables.
_delegateCall(
abi.encodeCall(
ITokenizedStrategy.initialize,
(_asset, _name, msg.sender, msg.sender, msg.sender)
)
);
// Store the tokenizedStrategyAddress at the standard implementation
// address storage slot so etherscan picks up the interface. This gets
// stored on initialization and never updated.
assembly {
sstore(
// keccak256('eip1967.proxy.implementation' - 1)
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
tokenizedStrategyAddress
)
}
}
/*//////////////////////////////////////////////////////////////
NEEDED TO BE OVERRIDDEN BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Can deploy up to '_amount' of 'asset' in the yield source.
*
* This function is called at the end of a {deposit} or {mint}
* call. Meaning that unless a whitelist is implemented it will
* be entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* @param _amount The amount of 'asset' that the strategy can attempt
* to deposit in the yield source.
*/
function _deployFunds(uint256 _amount) internal virtual;
/**
* @dev Should attempt to free the '_amount' of 'asset'.
*
* NOTE: The amount of 'asset' that is already loose has already
* been accounted for.
*
* This function is called during {withdraw} and {redeem} calls.
* Meaning that unless a whitelist is implemented it will be
* entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* Should not rely on asset.balanceOf(address(this)) calls other than
* for diff accounting purposes.
*
* Any difference between `_amount` and what is actually freed will be
* counted as a loss and passed on to the withdrawer. This means
* care should be taken in times of illiquidity. It may be better to revert
* if withdraws are simply illiquid so not to realize incorrect losses.
*
* @param _amount, The amount of 'asset' to be freed.
*/
function _freeFunds(uint256 _amount) internal virtual;
/**
* @dev Internal function to harvest all rewards, redeploy any idle
* funds and return an accurate accounting of all funds currently
* held by the Strategy.
*
* This should do any needed harvesting, rewards selling, accrual,
* redepositing etc. to get the most accurate view of current assets.
*
* NOTE: All applicable assets including loose assets should be
* accounted for in this function.
*
* Care should be taken when relying on oracles or swap values rather
* than actual amounts as all Strategy profit/loss accounting will
* be done based on this returned value.
*
* This can still be called post a shutdown, a strategist can check
* `TokenizedStrategy.isShutdown()` to decide if funds should be
* redeployed or simply realize any profits/losses.
*
* @return _totalAssets A trusted and accurate account for the total
* amount of 'asset' the strategy currently holds including idle funds.
*/
function _harvestAndReport()
internal
virtual
returns (uint256 _totalAssets);
/*//////////////////////////////////////////////////////////////
OPTIONAL TO OVERRIDE BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Optional function for strategist to override that can
* be called in between reports.
*
* If '_tend' is used tendTrigger() will also need to be overridden.
*
* This call can only be called by a permissioned role so may be
* through protected relays.
*
* This can be used to harvest and compound rewards, deposit idle funds,
* perform needed position maintenance or anything else that doesn't need
* a full report for.
*
* EX: A strategy that can not deposit funds without getting
* sandwiched can use the tend when a certain threshold
* of idle to totalAssets has been reached.
*
* This will have no effect on PPS of the strategy till report() is called.
*
* @param _totalIdle The current amount of idle funds that are available to deploy.
*/
function _tend(uint256 _totalIdle) internal virtual {}
/**
* @dev Optional trigger to override if tend() will be used by the strategy.
* This must be implemented if the strategy hopes to invoke _tend().
*
* @return . Should return true if tend() should be called by keeper or false if not.
*/
function _tendTrigger() internal view virtual returns (bool) {
return false;
}
/**
* @notice Returns if tend() should be called by a keeper.
*
* @return . Should return true if tend() should be called by keeper or false if not.
* @return . Calldata for the tend call.
*/
function tendTrigger() external view virtual returns (bool, bytes memory) {
return (
// Return the status of the tend trigger.
_tendTrigger(),
// And the needed calldata either way.
abi.encodeWithSelector(ITokenizedStrategy.tend.selector)
);
}
/**
* @notice Gets the max amount of `asset` that an address can deposit.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any deposit or mints to enforce
* any limits desired by the strategist. This can be used for either a
* traditional deposit limit or for implementing a whitelist etc.
*
* EX:
* if(isAllowed[_owner]) return super.availableDepositLimit(_owner);
*
* This does not need to take into account any conversion rates
* from shares to assets. But should know that any non max uint256
* amounts may be converted to shares. So it is recommended to keep
* custom amounts low enough as not to cause overflow when multiplied
* by `totalSupply`.
*
* @param . The address that is depositing into the strategy.
* @return . The available amount the `_owner` can deposit in terms of `asset`
*/
function availableDepositLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @notice Gets the max amount of `asset` that can be withdrawn.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any withdraw or redeem to enforce
* any limits desired by the strategist. This can be used for illiquid
* or sandwichable strategies. It should never be lower than `totalIdle`.
*
* EX:
* return TokenIzedStrategy.totalIdle();
*
* This does not need to take into account the `_owner`'s share balance
* or conversion rates from shares to assets.
*
* @param . The address that is withdrawing from the strategy.
* @return . The available amount that can be withdrawn in terms of `asset`
*/
function availableWithdrawLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Optional function for a strategist to override that will
* allow management to manually withdraw deployed funds from the
* yield source if a strategy is shutdown.
*
* This should attempt to free `_amount`, noting that `_amount` may
* be more than is currently deployed.
*
* NOTE: This will not realize any profits or losses. A separate
* {report} will be needed in order to record any profit/loss. If
* a report may need to be called after a shutdown it is important
* to check if the strategy is shutdown during {_harvestAndReport}
* so that it does not simply re-deploy all funds that had been freed.
*
* EX:
* if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {
* depositFunds...
* }
*
* @param _amount The amount of asset to attempt to free.
*/
function _emergencyWithdraw(uint256 _amount) internal virtual {}
/*//////////////////////////////////////////////////////////////
TokenizedStrategy HOOKS
//////////////////////////////////////////////////////////////*/
/**
* @notice Can deploy up to '_amount' of 'asset' in yield source.
* @dev Callback for the TokenizedStrategy to call during a {deposit}
* or {mint} to tell the strategy it can deploy funds.
*
* Since this can only be called after a {deposit} or {mint}
* delegateCall to the TokenizedStrategy msg.sender == address(this).
*
* Unless a whitelist is implemented this will be entirely permissionless
* and thus can be sandwiched or otherwise manipulated.
*
* @param _amount The amount of 'asset' that the strategy can
* attempt to deposit in the yield source.
*/
function deployFunds(uint256 _amount) external virtual onlySelf {
_deployFunds(_amount);
}
/**
* @notice Should attempt to free the '_amount' of 'asset'.
* @dev Callback for the TokenizedStrategy to call during a withdraw
* or redeem to free the needed funds to service the withdraw.
*
* This can only be called after a 'withdraw' or 'redeem' delegateCall
* to the TokenizedStrategy so msg.sender == address(this).
*
* @param _amount The amount of 'asset' that the strategy should attempt to free up.
*/
function freeFunds(uint256 _amount) external virtual onlySelf {
_freeFunds(_amount);
}
/**
* @notice Returns the accurate amount of all funds currently
* held by the Strategy.
* @dev Callback for the TokenizedStrategy to call during a report to
* get an accurate accounting of assets the strategy controls.
*
* This can only be called after a report() delegateCall to the
* TokenizedStrategy so msg.sender == address(this).
*
* @return . A trusted and accurate account for the total amount
* of 'asset' the strategy currently holds including idle funds.
*/
function harvestAndReport() external virtual onlySelf returns (uint256) {
return _harvestAndReport();
}
/**
* @notice Will call the internal '_tend' when a keeper tends the strategy.
* @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy.
*
* This can only be called after a tend() delegateCall to the TokenizedStrategy
* so msg.sender == address(this).
*
* We name the function `tendThis` so that `tend` calls are forwarded to
* the TokenizedStrategy.
* @param _totalIdle The amount of current idle funds that can be
* deployed during the tend
*/
function tendThis(uint256 _totalIdle) external virtual onlySelf {
_tend(_totalIdle);
}
/**
* @notice Will call the internal '_emergencyWithdraw' function.
* @dev Callback for the TokenizedStrategy during an emergency withdraw.
*
* This can only be called after a emergencyWithdraw() delegateCall to
* the TokenizedStrategy so msg.sender == address(this).
*
* We name the function `shutdownWithdraw` so that `emergencyWithdraw`
* calls are forwarded to the TokenizedStrategy.
*
* @param _amount The amount of asset to attempt to free.
*/
function shutdownWithdraw(uint256 _amount) external virtual onlySelf {
_emergencyWithdraw(_amount);
}
/**
* @dev Function used to delegate call the TokenizedStrategy with
* certain `_calldata` and return any return values.
*
* This is used to setup the initial storage of the strategy, and
* can be used by strategist to forward any other call to the
* TokenizedStrategy implementation.
*
* @param _calldata The abi encoded calldata to use in delegatecall.
* @return . The return value if the call was successful in bytes.
*/
function _delegateCall(
bytes memory _calldata
) internal returns (bytes memory) {
// Delegate call the tokenized strategy with provided calldata.
(bool success, bytes memory result) = tokenizedStrategyAddress
.delegatecall(_calldata);
// If the call reverted. Return the error.
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
// Return the result.
return result;
}
/**
* @dev Execute a function on the TokenizedStrategy and return any value.
*
* This fallback function will be executed when any of the standard functions
* defined in the TokenizedStrategy are called since they wont be defined in
* this contract.
*
* It will delegatecall the TokenizedStrategy implementation with the exact
* calldata and return any relevant values.
*
*/
fallback() external {
// load our target address
address _tokenizedStrategyAddress = tokenizedStrategyAddress;
// Execute external function using delegatecall and return any value.
assembly {
// Copy function selector and any arguments.
calldatacopy(0, 0, calldatasize())
// Execute function delegatecall.
let result := delegatecall(
gas(),
_tokenizedStrategyAddress,
0,
calldatasize(),
0,
0
)
// Get any return value
returndatacopy(0, 0, returndatasize())
// Return any return value or error back to the caller
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}
IBaseStrategy.sol 30 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
interface IBaseStrategy {
function tokenizedStrategyAddress() external view returns (address);
/*//////////////////////////////////////////////////////////////
IMMUTABLE FUNCTIONS
//////////////////////////////////////////////////////////////*/
function availableDepositLimit(
address _owner
) external view returns (uint256);
function availableWithdrawLimit(
address _owner
) external view returns (uint256);
function deployFunds(uint256 _assets) external;
function freeFunds(uint256 _amount) external;
function harvestAndReport() external returns (uint256);
function tendThis(uint256 _totalIdle) external;
function shutdownWithdraw(uint256 _amount) external;
function tendTrigger() external view returns (bool, bytes memory);
}
IStrategy.sol 7 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { ITokenizedStrategy } from "./ITokenizedStrategy.sol";
import { IBaseStrategy } from "./IBaseStrategy.sol";
interface IStrategy is IBaseStrategy, ITokenizedStrategy {}
ITokenizedStrategy.sol 168 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
// Interface that implements the 4626 standard and the implementation functions
interface ITokenizedStrategy is IERC4626, IERC20Permit {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event StrategyShutdown();
event NewTokenizedStrategy(
address indexed strategy,
address indexed asset,
string apiVersion
);
event Reported(
uint256 profit,
uint256 loss,
uint256 protocolFees,
uint256 performanceFees
);
event UpdatePerformanceFeeRecipient(
address indexed newPerformanceFeeRecipient
);
event UpdateKeeper(address indexed newKeeper);
event UpdatePerformanceFee(uint16 newPerformanceFee);
event UpdateManagement(address indexed newManagement);
event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);
event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);
event UpdatePendingManagement(address indexed newPendingManagement);
/*//////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////*/
function initialize(
address _asset,
string memory _name,
address _management,
address _performanceFeeRecipient,
address _keeper
) external;
/*//////////////////////////////////////////////////////////////
NON-STANDARD 4626 OPTIONS
//////////////////////////////////////////////////////////////*/
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function maxWithdraw(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
function maxRedeem(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
/*//////////////////////////////////////////////////////////////
MODIFIER HELPERS
//////////////////////////////////////////////////////////////*/
function requireManagement(address _sender) external view;
function requireKeeperOrManagement(address _sender) external view;
function requireEmergencyAuthorized(address _sender) external view;
/*//////////////////////////////////////////////////////////////
KEEPERS FUNCTIONS
//////////////////////////////////////////////////////////////*/
function tend() external;
function report() external returns (uint256 _profit, uint256 _loss);
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
function MAX_FEE() external view returns (uint16);
function FACTORY() external view returns (address);
/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/
function apiVersion() external view returns (string memory);
function pricePerShare() external view returns (uint256);
function management() external view returns (address);
function pendingManagement() external view returns (address);
function keeper() external view returns (address);
function emergencyAdmin() external view returns (address);
function performanceFee() external view returns (uint16);
function performanceFeeRecipient() external view returns (address);
function fullProfitUnlockDate() external view returns (uint256);
function profitUnlockingRate() external view returns (uint256);
function profitMaxUnlockTime() external view returns (uint256);
function lastReport() external view returns (uint256);
function isShutdown() external view returns (bool);
function unlockedShares() external view returns (uint256);
/*//////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////*/
function setPendingManagement(address) external;
function acceptManagement() external;
function setKeeper(address _keeper) external;
function setEmergencyAdmin(address _emergencyAdmin) external;
function setPerformanceFee(uint16 _performanceFee) external;
function setPerformanceFeeRecipient(
address _performanceFeeRecipient
) external;
function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external;
function setName(string calldata _newName) external;
function shutdownStrategy() external;
function emergencyWithdraw(uint256 _amount) external;
}
Read Contract
base 0x5001f3b5 → address
deployments 0x316b3739 → address
isDeployedStrategy 0x0d004424 → bool
keeper 0xaced1661 → address
lendingPool 0xa59a9973 → address
management 0x88a8d602 → address
performanceFeeRecipient 0xed27f7c9 → address
router 0xf887ea40 → address
sms 0xe436a60b → address
Write Contract 2 functions
These functions modify contract state and require a wallet transaction to execute.
newAaveV3Lender 0xa8403327
address _asset
returns: address
setAddresses 0x363bf964
address _management
address _performanceFeeRecipient
address _keeper
Recent Transactions
No transactions found for this address