MaverickV2Reward

Inherits: Nft, RewardAccounting, IMaverickV2Reward, Multicall, ReentrancyGuard

This reward contract is used to reward users who stake their stakingToken in this contract. The stakingToken can be any token with an ERC-20 interface including BoostedPosition LP tokens.

Incentive providers can permissionlessly add incentives to this contract that will be disbursed to stakers pro rata over a given duration that the incentive provider specifies as they add incentives. Incentives can be denominated in one of 5 possible reward tokens that the reward contract creator specifies on contract creation.

The contract creator also has the option of specifying veTokens associated with each of the up-to-5 reward tokens. When incentivizing a rewardToken that has a veToken specified, the staking users will receive a boost to their rewards depending on 1) how much ve tokens they own and 2) how long they stake their rewards disbursement.

State Variables

FOUR_YEARS

uint256 internal constant FOUR_YEARS = 1460 days;

BASE_STAKING_FACTOR

uint256 internal constant BASE_STAKING_FACTOR = 0.2e18;

STAKING_FACTOR_SLOPE

uint256 internal constant STAKING_FACTOR_SLOPE = 0.8e18;

BASE_PRORATA_FACTOR

uint256 internal constant BASE_PRORATA_FACTOR = 0.75e18;

PRORATA_FACTOR_SLOPE

uint256 internal constant PRORATA_FACTOR_SLOPE = 0.25e18;

UNBOOSTED_MIN_TIME_GAP

This function retrieves the minimum time gap in seconds that must have elasped between calls to pushUnboostedToVe().

uint256 public constant UNBOOSTED_MIN_TIME_GAP = 1 days;

stakingToken

This function retrieves the address of the token used for staking in this reward contract.

IERC20 public immutable stakingToken;

rewardToken0

IERC20 private immutable rewardToken0;

rewardToken1

IERC20 private immutable rewardToken1;

rewardToken2

IERC20 private immutable rewardToken2;

rewardToken3

IERC20 private immutable rewardToken3;

rewardToken4

IERC20 private immutable rewardToken4;

veToken0

IMaverickV2VotingEscrow private immutable veToken0;

veToken1

IMaverickV2VotingEscrow private immutable veToken1;

veToken2

IMaverickV2VotingEscrow private immutable veToken2;

veToken3

IMaverickV2VotingEscrow private immutable veToken3;

veToken4

IMaverickV2VotingEscrow private immutable veToken4;

_rewardGetter

mapping(address => address) private _rewardGetter;

MAX_DURATION

uint256 public constant MAX_DURATION = 40 days;

MIN_DURATION

uint256 public constant MIN_DURATION = 3 days;

rewardData

RewardData[5] public rewardData;

rewardTokenCount

uint256 public immutable rewardTokenCount;

vault

IMaverickV2RewardVault public immutable vault;

Functions

constructor

constructor(
    string memory name_,
    string memory symbol_,
    IERC20 _stakingToken,
    IERC20[] memory rewardTokens,
    IMaverickV2VotingEscrow[] memory veTokens
) Nft(name_, symbol_);

checkAmount

modifier checkAmount(uint256 amount);

mint

Stake Management Functions

function mint(address recipient) public returns (uint256 tokenId);

Parameters

NameTypeDescription

recipient

address

The address that owns the output NFT

mintToSender

Mints an NFT stake to caller. This NFT will not possesses any assets until a user stakes asset to the NFT tokenId as part of a separate call.

function mintToSender() public returns (uint256 tokenId);

stake

This function stakes the staking tokens to the specified tokenId. If tokenId=0 is passed in, then this function will look up the caller's tokenIds and stake to the zero-index tokenId. If the user does not yet have a staking NFT tokenId, this function will mint one for the sender and stake to that newly-minted tokenId.

The amount staked is derived by looking at the new balance on the vault(). So, for staking to yield a non-zero balance, the user will need to have transfered the stakingToken() to the vault() prior to calling stake. Note, tokens sent to the reward contract instead of the vault will not be stakable and instead will be eligible to be disbursed as rewards to stakers. This is an advanced usage function. If in doubt about the mechanics of staking, use transferAndStake() instead.

function stake(uint256 tokenId) public returns (uint256 amount, uint256 stakedTokenId);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose tokens to stake.

Returns

NameTypeDescription

amount

uint256

The amount of staking tokens staked (uint256).

stakedTokenId

uint256

TokenId where liquidity was staked to. This may differ from the input tokenIf if the input tokenId=0.

transferAndStake

This function transfers a specified amount of staking tokens from the caller to the staking vault() and stakes them on the recipient's behalf. The user has to approve this reward contract to transfer the staking token on their behalf for this function not to revert.

