Developers
Search…
🛣
Router - Combining Protocol Interactions
Computing transaction fees according to the specified logic

1. Introduction

The router goal is to be a one-stop contract for users interacting with the protocol. It allows to combine many different actions together across different modules, so they can all be done in one transaction.
Using this contract to interact with the protocol only requires one approval or permit transaction.
The router relies on mixer() function that can be called with a set of instructions, including the different actions it can perform and their parameters.
The mixer() function first loads or receives all the funds needed for further actions, either through receiving, claiming, or withdrawing tokens.
Then, it performs the necessary swaps to convert the funds it received into the tokens it needs for the next actions. Once funds are ready to be used in the protocol, the different actions previously specified are performed.
The actions that can be performed with the router contract are listed below. Note by the way that all actions can be combined with one another in just one transaction.
  • Claim ANGLE rewards from the gauge: claimRewards, only for gauges of type 0 and 1
  • Claim the weekly interest distributed in sanUSDC/EUR: claimWeeklyInterest
  • Stake tokens in gauges to earn ANGLE rewards: gaugeDeposit
  • Withdraw collateral from the protocol by burning sanTokens: withdraw
  • Minting agTokens (agEUR so far): mint
  • Deposit collateral to the protocol to get sanTokens: deposit
  • Opening a perpetual position: openPerpetual
  • Adding collateral to a previously opened position: addToPerpetual
  • Depositing ANGLE tokens to an existing veANGLE lock: veANGLEDeposit
  • Interacting with a VaultManager to create a vault, add or remove collateral, borrow stablecoins, repay a debt, permit an asset or transferring debt to another vault: borrower
Note that no more than 10 different actions can be perfomed in a mixer transaction.
A swap function with support for Uniswap V3 and 1inch allows users to perform those actions on any contract from potentially any token. This swap function also leaves the opportunity to users to wrap ETH or stETH to wstETH. Note however that users should be wary of using the correct routes otherwise they might lose their funds.
The router’s value lies in that it improves a lot the user experience when interacting with Angle Protocol’s contracts, by combining actions or recucing gas costs for example.

2. Contract Details

Interfaces

Implements Initializable and ReentrancyGuardUpgradeable from Open Zeppelin.
The contract is upgradeable.

Types

In this section, we introduce the types which are needed to interact with the mixer function of the contract.

ActionType

Enum corresponding to the arguments for the actions to perform in the mixer() function.
  • claimRewards (only for gauges of type 0 and 1)
  • claimWeeklyInterest
  • gaugeDeposit
  • withdraw
  • mint
  • deposit
  • openPerpetual
  • addToPerpetual
  • veANGLEDeposit
  • borrower

SwapType

Parameter to be specified in the ParamsSwapType argument when calling the mixer() function. It indicates if the swap needs to be performed through UniswapV3 or 1Inch.
  • UniswapV3
  • oneINCH
  • WrapStETH
  • None

ParamsSwapType

Arguments to specify when calling the mixer() function and performing a token swap. Users should be wary of using the correct routes to not risk losing funds. In particular they should make sure the end token of the swap is collateral.
  • inToken: token to swap for the collateral
  • collateral
  • amountIn: amount received and to be swapped
  • minAmountOut: slippage protection
  • args: path of the swap on UniswapV3 if swapType is UniswapV3, or the payload (data) received by the 1Inch API if swapType is oneINCH.
  • swapType: defined above

TransferType

Argument that needs to be specified when calling the mixer() function, to indicate which token is directly transferred and its quantity.
  • inToken
  • amountIn

PermitType

Arguments required for the mixer() function to perform the grant allowances to msg.sender through permit signatures.
  • token
  • owner: address to approve
  • value
  • deadline
  • v
  • r
  • s

PermitVaultManagerType

Type of data to pass to the router contract in the mixerVaultManagerPermitFunction to approve an address (normally the router) for all the vaults
  • vaultManager
  • owner
  • approved: whether to approve or not the owner for all the vaults in the VaultManager
  • deadline
  • v
  • r
  • s

Pairs

References to the contracts associated to a collateral-stablecoin pair.
  • poolManager
  • perpetualManager
  • sanToken
  • gauge

References

  • governor: address of the governor
  • guardian: address of the guardian
  • uniswapV3Router: address of Uniswap V3 router
  • oneInch: address of 1inch router

