Cardinal
Search
K

Reward Distributor

While just using a stake pool can be sufficient to keep track of total stake duration and lock the NFT in the user's wallet, a reward distributor can be optionally added to distribute rewards to staked NFTs.
Reward distributor, our provided implementation, is modeled similar to Stake pool, having both a reward_distributor and a reward_entry. The reward entry is unique for each mint and keeps track of how many rewards have been given out to that NFT to ensure that it gets its fair share.
#[account]
pub struct RewardDistributor {
pub bump: u8,
pub stake_pool: Pubkey,
pub kind: u8,
pub authority: Pubkey,
pub reward_mint: Pubkey,
pub reward_amount: u64,
pub reward_duration_seconds: u64,
pub rewards_issued: u64,
pub max_supply: Option<u64>,
}
#[account]
pub struct RewardEntry {
pub bump: u8,
pub mint: Pubkey,
pub reward_distributor: Pubkey,
pub reward_seconds_received: u64,
pub reward_amount_received: u64,
pub multiplier: u64,
}
A reward_distributor can be of 2 different kinds, Mint or Treasury/Transfer
Mint
  • If choosing reward distributor of kind Mint, the mint authority of the reward_mint will be transfered to the reward distributor upon initialization.
  • This means that it can mint unlimited tokens to stakers up until an optional max_supply
  • The authority (creator) of this reward distributor can always reclaim the mint_authority by closing the reward_distributor using the close instruction.
Treasury/Transfer
  • With this kind, an initial supply of tokens of the given reward_mint will be transferred to the reward_distributor upon intialization.
  • The reward distributor will be able to distribute rewards from its treasury / supply until it runs out or hits an optional max_supply.
  • If the reward distributor is running out of tokens, anyone can simply transfer more tokens to it directly via a wallet using the transfer instruction. The tokens are held in the associated_token_account of the reward_distributor for the reward_mint.
In both kinds of reward distributors, if the max_supply is hit, or the treasury runs out, the remaining rewards will be given out and the reward_seconds_received will be partially updated.
Because reward distributor is modeled separately from the stake_pool, a user can optionally claim their rewards at any time for the amount of time they have staked. Typically, this is done automatically when calling unstake in the client.
Reward distributor is a basic implementation that achieves a fixed linear payout structure, but modeling this as a separate program allows for any complex reward distribution logic to be implemented in a similar manner. Other implementations of other reward distributors are welcomed and encouraged. Examples that could be built:
  • Tiered reward system that distributes rewards based on specified stake tiers
  • Arbitrary non-linear reward functions
  • NFT mutator that modifies metadata based on stake duration
  • Probabilistic distributor that may or may not give a reward depending on the outcome of a random iteration. This could apply to a quest or mission with a given probability of success
Reward Distributor Multipliers
Multipliers is a feature that can tap a given token (via its reward_entry) to receive more rewards than the others. Only the authority of the pool can change the multiplier by calling the update_reward_entry instruction.
  • Modeling this separately allows the user/authority to either initialize their own reward_entries and update their multipliers later on or run arbitrary events/bonuses for specific NFTs at any time.
  • In addition, the authority may initialize all the entries up front and set the correct/desired multipliers for their NFTs such that it will correctly allocate when the user first stakes.