Skip to content

fix: address path ordering with mixed inputs#1063

Open
tuliomir wants to merge 3 commits intomasterfrom
fix/send-tx-address-path-ordering
Open

fix: address path ordering with mixed inputs#1063
tuliomir wants to merge 3 commits intomasterfrom
fix/send-tx-address-path-ordering

Conversation

@tuliomir
Copy link
Copy Markdown
Contributor

@tuliomir tuliomir commented Apr 13, 2026

Summary

Fixes the utxosAddressPath ordering bug in SendTransactionWalletService.prepareTx() when user-provided inputs mix HTR and custom token UTXOs.

Closes #1057

Problem

When users provide manual inputs, prepareTx() validates them in two passes:

  1. Custom tokens first (ignoreNative: true)
  2. HTR second (onlyNative: true)

The resulting utxosAddressPath is concatenated as [token_paths..., htr_paths...], regardless of the original input order. During signing, input i is signed with utxosAddressPath[i], causing mismatched signatures when HTR inputs appear before token inputs.

Why two passes are necessary

The two-pass structure is load-bearing and cannot be collapsed into a single pass. Fee-token change outputs are discovered during the first pass (custom token validation), and each one increases _feeAmount by FEE_PER_OUTPUT. The correct HTR amount can only be computed after all fee-token changes are accounted for. Processing everything in one pass would validate HTR against an incomplete fee total.

Fix

Adds an optional addressPathMap: Map<string, string> parameter to validateUtxos. Both passes populate this map keyed by ${txId}:${index}, then prepareTx rebuilds utxosAddressPath in this.inputs order. This preserves the two-pass fee calculation while decoupling address path collection from array concatenation order.

Acceptance criteria

  • Transactions with manually provided inputs mixing HTR and custom tokens produce valid signatures regardless of input ordering
  • The previously failing integration test scenario (fee token with HTR input first) passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Ensures address-paths for transaction inputs are collected in the exact input order and missing mappings are detected and reported as errors during transaction preparation.
    • Provides clearer rejection messages when an HTR input is present but HTR is not required by the transaction outputs.

Use a Map to collect address paths during the two-pass
validation (tokens first, HTR second), then rebuild in
this.inputs order. Fixes invalid signatures when users
provide HTR inputs before token inputs.

Closes #1057

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b68d75f4-ace7-4d47-92de-a1b6a0e9c66c

📥 Commits

Reviewing files that changed from the base of the PR and between 7c80c79 and d379bfb.

📒 Files selected for processing (2)
  • __tests__/wallet/sendTransactionWalletService.test.ts
  • src/wallet/sendTransactionWalletService.ts

📝 Walkthrough

Walkthrough

Introduce a Map-based collection of address paths during UTXO validation so utxosAddressPath is rebuilt in the original input order; update validateUtxos signature to accept an optional addressPathMap and throw when an input's address path is missing. Tests added to cover HTR/token ordering and rejection cases.

Changes

Cohort / File(s) Summary
SendTransaction logic
src/wallet/sendTransactionWalletService.ts
Add addressPathMap: Map<string,string> usage in two-pass UTXO validation, extend validateUtxos options to accept addressPathMap, populate the map during validation, rebuild utxosAddressPath in this.inputs order, and throw SendTxError if any input is missing a path.
Tests — send transaction
__tests__/wallet/sendTransactionWalletService.test.ts
Add three tests covering HTR input rejection when not required, two-pass validation/rebuild rejection message, and preservation of utxosAddressPath ordering matching provided inputs order.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

tests

Suggested reviewers

  • raul-oliveira
  • pedroferreira1

Poem

🐰
I hopped through maps and keyed each trace,
Matched inputs to paths in proper place.
No more swapped signs or signature woes,
Order restored — off the rabbit goes! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing address path ordering when inputs mix HTR and custom tokens, which is the core issue addressed.
Linked Issues check ✅ Passed All coding objectives from #1057 are met: addressPathMap parameter added to validateUtxos, both validation passes populate it, utxosAddressPath is rebuilt in input order, and error handling for missing paths is implemented.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing #1057: address path reordering logic in prepareTx, validateUtxos signature update, and corresponding unit tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/send-tx-address-path-ordering

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 87.94%. Comparing base (0ccc910) to head (d379bfb).

