LiquidityGaugeV1
Source Code
Source code of the LiquidityGaugeV1 can be found on Github. The following view methods and functions are using the 3pool as an example.
Deposit and Withdrawals¶
deposit¶
 LiquidityGauge.deposit(_value: uint256, addr: address = msg.sender):
Function to deposit _value amount of LP tokens into the gauge.
Emits: Deposit
| Input | Type | Description | 
|---|---|---|
_value |  uint256 |  Amount of tokens to deposit | 
addr |  address |  Address to deposit for. Defaults to msg.sender |  
Warning
Prior to depositing, ensure that the gauge has been approved to transfer amount LP tokens on behalf of the caller (see set_approve_deposit).
Source code
event Deposit:
    provider: indexed(address)
    value: uint256
# caller -> recipient -> can deposit?
approved_to_deposit: public(HashMap[address, HashMap[address, bool]])
@external
@nonreentrant('lock')
def deposit(_value: uint256, addr: address = msg.sender):
    """
    @notice Deposit `_value` LP tokens
    @param _value Number of tokens to deposit
    @param addr Address to deposit for
    """
    if addr != msg.sender:
        assert self.approved_to_deposit[msg.sender][addr], "Not approved"
    self._checkpoint(addr)
    if _value != 0:
        _balance: uint256 = self.balanceOf[addr] + _value
        _supply: uint256 = self.totalSupply + _value
        self.balanceOf[addr] = _balance
        self.totalSupply = _supply
        self._update_liquidity_limit(addr, _balance, _supply)
        assert ERC20(self.lp_token).transferFrom(msg.sender, self, _value)
    log Deposit(addr, _value)
withdraw¶
 LiquidityGauge.withdraw(_value: uint256):
Function to withdraw _value LP tokens from the gauge.
Emits: Withdraw
| Input | Type | Description | 
|---|---|---|
_value |  uint256 |  Amount of tokens to withdraw | 
Source code
event Withdraw:
    provider: indexed(address)
    value: uint256
@external
@nonreentrant('lock')
def withdraw(_value: uint256):
    """
    @notice Withdraw `_value` LP tokens
    @param _value Number of tokens to withdraw
    """
    self._checkpoint(msg.sender)
    _balance: uint256 = self.balanceOf[msg.sender] - _value
    _supply: uint256 = self.totalSupply - _value
    self.balanceOf[msg.sender] = _balance
    self.totalSupply = _supply
    self._update_liquidity_limit(msg.sender, _balance, _supply)
    assert ERC20(self.lp_token).transfer(msg.sender, _value)
    log Withdraw(msg.sender, _value)
approved_to_deposit¶
 LiquidityGauge.approved_to_deposit(arg0: address, arg1: address) -> bool: view
Getter method to check if address arg0 is approved to deposit for address arg1. Can be modified by calling set_approve_deposit.
Returns: true or flase (bool).
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  Caller | 
arg1 |  address |  Recipient | 
Source code
# caller -> recipient -> can deposit?
approved_to_deposit: public(HashMap[address, HashMap[address, bool]])
@external
def set_approve_deposit(addr: address, can_deposit: bool):
    """
    @notice Set whether `addr` can deposit tokens for `msg.sender`
    @param addr Address to set approval on
    @param can_deposit bool - can this account deposit for `msg.sender`?
    """
    self.approved_to_deposit[addr][msg.sender] = can_deposit
set_approve_deposit¶
 LiquidityGauge.set_approve_deposit(addr: address, can_deposit: bool):
Function to approve or revoke premission for address (arg0) to deposit into the gauge on behalf of the caller.
| Input | Type | Description | 
|---|---|---|
addr |  address |  Address to set approval for | 
can_deposit |  bool |  true or false | 
Source code
# caller -> recipient -> can deposit?
approved_to_deposit: public(HashMap[address, HashMap[address, bool]])
@external
def set_approve_deposit(addr: address, can_deposit: bool):
    """
    @notice Set whether `addr` can deposit tokens for `msg.sender`
    @param addr Address to set approval on
    @param can_deposit bool - can this account deposit for `msg.sender`?
    """
    self.approved_to_deposit[addr][msg.sender] = can_deposit
Contract Info Methods¶
minter¶
 LiquidityGauge.minter() -> address: view
Getter for the minter contract address.
Returns: minter contract (address).
Source code
interface Minter:
    def token() -> address: view
    def controller() -> address: view
    def minted(user: address, gauge: address) -> uint256: view
minter: public(address)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
crv_token¶
 LiquidityGauge.crv_token() -> address: view
Getter for the CRV token address.
Returns: CRV token (address).
Source code
crv_token: public(address)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
lp_token¶
 LiquidityGauge.lp_token() -> address: view
