LP tokens: consider 18 decimals to avoid initial-mint overflow with 18-decimal pairs #124

Closed
opened 2026-05-03 12:04:02 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-05-03 12:04:02 +00:00 (Migrated from gitlab.com)

Location

smartcontracts/contracts/pair/src/contract.rs (around line 419)

Current behavior

decimals: 6 — all LP tokens are created with 6 decimals.

Risk

If paired tokens have 18 decimals, the isqrt(amount_a × amount_b) initial LP calculation involves very large numbers (amount_a * amount_b could be ~10^36), potentially overflowing Uint128 (max ~1.84×10^38).

Notes

Not an immediate risk for typical Terra Classic tokens (6 decimals), but could be an issue if 18-decimal tokens are whitelisted.

Suggested direction

Evaluate bumping LP token decimals to 18 (or otherwise scaling the math) so initial liquidity mint stays within safe integer ranges for high-decimal asset pairs.

## Location `smartcontracts/contracts/pair/src/contract.rs` (around line 419) ## Current behavior `decimals: 6` — all LP tokens are created with 6 decimals. ## Risk If paired tokens have 18 decimals, the `isqrt(amount_a × amount_b)` initial LP calculation involves very large numbers (`amount_a * amount_b` could be ~10^36), potentially overflowing `Uint128` (max ~1.84×10^38). ## Notes Not an immediate risk for typical Terra Classic tokens (6 decimals), but could be an issue if 18-decimal tokens are whitelisted. ## Suggested direction Evaluate bumping LP token decimals to 18 (or otherwise scaling the math) so initial liquidity mint stays within safe integer ranges for high-decimal asset pairs.
PlasticDigits commented 2026-05-03 13:19:07 +00:00 (Migrated from gitlab.com)

mentioned in commit 5c8ec620d6

mentioned in commit 5c8ec620d6e137e5524572cb0b2acab16a7444de
PlasticDigits commented 2026-05-03 13:19:57 +00:00 (Migrated from gitlab.com)

Implemented in main (merge at 5ec48a2).

Summary

  • LP share CW20 mintable tokens are instantiated with 18 decimals (dex_common::pair::LP_TOKEN_DECIMALS), pair crate version 1.5.0.
  • Factory CreatePair and first provide_liquidity when both reserves are zero reject either asset CW20 with decimals > 18 (MAX_PAIR_ASSET_DECIMALS_BOOTSTRAP, same value 18). Matches Uint128-safe initial mint path (amount_a * amount_b).
  • Note: cw20-mintable already caps instantiation at 18 decimals; the on-chain checks remain defense in depth for other whitelisted CW20 templates.
  • Docs/skills/dApp comments cross-link #124.

@brouie — please verify.

Checklist for verification

  • cargo test in smartcontracts/ passes (302+ tests; includes pair_coverage_tests::test_lp_token_instantiated_with_lp_token_decimals_constant, test_create_pair_rejects_cw20_above_bootstrap_decimal_cap, test_empty_pool_provide_rejects_asset_decimals_above_bootstrap_cap, test_create_pair_accepts_bootstrap_decimal_cap_boundary).
  • New pair: CW20 TokenInfo on liquidity token shows decimals = 18.
  • CreatePair with a token whose TokenInfo.decimals is 19 fails with Pair asset CW20 decimals must be ≤ 18 (use a non–cw20-mintable test token or custom CW20 if needed).
  • First provide_liquidity on an empty pool fails the same way when either side reports > 18 decimals.
  • Pair with two 18-decimal assets still creates and seeds liquidity normally.
  • docs/contracts-terraclassic.md, docs/contracts-security-audit.md (P3), docs/README.md, skills/AGENTS_LOCALNET_TRADING_SWARM.md read coherently.

Issue left open pending your sign-off.

