-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add light minter, escrow examples #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Remove non-existent example directories from matrix (counter, basic-operations, etc.) - Keep only anchor/escrow and anchor/light-token-minter programs that exist - Fix unused mut warning in minter_test.rs
- Update workspace dependencies to use crates.io versions instead of git - light-sdk 0.18.0, light-token 0.3.0, light-hasher 5.0.0 - light-program-test 0.18.0, light-client 0.18.0 - Remove unnecessary dependencies that are re-exported: - light-sdk-macros, light-sdk-types (re-exported by light-sdk/light-token) - light-compressible (re-exported by light-sdk) - light-token-interface, light-token-types (re-exported by light-token) - Update imports to use re-exported paths
…creation - Switch light-protocol dependencies from crates.io to git rev 5a6ad4b - Add vault_bump to MakeOfferParams for PDA signing - Fix light_account authority seeds to use vault PDA seeds instead of auth seeds - Remove unused CreateTokenAccountCpi import
The light-token MintTo instruction creates an AccountMeta with writable flag for the authority account. This caused PrivilegeEscalation errors because mint_authority was only marked as signer, not writable.
Crowdfunding program using: - SPL mint for the token to raise - SPL ATAs for contributor token accounts - Light Protocol token account for the vault - SPL interface for SPL<->Light transfers Instructions: initialize, contribute, check_contributions, refund
Token swap AMM program using: - SPL mints for token A and token B - SPL ATAs for depositor/trader accounts - Light Protocol token accounts for pool_account_a and pool_account_b - SPL mint for liquidity tokens - SPL interface for SPL<->Light transfers Instructions: create_amm, create_pool, deposit_liquidity, swap, withdraw_liquidity
| derive_mint_compressed_address(&mint_seed.pubkey(), &address_tree.tree); | ||
| let (mint, bump) = find_mint_address(&mint_seed.pubkey()); | ||
|
|
||
| let rpc_result = rpc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use create proof inputs
Replace external path dependencies with their published crates.io versions: - light-sdk: 0.19.0 - light-sdk-macros: 0.19.0 - light-hasher: 5.0.0 - light-token: 0.4.0 - light-program-test: 0.19.0 - light-client: 0.19.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| pub fn contribute(&mut self, amount: u64) -> Result<()> { | ||
| // Check if the amount to contribute meets the minimum amount required | ||
| require!( | ||
| amount >= 1_u64.pow(self.mint_to_raise.decimals as u32), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Minimum contribution check is always 1 due to incorrect exponentiation base
The minimum contribution check uses 1_u64.pow(self.mint_to_raise.decimals as u32) which always evaluates to 1 regardless of the decimals value, since 1 raised to any power is 1.
Click to expand
Mechanism
The code at anchor/programs/fundraiser/src/instructions/contribute.rs:75 checks:
require!(
amount >= 1_u64.pow(self.mint_to_raise.decimals as u32),
FundraiserError::ContributionTooSmall
);For a token with 9 decimals:
1_u64.pow(9)= 1 (since 1^9 = 1)- The intended check was likely
10_u64.pow(9)= 1,000,000,000 (representing 1 whole token)
Actual vs Expected
- Actual: Minimum contribution is 1 token unit (smallest possible amount)
- Expected: Minimum contribution should be 1 whole token (10^decimals units)
Impact
This allows contributors to make dust contributions (e.g., 1 lamport worth of tokens), which could be used to spam the fundraiser with minimal cost or create many contributor accounts.
Recommendation: Change 1_u64.pow(self.mint_to_raise.decimals as u32) to 10_u64.pow(self.mint_to_raise.decimals as u32) to require a minimum of 1 whole token.
Was this helpful? React with 👍 or 👎 to provide feedback.
| require!( | ||
| self.fundraiser.duration | ||
| >= ((current_time - self.fundraiser.time_started) / SECONDS_TO_DAYS) as u16, | ||
| FundraiserError::FundraiserNotEnded | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 Refund time check is inverted - allows refunds during active fundraiser
The refund function's time check condition is inverted, allowing refunds while the fundraiser is still active instead of only after it has ended.
Click to expand
Mechanism
The code at anchor/programs/fundraiser/src/instructions/refund.rs:78-82 checks:
require!(
self.fundraiser.duration
>= ((current_time - self.fundraiser.time_started) / SECONDS_TO_DAYS) as u16,
FundraiserError::FundraiserNotEnded
);This condition duration >= elapsed_days is true when the fundraiser is still ongoing (elapsed time is less than or equal to duration).
Comparison with contribute.rs
In contribute.rs:89-92, the check is:
require!(
elapsed_days < self.fundraiser.duration,
FundraiserError::FundraiserEnded
);This correctly allows contributions only while elapsed_days < duration.
Actual vs Expected
- Actual: Refunds are allowed when
elapsed_days <= duration(during the fundraiser) - Expected: Refunds should only be allowed when
elapsed_days >= duration(after the fundraiser ends)
Impact
Contributors can request refunds while the fundraiser is still active, potentially draining the vault before the fundraiser has a chance to reach its goal. This defeats the purpose of the fundraiser mechanism.
Recommendation: Change the condition to ((current_time - self.fundraiser.time_started) / SECONDS_TO_DAYS) as u16 >= self.fundraiser.duration to only allow refunds after the fundraiser duration has passed.
Was this helpful? React with 👍 or 👎 to provide feedback.
| let ratio = I64F64::from_num(pool_a_balance) | ||
| .checked_mul(I64F64::from_num(pool_b_balance)) | ||
| .unwrap(); | ||
| if pool_a_balance > pool_b_balance { | ||
| ( | ||
| I64F64::from_num(amount_b) | ||
| .checked_mul(ratio) | ||
| .unwrap() | ||
| .to_num::<u64>(), | ||
| amount_b, | ||
| ) | ||
| } else { | ||
| ( | ||
| amount_a, | ||
| I64F64::from_num(amount_a) | ||
| .checked_div(ratio) | ||
| .unwrap() | ||
| .to_num::<u64>(), | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 Incorrect ratio calculation in deposit_liquidity uses product instead of ratio
The liquidity deposit ratio calculation multiplies pool balances instead of dividing them, resulting in wildly incorrect deposit amounts that don't maintain the pool's price ratio.
Click to expand
Mechanism
The code at anchor/programs/token-swap/src/instructions/deposit_liquidity.rs:47-66 calculates:
let ratio = I64F64::from_num(pool_a_balance)
.checked_mul(I64F64::from_num(pool_b_balance))
.unwrap();
if pool_a_balance > pool_b_balance {
(
I64F64::from_num(amount_b)
.checked_mul(ratio) // amount_a = amount_b * (pool_a * pool_b)
.unwrap()
.to_num::<u64>(),
amount_b,
)
} else {
(
amount_a,
I64F64::from_num(amount_a)
.checked_div(ratio) // amount_b = amount_a / (pool_a * pool_b)
.unwrap()
.to_num::<u64>(),
)
}Correct Formula
To maintain the pool ratio when adding liquidity:
amount_a / amount_b = pool_a_balance / pool_b_balance- So
amount_a = amount_b * (pool_a_balance / pool_b_balance)
Example
With pool_a = 1000, pool_b = 500, and user wants to deposit amount_b = 100:
- Actual:
ratio = 1000 * 500 = 500000,amount_a = 100 * 500000 = 50,000,000 - Expected:
ratio = 1000 / 500 = 2,amount_a = 100 * 2 = 200
Impact
Depositors will have their deposits calculated with completely wrong amounts, either depositing far more than intended or receiving incorrect LP token amounts. This breaks the AMM's constant product invariant and can lead to significant financial losses.
Recommendation: Change the ratio calculation to use division: let ratio = I64F64::from_num(pool_a_balance).checked_div(I64F64::from_num(pool_b_balance)).unwrap(); and adjust the subsequent calculations accordingly.
Was this helpful? React with 👍 or 👎 to provide feedback.
Uh oh!
There was an error while loading. Please reload this page.