EH-1: Humanize insufficient-gas fee-mismatch errors for end users (#371) #888

Merged
PlasticDigits merged 2 commits from verify/issue-371-fee-mismatch-user-copy into main 2026-06-13 02:40:13 +00:00
PlasticDigits commented 2026-06-12 12:00:30 +00:00 (Migrated from gitlab.com)

Summary

When Keplr (or another extension) signs a fee far below the dApp envelope on LocalTerra, the UI now shows short retail copy instead of developer diagnostics (GitLab issue refs, uluna amounts, npm ci hints, Station-specific steps).

  • extensionSignedFeeGuard.ts and the cosmes patch throw EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE; detailed diagnostics log to console.warn.
  • humanizeTerraTxError.ts maps legacy throws to the same retail copy.
  • terraBroadcast.ts no longer bypasses humanization for fee-undershoot errors.

Verification checklist

Acceptance item Result How verified
Error must not expose GitLab #127, shell commands, raw uluna, or gas unit values PASS extensionSignedFeeGuard.test.ts, humanizeTerraTxError.test.ts (verbatim issue repro string), humanizeUserFacingError.test.ts
Error must be short, plain-language, actionable (fee mismatch + reconnect + support) PASS Assert EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE in unit tests
Cosmes patch stays in sync and applies on npm ci PASS cosmesPatch127.test.ts — EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE present; npm ci + patch-package apply clean
broadcastTerraExecuteContracts surfaces humanized copy (not raw diagnostic) PASS terraBroadcast.test.ts — legacy diagnostic input → /Transaction fee mismatch/
Manual: Swap / on LocalTerra, Keplr low gas limit, approve swap SKIP LocalTerra not provisioned in verify VM (make has-localterra → not running; no .env.local). Automated tests cover the exact observed error string from the issue.

Commands

bash scripts/with-node.sh --cwd frontend-dapp -- npm ci
bash scripts/with-node.sh --cwd frontend-dapp -- npm run test:unit -- \
  src/utils/__tests__/extensionSignedFeeGuard.test.ts \
  src/utils/__tests__/humanizeTerraTxError.test.ts \
  src/utils/__tests__/humanizeUserFacingError.test.ts \
  src/services/terraclassic/__tests__/terraBroadcast.test.ts \
  src/services/terraclassic/__tests__/cosmesPatch127.test.ts
# 39 tests passed

Follow-ups

  • After merge, manual Keplr low-gas repro on LocalTerra Swap (make setup-cloud-localterra) to close the browser QA loop for EH-1.

Note

Low Risk
Error-message and logging only; post-sign fee validation behavior is unchanged aside from the thrown message text.

Overview
When a wallet signs fees far below the dApp envelope (LocalTerra post-sign guard), users now see Transaction fee mismatch. Please reconnect your wallet and try again. If the problem persists, contact support. instead of GitLab refs, uluna amounts, npm ci, or Station-specific steps.

extensionSignedFeeGuard.ts and the cosmes KeplrExtension patch return that retail string on failure while console.warn keeps the full diagnostic. humanizeTerraTxError and the general humanizeUserFacingError path map legacy long throws to the same copy. terraBroadcast drops the bypass that surfaced raw fee-guard messages without humanization.

Tests and AGENTS_TERRACLASSIC_GAS.md were updated to lock in the new UX and patch sync.

Reviewed by Cursor Bugbot for commit 630cacb79b. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary When Keplr (or another extension) signs a fee far below the dApp envelope on LocalTerra, the UI now shows short retail copy instead of developer diagnostics (GitLab issue refs, `uluna` amounts, `npm ci` hints, Station-specific steps). - `extensionSignedFeeGuard.ts` and the cosmes patch throw **`EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE`**; detailed diagnostics log to `console.warn`. - `humanizeTerraTxError.ts` maps legacy throws to the same retail copy. - `terraBroadcast.ts` no longer bypasses humanization for fee-undershoot errors. ## Verification checklist | Acceptance item | Result | How verified | |---|---|---| | Error must not expose `GitLab #127`, shell commands, raw `uluna`, or gas unit values | **PASS** | `extensionSignedFeeGuard.test.ts`, `humanizeTerraTxError.test.ts` (verbatim issue repro string), `humanizeUserFacingError.test.ts` | | Error must be short, plain-language, actionable (fee mismatch + reconnect + support) | **PASS** | Assert `EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE` in unit tests | | Cosmes patch stays in sync and applies on `npm ci` | **PASS** | `cosmesPatch127.test.ts` — `EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE` present; `npm ci` + patch-package apply clean | | `broadcastTerraExecuteContracts` surfaces humanized copy (not raw diagnostic) | **PASS** | `terraBroadcast.test.ts` — legacy diagnostic input → `/Transaction fee mismatch/` | | Manual: Swap `/` on LocalTerra, Keplr low gas limit, approve swap | **SKIP** | LocalTerra not provisioned in verify VM (`make has-localterra` → not running; no `.env.local`). Automated tests cover the exact observed error string from the issue. | ### Commands ```bash bash scripts/with-node.sh --cwd frontend-dapp -- npm ci bash scripts/with-node.sh --cwd frontend-dapp -- npm run test:unit -- \ src/utils/__tests__/extensionSignedFeeGuard.test.ts \ src/utils/__tests__/humanizeTerraTxError.test.ts \ src/utils/__tests__/humanizeUserFacingError.test.ts \ src/services/terraclassic/__tests__/terraBroadcast.test.ts \ src/services/terraclassic/__tests__/cosmesPatch127.test.ts # 39 tests passed ``` ## Follow-ups - After merge, manual Keplr low-gas repro on LocalTerra Swap (`make setup-cloud-localterra`) to close the browser QA loop for EH-1. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Error-message and logging only; post-sign fee validation behavior is unchanged aside from the thrown message text. > > **Overview** > When a wallet signs fees far below the dApp envelope (LocalTerra post-sign guard), users now see **`Transaction fee mismatch. Please reconnect your wallet and try again. If the problem persists, contact support.`** instead of GitLab refs, `uluna` amounts, `npm ci`, or Station-specific steps. > > **`extensionSignedFeeGuard.ts`** and the **cosmes `KeplrExtension` patch** return that retail string on failure while **`console.warn`** keeps the full diagnostic. **`humanizeTerraTxError`** and the general **`humanizeUserFacingError`** path map legacy long throws to the same copy. **`terraBroadcast`** drops the bypass that surfaced raw fee-guard messages without humanization. > > Tests and **`AGENTS_TERRACLASSIC_GAS.md`** were updated to lock in the new UX and patch sync. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 630cacb79b35ff966eafcbb665896f36602d3ff1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
ghost1 commented 2026-06-12 12:00:39 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-12 12:00:46 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-12 12:02:56 +00:00 (Migrated from gitlab.com)

Security review — MR !888

Commit reviewed: 630cacb79b35ff966eafcbb665896f36602d3ff1
Scope: EH-1 / #371 — humanize extension signed-fee undershoot errors for end users (extensionSignedFeeGuard.ts, humanizeTerraTxError.ts, terraBroadcast.ts, cosmes KeplrExtension patch, unit tests, docs).

Outcome: FINDINGS: 0 medium+

Summary: Security review: no medium+ findings on this diff.

This change reduces information disclosure by replacing developer diagnostics (GitLab refs, uluna/gas amounts, shell hints) with a fixed retail string in thrown errors and UI paths (tryHumanizeTerraTxMessage, humanizeUserFacingError, TxResultAlert). Detailed fee/gas context is retained only in console.warn. Post-sign fee validation (EXTENSION_SIGNED_FEE_MIN_PERCENT = 95%) and broadcast blocking behavior are unchanged.

Reviewed attack surfaces (no exploitable path found):

  • XSS / HTML injection: Error copy is a static constant; UI renders via React text nodes (no dangerouslySetInnerHTML).
  • Authn/authz / fee-guard bypass: No changes to signing, broadcast, or ratio checks — only error message text and humanization routing.
  • Attacker-controlled input → sink: Wallet-signed fee fields still feed diagnostics, but only to the browser console (not user-facing); this is strictly less exposure than the prior thrown diagnostic strings.
  • Prefix spoofing (EXTENSION_SIGNED_FEE_UNDERSHOOT_PREFIX): Would at most map to the same generic retail message; no privilege or funds impact.
  • Supply chain: No new dependencies; existing patch-package surface only.

Prior threads: None (first security review on this MR).

Inline findings: None.

## Security review — MR !888 **Commit reviewed:** `630cacb79b35ff966eafcbb665896f36602d3ff1` **Scope:** EH-1 / #371 — humanize extension signed-fee undershoot errors for end users (`extensionSignedFeeGuard.ts`, `humanizeTerraTxError.ts`, `terraBroadcast.ts`, cosmes `KeplrExtension` patch, unit tests, docs). **Outcome:** `FINDINGS: 0` medium+ **Summary:** Security review: no medium+ findings on this diff. This change reduces information disclosure by replacing developer diagnostics (GitLab refs, `uluna`/gas amounts, shell hints) with a fixed retail string in thrown errors and UI paths (`tryHumanizeTerraTxMessage`, `humanizeUserFacingError`, `TxResultAlert`). Detailed fee/gas context is retained only in `console.warn`. Post-sign fee validation (`EXTENSION_SIGNED_FEE_MIN_PERCENT` = 95%) and broadcast blocking behavior are unchanged. **Reviewed attack surfaces (no exploitable path found):** - **XSS / HTML injection:** Error copy is a static constant; UI renders via React text nodes (no `dangerouslySetInnerHTML`). - **Authn/authz / fee-guard bypass:** No changes to signing, broadcast, or ratio checks — only error message text and humanization routing. - **Attacker-controlled input → sink:** Wallet-signed fee fields still feed diagnostics, but only to the browser console (not user-facing); this is strictly less exposure than the prior thrown diagnostic strings. - **Prefix spoofing (`EXTENSION_SIGNED_FEE_UNDERSHOOT_PREFIX`):** Would at most map to the same generic retail message; no privilege or funds impact. - **Supply chain:** No new dependencies; existing patch-package surface only. **Prior threads:** None (first security review on this MR). **Inline findings:** None.
PlasticDigits commented 2026-06-12 12:38:02 +00:00 (Migrated from gitlab.com)

added 74 commits

  • 630cacb7...0b63e003 - 73 commits from branch main
  • f8bde22b - Merge origin/main into verify/issue-371-fee-mismatch-user-copy

Compare with previous version

added 74 commits <ul><li>630cacb7...0b63e003 - 73 commits from branch <code>main</code></li><li>f8bde22b - Merge origin/main into verify/issue-371-fee-mismatch-user-copy</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/170/diffs?diff_id=1849049740&start_sha=630cacb79b35ff966eafcbb665896f36602d3ff1)
PlasticDigits commented 2026-06-12 12:38:09 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with origin/main:

  • terraBroadcast.ts: kept main's split sign/broadcast recovery imports and isTerraTxTimeoutMessage; EH-1 humanization via tryHumanizeTerraTxMessage unchanged.
  • humanizeTerraTxError.ts / tests: retained retail fee-mismatch copy and prefix/user-message matching from #371; merged main's stricter negative assertions.
  • extensionSignedFeeGuard.ts: removed duplicate EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE export from auto-merge.
  • AGENTS_TERRACLASSIC_GAS.md: combined #371 UI-copy notes with main's cosmes patch SHA-256 guard (#367).
  • .cosmes-patch-sha256: updated to match the #371 cosmes patch (retail throw in KeplrExtension).