Implemented in `main` (merge at 5ec48a2). **Summary** - LP share CW20 mintable tokens are instantiated with **18 decimals** (`dex_common::pair::LP_TOKEN_DECIMALS`), pair crate version **1.5.0**. - **Factory `CreatePair`** and **first** `provide_liquidity` when both reserves are zero reject either asset CW20 with **`decimals > 18`** (`MAX_PAIR_ASSET_DECIMALS_BOOTSTRAP`, same value 18). Matches `Uint128`-safe initial mint path (`amount_a * amount_b`). - Note: `cw20-mintable` already caps instantiation at 18 decimals; the on-chain checks remain **defense in depth** for other whitelisted CW20 templates. - Docs/skills/dApp comments cross-link **#124**. @brouie — please verify. **Checklist for verification** - [ ] `cargo test` in `smartcontracts/` passes (302+ tests; includes `pair_coverage_tests::test_lp_token_instantiated_with_lp_token_decimals_constant`, `test_create_pair_rejects_cw20_above_bootstrap_decimal_cap`, `test_empty_pool_provide_rejects_asset_decimals_above_bootstrap_cap`, `test_create_pair_accepts_bootstrap_decimal_cap_boundary`). - [ ] New pair: CW20 `TokenInfo` on liquidity token shows **decimals = 18**. - [ ] `CreatePair` with a token whose `TokenInfo.decimals` is **19** fails with **Pair asset CW20 decimals must be ≤ 18** (use a non–cw20-mintable test token or custom CW20 if needed). - [ ] First `provide_liquidity` on an empty pool fails the same way when either side reports **> 18** decimals. - [ ] Pair with two **18-decimal** assets still **creates** and **seeds** liquidity normally. - [ ] `docs/contracts-terraclassic.md`, `docs/contracts-security-audit.md` (P3), `docs/README.md`, `skills/AGENTS_LOCALNET_TRADING_SWARM.md` read coherently. Issue left **open** pending your sign-off.
Brouie commented 2026-05-04 03:40:52 +00:00 (Migrated from gitlab.com)

verified via cargo test on smartcontracts/.

cargo test --workspace → 308 tests pass, 0 failures (matches your 302+ count, +6 from a doc-tests crate).

all 4 specifically-called-out #124 tests present and passing under pair_coverage_tests:::

  • test_lp_token_instantiated_with_lp_token_decimals_constant (LP token decimals = 18 invariant)
  • test_create_pair_rejects_cw20_above_bootstrap_decimal_cap (rejects 19+ decimal CW20)
  • test_create_pair_accepts_bootstrap_decimal_cap_boundary (accepts 18 boundary)
  • test_empty_pool_provide_rejects_asset_decimals_above_bootstrap_cap (provide_liquidity gate fires when either side > 18)

doc cross-links present in contracts-terraclassic.md, contracts-security-audit.md, README.md.

new-pair TokenInfo decimals = 18 implicit in the lp_token_instantiated test. live LocalTerra repro for CreatePair-with-19-decimal-token rejection deferred — the 4 unit tests cover the gate logic deterministically against the same on-chain code path.

verified via cargo test on smartcontracts/. `cargo test --workspace` → 308 tests pass, 0 failures (matches your 302+ count, +6 from a doc-tests crate). all 4 specifically-called-out #124 tests present and passing under `pair_coverage_tests::`: - `test_lp_token_instantiated_with_lp_token_decimals_constant` (LP token decimals = 18 invariant) - `test_create_pair_rejects_cw20_above_bootstrap_decimal_cap` (rejects 19+ decimal CW20) - `test_create_pair_accepts_bootstrap_decimal_cap_boundary` (accepts 18 boundary) - `test_empty_pool_provide_rejects_asset_decimals_above_bootstrap_cap` (provide_liquidity gate fires when either side > 18) doc cross-links present in contracts-terraclassic.md, contracts-security-audit.md, README.md. new-pair TokenInfo decimals = 18 implicit in the lp_token_instantiated test. live LocalTerra repro for CreatePair-with-19-decimal-token rejection deferred — the 4 unit tests cover the gate logic deterministically against the same on-chain code path.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-04 03:42:06 +00:00
PlasticDigits commented 2026-07-12 08:24:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #480

mentioned in issue #480
PlasticDigits commented 2026-08-23 06:48:17 +00:00 (Migrated from gitlab.com)

mentioned in issue #604

mentioned in issue #604
PlasticDigits commented 2026-08-27 08:27:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #629

mentioned in issue #629
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#124
No description provided.