Search
K
Comment on page
💧

Liquidity Gauges - Angle Staking Contracts

Smart contract used for distributing ANGLE rewards on mainnet

1. Introduction

The LiquidityGaugeV4 allows to stake an ERC20 token to receive as a reward another ERC20 token. The contract used at Angle was forked from Curve, with some modifications from the Angle Core Team.
This contract is the staking contract used to distribute ANGLE rewards to some Angle Protocol stakeholders (SLPs, LPs of pools with agTokens) on mainnet.
The particularity of this contract is that it supports multiple reward tokens (up to 8) and it allows veANGLE holders to get boosts on their ANGLE rewards when they stake their tokens.
The different LiquidityGaugeV4 contracts are connected to the AngleDistributor which automatically and every week distributes ANGLE rewards to these contracts based on how veANGLE holders voted in gauges. People staking in liquidity gauges can then directly claim their ANGLE tokens (and potentially other reward tokens in the contract).
People staking in this contract and earning veANGLE tokens can receive a boost on their ANGLE rewards. Note that boosts do not apply on other types of rewards. Like if CRV are given as a reward in this contract, if there were two people staking the same amount of tokens, but one with veANGLE and one without, these two people would receive the same amount of CRV rewards.
This contract is by itself an ERC-20 token, meaning people staking in a liquidity gauge contract own a token they can transfer.

2. Contract Details

Interfaces

Implements ERC20. This contract is upgradeable (note that this is one of the main differences with respect to Curve's contract).

Parameters

3. Key Mechanisms & Concepts

Curve Documentation

Most of key functions of this contract are detailed on Curve docs.

Upgradeability

Compared with Curve's implementation of LiquidityGaugeV4 contract, Angle contract is upgradeable.
The way this was implemented was simply by removing the content of the __init__ function (the constructor), putting it in the initialize function and having a boolean initialized variable set to true once initialize is called. To avoid hostile takeovers of the implementation, the same initialized boolean is modified in the __init__ function.

Changes Introduced

The main difference between Curve and Angle implementation is that Angle system considers ANGLE rewards the same way as general rewards. However just like Curve, ANGLE rewards do not get accrued the same way as other rewards would: boost can apply to ANGLE rewards for addresses that own veANGLE tokens.
We highlight below some changes in key functions.

_checkpoint_rewards

@internal
def _checkpoint_rewards(_user: address, _total_supply: uint256, _claim: bool, _receiver: address, _only_checkpoint:bool = False):
This function claims pending rewards and checkpoints rewards for a user and for a given token. It is this function that was modified to handle ANGLE rewards differently than CRV rewards are handled in Curve's equivalent.
To determine the amount of rewards for an address, this function uses total_supply of staked tokens, and the user_balance which corresponds to the amount of tokens staked.
To treat ANGLE rewards differently than other tokens, this function considers that if the reward token is the ANGLE token, the total_supply is equal to the working_supply of the contract, that is the supply modified by considering that people staking veANGLE tokens are staking more tokens.

deposit_reward_token

@external
@nonreentrant("lock")
def deposit_reward_token(_reward_token: address, _amount: uint256):
It is at the level of this function that reward tokens, included ANGLE, are distributed to this contract.
In Curve implementation, the amount of CRV rewards accruing to a gauge is determined directly in this LiquidityGaugeV4 contract that queries directly the GaugeController to know the relative weight. This is no longer needed with Angle, as the AngleDistributor can use this deposit_reward_token function to send each week the ANGLE rewards voted in the GaugeController.
The _checkpoint function from Curve contract which called the GaugeController was therefore removed as the logic of it is now included in the new version of the _checkpoint_rewards and in the new architecture routing ANGLE tokens to gauges.