Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xCe6Ced23118EDEb23054E06118a702797b13fc2F
Balance 0 ETH
Nonce 1
Code Size 8381 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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

Recent Transactions

No transactions found for this address