Sanity: 59 targeted unit tests passed (extensionSignedFeeGuard, humanizeTerraTxError, humanizeUserFacingError, terraBroadcast, cosmesPatch127).

Resolved merge conflicts with `origin/main`: - **`terraBroadcast.ts`**: kept main's split sign/broadcast recovery imports and `isTerraTxTimeoutMessage`; EH-1 humanization via `tryHumanizeTerraTxMessage` unchanged. - **`humanizeTerraTxError.ts` / tests**: retained retail fee-mismatch copy and prefix/user-message matching from #371; merged main's stricter negative assertions. - **`extensionSignedFeeGuard.ts`**: removed duplicate `EXTENSION_SIGNED_FEE_UNDERSHOOT_USER_MESSAGE` export from auto-merge. - **`AGENTS_TERRACLASSIC_GAS.md`**: combined #371 UI-copy notes with main's cosmes patch SHA-256 guard (#367). - **`.cosmes-patch-sha256`**: updated to match the #371 cosmes patch (retail throw in `KeplrExtension`). Sanity: 59 targeted unit tests passed (`extensionSignedFeeGuard`, `humanizeTerraTxError`, `humanizeUserFacingError`, `terraBroadcast`, `cosmesPatch127`).
PlasticDigits commented 2026-06-12 12:39:53 +00:00 (Migrated from gitlab.com)

Security review — MR !888

Commit reviewed: f8bde22b5e7aa37e625bb9c4f8d7a6c873bd087a
Scope: EH-1 / #371 — humanize extension signed-fee undershoot errors for end users (extensionSignedFeeGuard.ts, humanizeTerraTxError.ts, cosmes KeplrExtension patch, unit tests, docs). terraBroadcast.ts unchanged on this diff (humanization already routes via tryHumanizeTerraTxMessage on main).

Outcome: FINDINGS: 0 medium+

Summary: Security review: no medium+ findings on this diff.

This change reduces client-side information disclosure by replacing developer diagnostics (GitLab refs, uluna/gas amounts, shell hints) with a fixed retail string in thrown errors and UI paths (tryHumanizeTerraTxMessage, humanizeUserFacingError, TxResultAlert). Detailed fee/gas context is retained only in console.warn. Post-sign fee validation (EXTENSION_SIGNED_FEE_MIN_PERCENT = 95%) and broadcast blocking in terraWalletSignTxRaw / patched KeplrExtension are unchanged.

Reviewed attack surfaces (no exploitable path found):

  • XSS / HTML injection: User-facing copy is a static constant; UI renders via React text nodes (no dangerouslySetInnerHTML).
  • Authn/authz / fee-guard bypass: No changes to signing, ratio checks, or throw-on-undershoot behavior — only error message text and humanization routing.
  • Attacker-controlled input → sink: Wallet-signed fee fields still feed diagnostics, but only to the browser console (not user-facing); strictly less exposure than prior thrown diagnostic strings.
  • Prefix spoofing (EXTENSION_SIGNED_FEE_UNDERSHOOT_PREFIX): Would at most map to the same generic retail message; no privilege or funds impact.
  • Broadcast recovery / isDefiniteBroadcastRejection: Fee-guard failures still throw before broadcast; generic message does not weaken rejection classification vs the prior diagnostic throw.
  • Supply chain: No new dependencies; existing patch-package surface only (SHA-256 guard unchanged in intent).

