Account-Based Referrals
What are Account-Based Referrals?
The Account-Based Referral System rewards players for bringing new participants to Shrimp Farm.
When making a buy, players can optionally pass a referrer's wallet address.
Both the referrer and the new player get rewards from the transaction.
Referrals work through two key rewards:
- Referrer Fee: The referring player gets a percentage of the buy amount
- Cashback: The new player gets a discount on their purchase
Both amounts are tracked separately and can be claimed later through the game's reward system.
How the program handles referrals
Below is a plain‑English walkthrough of the referral flow. Feel free to expand the code blocks for the exact Rust implementation.
1 Account Structure (account.rs)
When a player makes a buy, they can include referral accounts:
referrer: The wallet address of the referring playerreferrer_state: The PlayerState account for that referrer- Both accounts are optional—players can buy without referrals
Show the Rust
account.rs
#[derive(Accounts)]
pub struct BuyAccounts<'info> {
#[account(mut)]
pub player: Signer<'info>,
/// CHECK: Custom check
#[account(address = game_state.authority)]
pub authority: AccountInfo<'info>,
#[account(
mut,
seeds = [GameState::SEED, authority.key().as_ref()],
bump
)]
pub game_state: Box<Account<'info, GameState>>,
#[account(
init_if_needed,
payer = player,
space = 8 + PlayerState::INIT_SPACE,
seeds = [player.key().as_ref(), PlayerState::SEED, authority.key().as_ref()],
bump
)]
pub player_state: Box<Account<'info, PlayerState>>,
#[account(
init_if_needed,
payer = player,
space = 8 + PlayerState::INIT_SPACE,
seeds = [referrer.as_ref().unwrap().key().as_ref(), PlayerState::SEED, authority.key().as_ref()],
bump
)]
pub referrer_state: Option<Box<Account<'info, PlayerState>>>,
/// CHECK: Can be any account
#[account()]
pub referrer: Option<AccountInfo<'info>>,
// ... other accounts
}
2 Processing Referrals (buy.rs / premarket_buy.rs)
During any buy transaction, the contract checks for referral accounts:
- Extract the referrer's public key if provided
- Validate the referrer exists and is registered
- Calculate fees and update both player states
- Track the total referral balance in the game state
Show the Rust
instructions/buy.rs
// Handle referrals
let referrer_key = referrer.as_ref().map(|x| x.key());
if let Some(referrer_pubkey) = referrer_key {
let referrer_state = &mut ctx.accounts.referrer_state.as_mut().unwrap();
let (_, _) = process_referral(
game_state,
player_state,
ctx.accounts.player.key(),
referrer_state,
referrer_pubkey,
amount,
)?;
}
3 Referral Logic (helpers.rs)
The core referral processing handles validation, fee calculation, and state updates:
- Validate the referrer is registered and not the same as the buyer
- Calculate referral fee (for referrer) and cashback (for buyer)
- Update both players' referral totals
- Track the combined amount in the game's sell and referral balance
Show the Rust
helpers.rs
pub fn process_referral(
game_state: &mut GameState,
player_state: &mut PlayerState,
player: Pubkey,
referrer_state: &mut PlayerState,
referrer: Pubkey,
amount: u64,
) -> Result<(u64, u64)> {
// Do nothing for no referrer
if referrer == pubkey!("11111111111111111111111111111111") {
return Ok((0, 0))
}
// Referrer must be a registered player
require!(referrer_state.registered, CustomErrors::InvalidReferrer);
// Can't be self
require!(!referrer.eq(&player), CustomErrors::InvalidReferrer);
// Returns (ref_fee, cashback)
let ref_fee;
let cashback;
// Proceed with referral
player_state.current_referrer = referrer;
// Calculate referral fee and cashback
ref_fee = amount
.checked_mul(REFERRAL_FEE)
.unwrap_or_default()
.checked_div(100)
.unwrap_or_default();
cashback = amount
.checked_mul(REFERRAL_CASHBACK)
.unwrap_or_default()
.checked_div(100)
.unwrap_or_default();
// Update referrer's total with their fee
referrer_state.referral_total = referrer_state.referral_total.checked_add(ref_fee).unwrap();
// Update buyer's referral total with their cashback
player_state.referral_total = player_state.referral_total.checked_add(cashback).unwrap();
// Add both ref fee and cashback to sell_and_ref_balance for tracking
game_state.sell_and_ref_balance = game_state
.sell_and_ref_balance
.checked_add(ref_fee)
.unwrap()
.checked_add(cashback)
.unwrap();
Ok((ref_fee, cashback))
}