3. Key Mechanisms & Concepts

Mixer Function (external)

mixer

1
function mixer(
2
PermitType[] memory paramsPermit,
3
TransferType[] memory paramsTransfer,
4
ParamsSwapType[] memory paramsSwap,
5
ActionType[] memory actions,
6
bytes[] calldata data
7
) external nonReentrant {
Copied!
This is the main function of the router. It allows to combine the different actions listed above into one transaction.
The way this function works is that it first fills the router balances via transfers and swaps. It then proceeds with each action in the order at which they are given.
Note that there is a risk of losing funds when engaging with this function: users can indeed specify paths to swap tokens to the desired token of their choice (in paramsSwap). Yet the protocol does not verify the payload given and cannot check that the swap performed by users actually gives the desired out token: in this case funds will be lost by the user.
The descriptions of what's expected in the types PermitType, TransferType, ParamsSwapType, ActionType are given in the above Types section.
Parameters:
  • paramsPermit: Array of params PermitType used to approve the router for a set of tokens with the permit standard. Users willing to interact with the contract with tokens that do not support permit should approve the contract for these tokens prior to interacting with it
  • paramsTransfer: Array of params TransferType used to transfer tokens to the router
  • paramsSwap: Array of params ParamsSwapType used to swap tokens previously transferred to the router
  • actions: List of actions to be performed by the router (in order of execution)
  • data: Array of encoded data for each of the actions performed in this mixer. Before calling an action, it is important to make sure to read the documentation of the associated internal functions to know how to exactly specify parameters.
Decoding Data
Here we explain for each action the type and order of the parameters to be given in the mixer contract.
For some actions (mint, deposit, openPerpetual, addToPerpetual, withdraw), users are required to give in the corresponding data the proportion of the amount of token they have brought prior to the router (through direct transfer or a swap) they want to use for the operation. If you want to use all the USDC you have brought (through an ETH -> USDC swap for instance) to mint stablecoins, you should use BASE_PARAMS as a proportion.
Note that the proportion that is given is a proportion of what is left. If you want to use 50% of your USDC for a mint and the rest for an openPerpetual, proportion used for the mint should be 50% (that is BASE_PARAMS/2), and proportion for the openPerpetual should be all that is left that is 100% (= BASE_PARAMS).
For some actions as well, there is an addressProcessed parameter which lets users precise whether they know the protocol contracts addresses or have specified an associated address. For instance, users may not know all our StableMaster address and only know the corresponding AgToken address, in which case if there is a parameter addressProcessed, they should set it to no and if the parameter is stablecoinOrStableMaster they should give the stablecoin address.
claimRewards
  1. 1.
    address user: address of the user to claim rewards for
  2. 2.
    uint256 proportionToBeTransferred: proportion of the claimed ANGLE tokens to be transferred back to the router to perform actions on it
  3. 3.
    address[] memory claimLiquidityGauges: Liquidity gauges where to claim
  4. 4.
    uint256[] memory claimPerpetualIDs: Perpetual IDs where to clam
  5. 5.
    bool addressProcessed
  6. 6.
    address[] memory stablecoins
  7. 7.
    address[] memory collateralsOrPerpetualManagers
claimWeeklyInterest
  1. 1.
    address user: user to claim for
  2. 2.
    address feeDistributor: contract to claim on
  3. 3.
    bool letInContract: whether the claimed sanTokens should stay in the router contract to be used for other actions
veANGLEDeposit
  1. 1.
    address user: user to deposit for
  2. 2.
    uint256 amount
gaugeDeposit
  1. 1.
    address user: user to deposit for
  2. 2.
    uint256 amount: proportion of the staked token to deposit
  3. 3.
    address stakedToken: token to deposit
  4. 4.
    address gauge: gauge where to deposit
  5. 5.
    bool shouldClaimRewards
deposit
  1. 1.
    address user: user to deposit for
  2. 2.
    uint256 amount: amount to deposit (it's a proportion of the corresponding's collateral balance)
  3. 3.
    bool addressProcessed
  4. 4.
    address stablecoinOrStableMaster
  5. 5.
    address collateral: token to deposit (it can be null if addressProcessed)
  6. 6.
    address poolManager: PoolManager associated to the collateral (null if addressProcessed is not true)
  7. 7.
    address sanToken: SanToken associated to the collateral (null if addressProcessed is not true)
withdraw
  1. 1.
    uint256 amount: amount of sanTokens to withdraw (it's a proportion of the sanToken balance available on the router)
  2. 2.
    bool addressProcessed
  3. 3.
    address stablecoinOrStableMaster
  4. 4.
    address collateralOrPoolManager
mint
  1. 1.
    address user: user to mint for
  2. 2.
    uint256 amount: amount to mint (it's a proportion of the corresponding's collateral balance)
  3. 3.
    uint256 minStableAmount: slippage protection
  4. 4.
    bool addressProcessed
  5. 5.
    address stablecoinOrStableMaster
  6. 6.
    address collateral: token to deposit (it can be null if addressProcessed)
  7. 7.
    address poolManager: PoolManager associated to the collateral (null if addressProcessed is not true)
openPerpetual
  1. 1.
    address user: user to open perpetual for
  2. 2.
    uint256 amount: amount to put as a margin (it's a proportion of the corresponding's collateral balance in the router contract)
  3. 3.
    uint256 amountCommitted: committed amount in the perpetual contract to create
  4. 4.
    uint256 extremeRateOracle: Maximum oracle value at which the vault should be created
  5. 5.
    uint256 minNetMargin: Minimum margin to store in the vault
  6. 6.
    bool addressProcessed
  7. 7.
    address stablecoinOrPerpetualManager
  8. 8.
    address collateral: Collateral to open perpetual from (it can be null if addressProcessed is true)
addToPerpetual
  1. 1.
    uint256 amount: amount to add to the margin (it's a proportion of the corresponding's collateral balance in the router contract)
  2. 2.
    uint256 vaultID: ID of the vault to add collateral to
  3. 3.
    bool addressProcessed
  4. 4.
    address stablecoinOrPerpetualManager
  5. 5.
    address collateral: Collateral associated to the perpetual contract of interest (it can be null if addressProcessed is true)
borrower
  1. 1.
    address collateral: Collateral associated to the VaultManager of interest
  2. 2.
    address stablecoin: Stablecoin associated to the VaultManager contract
  3. 3.
    address vaultManager: Contract to call
  4. 4.
    address to
  5. 5.
    address who
  6. 6.
    ActionBorrowType[] memory actionsBorrow
  7. 7.
    bytes[] memory dataBorrow
  8. 8.
    bytes memory repayData
The parameters 4 to 8 correspond to the parameters to pass to the angle function in VaultManager contracts. You can look at the corresponding docs of the function here.
Deconding Swap Data
It is possible to send ETH to the router contract for these to be wrapped to wETH or wstETH. If you're sending ETH (msg.value > 0), then to wrap to wETH you need to specify as inToken the wETH address, and to wrap to wstETH, you need to specify as inToken the wstETH address.
You can then swap these wrapped tokens or keep them like that to interact with other protocols functions.

mixerVaultManagerPermit

1
function mixerVaultManagerPermit(
2
PermitVaultManagerType[] memory paramsPermitVaultManager,
3
PermitType[] memory paramsPermit,
4
TransferType[] memory paramsTransfer,
5
ParamsSwapType[] memory paramsSwap,
6
ActionType[] memory actions,
7
bytes[] calldata data
8
) external;
Copied!
This function is a wrapper built on top of the mixer function used to grant approval to a VaultManager contract before performing actions on it through a gasless permit signature and then revoking this approval after these actions. It's normally safe to leave approval to the router contract on all your vaults for a VaultManager as it is checked that you cannot instruct to the router actions on a vault you do not control.
Parameters:
Beyond the mixer standard parameters, this function has a paramsPermitVaultManager parameter with all the different permit data needed to grant or revoke allowances to different VaultManager contracts. In the array, the signatures for granting approvals must be given before the signatures to revoke approvals.

Other external functions

Beyond the mixer functions, the router contract includes some wrappers which make it easy for anyone to interact with Angle contracts.

mint

1
function mint(
2
address user,
3
uint256 amount,
4
uint256 minStableAmount,
5
address stablecoin,
6
address collateral
7
) external nonReentrant {
Copied!
Function used to mint agTokens from the router.
Parameters:
  • user: Address to send the stablecoins to.
  • amount: Amount of collateral to use for the mint.
  • minStableAmount: minimum amount of token minted that needs to be received
  • stablecoin: Stablecoin to mint
  • collateral: Collateral to use to mint

burn

1
function burn(
2
address dest,
3
uint256 amount,
4
uint256 minCollatAmount,
5
address stablecoin,
6
address collateral
7
) external nonReentrant {
Copied!
Function used to burn agTokens for collateral.
Parameters:
  • dest: Address to send collateral to
  • amount: Amount of stablecoin to burn
  • minCollatAmount: Minimum amount of collateral to receive
  • stablecoin: Address of the agToken to burn.
  • collateral: Address of the collateral token to receive

claimRewards

There are two different versions of this function in the contract. The second version is designed to be more gas efficient than the firs one, and requires the perpetualManagers addresses to be passed instead of the stablecoins and collaterals ones.
1
function claimRewards(
2
address user,
3
address[] memory liquidityGauges,
4
uint256[] memory perpetualIDs,
5
address[] memory stablecoins,
6
address[] memory collaterals
7
) external nonReentrant {
Copied!
1
function claimRewards(
2
address user,
3
address[] memory liquidityGauges,
4
uint256[] memory perpetualIDs,
5
address[] memory perpetualManagers
6
) external nonReentrant {
Copied!
These functions can be used to claimRewards from multiple gauges of types 0 (boosted) and 1 (perpetuals). Rewards from gauges of types > 1 cannot be claimed using this function or the router.
Parameters:
  • user: Address of the user on behalf of who the rewards are claimed.
  • liquidityGauges: Addresses of the contracts to claim from
  • perpetualIDs: List of perpetual IDs to claim from, if claiming rewards from perpetual gauges
  • stablecoins: Addresses of the stablecoins the perpetualIDs are linked to
  • collaterals: Addresses of the collaterals the perpetuals from perpetualIDs are from.
  • perpetualManagers: Addresses of the concerned perpetual managers where to claim
Arrays can be empty if needed depending on where is claimed. For instance, if you're not claiming in any perpetualManager contract, the perpetualManagers and perpetualIDs array can be made empty.

Internal-only functions

These functions can be used only through the mixer when part of a mix of actions to be included in a transaction, or by the mixer function itself.

claimWeeklyInterest

1
function _claimWeeklyInterest(
2
address user,
3
IFeeDistributorFront feeDistributor,
4
bool letInContract
5
) internal returns (uint256 amount, IERC20 token) {
Copied!
Function used to claim the weekly interest distributed to veANGLE holders in sanUSDC_EUR.
user: address of the user on behalf of whom the router should claim the interest. feeDistributor: address of the FeeDistributor contract to claim from. If the claimed interest (sanUSDC/EUR tokens) need to be used by the router to perform other actions, then letInContract should be set to True.

withdraw

1
function _withdraw(
2
uint256 amount,
3
bool addressProcessed,
4
address stablecoinOrStableMaster,
5
address collateralOrPoolManager
6
) internal returns (uint256 withdrawnAmount, address) {
Copied!
Function used to withdraw collateral from the protocol against sanTokens.
amount is the amount of collateral to withdraw.
addressProcessed should be set to True if the address provided as stablecoinOrStableMaster and collateralOrPoolManager are the StableMaster’s and PoolManager’s, and False if it is the stablecoin’s and collateral’s.

transferAndSwap

1
function _transferAndSwap(
2
IERC20 inToken,
3
uint256 amount,
4
uint256 minAmountOut,
5
SwapType swapType,
6
bytes memory args
7
) internal returns (uint256 amountOut) {
Copied!
Function called by the mixer() function to swap the tokens sent by users into tokens accepted as collateral by the protocol.
inToken is the token sent by the user to be swapped by the router into accepted collateral. To swap from ETH or WETH, inToken should be the address of the WETH contract and ETH will be wrapped by the function. amount is the amount of inToken. args are the arguments that need to be passed to the specific protocols functions.
The swap parameters in args are not checked, meaning that users should be very careful of providing the same destination token in the path or payload than the collateral they specify in paramsSwap of the mixer, or they risk losing their funds.

Governance (guardian or governor)

This contract also includes some governance functions callable by the guardian or the governor of the protocol:
  • setGovernorOrGuardian
  • addStableMaster and removeStableMaster: to add support for a stablecoin in the protocol
  • addPairs and removePairs: to add/remove collateral-stablecoin pairs, with their dedicated liquidity gauges
  • setLiquidityGauges
  • changeAllowance
  • recoverERC20