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 directory | Source files |
|---|---|
frontend | 82 |
backend | 53 |
programs | 32 |
packages | 3 |
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.
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(- Line 29
token::transfer(CpiContext::new(cpi_program.clone(), cpi_accounts), *amount)?;: Makes a cross-program invocation into another program. - Line 29
token::transfer(CpiContext::new(cpi_program.clone(), cpi_accounts), *amount)?;: An SPL token transfer through the Token Program. - Line 40
pub depositor: Signer<'info>,: Requires this account to have signed the transaction. - Line 42
init_if_needed,: Creates the account only if it doesn't exist. Watch for re-initialisation bugs.
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(),- Line 97
// CpiContext::new(: Makes a cross-program invocation into another program. - Line 110
let authority_seeds = &[: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 118
token::mint_to(: Mints new tokens. The mint authority must sign. - Line 119
CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
programs/token-vault/programs/token-vault/src/instructions/withdraw_liquidity.rs L13–36 @ bdda586 · Apache-2.0 · originalpub 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(),- Line 15
let authority_seeds = &[: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 26
.checked_mul(I64F64::from_num(ctx.accounts.pool_account_a.amount)): Uses checked arithmetic so overflow fails instead of wrapping. - Line 34
token::transfer(: An SPL token transfer through the Token Program. - Line 35
CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
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>,- Line 18
init,: Creates and pays for a new account. Space and payer must be specified. - Line 21
seeds = [: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 24
bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - 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.
| Directory | Command | Runs |
|---|---|---|
. | npm run dev | turbo dev |
. | npm run build | turbo build |
. | npm run lint | turbo lint |
frontend | npm run dev | next dev --turbo |
frontend | npm run start | next start |
frontend | npm run build | next build |
frontend | npm run lint | next lint |
programs/battle-logic | npm run lint | prettier */*.js "*/**/*{.js,.ts}" --check |
programs/token-vault | npm run dev | next dev --turbo |
programs/token-vault | npm run start | next start |
programs/token-vault | npm run build | next build |
programs/token-vault | npm run lint | next lint |
programs/game-token-stake | npm run lint | prettier */*.js "*/**/*{.js,.ts}" --check |
programs/nft-mint | npm run test | echo "Error: no test specified" && exit 1 |
backend | npm run start | nest start |
backend | npm run build | nest build |
What you could build from it
- Fork the SuperStack copy and extend it within the Gaming gaps listed on the idea page.
- Learn the pattern first: Program Derived Addresses (PDAs)
- Learn the pattern first: Compressed NFTs and state compression
- Learn the pattern first: Building and sending transactions from a client