function transferAndStake(uint256 tokenId, uint256 _amount) public returns (uint256 amount, uint256 stakedTokenId);

Parameters

NameTypeDescription

tokenId

uint256

Nft tokenId to stake for the staked tokens.

_amount

uint256

The amount of staking tokens to transfer and stake.

Returns

NameTypeDescription

amount

uint256

The amount of staking tokens staked. May differ from input if there were unstaked tokens in the vault prior to this call.

stakedTokenId

uint256

TokenId where liquidity was staked to. This may differ from the input tokenIf if the input tokenId=0.

unstakeToOwner

This function initiates unstaking of a specified amount of staking tokens for the caller and sends them to a recipient.

function unstakeToOwner(uint256 tokenId, uint256 amount) public onlyTokenIdAuthorizedUser(tokenId);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose tokens to unstake.

amount

uint256

The amount of staking tokens to unstake (uint256).

unstake

This function initiates unstaking of a specified amount of staking tokens on behalf of a specific tokenId and sends them to a recipient.

To unstakeFrom, the caller must have an approval allowance of at least amount. Approvals follow the ERC-20 approval/allowance interface.

function unstake(uint256 tokenId, address recipient, uint256 amount) public onlyTokenIdAuthorizedUser(tokenId);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose tokens to unstake.

recipient

address

The address to which the unstaked tokens will be sent.

amount

uint256

The amount of staking tokens to unstake (uint256).

getRewardToOwner

This function retrieves the claimable reward for a specific reward token and stake duration for the caller.

function getRewardToOwner(uint256 tokenId, uint8 rewardTokenIndex, uint256 stakeDuration)
    external
    onlyTokenIdAuthorizedUser(tokenId)
    returns (RewardOutput memory);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose reward to claim.

rewardTokenIndex

uint8

The internal index of the reward token.

stakeDuration

uint256

The duration (in seconds) for which the rewards were staked.

Returns

NameTypeDescription

<none>

RewardOutput

rewardOutput A RewardOutput struct containing details about the claimable reward.

getRewardToOwnerForExistingVeLockup

This function retrieves the claimable reward for a specific reward token, stake duration, and lockup ID for the caller.

function getRewardToOwnerForExistingVeLockup(
    uint256 tokenId,
    uint8 rewardTokenIndex,
    uint256 stakeDuration,
    uint256 lockupId
) external onlyTokenIdAuthorizedUser(tokenId) returns (RewardOutput memory);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose reward to claim.

rewardTokenIndex

uint8

The internal index of the reward token.

stakeDuration

uint256

The duration (in seconds) for which the rewards were staked.

lockupId

uint256

The unique identifier for the specific lockup (optional).

Returns

NameTypeDescription

<none>

RewardOutput

rewardOutput A RewardOutput struct containing details about the claimable reward.

getReward

This function retrieves the claimable reward for a specific reward token and stake duration for a specified tokenId and sends it to a recipient. If the reward is staked in the corresponding veToken, a new lockup in the ve token will be created.

function getReward(uint256 tokenId, address recipient, uint8 rewardTokenIndex, uint256 stakeDuration)
    external
    onlyTokenIdAuthorizedUser(tokenId)
    returns (RewardOutput memory);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose reward to claim.

recipient

address

The address to which the claimed reward will be sent.

rewardTokenIndex

uint8

The internal index of the reward token.

stakeDuration

uint256

The duration (in seconds) for which the rewards will be staked in the ve contract.

Returns

NameTypeDescription

<none>

RewardOutput

rewardOutput A RewardOutput struct containing details about the claimable reward.

getRewardForExistingVeLockup

This function retrieves the claimable reward for a specific reward token, stake duration, lockup ID, and sends it to a recipient for a specified tokenId.

If the reward is staked in the corresponding veToken, the lockupId lockup will be extended on the veToken contract. Any existing lock on that lockupId will also be extended. To use this function, this reward contract will have to be approved as an extender on the veToken contract.

function getRewardForExistingVeLockup(
    uint256 tokenId,
    address recipient,
    uint8 rewardTokenIndex,
    uint256 stakeDuration,
    uint256 lockupId
) external onlyTokenIdAuthorizedUser(tokenId) returns (RewardOutput memory);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId whose reward to claim.

recipient

address

The address to which the claimed reward will be sent.

rewardTokenIndex

uint8

The internal index of the reward token.

stakeDuration

uint256

The duration (in seconds) for which the rewards will be staked in the ve contract.

lockupId

uint256

The unique identifier for the specific lockup to extend on the veToken contract.

Returns

NameTypeDescription