Getter for the lp token of the liquidity pool.
Returns: lp token (address).
Source code
lp_token: public(address)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
controller¶
 LiquidityGauge.controller() -> address: view
Getter for the gauge controller contract.
Returns: gauge controller contract (address).
Source code
controller: public(address)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
voting_escorw¶
 LiquidityGauge.voting_escrow() -> address: view
Getter for the voting-escrow token.
Returns: voting-escorw contract (address).
Source code
controller: public(address)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
totalSupply¶
 LiquidityGauge.totalSupply() -> uint256: view
Getter for the total supply of the lp token.
Returns: total lp token supply (uint256).
future_epoch_time¶
 LiquidityGauge.future_epoch_time() -> uint256: view
Getter for the future epoch time.
Returns: future epoch timestamp (uint256).
Source code
interface CRV20:
    def future_epoch_time_write() -> uint256: nonpayable
    def rate() -> uint256: view
future_epoch_time: public(uint256)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
@external
def future_epoch_time_write() -> uint256:
    """
    @notice Get timestamp of the next mining epoch start
            while simultaneously updating mining parameters
    @return Timestamp of the next epoch
    """
    _start_epoch_time: uint256 = self.start_epoch_time
    if block.timestamp >= _start_epoch_time + RATE_REDUCTION_TIME:
        self._update_mining_parameters()
        return self.start_epoch_time + RATE_REDUCTION_TIME
    else:
        return _start_epoch_time + RATE_REDUCTION_TIME
working_supply¶
 LiquidityGauge.working_supply() -> uint256: view
Getter for the working supply.
Returns: working supply (uint256).
period¶
 LiquidityGauge.period() -> int128: view
Getter for the current period. This variable is updated whenever _checkpoint function is called.
Returns: period (int128).
Source code
interface Controller:
    def period() -> int128: view
    def period_write() -> int128: nonpayable
    def period_timestamp(p: int128) -> uint256: view
    def gauge_relative_weight(addr: address, time: uint256) -> uint256: view
    def voting_escrow() -> address: view
    def checkpoint(): nonpayable
    def checkpoint_gauge(addr: address): nonpayable
period: public(int128)
@internal
def _checkpoint(addr: address):
    """
    @notice Checkpoint for a user
    @param addr User address
    """
    _token: address = self.crv_token
    _controller: address = self.controller
    _period: int128 = self.period
    _period_time: uint256 = self.period_timestamp[_period]
    _integrate_inv_supply: uint256 = self.integrate_inv_supply[_period]
    rate: uint256 = self.inflation_rate
    new_rate: uint256 = rate
    prev_future_epoch: uint256 = self.future_epoch_time
    if prev_future_epoch >= _period_time:
        self.future_epoch_time = CRV20(_token).future_epoch_time_write()
        new_rate = CRV20(_token).rate()
        self.inflation_rate = new_rate
    Controller(_controller).checkpoint_gauge(self)
    _working_balance: uint256 = self.working_balances[addr]
    _working_supply: uint256 = self.working_supply
    # Update integral of 1/supply
    if block.timestamp > _period_time:
        prev_week_time: uint256 = _period_time
        week_time: uint256 = min((_period_time + WEEK) / WEEK * WEEK, block.timestamp)
        for i in range(500):
            dt: uint256 = week_time - prev_week_time
            w: uint256 = Controller(_controller).gauge_relative_weight(self, prev_week_time / WEEK * WEEK)
            if _working_supply > 0:
                if prev_future_epoch >= prev_week_time and prev_future_epoch < week_time:
                    # If we went across one or multiple epochs, apply the rate
                    # of the first epoch until it ends, and then the rate of
                    # the last epoch.
                    # If more than one epoch is crossed - the gauge gets less,
                    # but that'd meen it wasn't called for more than 1 year
                    _integrate_inv_supply += rate * w * (prev_future_epoch - prev_week_time) / _working_supply
                    rate = new_rate
                    _integrate_inv_supply += rate * w * (week_time - prev_future_epoch) / _working_supply
                else:
                    _integrate_inv_supply += rate * w * dt / _working_supply
                # On precisions of the calculation
                # rate ~= 10e18
                # last_weight > 0.01 * 1e18 = 1e16 (if pool weight is 1%)
                # _working_supply ~= TVL * 1e18 ~= 1e26 ($100M for example)
                # The largest loss is at dt = 1
                # Loss is 1e-9 - acceptable
            if week_time == block.timestamp:
                break
            prev_week_time = week_time
            week_time = min(week_time + WEEK, block.timestamp)
    _period += 1
    self.period = _period
    self.period_timestamp[_period] = block.timestamp
    self.integrate_inv_supply[_period] = _integrate_inv_supply
    # Update user-specific integrals
    self.integrate_fraction[addr] += _working_balance * (_integrate_inv_supply - self.integrate_inv_supply_of[addr]) / 10 ** 18
    self.integrate_inv_supply_of[addr] = _integrate_inv_supply
    self.integrate_checkpoint_of[addr] = block.timestamp
