Lamport Conservation Remediation
How to fix lamport conservation violations in Solana programs.
Lamport Conservation Remediation
Overview
Related Detector: Lamport Conservation
Programs must maintain lamport conservation invariants at instruction boundaries. The fix is to validate total lamport balances before and after transfers, ensure CPI calls that move lamports are followed by balance verification, and use checked arithmetic for all lamport calculations.
Recommended Fix
Before (Vulnerable)
// Vulnerable: no conservation check
pub fn transfer_reward(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
**accounts[0].lamports.borrow_mut() -= amount;
**accounts[1].lamports.borrow_mut() += amount;
Ok(())
}
After (Fixed)
// Fixed: explicit conservation check
pub fn transfer_reward(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
let total_before = accounts[0].lamports() + accounts[1].lamports();
require!(accounts[0].lamports() >= amount, ProgramError::InsufficientFunds);
**accounts[0].lamports.borrow_mut() -= amount;
**accounts[1].lamports.borrow_mut() += amount;
let total_after = accounts[0].lamports() + accounts[1].lamports();
require!(total_before == total_after, ProgramError::InvalidArgument);
Ok(())
}
Alternative Mitigations
Use SPL Token Transfers
Where possible, use the SPL Token program for transfers instead of direct lamport manipulation. The Token program enforces its own conservation invariants.
token::transfer(
CpiContext::new(token_program.to_account_info(), Transfer {
from: source.to_account_info(),
to: destination.to_account_info(),
authority: authority.to_account_info(),
}),
amount,
)?;
Common Mistakes
Mistake: Checking Only One Side
// WRONG: only checks the source has enough, not that total is conserved
require!(vault.lamports() >= amount, Error::InsufficientFunds);
**vault.lamports.borrow_mut() -= amount;
**user.lamports.borrow_mut() += amount;
Always verify total conservation: sum_before == sum_after.
Mistake: Overflow in Addition
// WRONG: addition could overflow, masking conservation violation
let total = vault.lamports() + user.lamports();
Use checked_add to prevent silent overflow in balance sums.