Files with missing lines Patch % Lines
src/wallet/sendTransactionWalletService.ts 91.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1063   +/-   ##
=======================================
  Coverage   87.93%   87.94%           
=======================================
  Files         114      114           
  Lines        8910     8917    +7     
  Branches     2030     2032    +2     
=======================================
+ Hits         7835     7842    +7     
  Misses       1047     1047           
  Partials       28       28           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/wallet/sendTransactionWalletService.ts (1)

445-464: ⚠️ Potential issue | 🟠 Major

Handle manual HTR inputs even when the required HTR amount is 0n.

Line 447 still skips the native pass when htrAmount is 0n. If the caller manually includes HTR UTXOs for a custom-token-only send, those inputs never create HTR change and never populate addressPathMap, so Line 461 now fails with Address path not found.... SendTransactionWalletService.prepareTxData() already validates manual HTR inputs against 0n, so these two preparation paths still diverge here. A small hasUserHtrInput/cached-UTXO flag from the first scan would let this branch run validateUtxos when htrAmount > 0n || hasUserHtrInput.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/wallet/sendTransactionWalletService.ts` around lines 445 - 464, The code
skips the native-UTXO validation when htrAmount === 0n which breaks later lookup
for manually provided HTR inputs; update the condition around the validateUtxos
call in SendTransactionWalletService (the htrAmount / NATIVE_TOKEN_UID block) to
run when htrAmount > 0n OR when a flag indicating the caller provided manual HTR
UTXOs is true (e.g., hasUserHtrInput discovered during the initial UTXO scan in
prepareTxData). Ensure that hasUserHtrInput is set during the first scan of
inputs/utxos, then change the if from (htrAmount > 0n) to (htrAmount > 0n ||
hasUserHtrInput) so validateUtxos(htrTokenAmount, { onlyNative: true,
addressPathMap }) is invoked and addressPathMap gets populated before rebuilding
utxosAddressPath from this.inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/wallet/sendTransactionWalletService.ts`:
- Around line 445-464: The code skips the native-UTXO validation when htrAmount
=== 0n which breaks later lookup for manually provided HTR inputs; update the
condition around the validateUtxos call in SendTransactionWalletService (the
htrAmount / NATIVE_TOKEN_UID block) to run when htrAmount > 0n OR when a flag
indicating the caller provided manual HTR UTXOs is true (e.g., hasUserHtrInput
discovered during the initial UTXO scan in prepareTxData). Ensure that
hasUserHtrInput is set during the first scan of inputs/utxos, then change the if
from (htrAmount > 0n) to (htrAmount > 0n || hasUserHtrInput) so
validateUtxos(htrTokenAmount, { onlyNative: true, addressPathMap }) is invoked
and addressPathMap gets populated before rebuilding utxosAddressPath from
this.inputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dbae6d47-6258-4b8b-b394-dafa5c7b29ca

📥 Commits

Reviewing files that changed from the base of the PR and between 0ccc910 and 7c80c79.

📒 Files selected for processing (1)
  • src/wallet/sendTransactionWalletService.ts

Add tests for the utxosAddressPath ordering fix:
- Verify paths match input order when HTR comes before
  token inputs (regression test for #1057)
- Verify rejection of unnecessary HTR inputs when no
  HTR is needed in the transaction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tuliomir tuliomir self-assigned this Apr 13, 2026
@tuliomir tuliomir added the bug Something isn't working label Apr 13, 2026
@tuliomir tuliomir moved this from Todo to In Progress (WIP) in Hathor Network Apr 13, 2026
When a user provides an HTR input but the transaction
requires no HTR (no HTR outputs, no fees), the error
now explains the root cause instead of showing a
generic "address path not found" message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tuliomir tuliomir moved this from In Progress (WIP) to In Progress (Done) in Hathor Network Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: In Progress (Done)

Development

Successfully merging this pull request may close these issues.

fix: SendTransactionWalletService signs inputs with wrong address paths when mixing token types

1 participant