Skip to content

deposit_handler/withdrawal_handler: closed issue #463's missing cancel-path vault-balance check is still unfixed #545

Description

@abayomicornelius

Problem

Issue #463 ("deposit_handler::cancel_deposit (and withdrawal_handler::cancel_withdrawal) refund the recorded amount with no vault-balance invariant check, unlike execute_deposit's InsufficientVaultBalance guard") is closed, but cancel_deposit (contracts/deposit_handler/src/lib.rs, ~lines 530-580) is unchanged: it refunds the stored deposit.long_token_amount/deposit.short_token_amount directly, with no check against the vault's actual recorded or real balance:

let vault_client = DepositVaultClient::new(&env, &deposit_vault);

// Refund tokens
if deposit.long_token_amount > 0 {
    vault_client.transfer_out(
        &handler,
        &deposit.initial_long_token,
        &deposit.account,
        &deposit.long_token_amount,
    );
}
if deposit.short_token_amount > 0 {
    vault_client.transfer_out( /* same shape */ );
}

execute_deposit (in the same file) explicitly cross-checks the vault's actual recorded balance against the deposit's claimed contribution before moving funds and panics on a shortfall — cancel_deposit has no equivalent guard at all. withdrawal_handler::cancel_withdrawal has the identical shape (refunds the stored amount unconditionally, no balance check).

Why it matters

Both deposit_vault and withdrawal_vault hold pooled, commingled balances across every currently-pending record for a given token. Any scenario where the vault's actual balance for a token legitimately diverges from what a specific deposit/withdrawal record's stored amount claims (a fee-on-transfer token, or accounting drift from any of the other data_store/vault bugs already on file, such as #386/#542's record_transfer_in gaps) lets a single cancellation pay out more than that specific record ever contributed to the vault — funded silently out of other users' still-pending funds sitting in the same pooled vault. This is exactly the risk execute_deposit was hardened against, with cancel_deposit/cancel_withdrawal left with no equivalent hardening.

Scope

In scope

  • contracts/deposit_handler/src/lib.rs::cancel_deposit
  • contracts/withdrawal_handler/src/lib.rs::cancel_withdrawal

Suggested fix

Apply the same style of balance check execute_deposit already uses before refunding in both cancel paths — cap the refund at (or panic on) the vault's actual/recorded balance for that token, or track balances per-record-key so a cancellation can never draw on funds it did not itself deposit.

Verification

cargo test -p deposit-handler
cargo test -p withdrawal-handler

Add a test where the vault's real balance for a token is artificially short of a pending record's claimed amount, and assert cancel_deposit/cancel_withdrawal reverts (or caps the refund) rather than silently drawing on other users' funds.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardStellar WaveIssues in the Stellar wave programThird CampaignCampaign: Third CampaignbugSomething isn't workingpriority:highsize:s

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions