Skip to content

[risk-pool] send_premium_to_treasury and send_premium_to_backstop allow admin to double-spend premium already distributed via receive_premium #139

Description

@nonsobethel0-dev

Summary

contracts/risk-pool/src/lib.rs provides two admin functions — send_premium_to_treasury() (line 338) and send_premium_to_backstop() (line 352) — that transfer arbitrary amounts of USDC from the pool to the treasury or backstop address with no accounting of how much premium has already been distributed.

When receive_premium() is called, it splits the amount (80% LP, 10% treasury, 10% backstop) and immediately transfers the treasury and backstop shares. However, the two admin functions allow the admin to additionally drain pool liquidity to those same addresses — bypassing LP capital protection.

Code

pub fn send_premium_to_treasury(env: Env, caller: Address, amount: i128) {
    Self::require_admin(&env, &caller);
    // ← no check against AccumulatedPremium or any premium ledger
    token::Client::new(&env, &usdc).transfer(&env.current_contract_address(), &treasury, &amount);
}

Impact

  • Admin can call receive_premium (which already sends 10% to treasury) and then immediately call send_premium_to_treasury for the same amount, effectively double-paying the treasury from LP capital
  • There is no on-chain accounting of how much has been distributed — the admin can drain pool liquidity to trusted addresses without LP consent
  • This partially defeats the purpose of the 7-day timelock on execute_admin_withdrawal, which was designed to limit admin power over pool funds

Fix

Either remove these functions entirely (since receive_premium already handles distribution), or gate them with the same 7-day timelock mechanism and log the amounts against a premium-distribution ledger:

// Track cumulative distributions
let distributed: i128 = env.storage().instance().get(&StorageKey::TotalTreasuryDistributed).unwrap_or(0);
let available_for_distribution = accumulated_premium_10pct - distributed;
if amount > available_for_distribution { panic_with_error!(&env, Error::InsufficientFunds); }

Severity: High

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions