PP2: Contract: Arithmetic overflow (Cannot Sub) on any native LUNC transaction involving a slippage floor; affects swaps and liquidity provision #342

Closed
opened 2026-06-08 14:07:31 +00:00 by totdking · 15 comments
totdking commented 2026-06-08 14:07:31 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-08 14:09:09 +00:00 (Migrated from gitlab.com)

Summary

Any on-chain transaction involving native LUNC (auto-wrapped) that computes or enforces a slippage floor fails with an arithmetic overflow:

Overflow: Cannot Sub with <value * 0.995> and <value>: execute wasm contract failed

The underflow pattern is consistent: the smaller value is always value * 0.995 (the 0.5% slippage floor of the larger value), confirming the overflow is triggered when the contract attempts a subtraction of the form slippage_floor - offer_amount or equivalent where the floor is computed as less than the reference amount.

Two reproduction paths confirmed:

Path 1 -- Swap (LUNC to EMBER):

failed to execute message; message index: 1: Overflow: Cannot Sub with 9950000 and 10000000: execute wasm contract failed

Path 2 -- Provide Liquidity (LUNC-C/EMBER pool, 1 LUNC input):

failed to execute message; message index: 3: Overflow: Cannot Sub with 995000 and 1000000: execute wasm contract failed

Both follow the same N * 0.995 - N pattern. The different message indices (1 vs 3) reflect the different number of setup messages in each transaction type (swap = WrapDeposit + router send; liquidity = allowance + allowance + WrapDeposit + provide_liquidity).


Reproduction steps

Swap path:

  1. Navigate to / (Swap page) on LocalTerra
  2. Connect Keplr wallet (funded test account with LUNC)
  3. Select LUNC as token in, EMBER as token out
  4. Enter any amount
  5. Submit and approve in Keplr
  6. Observe: on-chain execution fails with Cannot Sub with 9950000 and 10000000

Liquidity path:

  1. Navigate to /pool on LocalTerra
  2. Connect Keplr wallet
  3. Open the LUNC-C/EMBER pair
  4. Check "Use native LUNC (auto-wrap)", enter 1 LUNC as Asset A, let Asset B auto-fill
  5. Click "Provide Liquidity" and approve in Keplr
  6. Observe: on-chain execution fails with Cannot Sub with 995000 and 1000000

Error detail

Transaction type Error message message index Values Ratio
LUNC to EMBER swap Cannot Sub with 9950000 and 10000000 1 9,950,000 / 10,000,000 0.995 (0.5% floor)
LUNC-C/EMBER provide liquidity Cannot Sub with 995000 and 1000000 3 995,000 / 1,000,000 0.995 (0.5% floor)

Both values satisfy smaller = larger * (1 - 0.005) exactly, confirming the slippage tolerance (0.5%) is the source of the subtraction operand.


Expected behavior

Transactions should execute successfully. If a slippage floor is not met, the contract should return a named error (MaxSpreadAssertion, MinReturnAssertion, etc.), not an unguarded arithmetic overflow that surfaces as a raw Overflow: Cannot Sub message.


Actual behavior

The contract panics with an unsigned integer underflow. Transactions are broadcast and included in a block but wasm execution fails. The error is not user-actionable.


Possible root cause area

Code review of smartcontracts/packages/dex-common/src/max_spread.rs and smartcontracts/contracts/pair/src/contract.rs confirms all guarded subtraction sites are safe:

  • max_spread.rs:239-242: belief-price path guards if expected_return > actual_return before subtracting -- safe
  • pair/contract.rs:812-814 (spot_linear_spread_over_gross): guards if ideal_output > gross_output before subtracting -- safe
  • pair/contract.rs:1110: gross_output.checked_sub(pool_commission_amount) -- commission is ~1.8% of gross, so gross > commission always; safe under normal conditions

The values 9950000 = 10000000 * 0.995 do not correspond to any commission or spread calculation. The exact checked_sub site could not be confirmed from static analysis alone. Possible location: an intermediate amount comparison in the router's sub-message handling, or a per-hop min_return enforced by the pair contract on one of the intermediate hops with an incorrect value computed by the frontend for the wrapped-token input amount.

Recommended next step: enable detailed wasm execution logs on localterra and capture the full stack trace including which contract and function triggered the overflow.


Impact assessment

  • Blocks: all native LUNC transactions involving a slippage floor -- swaps, liquidity provision, and likely withdrawals
  • Combined with ISSUE-017 (anyHopExceedsMaxSpread) and ISSUE-019 (gas underestimation), no swap path of any type can execute in the current QA environment
  • Liquidity provision with native LUNC is also blocked, affecting PL-6 and PL-9 in addition to swap items

Environment

  • Chain: localterra
  • LCD: http://localhost:1317
  • Wallet: Keplr (Terra Classic)
  • Browser: Chromium
  • Pages: / (Swap), /pool (Liquidity)
  • Slippage tolerance: 0.5% (default)
  • Network throttle applied: No

Severity: ~"blocker:limit-orders" -- on-chain arithmetic panic blocks all native LUNC transactions; raw overflow error surfaced to user.

Related checklist items: PP-2, PP-3, PP-4, PL-6, PL-9

cc: @PlasticDigits

### Summary Any on-chain transaction involving native LUNC (auto-wrapped) that computes or enforces a slippage floor fails with an arithmetic overflow: ``` Overflow: Cannot Sub with <value * 0.995> and <value>: execute wasm contract failed ``` The underflow pattern is consistent: the smaller value is always `value * 0.995` (the 0.5% slippage floor of the larger value), confirming the overflow is triggered when the contract attempts a subtraction of the form `slippage_floor - offer_amount` or equivalent where the floor is computed as less than the reference amount. Two reproduction paths confirmed: **Path 1 -- Swap (LUNC to EMBER):** ``` failed to execute message; message index: 1: Overflow: Cannot Sub with 9950000 and 10000000: execute wasm contract failed ``` **Path 2 -- Provide Liquidity (LUNC-C/EMBER pool, 1 LUNC input):** ``` failed to execute message; message index: 3: Overflow: Cannot Sub with 995000 and 1000000: execute wasm contract failed ``` Both follow the same `N * 0.995 - N` pattern. The different message indices (1 vs 3) reflect the different number of setup messages in each transaction type (swap = WrapDeposit + router send; liquidity = allowance + allowance + WrapDeposit + provide_liquidity). --- ### Reproduction steps **Swap path:** 1. Navigate to `/` (Swap page) on LocalTerra 2. Connect Keplr wallet (funded test account with LUNC) 3. Select LUNC as token in, EMBER as token out 4. Enter any amount 5. Submit and approve in Keplr 6. Observe: on-chain execution fails with `Cannot Sub with 9950000 and 10000000` **Liquidity path:** 1. Navigate to `/pool` on LocalTerra 2. Connect Keplr wallet 3. Open the LUNC-C/EMBER pair 4. Check "Use native LUNC (auto-wrap)", enter 1 LUNC as Asset A, let Asset B auto-fill 5. Click "Provide Liquidity" and approve in Keplr 6. Observe: on-chain execution fails with `Cannot Sub with 995000 and 1000000` --- ### Error detail | Transaction type | Error message | message index | Values | Ratio | |------------------|---------------|---------------|--------|-------| | LUNC to EMBER swap | `Cannot Sub with 9950000 and 10000000` | 1 | 9,950,000 / 10,000,000 | 0.995 (0.5% floor) | | LUNC-C/EMBER provide liquidity | `Cannot Sub with 995000 and 1000000` | 3 | 995,000 / 1,000,000 | 0.995 (0.5% floor) | Both values satisfy `smaller = larger * (1 - 0.005)` exactly, confirming the slippage tolerance (0.5%) is the source of the subtraction operand. --- ### Expected behavior Transactions should execute successfully. If a slippage floor is not met, the contract should return a named error (`MaxSpreadAssertion`, `MinReturnAssertion`, etc.), not an unguarded arithmetic overflow that surfaces as a raw `Overflow: Cannot Sub` message. --- ### Actual behavior The contract panics with an unsigned integer underflow. Transactions are broadcast and included in a block but wasm execution fails. The error is not user-actionable. --- ### Possible root cause area Code review of `smartcontracts/packages/dex-common/src/max_spread.rs` and `smartcontracts/contracts/pair/src/contract.rs` confirms all guarded subtraction sites are safe: - `max_spread.rs:239-242`: belief-price path guards `if expected_return > actual_return` before subtracting -- safe - `pair/contract.rs:812-814` (`spot_linear_spread_over_gross`): guards `if ideal_output > gross_output` before subtracting -- safe - `pair/contract.rs:1110`: `gross_output.checked_sub(pool_commission_amount)` -- commission is \~1.8% of gross, so gross \> commission always; safe under normal conditions The values `9950000 = 10000000 * 0.995` do not correspond to any commission or spread calculation. The exact `checked_sub` site could not be confirmed from static analysis alone. Possible location: an intermediate amount comparison in the router's sub-message handling, or a per-hop `min_return` enforced by the pair contract on one of the intermediate hops with an incorrect value computed by the frontend for the wrapped-token input amount. Recommended next step: enable detailed wasm execution logs on localterra and capture the full stack trace including which contract and function triggered the overflow. --- ### Impact assessment - Blocks: all native LUNC transactions involving a slippage floor -- swaps, liquidity provision, and likely withdrawals - Combined with ISSUE-017 (anyHopExceedsMaxSpread) and ISSUE-019 (gas underestimation), no swap path of any type can execute in the current QA environment - Liquidity provision with native LUNC is also blocked, affecting PL-6 and PL-9 in addition to swap items --- ### Environment - Chain: localterra - LCD: [http://localhost:1317](http://localhost:1317) - Wallet: Keplr (Terra Classic) - Browser: Chromium - Pages: `/` (Swap), `/pool` (Liquidity) - Slippage tolerance: 0.5% (default) - Network throttle applied: No --- **Severity:** ~"blocker:limit-orders" -- on-chain arithmetic panic blocks all native LUNC transactions; raw overflow error surfaced to user. **Related checklist items:** PP-2, PP-3, PP-4, PL-6, PL-9 cc: @PlasticDigits
totdking commented 2026-06-08 15:30:53 +00:00 (Migrated from gitlab.com)

changed title from PP2: Contract: Arithmetic overflow on LUNC to EMBER swap execution; `Cannot Sub with 9950000 and 10000000` to PP2: Contract: Arithmetic overflow (Cannot Sub) on any native LUNC transaction involving a slippage floor; affects swaps and liquidity provision

<p>changed title from <code class="idiff">PP2: Contract: Arithmetic overflow <span class="idiff left right deletion">on LUNC to EMBER swap execution; `Cannot Sub with 9950000 and 10000000`</span></code> to <code class="idiff">PP2: Contract: Arithmetic overflow <span class="idiff left right addition">(Cannot Sub) on any native LUNC transaction involving a slippage floor; affects swaps and liquidity provision</span></code></p>
totdking commented 2026-06-08 15:30:53 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
Brouie commented 2026-06-09 02:17:30 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
PlasticDigits commented 2026-06-09 06:50:07 +00:00 (Migrated from gitlab.com)

mentioned in commit ee182786a0

mentioned in commit ee182786a0ece990a3499cff6ee73e4a1afda5aa
PlasticDigits commented 2026-06-09 06:53:27 +00:00 (Migrated from gitlab.com)

mentioned in merge request !846

mentioned in merge request !846
PlasticDigits commented 2026-06-09 06:53:42 +00:00 (Migrated from gitlab.com)

MR !846 opened

Changes: nativeTransferTax.ts + net CW20 amounts in executeNativeSwap / native-wrap PoolPage provide.

Verify

  • npm test -- nativeTransferTax.test.ts
  • LUNC→EMBER swap succeeds (no Cannot Sub)
  • LUNC-C/EMBER native provide succeeds
## MR !846 opened **Changes:** `nativeTransferTax.ts` + net CW20 amounts in `executeNativeSwap` / native-wrap `PoolPage` provide. ### Verify - [ ] `npm test -- nativeTransferTax.test.ts` - [ ] LUNC→EMBER swap succeeds (no `Cannot Sub`) - [ ] LUNC-C/EMBER native provide succeeds
ghost1 commented 2026-06-09 06:53:47 +00:00 (Migrated from gitlab.com)

mentioned in merge request !847

mentioned in merge request !847
ghost1 commented 2026-06-09 06:53:50 +00:00 (Migrated from gitlab.com)

mentioned in merge request !849

mentioned in merge request !849
ghost1 commented 2026-06-09 06:53:52 +00:00 (Migrated from gitlab.com)

mentioned in merge request !848

mentioned in merge request !848
PlasticDigits commented 2026-06-09 07:08:51 +00:00 (Migrated from gitlab.com)

mentioned in commit df7f7ac974ce42d67aad4e8c41d408d6f3bed742

mentioned in commit df7f7ac974ce42d67aad4e8c41d408d6f3bed742
PlasticDigits commented 2026-06-09 07:12:14 +00:00 (Migrated from gitlab.com)

mentioned in commit b511e77e6a

mentioned in commit b511e77e6a2e0231acff1b3c305afef0827af9f2
PlasticDigits commented 2026-06-09 08:21:03 +00:00 (Migrated from gitlab.com)

Verification complete — #342

All acceptance and verification criteria PASS on main (83dc192).

Results

Criterion Result Evidence
nativeTransferTax.test.ts PASS Vitest green
LUNC→EMBER swap (no Cannot Sub) PASS wrap-swap.spec.ts E1 e2e-tx — tx success alert
LUNC-C/EMBER native provide PASS wrap-pool.spec.ts E7 e2e-tx — auto-wrap provide tx succeeds

Merged fix: !846 (nativeTransferTax.ts + post-tax CW20 amounts).

Re-verify checklist

  • npm test -- nativeTransferTax.test.ts
  • LUNC→EMBER swap succeeds (no Cannot Sub)
  • LUNC-C/EMBER native provide succeeds
## Verification complete — #342 All acceptance and verification criteria **PASS** on `main` (`83dc192`). ### Results | Criterion | Result | Evidence | |-----------|--------|----------| | `nativeTransferTax.test.ts` | **PASS** | Vitest green | | LUNC→EMBER swap (no Cannot Sub) | **PASS** | `wrap-swap.spec.ts` E1 e2e-tx — tx success alert | | LUNC-C/EMBER native provide | **PASS** | `wrap-pool.spec.ts` E7 e2e-tx — auto-wrap provide tx succeeds | Merged fix: !846 (`nativeTransferTax.ts` + post-tax CW20 amounts). ### Re-verify checklist - [ ] `npm test -- nativeTransferTax.test.ts` - [ ] LUNC→EMBER swap succeeds (no `Cannot Sub`) - [ ] LUNC-C/EMBER native provide succeeds
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-09 08:21:05 +00:00
Brouie commented 2026-06-10 01:51:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #353

mentioned in issue #353
PlasticDigits commented 2026-08-18 00:43:30 +00:00 (Migrated from gitlab.com)

mentioned in issue #559

mentioned in issue #559
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#342
No description provided.