LiquidityGaugeV3 retains a majority of LiquidityGaugeV2’s functionality such as tokenized deposits, and flexible onward staking with up to 8 reward tokens with some modifications.
Outline of modified functionality:
Ability to redirect claimed rewards to an alternative account.
Opt-in claiming of rewards on interactions with the gauge, instead of auto-claiming.
Retrieving rewards from the reward contract happens at a minimum of once an hour, for reduced gas costs.
Expose the amount of claimed and claimable rewards for users.
Removal of claim_historic_rewards function.
Modify claimable_reward to be a slightly less accurate view function.
Reward tokens can no longer be removed once set, adding more tokens requires providing the array of reward_tokens with any new tokens appended.
deposit(_value, _to) and withdraw(_value, _to) functions have an additional optional argument _claim_rewards, which when set to True will claim any pending rewards.
As this gauge maintains a similar API to LiquidityGaugeV2, the documentation only covers functions that were added or modified since the previous version.
Source Code
Source code of the LiquidityGaugeV3 can be found on Github. The following view methods and functions are using the alUSD/3crv gauge as an example.
Function to set the rewards receiver for any rewards claimed via claim_rewards.
Input
Type
Description
_receiver
address
Reward Receiver Address
Source code
rewards_receiver:public(HashMap[address,address])@externaldefset_rewards_receiver(_receiver:address):""" @notice Set the default reward receiver for the caller. @dev When set to ZERO_ADDRESS, rewards are sent to the caller @param _receiver Receiver address for any rewards claimed via `claim_rewards` """self.rewards_receiver[msg.sender]=_receiver
Getter for the timestamp of the last claim from reward_contract.
Returns: timestamp (uint256).
Source code
@view@externaldeflast_claim()->uint256:""" @notice Epoch timestamp of the last call to claim from `reward_contract` @dev Rewards are claimed at most once per hour in order to reduce gas costs """returnshift(self.reward_data,-160)
Function to claim all available reward tokens for _addr.
Input
Type
Description
_addr
address
Address to claim rewards for
_receiver
address
Receiver of the rewards. Defaults to msg.sender.
Source code
@external@nonreentrant('lock')defclaim_rewards(_addr:address=msg.sender,_receiver:address=ZERO_ADDRESS):""" @notice Claim available reward tokens for `_addr` @param _addr Address to claim for @param _receiver Address to transfer rewards to - if set to ZERO_ADDRESS, uses the default reward receiver for the caller """if_receiver!=ZERO_ADDRESS:assert_addr==msg.sender# dev: cannot redirect when claiming for another userself._checkpoint_rewards(_addr,self.totalSupply,True,_receiver)@internaldef_checkpoint_rewards(_user:address,_total_supply:uint256,_claim:bool,_receiver:address):""" @notice Claim pending rewards and checkpoint rewards for a user """# load reward tokens and integrals into memoryreward_tokens:address[MAX_REWARDS]=empty(address[MAX_REWARDS])reward_integrals:uint256[MAX_REWARDS]=empty(uint256[MAX_REWARDS])foriinrange(MAX_REWARDS):token:address=self.reward_tokens[i]iftoken==ZERO_ADDRESS:breakreward_tokens[i]=tokenreward_integrals[i]=self.reward_integral[token]reward_data:uint256=self.reward_dataif_total_supply!=0andreward_data!=0andblock.timestamp>shift(reward_data,-160)+CLAIM_FREQUENCY:# track balances prior to claimingreward_balances:uint256[MAX_REWARDS]=empty(uint256[MAX_REWARDS])foriinrange(MAX_REWARDS):token:address=self.reward_tokens[i]iftoken==ZERO_ADDRESS:breakreward_balances[i]=ERC20(token).balanceOf(self)# claim from reward contractreward_contract:address=convert(reward_data%2**160,address)raw_call(reward_contract,slice(self.reward_sigs,8,4))# dev: bad claim sigself.reward_data=convert(reward_contract,uint256)+shift(block.timestamp,160)# get balances after claim and calculate new reward integralsforiinrange(MAX_REWARDS):token:address=reward_tokens[i]iftoken==ZERO_ADDRESS:breakdI:uint256=10**18*(ERC20(token).balanceOf(self)-reward_balances[i])/_total_supplyifdI>0:reward_integrals[i]+=dIself.reward_integral[token]=reward_integrals[i]if_user!=ZERO_ADDRESS:user_balance:uint256=self.balanceOf[_user]receiver:address=_receiverif_claimand_receiver==ZERO_ADDRESS:# if receiver is not explicitly declared, check if a default receiver is setreceiver=self.rewards_receiver[_user]ifreceiver==ZERO_ADDRESS:# if no default receiver is set, direct claims to the userreceiver=_user# calculate new user reward integral and transfer any owed rewardsforiinrange(MAX_REWARDS):token:address=reward_tokens[i]iftoken==ZERO_ADDRESS:breakintegral:uint256=reward_integrals[i]integral_for:uint256=self.reward_integral_for[token][_user]ifintegral_for<integralor_total_supply==0:self.reward_integral_for[token][_user]=integralclaim_data:uint256=self.claim_data[_user][token]new_claimable:uint256=user_balance*(integral-integral_for)/10**18total_claimed:uint256=claim_data%2**128total_claimable:uint256=shift(claim_data,-128)+new_claimableif_claimandtotal_claimable>0:response:Bytes[32]=raw_call(token,concat(method_id("transfer(address,uint256)"),convert(receiver,bytes32),convert(total_claimable,bytes32),),max_outsize=32,)iflen(response)!=0:assertconvert(response,bool)self.claim_data[_user][token]=total_claimed+total_claimableelifnew_claimable>0:self.claim_data[_user][token]=total_claimed+shift(total_claimable,128)
Getter for the amount of already-claimed reward tokens _token for _addr.
Returns: claimable reward token amount (uint256).
Input
Type
Description
_addr
address
User Address
_token
address
Reward Token Address
Source code
# user -> [uint128 claimable amount][uint128 claimed amount]claim_data:HashMap[address,HashMap[address,uint256]]@view@externaldefclaimed_reward(_addr:address,_token:address)->uint256:""" @notice Get the number of already-claimed reward tokens for a user @param _addr Account to get reward amount for @param _token Token to get reward amount for @return uint256 Total amount of `_token` already claimed by `_addr` """returnself.claim_data[_addr][_token]%2**128
Getter for the number of claimable reward tokens for a user. This getter does not include pending claimable amounts in reward_contract.
Returns: claimable reward token amount (uint256).
Input
Type
Description
_addr
address
Address to claim rewards for
_token
address
Receiver of the rewards. Defaults to msg.sender.
Source code
# user -> [uint128 claimable amount][uint128 claimed amount]claim_data:HashMap[address,HashMap[address,uint256]]@view@externaldefclaimable_reward(_addr:address,_token:address)->uint256:""" @notice Get the number of claimable reward tokens for a user @dev This call does not consider pending claimable amount in `reward_contract`. Off-chain callers should instead use `claimable_rewards_write` as a view method. @param _addr Account to get reward amount for @param _token Token to get reward amount for @return uint256 Claimable reward token amount """returnshift(self.claim_data[_addr][_token],-128)
>>>LiquidityGaugeV3.claimable_rewards('todo'):
todo
Get the number of claimable reward tokens for a user. This function should be manually changed to “view” in the ABI. Calling it via a transaction will checkpoint a user’s rewards updating the value of claimable_reward. This function does not claim/distribute pending rewards for a user.
Returns: claimable reward token (uint256).
Source code
# user -> [uint128 claimable amount][uint128 claimed amount]claim_data:HashMap[address,HashMap[address,uint256]]@external@nonreentrant('lock')defclaimable_reward_write(_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 """ifself.reward_tokens[0]!=ZERO_ADDRESS:self._checkpoint_rewards(_addr,self.totalSupply,False,ZERO_ADDRESS)returnshift(self.claim_data[_addr][_token],-128)
>>>LiquidityGaugeV3.claimable_reward_write('todo'):
todo