Summary
pay_claim() in contracts/policy-engine/src/lib.rs (lines 247–258) calls token.transfer for policy.coverage_amount without first verifying the contract holds sufficient USDC. If the pool has been drained by concurrent claims or the Risk Pool failed to lock coverage capital, the token transfer will panic and the entire transaction reverts.
Code
pub fn pay_claim(env: Env, caller: Address, policy_id: u128) {
Self::require_claims_processor(&env, &caller);
let mut policy: Policy = Self::load_policy(&env, policy_id);
if policy.status != PolicyStatus::Active {
panic_with_error!(&env, Error::PolicyNotActive);
}
policy.status = PolicyStatus::Claimed;
env.storage().persistent().set(&StorageKey::Policy(policy_id), &policy);
let usdc: Address = env.storage().instance().get(&StorageKey::UsdcToken).unwrap();
token::Client::new(&env, &usdc)
.transfer(&env.current_contract_address(), &policy.policyholder, &policy.coverage_amount);
// ↑ no balance check — panics if contract has < coverage_amount USDC
}
Impact
- The policy status is written as
Claimed BEFORE the transfer
- If the transfer reverts (insufficient balance), the whole transaction rolls back — but the state write order is still wrong
- Multiple simultaneous claim payouts can race on limited pool liquidity
- Undercollateralized pools (e.g., after large claims or admin withdrawal) will permanently block claim settlement
Fix
Add a pre-transfer balance check:
let balance = token::Client::new(&env, &usdc).balance(&env.current_contract_address());
if balance < policy.coverage_amount {
panic_with_error!(&env, Error::InsufficientPool);
}
Severity: High
Summary
pay_claim()incontracts/policy-engine/src/lib.rs(lines 247–258) callstoken.transferforpolicy.coverage_amountwithout first verifying the contract holds sufficient USDC. If the pool has been drained by concurrent claims or the Risk Pool failed to lock coverage capital, the token transfer will panic and the entire transaction reverts.Code
Impact
ClaimedBEFORE the transferFix
Add a pre-transfer balance check:
Severity: High