Skip to content

refactor + audit hardening: boilerplate dedup + 6 security fixes - #47

Merged
szhygulin merged 1 commit into
mainfrom
refactor/reduce-size
Apr 21, 2026
Merged

refactor + audit hardening: boilerplate dedup + 6 security fixes#47
szhygulin merged 1 commit into
mainfrom
refactor/reduce-size

Conversation

@szhygulin

Copy link
Copy Markdown
Collaborator

Summary

  • Refactor (88b06cd): dedup token-meta + approval-chain boilerplate across action builders (Aave, Compound, Morpho, Lido, EigenLayer, sends). Shared helpers live in src/modules/shared/{token-meta,approval}.ts.
  • Security hardening (b606722): 1 Medium + 5 defensive fixes surfaced by a full-surface audit of the tx-construction pipeline:
    • swap exact-in (Medium): prepareSwap now asserts BigInt(quote.action.fromAmount) === parseUnits(args.amount, decimals) right after the decimals cross-check. Without this, a hostile/MITM'd LiFi response could inflate fromAmount (with toAmount scaled proportionally to dodge the toUsd/fromUsd > 10 gate) so the approval + swap bytes pull more than the MCP preview displays.
    • EIP-55 on recipient: prepareNativeSend / prepareTokenSend now reject mixed-case recipients with a wrong EIP-55 checksum via isAddress(x, { strict: true }); all-lowercase still accepted. Catches single-character case typos before bytes reach Ledger.
    • preview_send pin guard: re-calls return the existing pin verbatim unless refresh: true is passed. The preSignHash the user matched in chat can no longer silently drift before Ledger displays it.
    • TRON USB serialization: getTronLedgerAddress / signTronTxOnLedger run under a module-local promise-chain lock so concurrent HID opens queue instead of colliding on the exclusive transport.
    • Pairing URI label: printed URI is now labeled (sensitive — don't share; one-time pairing secret).
    • Dockerfile: runtime stage drops to USER node.
  • New regression test test/audit/01-swap-exact-in-approval-divergence.test.ts covers the Medium fix (refusal on drift + happy-path regression).

Test plan

  • npx vitest run — 444/444 tests pass
  • npx tsc --noEmit — clean
  • Manual: run a real LiFi swap through prepare_swappreview_sendsend_transaction on testnet or small mainnet amount, confirm no regression in the normal flow
  • Manual: call preview_send twice on the same handle, confirm second call returns the same preSignHash without refresh: true
  • Manual: attempt prepare_native_send with a mixed-case-wrong-checksum recipient, confirm refusal

🤖 Generated with Claude Code

… hardenings

- swap exact-in: assert BigInt(quote.action.fromAmount) equals parseUnits(args.amount, decimals);
  without this, a hostile/MITM'd LiFi quote could inflate fromAmount (toAmount scaled
  proportionally to dodge the toUsd/fromUsd>10 gate) and drive the approval/swap bytes
  to pull a different amount than the MCP preview displays
- prepareNativeSend / prepareTokenSend: reject mixed-case recipient with a wrong EIP-55
  checksum via isAddress(x, { strict: true }); all-lowercase still accepted, catches
  single-character case typos before the bytes reach Ledger
- preview_send: return the existing pin verbatim unless refresh:true is passed; the
  pre-sign hash the user matched in chat cannot silently drift before Ledger displays it
- TRON USB: serialize getTronLedgerAddress / signTronTxOnLedger through a module-local
  promise chain so concurrent HID opens queue instead of colliding on the exclusive
  transport
- setup: label printed pairing URI as sensitive / one-time
- Dockerfile: drop to USER node in the runtime stage
- test/audit/01-*: regression test for the VP-01 fromAmount assert + happy-path guard

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@szhygulin
szhygulin merged commit 57149ff into main Apr 21, 2026
3 checks passed
@szhygulin szhygulin mentioned this pull request Apr 21, 2026
3 tasks
@szhygulin
szhygulin deleted the refactor/reduce-size branch April 25, 2026 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant