Skip to content

Add Anchor example programs#26

Open
tilo-14 wants to merge 1 commit intomainfrom
pr/anchor-examples
Open

Add Anchor example programs#26
tilo-14 wants to merge 1 commit intomainfrom
pr/anchor-examples

Conversation

@tilo-14
Copy link
Contributor

@tilo-14 tilo-14 commented Feb 16, 2026

Summary

  • Add four Light Token Anchor example programs: escrow, fundraiser, token-swap, light-token-minter
  • Each program tests 5 token configurations (SPL, Token2022, Light, LightSpl, LightT22)
  • Shared test utilities crate for mint/ATA creation, balance verification, SPL interface PDAs
  • Fix light-token-minter: remove deprecated associated_token::bump (now derived on-chain)
  • Update CI workflow to test the four example programs

Programs

Program Description
escrow Peer-to-peer token swap with rent-free Light Token vaults
fundraiser Crowdfunding with contribute, claim, and refund flows
token-swap Constant-product AMM with rent-free pool vaults
light-token-minter Light Token mint creation and minting

Test plan

  • cargo test-sbf -p escrow
  • cargo test-sbf -p fundraiser
  • cargo test-sbf -p light-token-minter
  • cargo test-sbf -p swap_example

Open with Devin

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 11 additional findings in Devin Review.

Open in Devin Review

Comment on lines +73 to +76
require!(
amount >= 10_u64.pow(self.mint_to_raise.decimals as u32),
FundraiserError::ContributionTooSmall
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Fundraiser contribute() minimum amount check panics on overflow for high-decimal mints

The contribute() function computes the minimum contribution as 10_u64.pow(self.mint_to_raise.decimals as u32) without checking for overflow. If a mint has decimals > 19, this expression overflows u64.

Detailed Explanation

At programs/anchor/fundraiser/src/instructions/contribute.rs:74:

require!(
    amount >= 10_u64.pow(self.mint_to_raise.decimals as u32),
    FundraiserError::ContributionTooSmall
);

10_u64.pow(20) = 10^20 which exceeds u64::MAX (≈1.8×10^19). The workspace Cargo.toml sets overflow-checks = true for the release profile, so this would cause a panic (program abort) rather than silent wraparound.

While SPL Token mints typically use decimals 0-9, Token-2022 mints can be created with any u8 value for decimals. Since the fundraiser supports Token-2022 mints (via TokenConfig::Token2022), a malicious or misconfigured mint with decimals >= 20 would make the contribute instruction permanently fail with a panic.

Impact: A fundraiser created with a high-decimal mint would be unable to accept any contributions, effectively locking the fundraiser in a broken state.

Suggested change
require!(
amount >= 10_u64.pow(self.mint_to_raise.decimals as u32),
FundraiserError::ContributionTooSmall
);
let min_amount = 10_u64.checked_pow(self.mint_to_raise.decimals as u32)
.ok_or(FundraiserError::CalculationOverflow)?;
require!(
amount >= min_amount,
FundraiserError::ContributionTooSmall
);
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +77 to +80
require!(
params.amount >= MIN_AMOUNT_TO_RAISE.checked_mul(10_u64.pow(self.mint_to_raise.decimals as u32)).ok_or(FundraiserError::InvalidAmount)?,
FundraiserError::InvalidAmount
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Fundraiser initialize() minimum amount check panics on overflow for high-decimal mints

The initialize() function computes the minimum amount to raise as MIN_AMOUNT_TO_RAISE.checked_mul(10_u64.pow(self.mint_to_raise.decimals as u32)), but the inner pow call is unchecked and will panic for decimals > 19.

Detailed Explanation

At programs/anchor/fundraiser/src/instructions/initialize.rs:78:

require!(
    params.amount >= MIN_AMOUNT_TO_RAISE
        .checked_mul(10_u64.pow(self.mint_to_raise.decimals as u32))
        .ok_or(FundraiserError::InvalidAmount)?,
    FundraiserError::InvalidAmount
);

While checked_mul is used for the multiplication, the 10_u64.pow(decimals) call itself is not checked. For decimals >= 20, pow overflows u64 and panics (since overflow-checks = true in the release profile). The checked_mul never gets a chance to catch the overflow.

Impact: Creating a fundraiser with a high-decimal Token-2022 mint would cause the initialize instruction to panic, wasting the caller's transaction fee.

Suggested change
require!(
params.amount >= MIN_AMOUNT_TO_RAISE.checked_mul(10_u64.pow(self.mint_to_raise.decimals as u32)).ok_or(FundraiserError::InvalidAmount)?,
FundraiserError::InvalidAmount
);
let min_unit = 10_u64.checked_pow(self.mint_to_raise.decimals as u32)
.and_then(|v| MIN_AMOUNT_TO_RAISE.checked_mul(v))
.ok_or(FundraiserError::InvalidAmount)?;
require!(
params.amount >= min_unit,
FundraiserError::InvalidAmount
);
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

/// After compressing, the test loads cold accounts back to active state
/// before the next transaction.
/// Standard SPL/Token 2022 accounts are unaffected.
async fn warp_to_compress<R: Rpc + TestRpc + Indexer>(rpc: &mut R) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best put into common

Comment on lines 19 to 28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not all of these deps should be necessary only:
light-sdk
light-account
light-hasher
light-token

these should reexport whatever you need from the other crates.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applies to all tests.

) -> Result<()> {
let decimals = ctx.accounts.token_mint_a.decimals;
let (_, spl_interface_bump_a) =
find_spl_interface_pda(&ctx.accounts.token_mint_a.key(), false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be better to send the bump in instruction data

) -> Result<()> {
let is_light_to_light = is_light_account(&from) && is_light_account(&to);

if is_light_to_light {
Copy link
Contributor

@ananas-block ananas-block Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use TransferInterface instead?
This way we can remove the complete function.


let decimals_a = ctx.accounts.token_mint_a.decimals;
let (_, spl_interface_bump_a) =
find_spl_interface_pda(&ctx.accounts.token_mint_a.key(), false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here better put bump into ix data.

spl_interface_pda_bump: spl_interface_bump_a,
};

transfer_tokens(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use transfer interface directly

Comment on lines 196 to 220
load_light_mints(rpc, &ctx.payer, &[ctx.mint_a_pubkey, ctx.mint_b_pubkey]).await;
load_light_pdas(
rpc,
&ctx.payer,
&ctx.maker,
&ctx.program_id,
ctx.compression_config,
offer_pda,
vault_pda,
)
.await;
load_light_accounts(
rpc,
&ctx.payer,
&ctx.taker,
&[ctx.mint_a_pubkey, ctx.mint_b_pubkey],
)
.await;
load_light_accounts(
rpc,
&ctx.payer,
&ctx.maker,
&[ctx.mint_b_pubkey],
)
.await;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we have a unified load function now?

Peer-to-peer escrow, crowdfunding, AMM swap, and mint helper programs
demonstrating rent-free Light Token vaults with full test coverage
across SPL, Token-2022, and Light token standards.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants