Conversation
4c9e894 to
61dfdf8
Compare
| require!( | ||
| amount >= 10_u64.pow(self.mint_to_raise.decimals as u32), | ||
| FundraiserError::ContributionTooSmall | ||
| ); |
There was a problem hiding this comment.
🟡 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.
| 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 | |
| ); | |
Was this helpful? React with 👍 or 👎 to provide feedback.
| 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 | ||
| ); |
There was a problem hiding this comment.
🟡 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.
| 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 | |
| ); | |
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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
same here better put bump into ix data.
| spl_interface_pda_bump: spl_interface_bump_a, | ||
| }; | ||
|
|
||
| transfer_tokens( |
There was a problem hiding this comment.
use transfer interface directly
| 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; |
There was a problem hiding this comment.
don't we have a unified load function now?
5526128 to
bd39ca7
Compare
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.
bd39ca7 to
6a7061c
Compare
Summary
associated_token::bump(now derived on-chain)Programs
Test plan
cargo test-sbf -p escrowcargo test-sbf -p fundraisercargo test-sbf -p light-token-mintercargo test-sbf -p swap_example