period_timestamp¶
 LiquidityGauge.period_timestamp(arg0: uint256) -> uint256: view
Getter for timestamp of period arg0.
Returns: period timestamp (uint256).
| Input | Type | Description | 
|---|---|---|
arg0 |  uint256 |  Period (period) |  
Source code
period_timestamp: public(uint256[100000000000000000000000000000])
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
inflation_rate¶
 LiquidityGauge.inflation_rate() -> uint256: view
Getter for the current inflation rate.
Returns: rate (uint256).
Source code
interface CRV20:
    def future_epoch_time_write() -> uint256: nonpayable
    def rate() -> uint256: view
inflation_rate: public(uint256)
@external
def __init__(lp_addr: address, _minter: address):
    """
    @notice Contract constructor
    @param lp_addr Liquidity Pool contract address
    @param _minter Minter contract address
    """
    assert lp_addr != ZERO_ADDRESS
    assert _minter != ZERO_ADDRESS
    self.lp_token = lp_addr
    self.minter = _minter
    crv_addr: address = Minter(_minter).token()
    self.crv_token = crv_addr
    controller_addr: address = Minter(_minter).controller()
    self.controller = controller_addr
    self.voting_escrow = Controller(controller_addr).voting_escrow()
    self.period_timestamp[0] = block.timestamp
    self.inflation_rate = CRV20(crv_addr).rate()
    self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write()
User Info Methods¶
balanceOf¶
 LiquidityGauge.balaceOf(arg0: address) -> uint256: view
Getter method for the current amount of LP tokens that addr has deposited into the gauge.
Returns: amount (uint256).
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  User Address | 
working_balances (more on this)¶
 LiquidityGauge.working_balances(arg0: address) -> uint256: view
Getter for the working balance of user arg0. 
Returns: working balance (uint256).
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  User Address | 
Tip
Working balance essentially is the effective balance after the has been applied.
Checkpoints¶
user_checkpoint¶
 LiquidityGauge.user_checkpoint(addr: address) -> bool:
Function to record a checkpoint for addr and therefore updating their boost.
Returns: True (bool).
| Input | Type | Description | 
|---|---|---|
addr |  address |  Address | 
Source code
@external
def user_checkpoint(addr: address) -> bool:
    """
    @notice Record a checkpoint for `addr`
    @param addr User address
    @return bool success
    """
    assert (msg.sender == addr) or (msg.sender == self.minter)  # dev: unauthorized
    self._checkpoint(addr)
    self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply)
    return True
Note
This function is only callable by addr or Minter. Checkpoint can not be triggered for another user.
kick¶
 LiquidityGauge.kick(addr: address):
Function to kick address addr for abusing their boost.
Returns: True (bool)
| Input | Type | Description | 
|---|---|---|
addr |  address |  Address to kick | 
Source code
@external
def kick(addr: address):
    """
    @notice Kick `addr` for abusing their boost
    @dev Only if either they had another voting event, or their voting escrow lock expired
    @param addr Address to kick
    """
    _voting_escrow: address = self.voting_escrow
    t_last: uint256 = self.integrate_checkpoint_of[addr]
    t_ve: uint256 = VotingEscrow(_voting_escrow).user_point_history__ts(
        addr, VotingEscrow(_voting_escrow).user_point_epoch(addr)
    )
    _balance: uint256 = self.balanceOf[addr]
    assert ERC20(self.voting_escrow).balanceOf(addr) == 0 or t_ve > t_last # dev: kick not allowed
    assert self.working_balances[addr] > _balance * TOKENLESS_PRODUCTION / 100  # dev: kick not needed
    self._checkpoint(addr)
    self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply)
    return True
Warning
This function is only callable when the current boost for addr is greater than it should be, due to an expired veCRV lock.
integrate_fraction (todo)¶
 LiquidityGauge.integrate_fraction(arg0: address) -> uint256: view
Getter for the integrate fraction.
Returns: integrate fraction (uint256).
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  User Address | 
Source code
integrate_inv_supply (todo)¶
 LiquidityGauge.integrate_inv_supply(arg0: uint256) -> uint256: view
Getter for the integrate inverse supply at period arg0.
Returns:
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  Address | 
Source code
integrate_inv_supply_of (todo)¶
 LiquidityGauge.integrate_inv_supply_of(arg0: address) -> uint256: view
todo
Returns:
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  Address | 
Source code
integrate_checkpoint_of (todo)¶
 LiquidityGauge.integrate_checkpoint_of(arg0: address) -> uint256: view
todo
Returns:
| Input | Type | Description | 
|---|---|---|
arg0 |  address |  Address |