Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/MainnetController.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IAToken } from "aave-v3-origin/src/core/contracts/interfaces/IAToken.sol";
import { IPool as IAavePool } from "aave-v3-origin/src/core/contracts/interfaces/IPool.sol";
// This interface has been reviewed, and is compliant with the specs: https://eips.ethereum.org/EIPS/eip-7540
import { IERC7540 } from "forge-std/interfaces/IERC7540.sol";
import { AccessControl } from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { IERC4626 } from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import { Ethereum } from "spark-address-registry/Ethereum.sol";
import { IALMProxy } from "./interfaces/IALMProxy.sol";
import { ICCTPLike } from "./interfaces/CCTPInterfaces.sol";
import { IRateLimits } from "./interfaces/IRateLimits.sol";
import "./interfaces/ILayerZero.sol";
import { CCTPLib } from "./libraries/CCTPLib.sol";
import { CurveLib } from "./libraries/CurveLib.sol";
import { IDaiUsdsLike, IPSMLike, PSMLib } from "./libraries/PSMLib.sol";
import { OptionsBuilder } from "layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";
import { RateLimitHelpers } from "./RateLimitHelpers.sol";
interface IATokenWithPool is IAToken {
function POOL() external view returns(address);
}
interface IEthenaMinterLike {
function setDelegatedSigner(address delegateSigner) external;
function removeDelegatedSigner(address delegateSigner) external;
}
interface ICentrifugeToken is IERC7540 {
function cancelDepositRequest(uint256 requestId, address controller) external;
function cancelRedeemRequest(uint256 requestId, address controller) external;
function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)
external returns (uint256 assets);
function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)
external returns (uint256 shares);
}
interface IMapleTokenLike is IERC4626 {
function requestRedeem(uint256 shares, address receiver) external;
function removeShares(uint256 shares, address receiver) external;
}
interface IFarmLike {
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
}
interface ISUSDELike is IERC4626 {
function cooldownAssets(uint256 usdeAmount) external;
function cooldownShares(uint256 susdeAmount) external;
function unstake(address receiver) external;
}
interface IUSTBLike is IERC20 {
function subscribe(uint256 inAmount, address stablecoin) external;
}
interface IVaultLike {
function buffer() external view returns (address);
function draw(uint256 usdsAmount) external;
function wipe(uint256 usdsAmount) external;
}
interface ISparkVaultLike {
function take(uint256 assetAmount) external;
}
contract MainnetController is AccessControl {
using OptionsBuilder for bytes;
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
event LayerZeroRecipientSet(uint32 indexed destinationEndpointId, bytes32 layerZeroRecipient);
event MaxSlippageSet(address indexed pool, uint256 maxSlippage);
event MintRecipientSet(uint32 indexed destinationDomain, bytes32 mintRecipient);
event RelayerRemoved(address indexed relayer);
/**********************************************************************************************/
/*** State variables ***/
/**********************************************************************************************/
bytes32 public FREEZER = keccak256("FREEZER");
bytes32 public RELAYER = keccak256("RELAYER");
bytes32 public LIMIT_4626_DEPOSIT = keccak256("LIMIT_4626_DEPOSIT");
bytes32 public LIMIT_4626_WITHDRAW = keccak256("LIMIT_4626_WITHDRAW");
bytes32 public LIMIT_7540_DEPOSIT = keccak256("LIMIT_7540_DEPOSIT");
bytes32 public LIMIT_7540_REDEEM = keccak256("LIMIT_7540_REDEEM");
bytes32 public LIMIT_AAVE_DEPOSIT = keccak256("LIMIT_AAVE_DEPOSIT");
bytes32 public LIMIT_AAVE_WITHDRAW = keccak256("LIMIT_AAVE_WITHDRAW");
bytes32 public LIMIT_ASSET_TRANSFER = keccak256("LIMIT_ASSET_TRANSFER");
bytes32 public LIMIT_CURVE_DEPOSIT = keccak256("LIMIT_CURVE_DEPOSIT");
bytes32 public LIMIT_CURVE_SWAP = keccak256("LIMIT_CURVE_SWAP");
bytes32 public LIMIT_CURVE_WITHDRAW = keccak256("LIMIT_CURVE_WITHDRAW");
bytes32 public LIMIT_LAYERZERO_TRANSFER = keccak256("LIMIT_LAYERZERO_TRANSFER");
bytes32 public LIMIT_MAPLE_REDEEM = keccak256("LIMIT_MAPLE_REDEEM");
bytes32 public LIMIT_FARM_DEPOSIT = keccak256("LIMIT_FARM_DEPOSIT");
bytes32 public LIMIT_FARM_WITHDRAW = keccak256("LIMIT_FARM_WITHDRAW");
bytes32 public LIMIT_SPARK_VAULT_TAKE = keccak256("LIMIT_SPARK_VAULT_TAKE");
bytes32 public LIMIT_SUPERSTATE_SUBSCRIBE = keccak256("LIMIT_SUPERSTATE_SUBSCRIBE");
bytes32 public LIMIT_SUSDE_COOLDOWN = keccak256("LIMIT_SUSDE_COOLDOWN");
bytes32 public LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");
bytes32 public LIMIT_USDE_BURN = keccak256("LIMIT_USDE_BURN");
bytes32 public LIMIT_USDE_MINT = keccak256("LIMIT_USDE_MINT");
bytes32 public LIMIT_USDS_MINT = keccak256("LIMIT_USDS_MINT");
bytes32 public LIMIT_USDS_TO_USDC = keccak256("LIMIT_USDS_TO_USDC");
uint256 internal CENTRIFUGE_REQUEST_ID = 0;
address public buffer;
IALMProxy public proxy;
ICCTPLike public cctp;
IDaiUsdsLike public daiUsds;
IEthenaMinterLike public ethenaMinter;
IPSMLike public psm;
IRateLimits public rateLimits;
IVaultLike public vault;
IERC20 public dai;
IERC20 public usds;
IERC20 public usde;
IERC20 public usdc;
IUSTBLike public ustb;
ISUSDELike public susde;
uint256 public psmTo18ConversionFactor;
mapping(address pool => uint256 maxSlippage) public maxSlippages; // 1e18 precision
mapping(uint32 destinationDomain => bytes32 mintRecipient) public mintRecipients;
mapping(uint32 destinationEndpointId => bytes32 layerZeroRecipient) public layerZeroRecipients;
/**********************************************************************************************/
/*** Initialization ***/
/**********************************************************************************************/
constructor(
address admin_,
address proxy_,
address rateLimits_,
address vault_,
address psm_,
address daiUsds_,
address cctp_
) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
proxy = IALMProxy(proxy_);
rateLimits = IRateLimits(rateLimits_);
vault = IVaultLike(vault_);
buffer = IVaultLike(vault_).buffer();
psm = IPSMLike(psm_);
daiUsds = IDaiUsdsLike(daiUsds_);
cctp = ICCTPLike(cctp_);
ethenaMinter = IEthenaMinterLike(Ethereum.ETHENA_MINTER);
susde = ISUSDELike(Ethereum.SUSDE);
ustb = IUSTBLike(Ethereum.USTB);
dai = IERC20(daiUsds.dai());
usdc = IERC20(psm.gem());
usds = IERC20(Ethereum.USDS);
usde = IERC20(Ethereum.USDE);
psmTo18ConversionFactor = psm.to18ConversionFactor();
}
/**********************************************************************************************/
/*** Admin functions ***/
/**********************************************************************************************/
function setMintRecipient(uint32 destinationDomain, bytes32 mintRecipient) external {
_checkRole(DEFAULT_ADMIN_ROLE);
mintRecipients[destinationDomain] = mintRecipient;
emit MintRecipientSet(destinationDomain, mintRecipient);
}
function setLayerZeroRecipient(
uint32 destinationEndpointId,
bytes32 layerZeroRecipient
)
external
{
_checkRole(DEFAULT_ADMIN_ROLE);
layerZeroRecipients[destinationEndpointId] = layerZeroRecipient;
emit LayerZeroRecipientSet(destinationEndpointId, layerZeroRecipient);
}
function setMaxSlippage(address pool, uint256 maxSlippage) external {
_checkRole(DEFAULT_ADMIN_ROLE);
maxSlippages[pool] = maxSlippage;
emit MaxSlippageSet(pool, maxSlippage);
}
/**********************************************************************************************/
/*** Freezer functions ***/
/**********************************************************************************************/
function removeRelayer(address relayer) external {
_checkRole(FREEZER);
_revokeRole(RELAYER, relayer);
emit RelayerRemoved(relayer);
}
/**********************************************************************************************/
/*** Relayer vault functions ***/
/**********************************************************************************************/
function mintUSDS(uint256 usdsAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDS_MINT, usdsAmount);
// Mint USDS into the buffer
proxy.doCall(
address(vault),
abi.encodeCall(vault.draw, (usdsAmount))
);
// Transfer USDS from the buffer to the proxy
proxy.doCall(
address(usds),
abi.encodeCall(usds.transferFrom, (buffer, address(proxy), usdsAmount))
);
}
function burnUSDS(uint256 usdsAmount) external {
_checkRole(RELAYER);
_cancelRateLimit(LIMIT_USDS_MINT, usdsAmount);
// Transfer USDS from the proxy to the buffer
proxy.doCall(
address(usds),
abi.encodeCall(usds.transfer, (buffer, usdsAmount))
);
// Burn USDS from the buffer
proxy.doCall(
address(vault),
abi.encodeCall(vault.wipe, (usdsAmount))
);
}
/**********************************************************************************************/
/*** Relayer ERC20 functions ***/
/**********************************************************************************************/
function transferAsset(address asset, address destination, uint256 amount) external {
_checkRole(RELAYER);
_rateLimited(
RateLimitHelpers.makeAssetDestinationKey(LIMIT_ASSET_TRANSFER, asset, destination),
amount
);
proxy.doCall(
asset,
abi.encodeCall(IERC20(asset).transfer, (destination, amount))
);
}
/**********************************************************************************************/
/*** Relayer ERC4626 functions ***/
/**********************************************************************************************/
function depositERC4626(address token, uint256 amount) external returns (uint256 shares) {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_4626_DEPOSIT, token, amount);
// Note that whitelist is done by rate limits
IERC20 asset = IERC20(IERC4626(token).asset());
// Approve asset to token from the proxy (assumes the proxy has enough of the asset).
_approve(address(asset), token, amount);
// Deposit asset into the token, proxy receives token shares, decode the resulting shares
shares = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).deposit, (amount, address(proxy)))
),
(uint256)
);
}
function withdrawERC4626(address token, uint256 amount) external returns (uint256 shares) {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_4626_WITHDRAW, token, amount);
// Withdraw asset from a token, decode resulting shares.
// Assumes proxy has adequate token shares.
shares = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).withdraw, (amount, address(proxy), address(proxy)))
),
(uint256)
);
_cancelRateLimit(RateLimitHelpers.makeAssetKey(LIMIT_4626_DEPOSIT, token), amount);
}
// NOTE: !!! Rate limited at end of function !!!
function redeemERC4626(address token, uint256 shares) external returns (uint256 assets) {
_checkRole(RELAYER);
// Redeem shares for assets from the token, decode the resulting assets.
// Assumes proxy has adequate token shares.
assets = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).redeem, (shares, address(proxy), address(proxy)))
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(LIMIT_4626_WITHDRAW, token),
assets
);
_cancelRateLimit(RateLimitHelpers.makeAssetKey(LIMIT_4626_DEPOSIT, token), assets);
}
/**********************************************************************************************/
/*** Relayer ERC7540 functions ***/
/**********************************************************************************************/
function requestDepositERC7540(address token, uint256 amount) external {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_7540_DEPOSIT, token, amount);
// Note that whitelist is done by rate limits
IERC20 asset = IERC20(IERC7540(token).asset());
// Approve asset to vault from the proxy (assumes the proxy has enough of the asset).
_approve(address(asset), token, amount);
// Submit deposit request by transferring assets
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).requestDeposit, (amount, address(proxy), address(proxy)))
);
}
function claimDepositERC7540(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token));
uint256 shares = IERC7540(token).maxMint(address(proxy));
// Claim shares from the vault to the proxy
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).mint, (shares, address(proxy)))
);
}
function requestRedeemERC7540(address token, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitedAsset(
LIMIT_7540_REDEEM,
token,
IERC7540(token).convertToAssets(shares)
);
// Submit redeem request by transferring shares
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).requestRedeem, (shares, address(proxy), address(proxy)))
);
}
function claimRedeemERC7540(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token));
uint256 assets = IERC7540(token).maxWithdraw(address(proxy));
// Claim assets from the vault to the proxy
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).withdraw, (assets, address(proxy), address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer Centrifuge functions ***/
/**********************************************************************************************/
// NOTE: These cancelation methods are compatible with ERC-7887
function cancelCentrifugeDepositRequest(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token));
// NOTE: While the cancelation is pending, no new deposit request can be submitted
proxy.doCall(
token,
abi.encodeCall(
ICentrifugeToken(token).cancelDepositRequest,
(CENTRIFUGE_REQUEST_ID, address(proxy))
)
);
}
function claimCentrifugeCancelDepositRequest(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token));
proxy.doCall(
token,
abi.encodeCall(
ICentrifugeToken(token).claimCancelDepositRequest,
(CENTRIFUGE_REQUEST_ID, address(proxy), address(proxy))
)
);
}
function cancelCentrifugeRedeemRequest(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token));
// NOTE: While the cancelation is pending, no new redeem request can be submitted
proxy.doCall(
token,
abi.encodeCall(
ICentrifugeToken(token).cancelRedeemRequest,
(CENTRIFUGE_REQUEST_ID, address(proxy))
)
);
}
function claimCentrifugeCancelRedeemRequest(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token));
proxy.doCall(
token,
abi.encodeCall(
ICentrifugeToken(token).claimCancelRedeemRequest,
(CENTRIFUGE_REQUEST_ID, address(proxy), address(proxy))
)
);
}
/**********************************************************************************************/
/*** Relayer Aave functions ***/
/**********************************************************************************************/
function depositAave(address aToken, uint256 amount) external {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_AAVE_DEPOSIT, aToken, amount);
IERC20 underlying = IERC20(IATokenWithPool(aToken).UNDERLYING_ASSET_ADDRESS());
IAavePool pool = IAavePool(IATokenWithPool(aToken).POOL());
// Approve underlying to Aave pool from the proxy (assumes the proxy has enough underlying).
_approve(address(underlying), address(pool), amount);
// Deposit underlying into Aave pool, proxy receives aTokens
proxy.doCall(
address(pool),
abi.encodeCall(pool.supply, (address(underlying), amount, address(proxy), 0))
);
}
// NOTE: !!! Rate limited at end of function !!!
function withdrawAave(address aToken, uint256 amount)
external
returns (uint256 amountWithdrawn)
{
_checkRole(RELAYER);
IAavePool pool = IAavePool(IATokenWithPool(aToken).POOL());
// Withdraw underlying from Aave pool, decode resulting amount withdrawn.
// Assumes proxy has adequate aTokens.
amountWithdrawn = abi.decode(
proxy.doCall(
address(pool),
abi.encodeCall(
pool.withdraw,
(IATokenWithPool(aToken).UNDERLYING_ASSET_ADDRESS(), amount, address(proxy))
)
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(LIMIT_AAVE_WITHDRAW, aToken),
amountWithdrawn
);
_cancelRateLimit(
RateLimitHelpers.makeAssetKey(LIMIT_AAVE_DEPOSIT, aToken),
amountWithdrawn
);
}
/**********************************************************************************************/
/*** Relayer Curve StableSwap functions ***/
/**********************************************************************************************/
function swapCurve(
address pool,
uint256 inputIndex,
uint256 outputIndex,
uint256 amountIn,
uint256 minAmountOut
)
external returns (uint256 amountOut)
{
_checkRole(RELAYER);
amountOut = CurveLib.swap(CurveLib.SwapCurveParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
rateLimitId : LIMIT_CURVE_SWAP,
inputIndex : inputIndex,
outputIndex : outputIndex,
amountIn : amountIn,
minAmountOut : minAmountOut,
maxSlippage : maxSlippages[pool]
}));
}
function addLiquidityCurve(
address pool,
uint256[] memory depositAmounts,
uint256 minLpAmount
)
external returns (uint256 shares)
{
_checkRole(RELAYER);
shares = CurveLib.addLiquidity(CurveLib.AddLiquidityParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
addLiquidityRateLimitId : LIMIT_CURVE_DEPOSIT,
swapRateLimitId : LIMIT_CURVE_SWAP,
minLpAmount : minLpAmount,
maxSlippage : maxSlippages[pool],
depositAmounts : depositAmounts
}));
}
function removeLiquidityCurve(
address pool,
uint256 lpBurnAmount,
uint256[] memory minWithdrawAmounts
)
external returns (uint256[] memory withdrawnTokens)
{
_checkRole(RELAYER);
withdrawnTokens = CurveLib.removeLiquidity(CurveLib.RemoveLiquidityParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
rateLimitId : LIMIT_CURVE_WITHDRAW,
lpBurnAmount : lpBurnAmount,
minWithdrawAmounts : minWithdrawAmounts,
maxSlippage : maxSlippages[pool]
}));
}
/**********************************************************************************************/
/*** Relayer Ethena functions ***/
/**********************************************************************************************/
function setDelegatedSigner(address delegatedSigner) external {
_checkRole(RELAYER);
proxy.doCall(
address(ethenaMinter),
abi.encodeCall(ethenaMinter.setDelegatedSigner, (address(delegatedSigner)))
);
}
function removeDelegatedSigner(address delegatedSigner) external {
_checkRole(RELAYER);
proxy.doCall(
address(ethenaMinter),
abi.encodeCall(ethenaMinter.removeDelegatedSigner, (address(delegatedSigner)))
);
}
// Note that Ethena's mint/redeem per-block limits include other users
function prepareUSDeMint(uint256 usdcAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDE_MINT, usdcAmount);
_approve(address(usdc), address(ethenaMinter), usdcAmount);
}
function prepareUSDeBurn(uint256 usdeAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDE_BURN, usdeAmount);
_approve(address(usde), address(ethenaMinter), usdeAmount);
}
function cooldownAssetsSUSDe(uint256 usdeAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_SUSDE_COOLDOWN, usdeAmount);
proxy.doCall(
address(susde),
abi.encodeCall(susde.cooldownAssets, (usdeAmount))
);
}
// NOTE: !!! Rate limited at end of function !!!
function cooldownSharesSUSDe(uint256 susdeAmount)
external
returns (uint256 cooldownAmount)
{
_checkRole(RELAYER);
cooldownAmount = abi.decode(
proxy.doCall(
address(susde),
abi.encodeCall(susde.cooldownShares, (susdeAmount))
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(LIMIT_SUSDE_COOLDOWN, cooldownAmount);
}
function unstakeSUSDe() external {
_checkRole(RELAYER);
proxy.doCall(
address(susde),
abi.encodeCall(susde.unstake, (address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer Maple functions ***/
/**********************************************************************************************/
function requestMapleRedemption(address mapleToken, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitedAsset(
LIMIT_MAPLE_REDEEM,
mapleToken,
IMapleTokenLike(mapleToken).convertToAssets(shares)
);
proxy.doCall(
mapleToken,
abi.encodeCall(IMapleTokenLike(mapleToken).requestRedeem, (shares, address(proxy)))
);
}
function cancelMapleRedemption(address mapleToken, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_MAPLE_REDEEM, mapleToken));
proxy.doCall(
mapleToken,
abi.encodeCall(IMapleTokenLike(mapleToken).removeShares, (shares, address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer Superstate functions ***/
/**********************************************************************************************/
function subscribeSuperstate(uint256 usdcAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_SUPERSTATE_SUBSCRIBE, usdcAmount);
_approve(address(usdc), address(ustb), usdcAmount);
proxy.doCall(
address(ustb),
abi.encodeCall(ustb.subscribe, (usdcAmount, address(usdc)))
);
}
/**********************************************************************************************/
/*** Relayer DaiUsds functions ***/
/**********************************************************************************************/
function swapUSDSToDAI(uint256 usdsAmount)
external
onlyRole(RELAYER)
{
// Approve USDS to DaiUsds migrator from the proxy (assumes the proxy has enough USDS)
_approve(address(usds), address(daiUsds), usdsAmount);
// Swap USDS to DAI 1:1
proxy.doCall(
address(daiUsds),
abi.encodeCall(daiUsds.usdsToDai, (address(proxy), usdsAmount))
);
}
function swapDAIToUSDS(uint256 daiAmount)
external
onlyRole(RELAYER)
{
// Approve DAI to DaiUsds migrator from the proxy (assumes the proxy has enough DAI)
_approve(address(dai), address(daiUsds), daiAmount);
// Swap DAI to USDS 1:1
proxy.doCall(
address(daiUsds),
abi.encodeCall(daiUsds.daiToUsds, (address(proxy), daiAmount))
);
}
/**********************************************************************************************/
/*** Relayer PSM functions ***/
/**********************************************************************************************/
// NOTE: The param `usdcAmount` is denominated in 1e6 precision to match how PSM uses
// USDC precision for both `buyGemNoFee` and `sellGemNoFee`
function swapUSDSToUSDC(uint256 usdcAmount) external {
_checkRole(RELAYER);
PSMLib.swapUSDSToUSDC(PSMLib.SwapUSDSToUSDCParams({
proxy : proxy,
rateLimits : rateLimits,
daiUsds : daiUsds,
psm : psm,
usds : usds,
dai : dai,
rateLimitId : LIMIT_USDS_TO_USDC,
usdcAmount : usdcAmount,
psmTo18ConversionFactor : psmTo18ConversionFactor
}));
}
function swapUSDCToUSDS(uint256 usdcAmount) external {
_checkRole(RELAYER);
PSMLib.swapUSDCToUSDS(PSMLib.SwapUSDCToUSDSParams({
proxy : proxy,
rateLimits : rateLimits,
daiUsds : daiUsds,
psm : psm,
dai : dai,
usdc : usdc,
rateLimitId : LIMIT_USDS_TO_USDC,
usdcAmount : usdcAmount,
psmTo18ConversionFactor : psmTo18ConversionFactor
}));
}
// NOTE: !!! This function was deployed without integration testing !!!
// KEEP RATE LIMIT AT ZERO until LayerZero dependencies are live and
// all functionality has been thoroughly integration tested.
function transferTokenLayerZero(
address oftAddress,
uint256 amount,
uint32 destinationEndpointId
)
external payable
{
_checkRole(RELAYER);
_rateLimited(
keccak256(abi.encode(LIMIT_LAYERZERO_TRANSFER, oftAddress, destinationEndpointId)),
amount
);
// NOTE: Full integration testing of this logic is not possible without OFTs with
// approvalRequired == false. Add integration testing for this case before
// using in production.
if (ILayerZero(oftAddress).approvalRequired()) {
_approve(ILayerZero(oftAddress).token(), oftAddress, amount);
}
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
SendParam memory sendParams = SendParam({
dstEid : destinationEndpointId,
to : layerZeroRecipients[destinationEndpointId],
amountLD : amount,
minAmountLD : 0,
extraOptions : options,
composeMsg : "",
oftCmd : ""
});
// Query the min amount received on the destination chain and set it.
( ,, OFTReceipt memory receipt ) = ILayerZero(oftAddress).quoteOFT(sendParams);
sendParams.minAmountLD = receipt.amountReceivedLD;
MessagingFee memory fee = ILayerZero(oftAddress).quoteSend(sendParams, false);
proxy.doCallWithValue{value: fee.nativeFee}(
oftAddress,
abi.encodeCall(ILayerZero.send, (sendParams, fee, address(proxy))),
fee.nativeFee
);
}
/**********************************************************************************************/
/*** Relayer bridging functions ***/
/**********************************************************************************************/
function transferUSDCToCCTP(uint256 usdcAmount, uint32 destinationDomain) external {
_checkRole(RELAYER);
CCTPLib.transferUSDCToCCTP(CCTPLib.TransferUSDCToCCTPParams({
proxy : proxy,
rateLimits : rateLimits,
cctp : cctp,
usdc : usdc,
domainRateLimitId : LIMIT_USDC_TO_DOMAIN,
cctpRateLimitId : LIMIT_USDC_TO_CCTP,
mintRecipient : mintRecipients[destinationDomain],
destinationDomain : destinationDomain,
usdcAmount : usdcAmount
}));
}
/**********************************************************************************************/
/*** Relayer SPK Farm functions ***/
/**********************************************************************************************/
function depositToFarm(address farm, uint256 usdsAmount) external {
_checkRole(RELAYER);
_rateLimited(
keccak256(abi.encode(LIMIT_FARM_DEPOSIT, farm)),
usdsAmount
);
_approve(address(usds), farm, usdsAmount);
proxy.doCall(
farm,
abi.encodeCall(IFarmLike.stake, (usdsAmount))
);
}
function withdrawFromFarm(address farm, uint256 usdsAmount) external {
_checkRole(RELAYER);
_rateLimited(
keccak256(abi.encode(LIMIT_FARM_WITHDRAW, farm)),
usdsAmount
);
proxy.doCall(
farm,
abi.encodeCall(IFarmLike.withdraw, (usdsAmount))
);
proxy.doCall(
farm,
abi.encodeCall(IFarmLike.getReward, ())
);
}
/**********************************************************************************************/
/*** Spark Vault functions ***/
/**********************************************************************************************/
function takeFromSparkVault(address sparkVault, uint256 assetAmount) external {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_SPARK_VAULT_TAKE, sparkVault, assetAmount);
// Take assets from the vault
proxy.doCall(
sparkVault,
abi.encodeCall(ISparkVaultLike.take, (assetAmount))
);
}
/**********************************************************************************************/
/*** Relayer helper functions ***/
/**********************************************************************************************/
// NOTE: This logic was inspired by OpenZeppelin's forceApprove in SafeERC20 library
function _approve(address token, address spender, uint256 amount) internal {
bytes memory approveData = abi.encodeCall(IERC20.approve, (spender, amount));
// Call doCall on proxy to approve the token
( bool success, bytes memory data )
= address(proxy).call(abi.encodeCall(IALMProxy.doCall, (token, approveData)));
bytes memory approveCallReturnData;
if (success) {
// Data is the ABI-encoding of the approve call bytes return data, need to
// decode it first
approveCallReturnData = abi.decode(data, (bytes));
// Approve was successful if 1) no return value or 2) true return value
if (approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool))) {
return;
}
}
// If call was unsuccessful, set to zero and try again
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, 0)));
approveCallReturnData = proxy.doCall(token, approveData);
// Revert if approve returns false
require(
approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool)),
"MainnetController/approve-failed"
);
}
/**********************************************************************************************/
/*** Rate Limit helper functions ***/
/**********************************************************************************************/
function _rateLimited(bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(key, amount);
}
function _rateLimitedAsset(bytes32 key, address asset, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(RateLimitHelpers.makeAssetKey(key, asset), amount);
}
function _cancelRateLimit(bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitIncrease(key, amount);
}
function _rateLimitExists(bytes32 key) internal view {
require(
rateLimits.getRateLimitData(key).maxAmount > 0,
"MainnetController/invalid-action"
);
}
}
"
},
"lib/aave-v3-origin/src/core/contracts/interfaces/IAToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
import {IInitializableAToken} from './IInitializableAToken.sol';
/**
* @title IAToken
* @author Aave
* @notice Defines the basic interface for an AToken.
*/
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted during the transfer action
* @param from The user whose tokens are being transferred
* @param to The recipient
* @param value The scaled amount being transferred
* @param index The next liquidity index of the reserve
*/
event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
/**
* @notice Mints `amount` aTokens to `user`
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted aTokens
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
* @return `true` if the the previous balance of the user was 0
*/
function mint(
address caller,
address onBehalfOf,
uint256 amount,
uint256 index
) external returns (bool);
/**
* @notice Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @dev In some instances, the mint event could be emitted from a burn transaction
* if the amount to burn is less than the interest that the user accrued
* @param from The address from which the aTokens will be burned
* @param receiverOfUnderlying The address that will receive the underlying
* @param amount The amount being burned
* @param index The next liquidity index of the reserve
*/
function burn(address from, address receiverOfUnderlying, uint256 amount, uint256 index) external;
/**
* @notice Mints aTokens to the reserve treasury
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
*/
function mintToTreasury(uint256 amount, uint256 index) external;
/**
* @notice Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* @param from The address getting liquidated, current owner of the aTokens
* @param to The recipient
* @param value The amount of tokens getting transferred
*/
function transferOnLiquidation(address from, address to, uint256 value) external;
/**
* @notice Transfers the underlying asset to `target`.
* @dev Used by the Pool to transfer assets in borrow(), withdraw() and flashLoan()
* @param target The recipient of the underlying
* @param amount The amount getting transferred
*/
function transferUnderlyingTo(address target, uint256 amount) external;
/**
* @notice Handles the underlying received by the aToken after the transfer has been completed.
* @dev The default implementation is empty as with standard ERC20 tokens, nothing needs to be done after the
* transfer is concluded. However in the future there may be aTokens that allow for example to stake the underlying
* to receive LM rewards. In that case, `handleRepayment()` would perform the staking of the underlying asset.
* @param user The user executing the repayment
* @param onBehalfOf The address of the user who will get his debt reduced/removed
* @param amount The amount getting repaid
*/
function handleRepayment(address user, address onBehalfOf, uint256 amount) external;
/**
* @notice Allow passing a signed message to approve spending
* @dev implements the permit function as for
* https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner The owner of the funds
* @param spender The spender
* @param value The amount
* @param deadline The deadline timestamp, type(uint256).max for max deadline
* @param v Signature param
* @param s Signature param
* @param r Signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @return The address of the underlying asset
*/
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
/**
* @notice Returns the address of the Aave treasury, receiving the fees on this aToken.
* @return Address of the Aave treasury
*/
function RESERVE_TREASURY_ADDRESS() external view returns (address);
/**
* @notice Get the domain separator for the token
* @dev Return cached value if chainId matches cache, otherwise recomputes separator
* @return The domain separator of the token at current chain
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the nonce for owner.
* @param owner The address of the owner
* @return The nonce of the owner
*/
function nonces(address owner) external view returns (uint256);
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
}
"
},
"lib/aave-v3-origin/src/core/contracts/interfaces/IPool.sol": {
"content": "// 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: 1 for Stable, 2 for Variable
* @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 swapBorrowRateMode()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user swapping his rate mode
* @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
*/
event SwapBorrowRateMode(
address indexed reserve,
address indexed user,
DataTypes.InterestRateMode interestRateMode
);
/**
* @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 rebalanceStableBorrowRate()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user for which the rebalance has been executed
*/
event RebalanceStableBorrowRate(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 debt, 2 for Variable debt
* @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
* @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 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);
/**
* @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
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @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/stable 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 The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @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 The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @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/stable 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 The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @return The final amount repaid
*/
function repayWithATokens(
address asset,
uint256 amount,
uint256 interestRateMode
) external returns (uint256);
/**
* @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa
* @param asset The address of the underlying asset borrowed
* @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
*/
function swapBorrowRateMode(address asset, uint256 interestRateMode) external;
/**
* @notice Permissionless method which allows anyone to swap a users stable debt to variable debt
* @dev Introduced in favor of stable rate deprecation
* @param asset The address of the underlying asset borrowed
* @param user The address of the user whose debt will be swapped from stable to variable
*/
function swapToVariable(address asset, address user) external;
/**
* @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too
* much has been borrowed at a stable rate and suppliers are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
*/
function rebalanceStableBorrowRate(address asset, address user) external;
/**
* @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 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 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 on `modes` 1 or 2
* @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 mu
Submitted on: 2025-09-19 10:59:34
Comments
Log in to comment.
No comments yet.