Sol.College

Full lesson

MemeArena

Fight with your favorite memecoins

What it does

From the project README:

Users can mint NFTs of their Gladiator cards, which represent the memecoins set to battle. These cards allow players to assemble their team of Gladiators to face off against other users in exciting duels.
Original
MemeArenaLabs/MemeArena
SuperStack fork
Blockchains/MemeArena @ bdda586
Stars
2
Last push (original)
2024-10-09
Languages
TypeScript, Rust, JavaScript, Shell, CSS
Detected stack
AnchorMetaplexNext.jsweb3.js
Categories
Gaming
Licence
Apache-2.0
Homepage
https://gladiators-meme.vercel.app/

Architecture

170 source files. By extension: .ts ×84, .tsx ×59, .rs ×18, .js ×9.

Top-level directorySource files
frontend82
backend53
programs32
packages3

On-chain programs: programs/battle-logic/programs/battle-logic, programs/game-token-stake/programs/game-token-stake, programs/token-vault/programs/token-vault

Dapp: deploying

This fork is queued for its own live dapp on Sol.College, with a Devnet/Mainnet switch. It appears here, at /dapps/memearena/, once it is deployed and checked on devnet. Until then, run it locally with the commands below.

Key code, explained

Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.

MemeArenaLabs/MemeArena · programs/battle-logic/programs/battle-logic/src/instructions/deposit_token.rs L25–48 @ bdda586 · Apache-2.0 · original
            from: ctx.accounts.depositor.to_account_info(),            to: escrow_token_account.to_account_info(),            authority: ctx.accounts.depositor.to_account_info(),        };        token::transfer(CpiContext::new(cpi_program.clone(), cpi_accounts), *amount)?;         escrow_account.amount += amount;    }     Ok(())} #[derive(Accounts)]pub struct DepositToken<'info> {    #[account(mut)]    pub depositor: Signer<'info>,    #[account(        init_if_needed,        payer = depositor,        associated_token::mint = mint_1,        associated_token::authority = backend_wallet, // Change authority to backend wallet    )]    pub escrow_token_account_1: Account<'info, TokenAccount>, // Change to TokenAccount    #[account(
  1. Line 29 token::transfer(CpiContext::new(cpi_program.clone(), cpi_accounts), *amount)?;: Makes a cross-program invocation into another program.
  2. Line 29 token::transfer(CpiContext::new(cpi_program.clone(), cpi_accounts), *amount)?;: An SPL token transfer through the Token Program.
  3. Line 40 pub depositor: Signer<'info>,: Requires this account to have signed the transaction.
  4. Line 42 init_if_needed,: Creates the account only if it doesn't exist. Watch for re-initialisation bugs.
MemeArenaLabs/MemeArena · programs/token-vault/programs/token-vault/src/instructions/deposit_liquidity.rs L97–120 @ bdda586 · Apache-2.0 · original
    //     CpiContext::new(    //         ctx.accounts.token_program.to_account_info(),    //         Transfer {    //             from: ctx.accounts.depositor_account_b.to_account_info(),    //             to: ctx.accounts.pool_account_b.to_account_info(),    //             authority: ctx.accounts.depositor.to_account_info(),    //         },    //     ),    //     amount_b,    // )?;     // Mint the liquidity to user    let authority_bump = ctx.bumps.pool_authority;    let authority_seeds = &[        &ctx.accounts.pool.amm.to_bytes(),        &ctx.accounts.mint_a.key().to_bytes(),        //&ctx.accounts.mint_b.key().to_bytes(),        AUTHORITY_SEED,        &[authority_bump],    ];    let signer_seeds = &[&authority_seeds[..]];    token::mint_to(        CpiContext::new_with_signer(            ctx.accounts.token_program.to_account_info(),
  1. Line 97 // CpiContext::new(: Makes a cross-program invocation into another program.
  2. Line 110 let authority_seeds = &[: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 118 token::mint_to(: Mints new tokens. The mint authority must sign.
  4. Line 119 CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
MemeArenaLabs/MemeArena · programs/token-vault/programs/token-vault/src/instructions/withdraw_liquidity.rs L13–36 @ bdda586 · Apache-2.0 · original
pub fn withdraw_liquidity(ctx: Context<WithdrawLiquidity>, amount: u64) -> Result<()> {    let authority_bump = ctx.bumps.pool_authority;    let authority_seeds = &[        &ctx.accounts.pool.amm.to_bytes(),        &ctx.accounts.mint_a.key().to_bytes(),        //&ctx.accounts.mint_b.key().to_bytes(),        AUTHORITY_SEED,        &[authority_bump],    ];    let signer_seeds = &[&authority_seeds[..]];     // Transfer tokens from the pool    let amount_a = I64F64::from_num(amount)        .checked_mul(I64F64::from_num(ctx.accounts.pool_account_a.amount))        .unwrap()        .checked_div(I64F64::from_num(            ctx.accounts.mint_liquidity.supply + MINIMUM_LIQUIDITY,        ))        .unwrap()        .floor()        .to_num::<u64>();    token::transfer(        CpiContext::new_with_signer(            ctx.accounts.token_program.to_account_info(),
  1. Line 15 let authority_seeds = &[: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  2. Line 26 .checked_mul(I64F64::from_num(ctx.accounts.pool_account_a.amount)): Uses checked arithmetic so overflow fails instead of wrapping.
  3. Line 34 token::transfer(: An SPL token transfer through the Token Program.
  4. Line 35 CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
MemeArenaLabs/MemeArena · programs/token-vault/programs/token-vault/src/instructions/create_amm.rs L13–35 @ bdda586 · Apache-2.0 · original
 #[derive(Accounts)]#[instruction(id: Pubkey, fee: u16)]pub struct CreateAmm<'info> {    #[account(        init,        payer = payer,        space = Amm::LEN,        seeds = [            id.as_ref()        ],        bump,        constraint = fee < 10000 @ TutorialError::InvalidFee,    )]    pub amm: Account<'info, Amm>,     /// The admin of the AMM    /// CHECK: Read only, delegatable creation    pub admin: AccountInfo<'info>,     /// The account paying for all rents    #[account(mut)]    pub payer: Signer<'info>,
  1. Line 18 init,: Creates and pays for a new account. Space and payer must be specified.
  2. Line 21 seeds = [: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 24 bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  4. Line 35 pub payer: Signer<'info>,: Requires this account to have signed the transaction.

How to run, build and test

These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.

DirectoryCommandRuns
.npm run devturbo dev
.npm run buildturbo build
.npm run lintturbo lint
frontendnpm run devnext dev --turbo
frontendnpm run startnext start
frontendnpm run buildnext build
frontendnpm run lintnext lint
programs/battle-logicnpm run lintprettier */*.js "*/**/*{.js,.ts}" --check
programs/token-vaultnpm run devnext dev --turbo
programs/token-vaultnpm run startnext start
programs/token-vaultnpm run buildnext build
programs/token-vaultnpm run lintnext lint
programs/game-token-stakenpm run lintprettier */*.js "*/**/*{.js,.ts}" --check
programs/nft-mintnpm run testecho "Error: no test specified" && exit 1
backendnpm run startnest start
backendnpm run buildnest build

What you could build from it

Used in lessons