The V2 liquidity gauge adds a full ERC20 interface to the gauge, tokenizing deposits so they can be directly transferred between accounts without having to withdraw and redeposit. It also improves flexibility for onward staking, allowing staking to be enabled or disabled at any time and handling up to eight reward tokens at once.
Source Code
Source code of the LiquidityGaugeV2 can be found on Github. The following view methods and functions are using the AAVE liquidity gauge.
future_admin:public(address)# Can and will be a smart contract@externaldefcommit_transfer_ownership(addr:address):""" @notice Transfer ownership of GaugeController to `addr` @param addr Address to have ownership transferred to """assertmsg.sender==self.admin# dev: admin onlyself.future_admin=addrlogCommitOwnership(addr)@externaldefaccept_transfer_ownership():""" @notice Accept a pending ownership transfer """_admin:address=self.future_adminassertmsg.sender==_admin# dev: future admin onlyself.admin=_adminlogApplyOwnership(_admin)
eventCommitOwnership:admin:addressadmin:public(address)future_admin:public(address)# Can and will be a smart contract@externaldefcommit_transfer_ownership(addr:address):""" @notice Transfer ownership of GaugeController to `addr` @param addr Address to have ownership transferred to """assertmsg.sender==self.admin# dev: admin onlyself.future_admin=addrlogCommitOwnership(addr)
eventApplyOwnership:admin:addressadmin:public(address)future_admin:public(address)# Can and will be a smart contract@externaldefaccept_transfer_ownership():""" @notice Accept a pending ownership transfer """_admin:address=self.future_adminassertmsg.sender==_admin# dev: future admin onlyself.admin=_adminlogApplyOwnership(_admin)
Getter for the number of claimable reward token _token for user addr.
Returns: claimable reward amount (uint256).
Input
Type
Description
_addr
address
Address to get reward amount for
_token
address
Token to get reward amount for
Warning
This function determines the claimable reward by actually claiming and then returning the received amount. As such, it is state changing and only of use to off-chain integrators. The mutability should be manually changed to view within the ABI.
Source code
@external@nonreentrant('lock')defclaimable_reward(_addr:address,_token:address)->uint256:""" @notice Get the number of claimable reward tokens for a user @dev This function should be manually changed to "view" in the ABI Calling it via a transaction will claim available reward tokens @param _addr Account to get reward amount for @param _token Token to get reward amount for @return uint256 Claimable reward token amount """claimable:uint256=ERC20(_token).balanceOf(_addr)ifself.reward_contract!=ZERO_ADDRESS:self._checkpoint_rewards(_addr,self.totalSupply)claimable=ERC20(_token).balanceOf(_addr)-claimableintegral:uint256=self.reward_integral[_token]integral_for:uint256=self.reward_integral_for[_token][_addr]ifintegral_for<integral:claimable+=self.balanceOf[_addr]*(integral-integral_for)/10**18returnclaimable
Address to claim for (defaulted to msg.sender (caller) if no input)
Source code
@external@nonreentrant('lock')defclaim_rewards(_addr:address=msg.sender):""" @notice Claim available reward tokens for `_addr` @param _addr Address to claim for """self._checkpoint_rewards(_addr,self.totalSupply)
Address of staking contract. Set to ZERO_ADDRESS if staking rewards are being removed
_sigs
bytes32
A concatenation of three four-byte function signatures: stake, withdraw and getReward. The signatures are then right padded with empty bytes.
_reward_tokens
address
Array of reward tokens received from the staking contract
Note
This action is only possible via the contract admin. It cannot be called when the gauge has no deposits. As a safety precaution, this call validates all the signatures with the following sequence of actions: 1. LP tokens are deposited into the new staking contract, verifying that the deposit signature is correct. 2. balanceOf is called on the LP token to confirm that the gauge’s token balance is not zero. 3. The LP tokens are withdrawn, verifying that the withdraw function signature is correct. 4. balanceOf is called on the LP token again, to confirm that the gauge has successfully withdrawn it’s entire balance. 5. A call to claim rewards is made to confirm that it does not revert.
These checks are required to protect against an incorrectly designed staking contract or incorrectly structured input arguments.
Note
It is also possible to claim from a reward contract that does not require onward staking. In this case, use 00000000 for the function selectors for both staking and withdrawing.
Source code
@external@nonreentrant('lock')defset_rewards(_reward_contract:address,_sigs:bytes32,_reward_tokens:address[MAX_REWARDS]):""" @notice Set the active reward contract @dev A reward contract cannot be set while this contract has no deposits @param _reward_contract Reward contract address. Set to ZERO_ADDRESS to disable staking. @param _sigs Four byte selectors for staking, withdrawing and claiming, right padded with zero bytes. If the reward contract can be claimed from but does not require staking, the staking and withdraw selectors should be set to 0x00 @param _reward_tokens List of claimable tokens for this reward contract """assertmsg.sender==self.adminlp_token:address=self.lp_tokencurrent_reward_contract:address=self.reward_contracttotal_supply:uint256=self.totalSupplyifcurrent_reward_contract!=ZERO_ADDRESS:self._checkpoint_rewards(ZERO_ADDRESS,total_supply)withdraw_sig:Bytes[4]=slice(self.reward_sigs,4,4)ifconvert(withdraw_sig,uint256)!=0:iftotal_supply!=0:raw_call(current_reward_contract,concat(withdraw_sig,convert(total_supply,bytes32)))ERC20(lp_token).approve(current_reward_contract,0)if_reward_contract!=ZERO_ADDRESS:assert_reward_contract.is_contract# dev: not a contractsigs:bytes32=_sigsdeposit_sig:Bytes[4]=slice(sigs,0,4)withdraw_sig:Bytes[4]=slice(sigs,4,4)ifconvert(deposit_sig,uint256)!=0:# need a non-zero total supply to verify the sigsasserttotal_supply!=0# dev: zero total supplyERC20(lp_token).approve(_reward_contract,MAX_UINT256)# it would be Very Bad if we get the signatures wrong here, so# we do a test deposit and withdrawal prior to setting themraw_call(_reward_contract,concat(deposit_sig,convert(total_supply,bytes32)))# dev: failed depositassertERC20(lp_token).balanceOf(self)==0raw_call(_reward_contract,concat(withdraw_sig,convert(total_supply,bytes32)))# dev: failed withdrawassertERC20(lp_token).balanceOf(self)==total_supply# deposit and withdraw are good, time to make the actual depositraw_call(_reward_contract,concat(deposit_sig,convert(total_supply,bytes32)))else:assertconvert(withdraw_sig,uint256)==0# dev: withdraw without depositself.reward_contract=_reward_contractself.reward_sigs=_sigsforiinrange(MAX_REWARDS):if_reward_tokens[i]!=ZERO_ADDRESS:self.reward_tokens[i]=_reward_tokens[i]elifself.reward_tokens[i]!=ZERO_ADDRESS:self.reward_tokens[i]=ZERO_ADDRESSelse:asserti!=0# dev: no reward tokenbreakif_reward_contract!=ZERO_ADDRESS:# do an initial checkpoint to verify that claims are workingself._checkpoint_rewards(ZERO_ADDRESS,total_supply)
is_killed:public(bool)@externaldefset_killed(_is_killed:bool):""" @notice Set the killed status for this contract @dev When killed, the gauge always yields a rate of 0 and so cannot mint CRV @param _is_killed Killed status to set """assertmsg.sender==self.adminself.is_killed=_is_killed
is_killed:public(bool)@externaldefset_killed(_is_killed:bool):""" @notice Set the killed status for this contract @dev When killed, the gauge always yields a rate of 0 and so cannot mint CRV @param _is_killed Killed status to set """assertmsg.sender==self.adminself.is_killed=_is_killed
Getter for the decimals of the liquidity gauge token.
Returns: decimals (uint256).
Source code
@view@externaldefdecimals()->uint256:""" @notice Get the number of decimals for this token @dev Implemented as a view method to reduce gas costs @return uint256 decimal places """return18