Architecture Overview
Overview of the organization of the code of Core Module of the Angle Protocol
The repository for the Core Module of Angle Protocol can be found on Github here, it is the angle-core repo.
Angle Protocol Smart Contract Architecture

Main Contracts

The main contracts in Angle Protocol Core Module and their purposes are:
The main (and only) entry point for Users who want to mint/burn stablecoins, and for SLPs who want to deposit/withdraw collateral. There is one such contract per stablecoin.
A StableMaster contract handles all the collateral types accepted for a given stablecoin. It does all the accounting, contains the logic for the fees and directly interacts with the AgToken and SanToken contracts handling respectively Angle's stablecoins and SLP tokens.
The main interactions agents have with this contract happen with the following methods:
  • ​mint(): for a user to get stablecoins from collateral
  • ​burn(): for a user to burn stablecoins and redeem collateral
  • ​deposit(): for a SLP to deposit into the corresponding pool
  • ​withdraw(): for a SLP to withdraw from the corresponding pool
It is also used to propagate changes at the level of one stablecoin, like a governance change to all underlying contracts.
The contracts handling Hedging Agents' positions. There is one such contract per stablecoin/collateral. These contracts are upgradeable and implement the EIP-721 token standard, which means that a HA can own several perpetuals for a given stablecoin/collateral pair, that these perpetuals are non-fungible, and that ownership of these perpetuals can be transferred like a standard NFT.
Hedging Agents interact directly with this contract to open new perpetuals, to increase/decrease the leverage amount of their perpetual, to transfer their perpetuals to other addresses or to claim the rewards in governance tokens they get in some occasions with their perpetual.
  • ​openPerpetual(): for a HA to join the protocol and open a leveraged position
  • ​closePerpetual(): for a HA to close position and get the current amount of her position depending on the entry oracle value and the current oracle value
  • ​addToPerpetual(): for a HA to decrease the leverage of a given position by adding collateral to it
  • ​removeFromPerpetual(): for a HA to cash out some collateral of a perpetual she controls and hence increase leverage
  • ​getReward(): for a HA to withdraw the rewards accumulated with a given perpetual
Keepers interact with this contract to liquidate perpetuals with negative positions or to cash out perpetuals when there are too many of them:
  • ​liquidatePerpetuals(): to liquidate unhealthy perpetuals that reached the maintenance margin
  • ​forceClosePerpetuals(): forces the cash out of perpetuals in the case where the amount covered by Hedging Agents is too big compared with what they can cover

Supporting Contracts


The Core contract maintains the integrity of the module, it is the contract storing the addresses with the governor role and the guardian address. It also stores the references to all the stablecoins of the Core Module (all the StableMaster contracts). Whenever there is a new governor address in Angle, then Core makes sure that this change is effective across most contracts of Angle's protocol.
The Core contract does not propagate changes to some bricks of the module like the oracle contracts.
It is at the level of this contract that a stablecoin can be deployed and considered part of Angle protocol.


AgTokens are the stablecoins that users receive when they give collateral for stability: AgToken contracts are the contracts representing these stablecoins, they are all associated to a StableMaster contract, which is the only contract within this module with the ability to mint agTokens or burn it against collateral.
Other contracts from other modules may have minting rights on the AgToken contract.
They implement most of the standard EIP-20/ERC20 token methods, with slight modifications. All AgToken contracts are upgradeable and also implement EIP-2612 which thanks to the permit function enables gas-less transfers and single transaction approve+actions.

​SanToken Contracts​

The tokens that Standard Liquidity Providers receive when they contribute to a collateral pool for a given stablecoin are called sanTokens: SanToken contracts represent these tokens. There is one SanToken contract per pair stablecoin/collateral.
These tokens are interest bearing and implement most of the standard EIP-20/ERC20 token methods. Like the AgToken contracts, all SanToken contracts are upgradeable and also implement EIP-2612.
Also, similarly to AgToken contracts, only the corresponding StableMaster contract can mint sanTokens or burn it against the corresponding amount of collateral.
There is one PoolManager contract per pair stablecoin/collateral. Whenever a new collateral is deployed for a stablecoin, a specific PoolManager should be deployed.
This contract manages the strategies responsible for getting yield on the collateral and reports back to the StableMaster in case of gains or losses. This contract stores all the collateral for a pool, and it is the only place of the module that holds collateral. For instance, when a user calls the StableMaster to get stablecoins from collateral, this collateral sent is directly transferred to the PoolManager that corresponds. The role of the PoolManager is then to make efficient use of this collateral through strategies in order to get yield on it.
Some fees and parameters of the module depend on quantities which are expensive to compute at each transaction. For instance, slippage for SLPs depend on the collateral ratio of the module, which is expensive to compute since it requires doing an oracle read for all collateral types. The Core module then relies on keepers to call the function computing the collateral ratio once in a while and update fees accordingly.
FeeManager contracts are the place with which keepers interact. There is one FeeManager contract per pair stablecoin/collateral.
Each contract can also be used to give some modularity to the fees that are taken and computed without keepers. For example, mint and burn fees for users depend on the hedge curve by HAs, with the FeeManager contract, governance can induce a dependence on the collateral ratio too.
The main functions with which keepers can interact are the following:
  • ​updateUsersSLP(): to change parameters linked to stable holders and SLPs in the corresponding StableMaster
  • ​updateHA(): to change the parameters related to HAs opening and closing their perpetuals in PerpetualManager

​Oracle Contracts​

There is in this module one oracle contract per pair collateral/stablecoin. Whenever a new collateral is introduced for a stablecoin, a new oracle contract is deployed and a reference to it is created in the corresponding contracts (StableMaster, PerpetualManager).
Depending on the pair of interests, an oracle contract may read through a single Chainlink feed, a Uniswap circuit and a Chainlink circuit, a Uniswap v3 pool and a Chainlink circuit, ...

Other Side Contracts

These contracts are deployed as soon as a new strategy is activated for a collateral or as soon as a new lender or yield farming platform is added to a strategy. A strategy contract is responsible for the interaction between the protocol's reserves in the PoolManager contract and the different yield farming platforms associated to it.
The first strategy of the protocol consists in optimizing for the best APY between Compound and Aave. It is at the level of the corresponding strategy contract that the protocol is choosing between withdrawing from Compound or withdrawing from Aave, and between lending to one of those.
A Lender contract is the interface between the protocol and a lending platform in the context of the first strategy implemented by the module. There is one such contract per lending or yield farming platform associated to a strategy. Each contract contains the logic associated to its corresponding platform.
If there are two collateral types for the module, each using a single strategy involving lending to Compound and Aave, then the protocol will have two different Strategy contracts (one per collateral), and 4 different Lending contracts (two per Strategy).
Keepers interact with Strategy contracts when it comes to adjusting debt ratios to lending strategies and recording capital gains by calling the harvest function.

Utility Contracts

Angle's Core Module code base relies on a vast amount of libraries (from OpenZeppelin, Uniswap, or found in other contracts). They are stored in the external folder of the repo. Still, for the particular needs of the protocol, some libraries and contracts were developed internally to be reused at different places of the code.


This contract contains some internal utility functions and modifiers that are used in all the contracts of the module. Among other things it has a method to compute piecewise linear functions and modifiers to check if fees passed as input to functions called by governance are valid.


It is inspired from OpenZeppelin's Pausable contract and generalizes it. Like the contract above, this module can only be used through inheritance.
This contract enables to make functions that can be paused for some categories but not others. It is for instance used in the StableMaster contract to pause mint or burn of stablecoins against a given collateral but not against another collateral.

Access Control Conventions and Roles

Beyond the GOVERNOR_ROLE and GUARDIAN_ROLE introduced in the global section, this module introduces a set of different roles and permissions. These include:
The Core contract maintains the integrity of these roles across all the contracts of the module.


The CORE_ROLE enables to make some changes to the underlying StableMaster contracts. It is given to the Core contract. When changes need to be propagated across all the contracts of the protocol (like a guardian getting revoked, or a new governor being promoted), then the core calls the functions of the StableMaster notifying this change.
This role can grant or revoke many roles in the StableMaster contract like the governor, the guardian or the aToken role.


This is a role given to some addresses to sell the COMP and AAVE tokens accumulated by the yield strategies. To optimize the sales, only whitelisted addresses can perform it. They therefore have the freedom to specify the 1Inch path with which the swap should be performed.


The STABLEMASTER_ROLE is found in the PoolManager, the AgToken and the SanToken contracts. It is only given to StableMaster contracts. It serves to propagating governance changes from the StableMaster contract and to ask the AgToken and SanToken contracts to mint or burn their underlying tokens.


A PoolManager is basically to hub when it comes to a stablecoin/collateral pair, most of the changes in parameters or in oracles related to a pair go through this type of contract.
Thanks to the POOLMANAGER_ROLE , PoolManager contracts are able to communicate with all contracts of the protocol associated to their collateral. It is for instance used in the FeeManager , Strategy and PerpetualManager contracts to propagate governance changes.


This role is given to Strategy contracts to let them interact with the corresponding PoolManager contract and report their gains or losses


The FEEMANAGER_ROLE is given to the FeeManager contracts allowed to update some protocol parameters (including fee and slippage for SLPs) as a function of the collateral ratio or of some other parameters.
It is found in the StableMaster and PerpetualManager contracts with which FeeManager contracts interact.


Even though it is never formally defined in the module, the PERPETUALMANAGER_ROLE is indirectly used in the StableMaster contract when a PerpetualManager seeks to call updateStockUsers.