<none>

RewardOutput

rewardOutput A RewardOutput struct containing details about the claimable reward.

pushUnboostedToVe

Admin Functions

function pushUnboostedToVe(uint8 rewardTokenIndex)
    public
    returns (uint128 amount, uint48 timepoint, uint256 batchIndex);

Parameters

NameTypeDescription

rewardTokenIndex

uint8

The internal index of the reward token.

Returns

NameTypeDescription

amount

uint128

The amount of unboosted rewards pushed (uint128).

timepoint

uint48

The timestamp associated with the pushed rewards (uint48).

batchIndex

uint256

The batch index for the pushed rewards (uint256).

rewardInfo

View Functions

function rewardInfo() public view returns (RewardInfo[] memory info);

Returns

NameTypeDescription

info

RewardInfo[]

An array of RewardInfo structs containing details about each reward token.

contractInfo

This function retrieves information about all available reward tokens and overall contract details for this reward contract.

function contractInfo() external view returns (RewardInfo[] memory info, ContractInfo memory _contractInfo);

Returns

NameTypeDescription

info

RewardInfo[]

An array of RewardInfo structs containing details about each reward token.

_contractInfo

ContractInfo

A ContractInfo struct containing overall contract details.

earned

This function calculates the total amount of all earned rewards for a specific tokenId across all reward tokens.

function earned(uint256 tokenId) public view returns (EarnedInfo[] memory earnedInfo);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId for which to calculate earned rewards.

Returns

NameTypeDescription

earnedInfo

EarnedInfo[]

An array of EarnedInfo structs containing details about earned rewards for each supported token.

earned

This function calculates the total amount of all earned rewards for a specific tokenId across all reward tokens.

function earned(uint256 tokenId, IERC20 rewardTokenAddress) public view returns (uint256);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId for which to calculate earned rewards.

rewardTokenAddress

IERC20

Returns

NameTypeDescription

<none>

uint256

earnedInfo An array of EarnedInfo structs containing details about earned rewards for each supported token.

_earned

function _earned(uint256 tokenId, RewardData storage data) internal view returns (uint256);

tokenIndex

This function retrieves the internal index associated with a specific reward token address.

function tokenIndex(IERC20 rewardToken) public view returns (uint8 rewardTokenIndex);

Parameters

NameTypeDescription

rewardToken

IERC20

The address of the reward token to get the index for.

Returns

NameTypeDescription

rewardTokenIndex

uint8

The internal index of the token within the reward contract (uint8).

rewardTokenByIndex

This function retrieves the reward token contract associated with a specific index within the reward contract.

function rewardTokenByIndex(uint8 index) public view returns (IERC20 output);

Parameters

NameTypeDescription

index

uint8

The index of the reward token to retrieve.

Returns

NameTypeDescription

output

IERC20

The IERC20 contract associated with the index.

veTokenByIndex

This function retrieves the veToken contract associated with a specific index within the reward contract.

function veTokenByIndex(uint8 index) public view returns (IMaverickV2VotingEscrow output);

Parameters

NameTypeDescription

index

uint8

The index of the veToken to retrieve.

Returns

NameTypeDescription

output

IMaverickV2VotingEscrow

The IMaverickV2VotingEscrow contract associated with the index.

tokenList

This function retrieves a list of all supported tokens in the reward contract.

function tokenList(bool includeStakingToken) public view returns (IERC20[] memory tokens);

Parameters

NameTypeDescription

includeStakingToken

bool

A flag indicating whether to include the staking token in the list.

Returns

NameTypeDescription

tokens

IERC20[]

An array of IERC20 token addresses.

_updateGlobalReward

Updates the global reward state for a given reward token.

Each time a user stakes or unstakes or a incentivizer adds incentives, this function must be called in order to checkpoint the rewards state before the new stake/unstake/notify occurs.

function _updateGlobalReward(RewardData storage data) internal;

_updateReward

Updates the reward state associated with an tokenId. Also updates the global reward state.

This function checkpoints the data for a user before they stake/unstake.

function _updateReward(uint256 tokenId, RewardData storage data) internal;

_deltaEarned

Amount an tokenId has earned since that tokenId last did a stake/unstake.

deltaEarned = balance * (rewardPerToken - userRewardPerTokenPaid)

function _deltaEarned(uint256 tokenId, RewardData storage data) internal view returns (uint256);

_deltaRewardPerToken

Amount of new rewards accrued to tokens since last checkpoint.

function _deltaRewardPerToken(RewardData storage data) internal view returns (uint256);

_lastTimeRewardApplicable

The smaller of: 1) time of end of reward period and 2) current block timestamp.

