🔴 Priority: Critical
Difficulty: Hard
Estimated Effort: 2-3 days
Relevant Files: contracts/src/lib.rs, contracts/src/test.rs
Labels: security, priority:critical, soroban
Requirements
-
Reentrancy Vulnerability Remediation
- The current
payout() function updates state (HasReceivedPayout) after executing the token transfer:
token_client.transfer(&env.current_contract_address(), &recipient, &pool_size);
env.storage().persistent().set(&DataKey::HasReceivedPayout(recipient.clone()), &true);
- While Soroban currently limits reentrancy via standard cross-contract calls, future protocol upgrades or specific token implementations (like custom wrapped tokens) might introduce reentrancy vectors.
- Refactor
payout() to strictly follow the Checks-Effects-Interactions (CEI) pattern.
-
State Update Relocation
- Move the
set(&DataKey::HasReceivedPayout, &true) state update to happen before token_client.transfer().
- Ensure that the TTL extensions also occur before the external token transfer call.
-
Reentrancy Guard Mutex (Optional but Recommended)
- Implement a simple lock in instance storage:
DataKey::IsExecutingPayout.
- Set it to
true at the start of payout(), and clear it at the end.
- Assert
!IsExecutingPayout at the beginning of both contribute() and payout().
-
Testing
- Unit test: Verify the CEI pattern is implemented (the state changes even if the transfer fails in a mock).
- Write a mock malicious token contract that attempts to call
payout() again during the transfer() callback.
- Verify that the malicious reentrant call panics with "Already received payout" or "Reentrancy detected".
- Target: 100% coverage on the payout function.
🔴 Priority: Critical
Difficulty: Hard
Estimated Effort: 2-3 days
Relevant Files:
contracts/src/lib.rs,contracts/src/test.rsLabels:
security,priority:critical,sorobanRequirements
Reentrancy Vulnerability Remediation
payout()function updates state (HasReceivedPayout) after executing the token transfer:payout()to strictly follow the Checks-Effects-Interactions (CEI) pattern.State Update Relocation
set(&DataKey::HasReceivedPayout, &true)state update to happen beforetoken_client.transfer().Reentrancy Guard Mutex (Optional but Recommended)
DataKey::IsExecutingPayout.trueat the start ofpayout(), and clear it at the end.!IsExecutingPayoutat the beginning of bothcontribute()andpayout().Testing
payout()again during thetransfer()callback.