Skip to content

Missing Slippage Protection in Payment Settlement Conversion #6

Description

@elizabetheonoja-art

Problem Statement / Feature Objective
The settlement contract converts resource token balances to the settlement currency using the current oracle exchange rate at the time of finalize_settlement(). Because the conversion happens as a single atomic swap without any slippage tolerance check, even a 1-basis-point adverse price movement between oracle read and execution causes the user to receive fewer settlement tokens than expected. In volatile market conditions, the deviation can exceed 5%, causing significant value loss for users. The contract needs a user-defined min_expected_amount parameter and a protocol-enforced MAX_SLIPPAGE_BPS (basis points) bound that rejects settlement if the converted amount deviates beyond tolerance.

Technical Invariants & Bounds
Slippage is computed as: slippage_bps = (expected_amount - actual_amount) * 10000 / expected_amount, where both amounts are i128 fixed-point with 7 decimal places. MAX_SLIPPAGE_BPS must be a protocol constant in range [1, 500] (0.01% to 5%). User can optionally set a tighter min_expected_amount parameter. The oracle rate R is an i128 with 7 decimals. The settlement amount S = volume * R / 1e7 where volume is also i128. The conversion must use checked_mul and checked_div to prevent overflow. The max settlement volume per call is MAX_VOLUME = 1_000_000 * 1e7 (1M tokens). Max conversion amount is MAX_VOLUME * MAX_RATE / 1e7 where MAX_RATE = 1_000_000 * 1e7. The product MAX_VOLUME * MAX_RATE = 1e12 * 1e7 = 1e19 which fits in i128 (~1.7e38). The total operation cost increase is ~15,000 instructions (two additional multiplications, one comparison).

Codebase Navigation Guide
Settlement conversion logic: contracts/settlement/src/lib.rsfinalize_settlement() around line 142 calls convert_to_settlement_currency() at line 178 in contracts/settlement/src/conversion.rs. Oracle rate fetching: contracts/settlement/src/rate_application.rsget_rate() at line 42. The settlement function signature is in contracts/settlement/src/interface.rs or directly annotated with #[contractimpl]. User-facing parameter structures are in contracts/settlement/src/types.rs. The SettlementArgs struct likely contains token_address, volume, recipient. Current test cases in contracts/settlement/src/test.rs do not test slippage scenarios.

Implementation Blueprint
Step 1: Add min_expected_amount: Option<i128> to the SettlementArgs struct in contracts/settlement/src/types.rs. Step 2: Add MAX_SLIPPAGE_BPS: u32 = 100 (1%) to contracts/settlement/src/constants.rs. Step 3: In conversion.rs, before executing conversion, compute expected_amount = volume * oracle_rate / 1e7. After conversion, compute actual_amount. Reject if (expected_amount - actual_amount) * 10000 / expected_amount > MAX_SLIPPAGE_BPS OR if actual_amount < min_expected_amount (if user provided). Step 4: Emit a SlippageProtectionTriggered event when rejection occurs. Step 5: Update function signature to return Result<SettlementResult, SettlementError> where SettlementError includes SlippageExceeded variant. Step 6: Add 4 test cases: (a) zero slippage succeeds, (b) slippage within tolerance succeeds, (c) slippage exceeds tolerance fails, (d) user min_expected_amount higher than actual fails. Step 7: Run cargo test --package settlement.

Metadata

Metadata

Assignees

Labels

Complexity: HardcoreIssues requiring deep systems-level engineering rigorGrantFox OSSIssue tracked in GrantFox OSSLayer: Core-EngineCore contract engine layerMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignType: Core-ArchitectureCore architecture design issues

Type

No type
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