function _lastTimeRewardApplicable(uint256 dataFinishAt) internal view returns (uint256);

_updateAllRewards

Update all rewards.

function _updateAllRewards(uint256 tokenId) internal;

_stake

Internal User Functions

function _stake(uint256 tokenId) internal nonReentrant returns (uint256 amount);

_unstake

Functions using this function must check that sender has access to the tokenId for this to be / safely called.

function _unstake(uint256 tokenId, address recipient, uint256 amount) internal nonReentrant checkAmount(amount);

boostedAmount

This function calculates the boosted amount an tokenId would receive based on their veToken balance and stake duration.

function boostedAmount(uint256 tokenId, IMaverickV2VotingEscrow veToken, uint256 rawAmount, uint256 stakeDuration)
    public
    view
    returns (uint256 earnedAmount, bool asVe);

Parameters

NameTypeDescription

tokenId

uint256

The address of the tokenId for which to calculate the boosted amount.

veToken

IMaverickV2VotingEscrow

The IMaverickV2VotingEscrow contract representing the veToken used for boosting.

rawAmount

uint256

The raw (unboosted) amount.

stakeDuration

uint256

The duration (in seconds) for which the rewards would be staked.

Returns

NameTypeDescription

earnedAmount

uint256

The boosted amount the tokenId would receive (uint256).

asVe

bool

A boolean indicating whether the boosted amount is staked in the veToken (true) or is disbursed without ve staking required (false).

_boostAndPay

Internal function for computing the boost and then transferring/staking the resulting rewards. Can not be safely called without checking that the caller has permissions to access the tokenId.

function _boostAndPay(
    uint256 tokenId,
    address recipient,
    IERC20 rewardToken,
    IMaverickV2VotingEscrow veToken,
    uint256 rawAmount,
    uint256 stakeDuration,
    uint256 lockupId
) internal returns (RewardOutput memory rewardOutput);

_getReward

Internal getReward function. Can not be safely called without checking that the caller has permissions to access the account.

function _getReward(uint256 tokenId, address recipient, uint8 rewardTokenIndex, uint256 stakeDuration, uint256 lockupId)
    internal
    nonReentrant
    returns (RewardOutput memory rewardOutput);

notifyRewardAmount

Add Reward

The duration of the distribution may not be the same as the input duration. If this notify amount is less than the amount already pending disbursement, then this new amount will be distributed as the same rate as the existing rate and that will dictate the duration. Alternatively, if the amount is more than the pending disbursement, then the input duration will be honored and all pending disbursement tokens will also be distributed at this newly set rate.

function notifyRewardAmount(IERC20 rewardToken, uint256 duration) public nonReentrant returns (uint256);

Parameters

NameTypeDescription

rewardToken

IERC20

The address of the reward token to distribute.

duration

uint256

The duration (in seconds) over which to distribute the rewards.

Returns

NameTypeDescription

<none>

uint256

_duration The duration in seconds that the incentives will be distributed over.

transferAndNotifyRewardAmount

This function transfers a specified amount of reward tokens from the caller to distribute them over a defined duration. The caller will need to approve this rewards contract to make the transfer on the caller's behalf. See notifyRewardAmount for details of how the duration is set by the rewards contract.

function transferAndNotifyRewardAmount(IERC20 rewardToken, uint256 duration, uint256 amount) public returns (uint256);

Parameters

NameTypeDescription

rewardToken

IERC20

The address of the reward token to transfer.

duration

uint256

The duration (in seconds) over which to distribute the rewards.

amount

uint256

The amount of reward tokens to transfer.

Returns

NameTypeDescription

<none>

uint256

_duration The duration in seconds that the incentives will be distributed over.

_notifyRewardAmount

Called by reward depositor to recompute the reward rate. If notifier sends more than remaining amount, then notifier sets the rate. Else, we extend the duration at the current rate.

function _notifyRewardAmount(IERC20 rewardToken, uint256 duration) internal returns (uint256);

tokenURI

Required Overrides

function tokenURI(uint256 tokenId) public view virtual override(Nft, INft) returns (string memory);

name

function name() public view override(INft, Nft) returns (string memory);

symbol

function symbol() public view override(INft, Nft) returns (string memory);

Structs

RewardData

struct RewardData {
    uint64 finishAt;
    uint64 updatedAt;
    uint128 rewardRate;
    uint128 escrowedReward;
    uint128 unboostedAmount;
    uint256 lastUnboostedPushTimestamp;
    uint256 rewardPerTokenStored;
    mapping(uint256 tokenId => uint256) userRewardPerTokenPaid;
    mapping(uint256 tokenId => uint128) rewards;
}

Last updated