Address Contract Verified
Address
0xCe6Ced23118EDEb23054E06118a702797b13fc2F
Balance
0 ETH
Nonce
1
Code Size
8381 bytes
Creator
0x914d7Fec...43d7 at tx 0xf80137c3...31a001
Indexed Transactions
0
Contract Bytecode
8381 bytes
0x608060405234801561000f575f5ffd5b5060043610610111575f3560e01c8063a4757b0f1161009e578063c531de401161006e578063c531de4014610216578063cd086d4514610229578063d740871514610250578063eed88b8d14610272578063f2fde38b14610285575f5ffd5b8063a4757b0f146101c0578063a5fbb680146101d0578063ac9650d8146101e3578063ad89eb1e14610203575f5ffd5b80635c975abb116100e45780635c975abb14610158578063715018a6146101795780638456cb59146101815780638da5cb5b14610189578063a3d5b255146101ad575f5ffd5b80630f198b301461011557806338957dd91461012a5780633f4ba83a1461013d57806351d3bf6d14610145575b5f5ffd5b610128610123366004611acc565b610298565b005b610128610138366004611acc565b610583565b6101286106af565b610128610153366004611ae5565b6106c1565b5f54600160a01b900460ff1660405190151581526020015b60405180910390f35b610128610780565b610128610791565b5f546001600160a01b03165b6040516001600160a01b039091168152602001610170565b6101286101bb366004611b0a565b6107a1565b5f546001600160a01b0316610195565b6101286101de366004611b48565b6107d6565b6101f66101f1366004611bc7565b610ae1565b6040516101709190611c28565b610128610211366004611bc7565b610bc8565b610128610224366004611ca6565b610c04565b6101957f0000000000000000000000004655ce3d625a63d30ba704087e52b4c31e38188b81565b61026461025e366004611cb7565b505f1990565b604051908152602001610170565b610128610280366004611cd2565b610ccc565b610128610293366004611cb7565b610d04565b6102a0610d43565b80604001355f036102c457604051631f2a200560e01b815260040160405180910390fd5b6102d96102d46020830183611cb7565b610d6d565b5f6001816102ea6020850185611cb7565b6001600160a01b03166001600160a01b031681526020019081526020015f2090505f816001015f8460200160208101906103249190611cb7565b6001600160a01b0316815260208101919091526040015f9081205460ff16915081600381111561035657610356611cfc565b036103745760405163bc0bf40160e01b815260040160405180910390fd5b6040830135600282600381111561038d5761038d611cfc565b03610507575f806103a46040870160208801611cb7565b6001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156103f5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104199190611d10565b9050805f0361043b57604051631f2a200560e01b815260040160405180910390fd5b8083111561044b57600191508092505b61047233308561046160408b0160208c01611cb7565b6001600160a01b0316929190611097565b81610500575f6104886040880160208901611cb7565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156104cc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104f09190611d10565b9050808411156104fe578093505b505b505061051d565b61051d3330836104616040890160208a01611cb7565b61057d61052d6020860186611cb7565b61053d6040870160208801611cb7565b60408051606081018252875460ff80821615158352610100820416151560208301526201000090046001600160a01b0316918101919091528490866110fe565b50505050565b61058b610d43565b80604001355f036105af57604051631f2a200560e01b815260040160405180910390fd5b6105bf6102d46020830183611cb7565b5f6001816105d06020850185611cb7565b6001600160a01b03166001600160a01b031681526020019081526020015f2090505f816001015f84602001602081019061060a9190611cb7565b6001600160a01b0316815260208101919091526040015f9081205460ff16915081600381111561063c5761063c611cfc565b0361065a5760405163bc0bf40160e01b815260040160405180910390fd5b6106aa61066a6020850185611cb7565b60408051606081018252855460ff80821615158352610100820416151560208301526201000090046001600160a01b0316818301529086013590846112d5565b505050565b6106b76114a3565b6106bf6114cf565b565b6106c9610d43565b6106d96102d46020830183611cb7565b6106e66020820182611cb7565b6001600160a01b031663fae9fed033836020013560405180606001604052808660400160208101906107189190611d27565b60ff1681526020018660600135815260200186608001358152506040518463ffffffff1660e01b815260040161075093929190611d47565b5f604051808303815f87803b158015610767575f5ffd5b505af1158015610779573d5f5f3e3d5ffd5b5050505050565b6107886114a3565b6106bf5f611523565b6107996114a3565b6106bf611572565b5f546001600160a01b031633146107cb57604051633a02626960e01b815260040160405180910390fd5b6106aa8383836115b4565b6107de610d43565b6107ee6102d46020830183611cb7565b5f6107f882611638565b905061080a60e0830160c08401611d8a565b610812575050565b5f6001816108236020860186611cb7565b6001600160a01b03166001600160a01b031681526020019081526020015f2090505f5b825181101561057d5782818151811061086157610861611da9565b60200260200101515f0315610ad6575f60018301816108836020880188611dbd565b8581811061089357610893611da9565b90506020020160208101906108a89190611cb7565b6001600160a01b031681526020808201929092526040015f9081205460ff169250906108d690870187611dbd565b848181106108e6576108e6611da9565b90506020020160208101906108fb9190611cb7565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561093f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109639190611d10565b9050805f03610973575050610ad6565b84838151811061098557610985611da9565b60200260200101518110156109b457808584815181106109a7576109a7611da9565b6020026020010181815250505b5f8260038111156109c7576109c7611cfc565b03610a3457610a2f338685815181106109e2576109e2611da9565b60200260200101518880602001906109fa9190611dbd565b87818110610a0a57610a0a611da9565b9050602002016020810190610a1f9190611cb7565b6001600160a01b03169190611741565b610ad3565b610ad3610a446020880188611cb7565b610a516020890189611dbd565b86818110610a6157610a61611da9565b9050602002016020810190610a769190611cb7565b878681518110610a8857610a88611da9565b602090810291909101810151604080516060810182528a5460ff80821615158352610100820416151594820194909452620100009093046001600160a01b03169083015290866110fe565b50505b600101610846565b50565b604080515f8152602081019091526060908267ffffffffffffffff811115610b0b57610b0b611e03565b604051908082528060200260200182016040528015610b3e57816020015b6060815260200190600190039081610b295790505b5091505f5b83811015610bbf57610b9a30868684818110610b6157610b61611da9565b9050602002810190610b739190611e17565b85604051602001610b8693929190611e5a565b604051602081830303815290604052611772565b838281518110610bac57610bac611da9565b6020908102919091010152600101610b43565b50505b92915050565b5f5b818110156106aa57610bfc838383818110610be757610be7611da9565b90506020020160208101906102d49190611cb7565b600101610bca565b610c0c610d43565b610c196020820182611cb7565b6001600160a01b031663d505accf333060208501356040860135610c436080880160608901611d27565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152608084013560a482015260a084013560c482015260e4015f604051808303815f87803b158015610cb3575f5ffd5b505af1925050508015610cc4575060015b15610ade5750565b5f546001600160a01b03163314610cf657604051633a02626960e01b815260040160405180910390fd5b610d0082826117e4565b5050565b610d0c6114a3565b6001600160a01b038116610d3a57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610ade81611523565b5f54600160a01b900460ff16156106bf5760405163d93c066560e01b815260040160405180910390fd5b6001600160a01b0381165f9081526001602052604090205460ff16610ade57604051631652e7b760e01b81526001600160a01b0382811660048301527f0000000000000000000000004655ce3d625a63d30ba704087e52b4c31e38188b1690631652e7b7906024016040805180830381865afa158015610def573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e139190611eb0565b515f03610e335760405163926fe7ff60e01b815260040160405180910390fd5b6001600160a01b0381165f81815260016020908152604080832081516338d52e0f60e01b815291519094926338d52e0f92600480820193918290030181865afa158015610e82573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ea69190611eff565b60408051600481526024810182526020810180516001600160e01b0316635060f8af60e11b17905290519192505f91829182916001600160a01b03861691610eed91611f1a565b5f60405180830381855afa9150503d805f8114610f25576040519150601f19603f3d011682016040523d82523d5f602084013e610f2a565b606091505b50915091508115610fec575f81806020019051810190610f4a9190611eff565b6001600160a01b038681165f81815260018a810160209081526040808420805460ff1990811690941790559486168352918490208054909116600217905582516338d52e0f60e01b8152925193945090926338d52e0f9260048082019392918290030181865afa158015610fc0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fe49190611eff565b935050610ff0565b8392505b6001600160a01b038381165f818152600188810160209081526040808420805460ff1916600317905580516060810182528381528a87169586141592810183905281018590528a546201000090950262010000600160b01b031961010090930261ffff1990961695909517909217169290921788559051918816917fa51d0c2ac6e3d6ddd29a3a38436525dd8e7a10da347d2d4a9f2148d9e3bfbe1c9190a2505050505050565b6040516001600160a01b03848116602483015283811660448301526064820183905261057d9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506118b3565b61110c81836020015161191f565b1561123657604082015161112b906001600160a01b0386169085611946565b600381600381111561113f5761113f611cfc565b036111bf576040808301519051636e553f6560e01b8152600481018590523060248201526001600160a01b0390911690636e553f65906044016020604051808303815f875af1158015611194573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b89190611d10565b9250611236565b604080830151905163e25ec34960e01b8152600481018590523060248201526001600160a01b039091169063e25ec349906044016020604051808303815f875af115801561120f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112339190611d10565b92505b604082015161124f906001600160a01b03168685611946565b6001600160a01b038516636e553f6584336040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044016020604051808303815f875af11580156112a9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112cd9190611d10565b505050505050565b6112e381836020015161191f565b156114275760408051635d043b2960e11b81526004810185905230602482015233604482015290516001600160a01b0386169163ba08765291606480830192602092919082900301815f875af115801561133f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113639190611d10565b9250600381600381111561137957611379611cfc565b0361140d5760408201516001600160a01b031663ba08765284335b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201523060448201526064016020604051808303815f875af11580156113e3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114079190611d10565b5061057d565b60408201516001600160a01b031663090edf9a8433611394565b60408051635d043b2960e11b8152600481018590523360248201819052604482015290516001600160a01b0386169163ba08765291606480830192602092919082900301815f875af115801561147f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107799190611d10565b5f546001600160a01b031633146106bf5760405163118cdaa760e01b8152336004820152602401610d31565b6114d76119d5565b5f805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61157a610d43565b5f805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115063390565b5f198181116115c357806115c5565b815b91506115db6001600160a01b0385168484611741565b826001600160a01b0316846001600160a01b0316336001600160a01b03167fc7af665d489507e14ae25ac7ab0030fc7f570869610bdd32117ea56b60ae5c618560405161162a91815260200190565b60405180910390a450505050565b60606001600160a01b037f0000000000000000000000004655ce3d625a63d30ba704087e52b4c31e38188b1663d6976b406116766020850185611cb7565b6116836020860186611dbd565b3361169460e0890160c08a01611d8a565b61169e57336116a0565b305b886040013560405180606001604052808b60600160208101906116c39190611d27565b60ff1681526020018b6080013581526020018b60a001358152506040518863ffffffff1660e01b81526004016116ff9796959493929190611f35565b5f604051808303815f875af115801561171a573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610bc29190810190611fdb565b6040516001600160a01b038381166024830152604482018390526106aa91859182169063a9059cbb906064016110cc565b60605f5f846001600160a01b03168460405161178e9190611f1a565b5f60405180830381855af49150503d805f81146117c6576040519150601f19603f3d011682016040523d82523d5f602084013e6117cb565b606091505b50915091506117db8583836119fe565b95945050505050565b604080515f808252602082019092526001600160a01b03841690839060405161180d9190611f1a565b5f6040518083038185875af1925050503d805f8114611847576040519150601f19603f3d011682016040523d82523d5f602084013e61184c565b606091505b505090508061186e57604051630db2c7f160e31b815260040160405180910390fd5b6040518281526001600160a01b0384169033907fb7c602059992183c7b767c08204223afc99f1895fd175adf9ece23ce9f5bb8b79060200160405180910390a3505050565b5f5f60205f8451602086015f885af1806118d2576040513d5f823e3d81fd5b50505f513d915081156118e95780600114156118f6565b6001600160a01b0384163b155b1561057d57604051635274afe760e01b81526001600160a01b0385166004820152602401610d31565b5f600183600381111561193457611934611cfc565b1415801561193f5750815b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526119978482611a5a565b61057d576040516001600160a01b0384811660248301525f60448301526119cb91869182169063095ea7b3906064016110cc565b61057d84826118b3565b5f54600160a01b900460ff166106bf57604051638dfc202b60e01b815260040160405180910390fd5b606082611a1357611a0e82611aa3565b61193f565b8151158015611a2a57506001600160a01b0384163b155b15611a5357604051639996b31560e01b81526001600160a01b0385166004820152602401610d31565b5092915050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015611a9957508115611a8b5780600114611a99565b5f866001600160a01b03163b115b9695505050505050565b805115611ab35780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b5f6060828403128015611add575f5ffd5b509092915050565b5f60a0828403128015611add575f5ffd5b6001600160a01b0381168114610ade575f5ffd5b5f5f5f60608486031215611b1c575f5ffd5b8335611b2781611af6565b92506020840135611b3781611af6565b929592945050506040919091013590565b5f60208284031215611b58575f5ffd5b813567ffffffffffffffff811115611b6e575f5ffd5b820160e0818503121561193f575f5ffd5b5f5f83601f840112611b8f575f5ffd5b50813567ffffffffffffffff811115611ba6575f5ffd5b6020830191508360208260051b8501011115611bc0575f5ffd5b9250929050565b5f5f60208385031215611bd8575f5ffd5b823567ffffffffffffffff811115611bee575f5ffd5b611bfa85828601611b7f565b90969095509350505050565b5f5b83811015611c20578181015183820152602001611c08565b50505f910152565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611c9a57603f1987860301845281518051808752611c77816020890160208501611c06565b601f01601f19169590950160209081019550938401939190910190600101611c4e565b50929695505050505050565b5f60c0828403128015611add575f5ffd5b5f60208284031215611cc7575f5ffd5b813561193f81611af6565b5f5f60408385031215611ce3575f5ffd5b8235611cee81611af6565b946020939093013593505050565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215611d20575f5ffd5b5051919050565b5f60208284031215611d37575f5ffd5b813560ff8116811461193f575f5ffd5b6001600160a01b03841681526020810183905260a08101611d826040830184805160ff16825260208082015190830152604090810151910152565b949350505050565b5f60208284031215611d9a575f5ffd5b8135801515811461193f575f5ffd5b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e19843603018112611dd2575f5ffd5b83018035915067ffffffffffffffff821115611dec575f5ffd5b6020019150600581901b3603821315611bc0575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b5f5f8335601e19843603018112611e2c575f5ffd5b83018035915067ffffffffffffffff821115611e46575f5ffd5b602001915036819003821315611bc0575f5ffd5b828482375f8382015f81528351611e75818360208801611c06565b0195945050505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715611ea857611ea8611e03565b604052919050565b5f6040828403128015611ec1575f5ffd5b506040805190810167ffffffffffffffff81118282101715611ee557611ee5611e03565b604052825181526020928301519281019290925250919050565b5f60208284031215611f0f575f5ffd5b815161193f81611af6565b5f8251611f2b818460208701611c06565b9190910192915050565b6001600160a01b03881681526101006020820181905281018690525f876101208301825b89811015611f89578235611f6c81611af6565b6001600160a01b0316825260209283019290910190600101611f59565b506001600160a01b038881166040860152871660608501529150611faa9050565b60808201849052825160ff1660a0830152602083015160c0830152604083015160e083015298975050505050505050565b5f60208284031215611feb575f5ffd5b815167ffffffffffffffff811115612001575f5ffd5b8201601f81018413612011575f5ffd5b805167ffffffffffffffff81111561202b5761202b611e03565b8060051b61203b60208201611e7f565b91825260208184018101929081019087841115612056575f5ffd5b6020850194505b8385101561207c5784518083526020958601959093509091019061205d565b97965050505050505056fea2646970667358221220951935fff056cb3bf5fd29b1e3d2c1eeb06ca267beffaf13a015964028a263d864736f6c634300081b0033
Verified Source Code Full Match
Compiler: v0.8.27+commit.40a35a09
EVM: shanghai
Optimization: Yes (200 runs)
IRewardsController.sol 351 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {IRewardsDistributor} from './IRewardsDistributor.sol';
interface IRewardsController is IRewardsDistributor {
/**
* @notice Event is emitted when an asset is initialized.
* @param asset Address of the new `asset` added
*/
event AssetInitialized(address indexed asset);
/**
* @notice Event is emitted when a `targetLiquidity` of the `asset` is changed.
* @param asset Address of the `asset`
* @param newTargetLiquidity New amount of `targetLiquidity` set for the `asset`
*/
event TargetLiquidityUpdated(address indexed asset, uint256 newTargetLiquidity);
/**
* @notice Event is emitted when a `lastUpdatedTimestamp` of the `asset` is updated.
* @param asset Address of the `asset`
* @param newTimestamp New value of `lastUpdatedTimestamp` updated for the `asset`
*/
event LastTimestampUpdated(address indexed asset, uint256 newTimestamp);
/**
* @notice Event is emitted when a reward is initialized for concrete `asset`.
* @param asset Address of the `asset`
* @param reward Address of the `reward`
*/
event RewardInitialized(address indexed asset, address indexed reward);
/**
* @notice Event is emitted when a reward config is updated.
* @param asset Address of the `asset`
* @param reward Address of the `reward`
* @param maxEmissionPerSecond Amount of maximum possible rewards emission per second
* @param distributionEnd Timestamp after which distribution ends
* @param rewardPayer Address from where rewards will be transferred
*/
event RewardConfigUpdated(
address indexed asset,
address indexed reward,
uint256 maxEmissionPerSecond,
uint256 distributionEnd,
address rewardPayer
);
/**
* @notice Event is emitted when a `reward` index is updated.
* @param asset Address of the `asset`
* @param reward Address of the `reward`
* @param newIndex New `reward` index updated for certain `asset`
*/
event RewardIndexUpdated(address indexed asset, address indexed reward, uint256 newIndex);
/**
* @notice Event is emitted when a user interacts with the asset (transfer, mint, burn) or manually updates the rewards data or claims them
* @param asset Address of the `asset`
* @param reward Address of the `reward`, which `user` data is updated
* @param user Address of the `user` whose `reward` data is updated
* @param newIndex Reward index set after update
* @param accruedFromLastUpdate Amount of accrued rewards from last update
*/
event UserDataUpdated(
address indexed asset,
address indexed reward,
address indexed user,
uint256 newIndex,
uint256 accruedFromLastUpdate
);
/**
* @notice Event is emitted when a `user` `reward` is claimed.
* @param asset Address of the `asset`, whose `reward` was claimed
* @param reward Address of the `reward`, which is claimed
* @param user Address of the `user` whose `reward` is claimed
* @param receiver Address of the funds receiver
* @param amount Amount of the received funds
*/
event RewardClaimed(
address indexed asset,
address indexed reward,
address indexed user,
address receiver,
uint256 amount
);
/**
* @dev Attempted to update data on the `asset` before it was initialized.
*/
error AssetNotInitialized(address asset);
/**
* @dev Attempted to change the configuration of the `reward` before it was initialized.
*/
error RewardNotInitialized(address reward);
/**
* @dev Attempted to set `distributionEnd` less than `block.timestamp` during `reward` initialization.
*/
error InvalidDistributionEnd();
/**
* @dev Attempted to initialize more rewards than limit.
*/
error MaxRewardsLengthReached();
// DEFAULT_ADMIN_ROLE
/////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Configures asset: sets `targetLiquidity` and updates `lastUpdatedTimestamp`.
* If the asset has already been initialized, then updates the rewards indexes and `lastUpdatedTimestamp`,
* also changes `targetLiquidity`, otherwise initializes asset and rewards.
* @dev `targetLiquidity` should be greater than 1 whole token.
* `maxEmissionPerSecond` inside `rewardConfig` should be less than 1000 tokens and greater than 2 wei.
* It must also be greater than `targetLiquidity * 1000 / 1e18`. Check EmissionMath.sol for more info.
* if `maxEmissionPerSecond` is zero or `distributionEnd` is less than current `block.timestamp`,
* then disable distribution for this `reward` if it was previously initialized.
* It can't initialize already disabled reward.
* @param asset Address of the `asset` to be configured/initialized
* @param targetLiquidity Amount of liquidity where will be the maximum emission of rewards per second applied
* @param rewardConfigs Optional array of reward configs, can be empty
*/
function configureAssetWithRewards(
address asset,
uint256 targetLiquidity,
RewardSetupConfig[] calldata rewardConfigs
) external;
// REWARDS_ADMIN_ROLE
/////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Configures already initialized rewards for certain `asset`: sets `distributionEnd` and `maxEmissionPerSecond`.
* If any reward hasn't initialized before then it reverts.
* Before setting new configuration updates all rewards indexes for `asset`.
* @dev `maxEmissionPerSecond` inside `rewardConfig` should be less than 1000 tokens and greater than 2 wei.
* It must also be greater than `targetLiquidity * 1000 / 1e18`. Check EmissionMath.sol for more info.
* If `maxEmissionPerSecond` is zero or `distributionEnd` is less than the current `block.timestamp`,
* then distribution for this `reward` will be disabled.
* @param asset Address of the `asset` whose reward should be configured
* @param rewardConfigs Array of structs with params to set
*/
function configureRewards(address asset, RewardSetupConfig[] calldata rewardConfigs) external;
/////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Special hook, which is called every time `StakeToken` makes `_update` or `slash`.
* Makes an update and calculates new `index` and `accrued`. Also updates `lastUpdateTimestamp`.
* @dev All variables are passed here before the actual update.
* @param totalSupply Total supply of `StakeToken`
* @param totalAssets Total assets of `StakeToken`
* @param user User, whose `index` and rewards accrued will be updated, if address is zero then skips user update
* @param userBalance Amount of `StakeToken` shares owned by user
*/
function handleAction(
uint256 totalSupply,
uint256 totalAssets,
address user,
uint256 userBalance
) external;
/**
* @notice Updates all `reward` indexes and `lastUpdateTimestamp` for the `asset`.
* @param asset Address of the `asset` whose rewards will be updated
*/
function updateAsset(address asset) external;
/**
* @notice Returns an array of all initialized assets (all `StakeTokens`, which are initialized here).
* @dev Return zero data if assets aren't set.
* @return assets Array of asset addresses
*/
function getAllAssets() external view returns (address[] memory assets);
/**
* @notice Returns an array of all initialized rewards for a certain `asset`.
* @dev Return zero data if asset or rewards aren't set.
* @param asset Address of the `asset` whose rewards should be returned
* @return rewards Array of reward addresses
*/
function getAllRewards(address asset) external view returns (address[] memory rewards);
/**
* @notice Returns all data about the asset and its rewards.
* @dev Return zero data if asset or rewards aren't set.
* Function made without some gas optimizations, so it's recommended to avoid calling it often from non-view method or inside batch.
* If the emission for a specific reward has ended at the time of the call (i.e., block.timestamp >= distributionEnd),
* the function will return a zero emission, even though there may still be remaining rewards.
* Note that the actual reward data will be updated the next time someone manually refreshes the data or interacts with the `StakeToken`.
* @param asset Address of the `asset` whose params should be returned
* @return assetData `targetLiquidity` and `lastUpdatedTimestamp` inside struct
* @return rewardsData All data about rewards including addresses and `RewardData`
*/
function getAssetAndRewardsData(
address asset
)
external
view
returns (AssetDataExternal memory assetData, RewardDataExternal[] memory rewardsData);
/**
* @notice Returns data about the asset.
* @dev Return zero data if asset isn't set.
* @param asset Address of the `asset` whose params should be returned
* @return assetData `targetLiquidity` and `lastUpdatedTimestamp` inside struct
*/
function getAssetData(address asset) external view returns (AssetDataExternal memory assetData);
/**
* @notice Returns data about the reward.
* @dev Return zero data if asset or rewards aren't set.
* If the emission has ended at the time of the call (i.e., block.timestamp >= distributionEnd), the function will return a zero emission,
* even though there may still be remaining rewards.
* Note that the actual reward data will be updated the next time someone manually refreshes the data or interacts with the `StakeToken`.
* @param asset Address of the `asset` whose `reward` params should be returned
* @param reward Address of the `reward` whose params should be returned
* @return rewardData `index`, `maxEmissionPerSecond` and `distributionEnd` and address inside struct, address is duplicated from external one
*/
function getRewardData(
address asset,
address reward
) external view returns (RewardDataExternal memory rewardData);
/**
* @notice Returns data about the reward emission.
* @dev Return zero data if asset or rewards aren't set.
* If `maxEmissionPerSecond` is equal to 1 wei, then `flatEmission` will be 0, although in fact it is not 0 and emission is taken into account correctly inside the code.
* Here this calculation is made specifically to simplify the function behaviour.
* If the emission has ended at the time of the call (i.e., block.timestamp >= distributionEnd), the function will return a zero max and flat emissions,
* even though there may still be remaining rewards.
* Note that the actual reward data will be updated the next time someone manually refreshes the data or interacts with the `StakeToken`.
* @param asset Address of the `asset` whose `reward` emission params should be returned
* @param reward Address of the `reward` whose emission params should be returned
* @return emissionData `targetLiquidity`, `targetLiquidityExcess`, `maxEmission` and `flatEmission` inside struct
*/
function getEmissionData(
address asset,
address reward
) external view returns (EmissionData memory emissionData);
/**
* @notice Returns `user` `index` and `accrued` for all rewards for certain `asset` at the time of the last user update.
* If you want to get current `accrued` of all rewards, see `calculateCurrentUserRewards`.
* @dev Return zero data if asset or rewards aren't set.
* @param asset Address of the `asset` for which the rewards are accumulated
* @param user Address of `user` accumulating rewards
* @return rewards Array of `reward` addresses
* @return userData `index` and `accrued` inside structs
*/
function getUserDataByAsset(
address asset,
address user
) external view returns (address[] memory rewards, UserDataExternal[] memory userData);
/**
* @notice Returns `user` `index` and `accrued` for certain `asset` and `reward` at the time of the last user update.
* If you want to calculate current `accrued` of the `reward`, see `calculateCurrentUserReward`.
* @dev Return zero data if asset or rewards aren't set.
* @param asset Address of the `asset` for which the `reward` is accumulated
* @param reward Address of the accumulating `reward`
* @param user Address of `user` accumulating rewards
* @return data `index` and `accrued` inside struct
*/
function getUserDataByReward(
address asset,
address reward,
address user
) external view returns (UserDataExternal memory data);
/**
* @notice Returns current `reward` indexes for `asset`.
* @dev Return zero if asset or rewards aren't set.
* Function made without some gas optimizations, so it's recommended to avoid calling it often from non-view method or inside batch.
* @param asset Address of the `asset` whose indexes of rewards should be calculated
* @return rewards Array of `reward` addresses
* @return indexes Current indexes
*/
function calculateRewardIndexes(
address asset
) external view returns (address[] memory rewards, uint256[] memory indexes);
/**
* @notice Returns current `index` for certain `asset` and `reward`.
* @dev Return zero if asset or rewards aren't set.
* @param asset Address of the `asset` whose `index` of `reward` should be calculated
* @param reward Address of the accumulating `reward`
* @return index Current `index`
*/
function calculateRewardIndex(
address asset,
address reward
) external view returns (uint256 index);
/**
* @notice Returns `emissionPerSecondScaled` for certain `asset` and `reward`. Returned value scaled to 18 decimals.
* @dev Return zero if asset or rewards aren't set.
* @param asset Address of the `asset` which current emission of `reward` should be returned
* @param reward Address of the `reward` which `emissionPerSecond` should be returned
* @return emissionPerSecondScaled Current amount of rewards distributed every second (scaled to 18 decimals)
*/
function calculateCurrentEmissionScaled(
address asset,
address reward
) external view returns (uint256 emissionPerSecondScaled);
/**
* @notice Returns `emissionPerSecond` for certain `asset` and `reward`.
* @dev Return zero if asset or rewards aren't set.
* An integer quantity is returned, although the accuracy of the calculations in reality is higher.
* @param asset Address of the `asset` which current emission of `reward` should be returned
* @param reward Address of the `reward` which `emissionPerSecond` should be returned
* @return emissionPerSecond Current amount of rewards distributed every second
*/
function calculateCurrentEmission(
address asset,
address reward
) external view returns (uint256 emissionPerSecond);
/**
* @notice Calculates and returns `user` `accrued` amounts for all rewards for certain `asset`.
* @dev Return zero data if asset or rewards aren't set.
* Function made without some gas optimizations, so it's recommended to avoid calling it often from non-view method or inside batch.
* @param asset Address of the `asset` whose rewards are accumulated
* @param user Address of `user` accumulating rewards
* @return rewards Array of `reward` addresses
* @return rewardsAccrued Array of current calculated `accrued` amounts
*/
function calculateCurrentUserRewards(
address asset,
address user
) external view returns (address[] memory rewards, uint256[] memory rewardsAccrued);
/**
* @notice Calculates and returns `user` `accrued` amount for certain `reward` and `asset`.
* @dev Return zero if asset or rewards aren't set.
* @param asset Address of the `asset` whose reward is accumulated
* @param reward Address of the `reward` that accumulates for the user
* @param user Address of `user` accumulating rewards
* @return rewardAccrued Amount of current calculated `accrued` amount
*/
function calculateCurrentUserReward(
address asset,
address reward,
address user
) external view returns (uint256 rewardAccrued);
}
UmbrellaBatchHelper.sol 364 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/IERC20.sol';
import {IERC20Permit} from 'openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol';
import {Ownable} from 'openzeppelin-contracts/contracts/access/Ownable.sol';
import {SafeERC20} from 'openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol';
import {Pausable} from 'openzeppelin-contracts/contracts/utils/Pausable.sol';
import {Multicall} from 'openzeppelin-contracts/contracts/utils/Multicall.sol';
import {IRescuableBase, RescuableBase} from 'solidity-utils/contracts/utils/RescuableBase.sol';
import {Rescuable} from 'solidity-utils/contracts/utils/Rescuable.sol';
import {IUmbrellaBatchHelper} from './interfaces/IUmbrellaBatchHelper.sol';
import {IUniversalToken} from './interfaces/IUniversalToken.sol';
import {IStataTokenV2} from 'aave-v3-origin/contracts/extensions/stata-token/interfaces/IStataTokenV2.sol';
import {IERC4626StataToken} from 'aave-v3-origin/contracts/extensions/stata-token/interfaces/IERC4626StataToken.sol';
import {IStakeToken} from '../stakeToken/interfaces/IStakeToken.sol';
import {IERC4626StakeToken} from '../stakeToken/interfaces/IERC4626StakeToken.sol';
import {IRewardsController} from '../rewards/interfaces/IRewardsController.sol';
import {IRewardsStructs} from '../rewards/interfaces/IRewardsStructs.sol';
/**
* @title UmbrellaBatchHelper
* @notice UmbrellaBatchHelper is a utility contract designed to consolidate multiple transactions into a single one.
* It simplifies deposits, withdrawals, restaking, and cooldown activation,
* making these actions more convenient for holders of multiple `StakeToken`s.
* @author BGD labs
*/
contract UmbrellaBatchHelper is IUmbrellaBatchHelper, Ownable, Pausable, Multicall, Rescuable {
using SafeERC20 for *;
/**
* @notice Defines possible conversion paths for a `StakeToken`.
* @dev Used internally to determine how a token can be converted to/from a `StakeToken`.
* @param None Indicates that the token cannot be directly converted to or from a `StakeToken`.
* @param StataToken Indicates that deposit starts from or withdrawals ends with a `StataToken`.
* @param AToken Indicates that deposit starts from or withdrawals ends with an `AToken`.
* @param Token Indicates that deposit starts from or withdrawals ends with a regular `Token`.
*/
enum Path {
None,
StataToken,
AToken,
Token
}
struct Info {
/// @notice Set to true, when path is initialized for `StakeToken`
bool initialized;
/// @notice Set to true, when underlying token of stake is stata
bool isStata;
/// @notice Address of the underlying token from stake
IUniversalToken stakeTokenUnderlying;
}
struct Config {
/// @notice 1-slot info
Info info;
/// @notice Mapping to get start/end path from `transactionToken` or `reward`
mapping(address => Path) tokenToPath;
}
/// @notice Internal mapping with `StakeToken` path configs
mapping(IStakeToken => Config) internal _configs;
/// @inheritdoc IUmbrellaBatchHelper
IRewardsController public immutable REWARDS_CONTROLLER;
constructor(address rewardsController_, address owner_) Ownable(owner_) {
require(rewardsController_ != address(0), ZeroAddress());
REWARDS_CONTROLLER = IRewardsController(rewardsController_);
}
/// @inheritdoc IUmbrellaBatchHelper
function initializePath(IStakeToken[] calldata stakeTokens) external {
for (uint256 i; i < stakeTokens.length; ++i) {
_checkAndInitializePath(stakeTokens[i]);
}
}
/// @inheritdoc IUmbrellaBatchHelper
function cooldownPermit(CooldownPermit calldata p) external whenNotPaused {
_checkAndInitializePath(p.stakeToken);
// Due to the fact, that `StakeToken` uses `_msgSender()` inside digest, then signature shouldn't be able
// to be reused by external actor, that's why there's no try-catch here
p.stakeToken.cooldownWithPermit(
_msgSender(),
p.deadline,
IERC4626StakeToken.SignatureParams(p.v, p.r, p.s)
);
}
/// @inheritdoc IUmbrellaBatchHelper
function claimRewardsPermit(ClaimPermit calldata p) external whenNotPaused {
_checkAndInitializePath(p.stakeToken);
uint256[] memory amounts = _claimRewardsPermit(p);
// If restake is set to true, then rewards are transferred to this contract, otherwise to `_msgSender()`
if (!p.restake) {
return;
}
Config storage config = _configs[p.stakeToken];
// `amounts` length is always the same as `p.rewards` length
for (uint256 i; i < amounts.length; ++i) {
if (amounts[i] == 0) {
continue;
}
Path startPath = config.tokenToPath[p.rewards[i]];
// If `reward` is `aToken` or another token with dynamic balance, then transfer could lead to some wei loss
uint256 actualAmountReceived = IERC20(p.rewards[i]).balanceOf(address(this));
if (actualAmountReceived == 0) {
continue;
}
if (actualAmountReceived < amounts[i]) {
amounts[i] = actualAmountReceived;
}
if (startPath == Path.None) {
// Can't restake this token, so just transfer to `_msgSender()`
IERC20(p.rewards[i]).safeTransfer(_msgSender(), amounts[i]);
} else {
// Restake token
_depositToStake(p.stakeToken, p.rewards[i], amounts[i], config.info, startPath);
}
}
}
/// @inheritdoc IUmbrellaBatchHelper
function permit(Permit calldata p) external whenNotPaused {
// To prevent a griefing attack where a malicious actor duplicates the `permit` call (with the same signature and params)
// directly to the token we wrap it into a `try-catch` block
try
IERC20Permit(p.token).permit(_msgSender(), address(this), p.value, p.deadline, p.v, p.r, p.s)
{} catch {}
}
/// @inheritdoc IUmbrellaBatchHelper
function deposit(IOData calldata io) external whenNotPaused {
require(io.value != 0, ZeroAmount());
_checkAndInitializePath(io.stakeToken);
Config storage config = _configs[io.stakeToken];
Path path = config.tokenToPath[io.edgeToken];
require(path != Path.None, InvalidEdgeToken());
uint256 value = io.value;
if (path == Path.AToken) {
bool wholeBalanceTransferred;
// If we are using `aToken`s, then we can't guarantee that whole balance will be sent to the helper, cause of it's dynamic growth
// So, setting `io.value` more than actual balance will transfer all balance available
uint256 balanceInCurrentBlock = IERC20(io.edgeToken).balanceOf(_msgSender());
require(balanceInCurrentBlock != 0, ZeroAmount());
if (value > balanceInCurrentBlock) {
wholeBalanceTransferred = true;
value = balanceInCurrentBlock;
}
IERC20(io.edgeToken).safeTransferFrom(_msgSender(), address(this), value);
// `aToken` transfer could lead to some wei being lost if not whole balance has been transferred
if (!wholeBalanceTransferred) {
uint256 actualAmountReceived = IERC20(io.edgeToken).balanceOf(address(this));
if (value > actualAmountReceived) {
value = actualAmountReceived;
}
}
} else {
// Transfer `StataToken` and `Token` without dynamic balance growth
IERC20(io.edgeToken).safeTransferFrom(_msgSender(), address(this), value);
}
_depositToStake(io.stakeToken, io.edgeToken, value, config.info, path);
}
/// @inheritdoc IUmbrellaBatchHelper
function redeem(IOData calldata io) external whenNotPaused {
require(io.value != 0, ZeroAmount());
_checkAndInitializePath(io.stakeToken);
Config storage config = _configs[io.stakeToken];
Path path = config.tokenToPath[io.edgeToken];
require(path != Path.None, InvalidEdgeToken());
_redeemFromStake(io.stakeToken, io.value, config.info, path);
}
/// @inheritdoc IUmbrellaBatchHelper
function pause() external onlyOwner {
_pause();
}
/// @inheritdoc IUmbrellaBatchHelper
function unpause() external onlyOwner {
_unpause();
}
function whoCanRescue() public view override returns (address) {
return owner();
}
function maxRescue(
address
) public pure override(IRescuableBase, RescuableBase) returns (uint256) {
return type(uint256).max;
}
/**
* @notice Claims rewards on behalf of `_msgSender`.
* @dev Rewards could be transferred to this balance (if `restake` flag is `true`) or to the `_msgSender`
* @param p Struct with all necessary data
*/
function _claimRewardsPermit(ClaimPermit calldata p) internal returns (uint256[] memory) {
// Due to the fact, that `RewardsController` uses `msg.sender` inside digest, then signature shouldn't
// be able to be reused by external actor, that's why there's no try-catch here
return
REWARDS_CONTROLLER.claimSelectedRewardsPermit(
address(p.stakeToken),
p.rewards,
_msgSender(),
p.restake ? address(this) : _msgSender(),
p.deadline,
IRewardsStructs.SignatureParams(p.v, p.r, p.s)
);
}
/**
* @notice Deposits `edgeToken` using smart route to `StakeToken`
* @param edgeToken Address of already transferred token
* @param value Amount of `edgeToken` transferred
* @param info Struct with common information about `StakeToken`
* @param startPath Path to start from, can have any value (`StataToken/AToken/Token`) except `None`
*/
function _depositToStake(
IStakeToken stakeToken,
address edgeToken,
uint256 value,
Info memory info,
Path startPath
) internal {
// deposit to stata if needed
if (_needToUseStata(startPath, info.isStata)) {
IERC20(edgeToken).forceApprove(address(info.stakeTokenUnderlying), value);
// rewrite the amount of tokens to be deposited to stake
if (startPath == Path.Token) {
value = info.stakeTokenUnderlying.deposit(value, address(this));
} else {
// only aToken remains here
value = info.stakeTokenUnderlying.depositATokens(value, address(this));
}
}
// deposit underlying asset (stata or common token) to stake
info.stakeTokenUnderlying.forceApprove(address(stakeToken), value);
stakeToken.deposit(value, _msgSender());
}
/**
* @notice Redeems `edgeToken` using smart route from `StakeToken`
* @param value Amount of `StakeToken` to be redeemed
* @param info Struct with common information about `StakeToken`
* @param endPath Token that ends the path, can have any value (`StataToken/AToken/Token`) except `None`
*/
function _redeemFromStake(
IStakeToken stakeToken,
uint256 value,
Info memory info,
Path endPath
) internal {
if (_needToUseStata(endPath, info.isStata)) {
// redeem stata from stake and rewrite the amount of tokens to be redeemed from stata
value = stakeToken.redeem(value, address(this), _msgSender());
if (endPath == Path.Token) {
// redeem Token from stata
info.stakeTokenUnderlying.redeem(value, _msgSender(), address(this));
} else {
// only `aToken` remains here
info.stakeTokenUnderlying.redeemATokens(value, _msgSender(), address(this));
}
} else {
stakeToken.redeem(value, _msgSender(), _msgSender());
}
}
/**
* @notice Checks that smart route is initialized. Initializes if it's possible and hasn't been made before.
* @dev Reverts if it's not possible.
* @param stakeToken Address of `StakeToken`
*/
function _checkAndInitializePath(IStakeToken stakeToken) internal {
if (!_configs[stakeToken].info.initialized) {
// check that `StakeToken` was initialized inside `RewardsController`
require(
REWARDS_CONTROLLER.getAssetData(address(stakeToken)).targetLiquidity != 0,
NotInitializedStake()
);
Config storage config = _configs[stakeToken];
address underlyingOfStakeToken = stakeToken.asset();
address token;
// check if underlying token is stata or common token (like GHO or LP-token)
(bool success, bytes memory data) = address(underlyingOfStakeToken).staticcall(
abi.encodeWithSelector(IERC4626StataToken.aToken.selector)
);
if (success) {
address aToken = abi.decode(data, (address));
config.tokenToPath[underlyingOfStakeToken] = Path.StataToken;
config.tokenToPath[aToken] = Path.AToken;
// Asset of `StataToken` is `Token` itself, not `aToken`
token = IUniversalToken(underlyingOfStakeToken).asset();
} else {
token = underlyingOfStakeToken;
}
config.tokenToPath[token] = Path.Token;
config.info = Info({
initialized: true,
isStata: underlyingOfStakeToken != token,
stakeTokenUnderlying: IUniversalToken(underlyingOfStakeToken)
});
emit AssetPathInitialized(address(stakeToken));
}
}
/**
* @notice Checks if `deposit/withdrawal` to/from `StataToken` is needed or not.
* @param path Path to start from / end with
* @param isStata Flag, true is underlying of `StakeToken` is `StataToken`, false otherwise
*/
function _needToUseStata(Path path, bool isStata) internal pure returns (bool) {
// If `isStata == false`, then path could be only `Token` -> always return `false`
// If `isStata == true`, then path could be `Token`, `AToken` and `StataToken` -> return `false` if `path` is `StataToken`, `true` otherwise
return path != Path.StataToken && isStata;
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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);
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 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);
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
SafeERC20.sol 199 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
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 silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
Pausable.sol 119 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
Multicall.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Multicall.sol)
pragma solidity ^0.8.20;
import {Address} from "./Address.sol";
import {Context} from "./Context.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
* careful about sending transactions invoking {multicall}. For example, a relay address that filters function
* selectors won't filter calls nested within a {multicall} operation.
*
* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
* {_msgSender} are not propagated to subcalls.
*/
abstract contract Multicall is Context {
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
bytes memory context = msg.sender == _msgSender()
? new bytes(0)
: msg.data[msg.data.length - _contextSuffixLength():];
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
}
return results;
}
}
RescuableBase.sol 30 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from 'openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol';
import {IRescuableBase} from './interfaces/IRescuableBase.sol';
abstract contract RescuableBase is IRescuableBase {
using SafeERC20 for IERC20;
/// @inheritdoc IRescuableBase
function maxRescue(address erc20Token) public view virtual returns (uint256);
function _emergencyTokenTransfer(address erc20Token, address to, uint256 amount) internal {
uint256 max = maxRescue(erc20Token);
amount = max > amount ? amount : max;
IERC20(erc20Token).safeTransfer(to, amount);
emit ERC20Rescued(msg.sender, erc20Token, to, amount);
}
function _emergencyEtherTransfer(address to, uint256 amount) internal {
(bool success, ) = to.call{value: amount}(new bytes(0));
if (!success) {
revert EthTransferFailed();
}
emit NativeTokensRescued(msg.sender, to, amount);
}
}
Rescuable.sol 37 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/IERC20.sol';
import {RescuableBase} from './RescuableBase.sol';
import {IRescuable} from './interfaces/IRescuable.sol';
/**
* @title Rescuable
* @author BGD Labs
* @notice abstract contract with the methods to rescue tokens (ERC20 and native) from a contract
*/
abstract contract Rescuable is RescuableBase, IRescuable {
/// @notice modifier that checks that caller is allowed address
modifier onlyRescueGuardian() {
if (msg.sender != whoCanRescue()) {
revert OnlyRescueGuardian();
}
_;
}
/// @inheritdoc IRescuable
function emergencyTokenTransfer(
address erc20Token,
address to,
uint256 amount
) external virtual onlyRescueGuardian {
_emergencyTokenTransfer(erc20Token, to, amount);
}
/// @inheritdoc IRescuable
function emergencyEtherTransfer(address to, uint256 amount) external virtual onlyRescueGuardian {
_emergencyEtherTransfer(to, amount);
}
function whoCanRescue() public view virtual returns (address);
}
IUmbrellaBatchHelper.sol 165 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IRescuable} from 'solidity-utils/contracts/utils/interfaces/IRescuable.sol';
import {IRewardsController} from '../../rewards/interfaces/IRewardsController.sol';
import {IStakeToken} from '../../stakeToken/interfaces/IStakeToken.sol';
interface IUmbrellaBatchHelper is IRescuable {
struct CooldownPermit {
/// @notice Address of the `StakeToken`, which `cooldown` should be activated via signature
IStakeToken stakeToken;
/// @notice Deadline of the signature
uint256 deadline;
/// @notice Signature params
uint8 v;
bytes32 r;
bytes32 s;
}
struct ClaimPermit {
/// @notice Address of the `StakeToken`, whose rewards could be claimed or restaked
IStakeToken stakeToken;
/// @notice Addresses of the rewards
address[] rewards;
/// @notice Deadline of the signature
uint256 deadline;
/// @notice Signature params
uint8 v;
bytes32 r;
bytes32 s;
/// @notice Flag to determine the direction of funds, simply claim or try to make a transfer and restake them
/// @dev If restake flag is set to true, then signature should be signed using `UmbrellaBatchHelper` contract address as a rewards receiver
/// @dev Otherwise, the receiver in the signature must match the `msg.sender`
bool restake;
}
/// @dev Doesn't work with `DAI`, as it's incompatible with the `ERC-2612` standard
struct Permit {
/// @notice Address of the token to call permit
address token;
/// @notice Amount of funds to permit
uint256 value;
/// @notice Deadline of the signature
uint256 deadline;
/// @notice Signature params
uint8 v;
bytes32 r;
bytes32 s;
}
struct IOData {
/// @notice Address of the `StakeToken`
IStakeToken stakeToken;
/// @notice Deposit start token or redemption end token
address edgeToken;
/// @notice Amount of funds to be deposited or amount of funds to be burned during `redeem`
uint256 value;
}
/**
* @notice Event is emitted when the path of `StakeToken` is initialized.
* @param stakeToken Address of the `StakeToken` which path is initialized
*/
event AssetPathInitialized(address indexed stakeToken);
/**
* @dev Attempted to set zero address.
*/
error ZeroAddress();
/**
* @dev Attempted to use an invalid token for deposit/redeem.
*/
error InvalidEdgeToken();
/**
* @dev Attempted to initialize path for `StakeToken`, which wasn't configured inside `RewardsController`.
* (Without initialization inside `RewardsController` `StakeToken` isn't working at all.)
*/
error NotInitializedStake();
/**
* @dev Attempted to `deposit/redeem` zero amount.
*/
error ZeroAmount();
/**
* @notice Helps to initialize paths for several `StakeToken`s.
* @dev Optional, can be skipped, useful to avoid overpaying gas for early adopters of new `StakeToken`s.
* @param stakeTokens Array of `StakeToken`s
*/
function initializePath(IStakeToken[] calldata stakeTokens) external;
/**
* @notice Trigger `cooldown` on specified `StakeToken` via signature.
* @param cooldownPermit_ Struct with necessary data and signature.
*/
function cooldownPermit(CooldownPermit calldata cooldownPermit_) external;
/**
* @notice Claims rewards using a signature.
* @dev Transfers rewards to `_msgSender`, in the token accrued or in `StakeToken`s, depending on the `restake` option.
*
* The user must specify the `StakeToken` and the list of rewards to claim, along with a valid signature for the helper contract.
* - If `restake` is `true`, the rewards receiver (used in the signature) should be this contract.
* - Otherwise, signature will use `_msgSender` as rewards recipient.
*
* Regardless of the `restake` option, `msg.sender` always receives rewards from the `RewardsController` or freshly minted `StakeToken`s (if possible).
*
* @param claimPermit_ Struct containing the required data and signature.
*/
function claimRewardsPermit(ClaimPermit calldata claimPermit_) external;
/**
* @notice Adjusts the user's token allowance for this helper contract via permit signature.
* @dev This function should be used in conjunction with the `deposit/redeem` functions.
* It allows this contract to call `transferFrom` or `redeem` on behalf of `_msgSender` during token `deposit/redeem`.
* @param permit_ Struct containing the required data and signature.
*/
function permit(Permit calldata permit_) external;
/**
* @notice Handles deposits
* @dev The necessary `allowance` must be allocated before the call, for example by using `permit`.
*
* `edgeToken` should indicate the token used to start the deposit process from in order to receive a `StakeToken`.
* The user can start with a `Token`, `aToken` or `StataToken`.
*
* If the specified token's address cannot be used for direct deposit to the `StakeToken`
* (via `StataToken`, if required), the transaction will fail.
*
* @param io Struct containing the required data.
*/
function deposit(IOData calldata io) external;
/**
* @notice Handles redemptions.
* @dev The necessary `allowance` must be allocated before the call, for example by using `permit`.
* When withdrawing funds, the user must specify the desired output token using the `edgeToken`.
*
* If the specified token's address cannot be used for direct redemption from the `StakeToken` (via `StataToken`, if required),
* the transaction will fail.
*
* @param io Struct containing the required data.
*/
function redeem(IOData calldata io) external;
/**
* @notice Pauses the contract, can be called by `owner`.
* Emits a {Paused} event.
*/
function pause() external;
/**
* @notice Unpauses the contract, can be called by `owner`.
* Emits a {Unpaused} event.
*/
function unpause() external;
/**
* @notice Returns the `RewardsController` contract address.
* @return Address wrapped to interface of `RewardsController`
*/
function REWARDS_CONTROLLER() external returns (IRewardsController);
}
IUniversalToken.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IStataTokenV2} from 'aave-v3-origin/contracts/extensions/stata-token/interfaces/IStataTokenV2.sol';
/**
* @title IUniversalToken
* @notice IUniversalToken is renamed interface of IStataTokenV2, because it includes the interface of a regular IERC20 token and IStataTokenV2.
* This is necessary to avoid confusion in names inside `UmbrellaBatchHelper`, since it allows both `StataTokenV2`, `ERC20Permit` and `ERC20` calls (like transfer, approve, etc).
* @author BGD labs
*/
interface IUniversalToken is IStataTokenV2 {
}
IStataTokenV2.sol 22 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC4626} from 'openzeppelin-contracts/contracts/interfaces/IERC4626.sol';
import {IERC20Permit} from 'openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol';
import {IERC4626StataToken} from './IERC4626StataToken.sol';
import {IERC20AaveLM} from './IERC20AaveLM.sol';
interface IStataTokenV2 is IERC4626, IERC20Permit, IERC4626StataToken, IERC20AaveLM {
/**
* @notice Checks if the passed actor is permissioned emergency admin.
* @param actor The reward to claim
* @return bool signaling if actor can pause the vault.
*/
function canPause(address actor) external view returns (bool);
/**
* @notice Pauses/unpauses all system's operations
* @param paused boolean determining if the token should be paused or unpaused
*/
function setPaused(bool paused) external;
}
IERC4626StataToken.sol 83 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IPool, IPoolAddressesProvider} from '../../../interfaces/IPool.sol';
interface IERC4626StataToken {
struct SignatureParams {
uint8 v;
bytes32 r;
bytes32 s;
}
error PoolAddressMismatch(address pool);
error StaticATokenInvalidZeroShares();
error OnlyPauseGuardian(address caller);
/**
* @notice The pool associated with the aToken.
* @return The pool address.
*/
function POOL() external view returns (IPool);
/**
* @notice The poolAddressesProvider associated with the pool.
* @return The poolAddressesProvider address.
*/
function POOL_ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
/**
* @notice Burns `shares` of static aToken, with receiver receiving the corresponding amount of aToken
* @param shares The shares to withdraw, in static balance of StaticAToken
* @param receiver The address that will receive the amount of `ASSET` withdrawn from the Aave protocol
* @return amountToWithdraw: aToken send to `receiver`, dynamic balance
**/
function redeemATokens(
uint256 shares,
address receiver,
address owner
) external returns (uint256);
/**
* @notice Deposits aTokens and mints static aTokens to msg.sender
* @param assets The amount of aTokens to deposit (e.g. deposit of 100 aUSDC)
* @param receiver The address that will receive the static aTokens
* @return uint256 The amount of StaticAToken minted, static balance
**/
function depositATokens(uint256 assets, address receiver) external returns (uint256);
/**
* @notice Universal deposit method for proving aToken or underlying liquidity with permit
* @param assets The amount of aTokens or underlying to deposit
* @param receiver The address that will receive the static aTokens
* @param deadline Must be a timestamp in the future
* @param sig A `secp256k1` signature params from `msgSender()`
* @return uint256 The amount of StaticAToken minted, static balance
**/
function depositWithPermit(
uint256 assets,
address receiver,
uint256 deadline,
SignatureParams memory sig,
bool depositToAave
) external returns (uint256);
/**
* @notice The aToken used inside the 4626 vault.
* @return address The aToken address.
*/
function aToken() external view returns (address);
/**
* @notice Returns the current asset price of the stataToken.
* The price is calculated as `underlying_price * exchangeRate`.
* It is important to note that:
* - `underlying_price` is the price obtained by the aave-oracle and is subject to it's internal pricing mechanisms.
* - as the price is scaled over the exchangeRate, but maintains the same precision as the underlying the price might be underestimated by 1 unit.
* - when pricing multiple `shares` as `shares * price` keep in mind that the error compounds.
* @return price the current asset price.
*/
function latestAnswer() external view returns (int256);
}
IStakeToken.sol 8 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {IERC20Permit} from 'openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol';
import {IERC4626StakeToken} from './IERC4626StakeToken.sol';
interface IStakeToken is IERC4626StakeToken, IERC20Permit {}
IERC4626StakeToken.sol 232 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {IERC4626} from 'openzeppelin-contracts/contracts/interfaces/IERC4626.sol';
interface IERC4626StakeToken is IERC4626 {
struct CooldownSnapshot {
/// @notice Amount of shares available to redeem
uint192 amount;
/// @notice Timestamp after which funds will be unlocked for withdrawal
uint32 endOfCooldown;
/// @notice Period of time to withdraw funds after end of cooldown
uint32 withdrawalWindow;
}
struct SignatureParams {
uint8 v;
bytes32 r;
bytes32 s;
}
/**
* @notice Event is emitted when a cooldown of staker is changed.
* @param user Staker address
* @param amount Amount of shares on the time cooldown is changed
* @param endOfCooldown Future timestamp, from which funds can be withdrawn
* @param unstakeWindow Duration of time to withdraw funds
*/
event StakerCooldownUpdated(
address indexed user,
uint256 amount,
uint256 endOfCooldown,
uint256 unstakeWindow
);
/**
* @notice Event is emitted when a user installs/disables the operator for cooldown.
* @param user User address
* @param operator Address of operator to install/disable
* @param flag Flag responsible for setting/disabling operator
*/
event CooldownOperatorSet(address indexed user, address indexed operator, bool flag);
/**
* @notice Event is emitted when a successful slash occurs
* @param destination Address, where funds transferred to
* @param amount Amount of funds transferred
*/
event Slashed(address indexed destination, uint256 amount);
/**
* @notice Event is emitted when `cooldown` is changed to the new one
* @param oldCooldown Old `cooldown` duration
* @param newCooldown New `cooldown` duration
*/
event CooldownChanged(uint256 oldCooldown, uint256 newCooldown);
/**
* @notice Event is emitted when `unstakeWindow` is changed to the new one
* @param oldUnstakeWindow Old `unstakeWindow` duration
* @param newUnstakeWindow new `unstakeWindow` duration
*/
event UnstakeWindowChanged(uint256 oldUnstakeWindow, uint256 newUnstakeWindow);
/**
* @dev Attempted to set zero address as a variable.
*/
error ZeroAddress();
/**
* @dev Attempted to call cooldown without locked liquidity.
*/
error ZeroBalanceInStaking();
/**
* @dev Attempted to slash for zero amount of assets.
*/
error ZeroAmountSlashing();
/**
* @dev Attempted to slash with insufficient funds in staking.
*/
error ZeroFundsAvailable();
/**
* @dev Attempted to call cooldown without approval for `cooldownOnBehalf`.
* @param owner Address of user, which cooldown wasn't triggered
* @param spender Address of `msg.sender`
*/
error NotApprovedForCooldown(address owner, address spender);
/**
* @notice Deposits by issuing approval for the required number of tokens (if `asset` supports the `permit` function).
* Emits a {Deposit} event.
* @param assets Amount of assets to be deposited
* @param receiver Receiver of shares
* @param deadline Signature deadline for issuing approve
* @param sig Signature parameters
* @return Amount of shares received
*/
function depositWithPermit(
uint256 assets,
address receiver,
uint256 deadline,
SignatureParams calldata sig
) external returns (uint256);
/**
* @notice Triggers user's `cooldown` using signature.
* Emits a {StakerCooldownUpdated} event.
* @param user The address, which `cooldown` will be triggered
* @param deadline Signature deadline for issuing approve
* @param sig Signature parameters
*/
function cooldownWithPermit(
address user,
uint256 deadline,
SignatureParams calldata sig
) external;
/**
* @notice Activates the cooldown period to unstake for `msg.sender`.
* It can't be called if the user is not staking.
* Emits a {StakerCooldownUpdated} event.
*/
function cooldown() external;
/**
* @notice Activates the cooldown period to unstake for a certain user.
* It can't be called if the user is not staking.
* `from` must set as `cooldownOperator` for `msg.sender` so that he can activate the cooldown on his behalf.
* Emits a {StakerCooldownUpdated} event.
* @param from Address at which the `cooldown` will be activated
*/
function cooldownOnBehalfOf(address from) external;
/**
* @notice Sets the ability to call `cooldownOnBehalf` for `msg.sender` by specified `operator` to `true` or `false`.
* Doesn't revert if the new `flag` value is the same as the old one.
* Emits a {CooldownOnBehalfChanged} event.
* @param operator The address that the ability to call `cooldownOnBehalf` for `msg.sender` can be changed
* @param flag True - to activate this ability, false - to deactivate
*/
function setCooldownOperator(address operator, bool flag) external;
/**
* @notice Executes a slashing of the asset of a certain amount, transferring the seized funds
* to destination. Decreasing the amount of underlying will automatically adjust the exchange rate.
* If the amount exceeds maxSlashableAmount then the second one is taken.
* Can only be called by the `owner`.
* Emits a {Slashed} event.
* @param destination Address where seized funds will be transferred
* @param amount Amount to be slashed
* @return amount Amount slashed
*/
function slash(address destination, uint256 amount) external returns (uint256);
/**
* @notice Pauses the contract, can be called by `owner`.
* Emits a {Paused} event.
*/
function pause() external;
/**
* @notice Unpauses the contract, can be called by `owner`.
* Emits a {Unpaused} event.
*/
function unpause() external;
/**
* @notice Sets a new `cooldown` duration.
* Can only be called by the `owner`.
* Emits a {CooldownChanged} event.
* @param cooldown Amount of seconds users have to wait between starting the `cooldown` and being able to withdraw funds
*/
function setCooldown(uint256 cooldown) external;
/**
* @notice Sets a new `unstakeWindow` duration.
* Can only be called by the `owner`.
* Emits a {UnstakeWindowChanged} event.
* @param newUnstakeWindow Amount of seconds users have to withdraw after `cooldown`
*/
function setUnstakeWindow(uint256 newUnstakeWindow) external;
/**
* @notice Returns current `cooldown` duration.
* @return _cooldown duration
*/
function getCooldown() external view returns (uint256);
/**
* @notice Returns current `unstakeWindow` duration.
* @return _unstakeWindow duration
*/
function getUnstakeWindow() external view returns (uint256);
/**
* @notice Returns the last activated user `cooldown`. Contains the amount of tokens and timestamp.
* May return zero values if all funds have been withdrawn or transferred.
* @param user Address of user
* @return User's cooldown snapshot
*/
function getStakerCooldown(address user) external view returns (CooldownSnapshot memory);
/**
* @notice Returns true if the user's cooldown can be triggered by an operator, false - otherwise.
* @param user Address of the user.
* @param operator Address of an operator.
* @return Is operator set for `cooldownOnBehalf`
*/
function isCooldownOperator(address user, address operator) external view returns (bool);
/**
* @notice Returns the next unused nonce for an address, which could be used inside signature for `cooldownWithPermit()` function.
* @param owner Address for which unused `cooldown` nonce will be returned
* @return The next unused `cooldown` nonce
*/
function cooldownNonces(address owner) external view returns (uint256);
/**
* @notice Returns the maximum slashable assets available for now.
* @return Maximum assets available for slash
*/
function getMaxSlashableAssets() external view returns (uint256);
/**
* @notice Returns the minimum amount of assets, which can't be slashed.
* @return Minimum assets value that cannot be slashed
*/
function MIN_ASSETS_REMAINING() external view returns (uint256);
}
IRewardsStructs.sol 62 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
/**
* @title IRewardsStructs interface
* @notice An interface containing structures that can be used externally.
* @author BGD labs
*/
interface IRewardsStructs {
struct RewardSetupConfig {
/// @notice Reward address
address reward;
/// @notice Address, from which this reward will be transferred (should give approval to this address)
address rewardPayer;
/// @notice Maximum possible emission rate of rewards per second
uint256 maxEmissionPerSecond;
/// @notice End of the rewards distribution
uint256 distributionEnd;
}
struct AssetDataExternal {
/// @notice Liquidity value at which there will be maximum emission per second (expected amount of asset to be deposited into `StakeToken`)
uint256 targetLiquidity;
/// @notice Timestamp of the last update
uint256 lastUpdateTimestamp;
}
struct RewardDataExternal {
/// @notice Reward address
address addr;
/// @notice Liquidity index of the reward set during the last update
uint256 index;
/// @notice Maximum possible emission rate of rewards per second
uint256 maxEmissionPerSecond;
/// @notice End of the reward distribution
uint256 distributionEnd;
}
struct EmissionData {
/// @notice Liquidity value at which there will be maximum emission per second applied
uint256 targetLiquidity;
/// @notice Liquidity value after which emission per second will be flat
uint256 targetLiquidityExcess;
/// @notice Maximum possible emission rate of rewards per second (can be with or without scaling to 18 decimals, depending on usage in code)
uint256 maxEmission;
/// @notice Flat emission value per second (can be with or without scaling, depending on usage in code)
uint256 flatEmission;
}
struct UserDataExternal {
/// @notice Liquidity index of the user reward set during the last update
uint256 index;
/// @notice Amount of accrued rewards that the user earned at the time of his last index update (pending to claim)
uint256 accrued;
}
struct SignatureParams {
uint8 v;
bytes32 r;
bytes32 s;
}
}
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;
}
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
Address.sol 150 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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 Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
/**
* @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
* {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value);
}
(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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}.
*/
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
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
IRescuableBase.sol 39 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
/**
* @title IRescuableBase
* @author BGD Labs
* @notice interface containing the objects, events and methods definitions of the RescuableBase contract
*/
interface IRescuableBase {
error EthTransferFailed();
/**
* @notice emitted when erc20 tokens get rescued
* @param caller address that triggers the rescue
* @param token address of the rescued token
* @param to address that will receive the rescued tokens
* @param amount quantity of tokens rescued
*/
event ERC20Rescued(
address indexed caller,
address indexed token,
address indexed to,
uint256 amount
);
/**
* @notice emitted when native tokens get rescued
* @param caller address that triggers the rescue
* @param to address that will receive the rescued tokens
* @param amount quantity of tokens rescued
*/
event NativeTokensRescued(address indexed caller, address indexed to, uint256 amount);
/**
* @notice method that defined the maximum amount rescuable for any given asset.
* @dev there's currently no way to limit the rescuable "native asset", as we assume erc20s as intended underlying.
* @return the maximum amount of
*/
function maxRescue(address erc20Token) external view returns (uint256);
}
IRescuable.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import {IRescuableBase} from './IRescuableBase.sol';
/**
* @title IRescuable
* @author BGD Labs
* @notice interface containing the objects, events and methods definitions of the Rescuable contract
*/
interface IRescuable is IRescuableBase {
error OnlyRescueGuardian();
/**
* @notice method called to rescue tokens sent erroneously to the contract. Only callable by owner
* @param erc20Token address of the token to rescue
* @param to address to send the tokens
* @param amount of tokens to rescue
*/
function emergencyTokenTransfer(address erc20Token, address to, uint256 amount) external;
/**
* @notice method called to rescue ether sent erroneously to the contract. Only callable by owner
* @param to address to send the eth
* @param amount of eth to rescue
*/
function emergencyEtherTransfer(address to, uint256 amount) external;
}
IERC4626.sol 230 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-4626 "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);
}
IERC20AaveLM.sol 107 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IERC20AaveLM {
struct UserRewardsData {
uint128 rewardsIndexOnLastInteraction;
uint128 unclaimedRewards;
}
struct RewardIndexCache {
bool isRegistered;
uint248 lastUpdatedIndex;
}
error ZeroIncentivesControllerIsForbidden();
error InvalidClaimer(address claimer);
error RewardNotInitialized(address reward);
event RewardTokenRegistered(address indexed reward, uint256 startIndex);
/**
* @notice Claims rewards from `INCENTIVES_CONTROLLER` and updates internal accounting of rewards.
* @param reward The reward to claim
* @return uint256 Amount collected
*/
function collectAndUpdateRewards(address reward) external returns (uint256);
/**
* @notice Claim rewards on behalf of a user and send them to a receiver
* @dev Only callable by if sender is onBehalfOf or sender is approved claimer
* @param onBehalfOf The address to claim on behalf of
* @param receiver The address to receive the rewards
* @param rewards The rewards to claim
*/
function claimRewardsOnBehalf(
address onBehalfOf,
address receiver,
address[] memory rewards
) external;
/**
* @notice Claim rewards and send them to a receiver
* @param receiver The address to receive the rewards
* @param rewards The rewards to claim
*/
function claimRewards(address receiver, address[] memory rewards) external;
/**
* @notice Claim rewards
* @param rewards The rewards to claim
*/
function claimRewardsToSelf(address[] memory rewards) external;
/**
* @notice Get the total claimable rewards of the contract.
* @param reward The reward to claim
* @return uint256 The current balance + pending rewards from the `_incentivesController`
*/
function getTotalClaimableRewards(address reward) external view returns (uint256);
/**
* @notice Get the total claimable rewards for a user in asset decimals
* @param user The address of the user
* @param reward The reward to claim
* @return uint256 The claimable amount of rewards in asset decimals
*/
function getClaimableRewards(address user, address reward) external view returns (uint256);
/**
* @notice The unclaimed rewards for a user in asset decimals
* @param user The address of the user
* @param reward The reward to claim
* @return uint256 The unclaimed amount of rewards in asset decimals
*/
function getUnclaimedRewards(address user, address reward) external view returns (uint256);
/**
* @notice The underlying asset reward index in RAY
* @param reward The reward to claim
* @return uint256 The underlying asset reward index in RAY
*/
function getCurrentRewardsIndex(address reward) external view returns (uint256);
/**
* @notice Returns reference a/v token address used on INCENTIVES_CONTROLLER for tracking
* @return address of reference token
*/
function getReferenceAsset() external view returns (address);
/**
* @notice The IERC20s that are currently rewarded to addresses of the vault via LM on incentivescontroller.
* @return IERC20 The IERC20s of the rewards.
*/
function rewardTokens() external view returns (address[] memory);
/**
* @notice Fetches all rewardTokens from the incentivecontroller and registers the missing ones.
*/
function refreshRewardTokens() external;
/**
* @notice Checks if the passed token is a registered reward.
* @param reward The reward to claim
* @return bool signaling if token is a registered reward.
*/
function isRegisteredRewardToken(address reward) external view returns (bool);
}
IPool.sol 871 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
import {DataTypes} from '../protocol/libraries/types/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);
}
IRewardsDistributor.sol 225 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {IRewardsStructs} from './IRewardsStructs.sol';
interface IRewardsDistributor is IRewardsStructs {
/**
* @notice Event is emitted when a `user` or admin installs/disables `claimer` for claiming user rewards.
* @param user Address of the `user`
* @param claimer Address of the `claimer` to install/disable
* @param caller Address of the `msg.sender` who changes claimer
* @param flag Flag responsible for setting/disabling `claimer`
*/
event ClaimerSet(
address indexed user,
address indexed claimer,
address indexed caller,
bool flag
);
/**
* @dev Attempted to use signature with expired deadline.
*/
error ExpiredSignature(uint256 deadline);
/**
* @dev Mismatched signature.
*/
error InvalidSigner(address signer, address owner);
/**
* @dev Attempted to claim `reward` without authorization.
*/
error ClaimerNotAuthorized(address claimer, address user);
/**
* @dev Attempted to claim rewards for assets while arrays lengths don't match.
*/
error LengthsDontMatch();
/**
* @dev Attempted to set zero address.
*/
error ZeroAddress();
// DEFAULT_ADMIN_ROLE
/////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Installs/disables `claimer` for claiming `user` rewards.
* @param user Address of the `user`
* @param claimer Address of the `claimer` to install/disable
* @param flag Flag responsible for setting/disabling `claimer`
*/
function setClaimer(address user, address claimer, bool flag) external;
/////////////////////////////////////////////////////////////////////////////////////////
/**
* @notice Installs/disables `claimer` for claiming `msg.sender` rewards.
* @param claimer Address of the `claimer` to install/disable
* @param flag Flag responsible for setting/disabling `claimer`
*/
function setClaimer(address claimer, bool flag) external;
/**
* @notice Claims all existing `rewards` for a certain `asset` on behalf of `msg.sender`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @dev Always claims all `rewards`.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return rewards Array containing the addresses of all `reward` tokens claimed
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimAllRewards(
address asset,
address receiver
) external returns (address[] memory rewards, uint256[] memory amounts);
/**
* @notice Claims all existing `rewards` on behalf of `user` for a certain `asset` by `msg.sender`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @dev Always claims all `rewards`.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return rewards Array containing the addresses of all `reward` tokens claimed
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimAllRewardsOnBehalf(
address asset,
address user,
address receiver
) external returns (address[] memory rewards, uint256[] memory amounts);
/**
* @notice Claims all existing `rewards` on behalf of `user` for a certain `asset` using signature.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @dev Always claims all `rewards`.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @param deadline Signature deadline for claiming
* @param sig Signature parameters
* @return rewards Array containing the addresses of all `reward` tokens claimed
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimAllRewardsPermit(
address asset,
address user,
address receiver,
uint256 deadline,
SignatureParams calldata sig
) external returns (address[] memory rewards, uint256[] memory amounts);
/**
* @notice Claims selected `rewards` of `msg.sender` for a certain `asset`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param rewards Array of `reward` addresses, which should be claimed
* @param receiver Address of the funds receiver
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimSelectedRewards(
address asset,
address[] calldata rewards,
address receiver
) external returns (uint256[] memory amounts);
/**
* @notice Claims selected `rewards` on behalf of `user` for a certain `asset` by `msg.sender`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param rewards Array of `reward` addresses, which should be claimed
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimSelectedRewardsOnBehalf(
address asset,
address[] calldata rewards,
address user,
address receiver
) external returns (uint256[] memory amounts);
/**
* @notice Claims selected `rewards` on behalf of `user` for a certain `asset` using signature.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @param asset Address of the `asset` whose `rewards` should be claimed
* @param rewards Array of `reward` addresses, which should be claimed
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @param deadline Signature deadline for claiming
* @param sig Signature parameters
* @return amounts Array containing the corresponding `amounts` of each `reward` claimed
*/
function claimSelectedRewardsPermit(
address asset,
address[] calldata rewards,
address user,
address receiver,
uint256 deadline,
SignatureParams calldata sig
) external returns (uint256[] memory amounts);
/**
* @notice Claims all existing `rewards` of `msg.sender` across multiple `assets`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @dev Always claims all `rewards`.
* @param assets Array of addresses representing the `assets`, whose `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return rewards Two-dimensional array where each inner array contains the addresses of `reward` tokens for a specific `asset`
* @return amounts Two-dimensional array where each inner array contains the amounts of each `reward` claimed for a specific `asset`
*/
function claimAllRewards(
address[] calldata assets,
address receiver
) external returns (address[][] memory rewards, uint256[][] memory amounts);
/**
* @notice Claims all existing `rewards` on behalf of `user` across multiple `assets` by `msg.sender`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @dev Always claims all `rewards`.
* @param assets Array of addresses representing the `assets`, whose `rewards` should be claimed
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return rewards Two-dimensional array where each inner array contains the addresses of `reward` tokens for a specific `asset`
* @return amounts Two-dimensional array where each inner array contains the amounts of each `reward` claimed for a specific `asset`
*/
function claimAllRewardsOnBehalf(
address[] calldata assets,
address user,
address receiver
) external returns (address[][] memory rewards, uint256[][] memory amounts);
/**
* @notice Claims selected `rewards` of `msg.sender` across multiple `assets`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @param assets Array of addresses representing the `assets`, whose `rewards` should be claimed
* @param rewards Two-dimensional array where each inner array contains the addresses of `rewards` for a specific `asset`
* @param receiver Address of the funds receiver
* @return amounts Two-dimensional array where each inner array contains the amounts of each `reward` claimed for a specific `asset`
*/
function claimSelectedRewards(
address[] calldata assets,
address[][] calldata rewards,
address receiver
) external returns (uint256[][] memory);
/**
* @notice Claims selected `rewards` on behalf of `user` across multiple `assets` by `msg.sender`.
* Makes an update and calculates new `index` and `accrued` `rewards` before claim.
* @param assets Array of addresses representing the `assets`, whose `rewards` should be claimed
* @param rewards Two-dimensional array where each inner array contains the addresses of `rewards` for a specific `asset`
* @param user Address of user, which accrued `rewards` should be claimed
* @param receiver Address of the funds receiver
* @return amounts Two-dimensional array where each inner array contains the amounts of each `reward` claimed for a specific `asset`
*/
function claimSelectedRewardsOnBehalf(
address[] calldata assets,
address[][] calldata rewards,
address user,
address receiver
) external returns (uint256[][] memory);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
Errors.sol 34 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-20 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);
}
IPoolAddressesProvider.sol 227 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @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;
}
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;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Read Contract
REWARDS_CONTROLLER 0xcd086d45 → address
maxRescue 0xd7408715 → uint256
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
whoCanRescue 0xa4757b0f → address
Write Contract 13 functions
These functions modify contract state and require a wallet transaction to execute.
claimRewardsPermit 0x78d270f0
tuple p
cooldownPermit 0xa475babd
tuple p
deposit 0xe4ca5f40
tuple io
emergencyEtherTransfer 0xeed88b8d
address to
uint256 amount
emergencyTokenTransfer 0xa3d5b255
address erc20Token
address to
uint256 amount
initializePath 0xad89eb1e
address[] stakeTokens
multicall 0xac9650d8
bytes[] data
returns: bytes[]
pause 0x8456cb59
No parameters
permit 0xd96c37e4
tuple p
redeem 0xbe3da06b
tuple io
renounceOwnership 0x715018a6
No parameters
transferOwnership 0xf2fde38b
address newOwner
unpause 0x3f4ba83a
No parameters
Token Balances (2)
View Transfers →Recent Transactions
No transactions found for this address