Prior threads: Review on 630cacb (pre–origin/main merge) — same conclusion; re-reviewed current HEAD f8bde22 after merge.

Inline findings: None.

## Security review — MR !888 **Commit reviewed:** `f8bde22b5e7aa37e625bb9c4f8d7a6c873bd087a` **Scope:** EH-1 / #371 — humanize extension signed-fee undershoot errors for end users (`extensionSignedFeeGuard.ts`, `humanizeTerraTxError.ts`, cosmes `KeplrExtension` patch, unit tests, docs). `terraBroadcast.ts` unchanged on this diff (humanization already routes via `tryHumanizeTerraTxMessage` on `main`). **Outcome:** `FINDINGS: 0` medium+ **Summary:** Security review: no medium+ findings on this diff. This change **reduces** client-side information disclosure by replacing developer diagnostics (GitLab refs, `uluna`/gas amounts, shell hints) with a fixed retail string in thrown errors and UI paths (`tryHumanizeTerraTxMessage`, `humanizeUserFacingError`, `TxResultAlert`). Detailed fee/gas context is retained only in `console.warn`. Post-sign fee validation (`EXTENSION_SIGNED_FEE_MIN_PERCENT` = 95%) and broadcast blocking in `terraWalletSignTxRaw` / patched `KeplrExtension` are unchanged. **Reviewed attack surfaces (no exploitable path found):** - **XSS / HTML injection:** User-facing copy is a static constant; UI renders via React text nodes (no `dangerouslySetInnerHTML`). - **Authn/authz / fee-guard bypass:** No changes to signing, ratio checks, or throw-on-undershoot behavior — only error message text and humanization routing. - **Attacker-controlled input → sink:** Wallet-signed fee fields still feed diagnostics, but only to the browser console (not user-facing); strictly less exposure than prior thrown diagnostic strings. - **Prefix spoofing (`EXTENSION_SIGNED_FEE_UNDERSHOOT_PREFIX`):** Would at most map to the same generic retail message; no privilege or funds impact. - **Broadcast recovery / `isDefiniteBroadcastRejection`:** Fee-guard failures still throw before broadcast; generic message does not weaken rejection classification vs the prior diagnostic throw. - **Supply chain:** No new dependencies; existing patch-package surface only (SHA-256 guard unchanged in intent). **Prior threads:** Review on `630cacb` (pre–`origin/main` merge) — same conclusion; re-reviewed current HEAD `f8bde22` after merge. **Inline findings:** None.
PlasticDigits commented 2026-06-13 02:40:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 87b6f9a3da

mentioned in commit 87b6f9a3da64467062650551294f42987343a756
PlasticDigits (Migrated from gitlab.com) merged commit 87b6f9a3da into main 2026-06-13 02:40:13 +00:00
Sign in to join this conversation.
No reviewers
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!888
No description provided.