Category: security, bug
Problem
payment_escrow supports two asset types, AssetType::Xlm and AssetType::Usdc (lines 12-15), and every normal transfer path (deposit, release, release_partial, expire, refund, resolve_dispute) is asset-type-aware via token_address()/transfer_from_contract(). However, emergency_drain (lines 503-553) hardcodes a single token: let usdc_token: Address = env.storage().instance().get(&DataKey::UsdcToken).unwrap(); and only ever transfers the contract's USDC balance to the emergency treasury. There is no equivalent path that reads DataKey::XlmToken and drains XLM-denominated escrow balances.
Impact
In a genuine emergency (e.g. a critical bug discovered in the escrow logic, or a compromised admin key actively draining funds through normal channels), the documented 3-of-3-signer emergency drain — the contract's designated last-resort fund-recovery mechanism per EMERGENCY_RUNBOOK.md — can rescue USDC but leaves any XLM held in escrow completely unprotected and unrecoverable through this path.
Suggested fix
Parameterize emergency_drain by AssetType (or add a second emergency_drain_xlm following the same 3-signer/cooldown logic) so both supported asset types can be swept to the treasury during an incident. Update EMERGENCY_RUNBOOK.md to document the XLM drain procedure once added.
Category: security, bug
Problem
payment_escrowsupports two asset types,AssetType::XlmandAssetType::Usdc(lines 12-15), and every normal transfer path (deposit,release,release_partial,expire,refund,resolve_dispute) is asset-type-aware viatoken_address()/transfer_from_contract(). However,emergency_drain(lines 503-553) hardcodes a single token:let usdc_token: Address = env.storage().instance().get(&DataKey::UsdcToken).unwrap();and only ever transfers the contract's USDC balance to the emergency treasury. There is no equivalent path that readsDataKey::XlmTokenand drains XLM-denominated escrow balances.Impact
In a genuine emergency (e.g. a critical bug discovered in the escrow logic, or a compromised admin key actively draining funds through normal channels), the documented 3-of-3-signer emergency drain — the contract's designated last-resort fund-recovery mechanism per
EMERGENCY_RUNBOOK.md— can rescue USDC but leaves any XLM held in escrow completely unprotected and unrecoverable through this path.Suggested fix
Parameterize
emergency_drainbyAssetType(or add a secondemergency_drain_xlmfollowing the same 3-signer/cooldown logic) so both supported asset types can be swept to the treasury during an incident. UpdateEMERGENCY_RUNBOOK.mdto document the XLM drain procedure once added.