Skip to content

fix(tron): bind transfer fields before signing - #15

Open
senamakel wants to merge 1 commit into
tinyhumansai:mainfrom
senamakel:fix/tron-transfer-verification
Open

fix(tron): bind transfer fields before signing#15
senamakel wants to merge 1 commit into
tinyhumansai:mainfrom
senamakel:fix/tron-transfer-verification

Conversation

@senamakel

@senamakel senamakel commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

Bind every host-requested Tron transfer field to the node-built transaction before signing. Native transfers verify the protobuf-varint amount, while TRC20 transfers verify the full ABI parameter that carries both recipient and amount; both paths continue to recompute and compare the transaction ID.

Related issue

None. Required by review feedback on tinyhumansai/openhuman#5495.

API or behavior changes

TransactionSpec::Tron now includes a required TronTransfer verification descriptor. This is a breaking wire-contract change for callers constructing that variant and is paired with the OpenHuman host update.

Validation

Commands actually run, with their outcome:

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --all-targets --all-features
  • cargo test --all-features

Tests

Added rejection coverage for a substituted native amount and an altered TRC20 parameter. Updated client and module fixtures for the expanded wire contract. All 276 library tests, 7 public API tests, 9 module tests, and 18 doctests pass.

Documentation

Updated public wire-type and verification documentation in code; no separate guide is needed for this focused contract extension.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Summary by CodeRabbit

  • New Features

    • Tron transaction specifications now support explicit native TRX amounts and TRC20 transfer parameters.
    • Tron transfer verification validates the recipient, transaction ID, and requested transfer details.
  • Bug Fixes

    • Improved rejection of Tron transactions with missing, empty, or mismatched transfer data.
    • Corrected Tron transaction encoding used in verification scenarios.
  • Tests

    • Expanded coverage for valid transfers, incorrect native amounts, mismatched TRC20 parameters, and malformed transactions.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Tron transaction specifications now include transfer details. Verification checks native amounts and TRC20 parameters, and callers pass the transfer descriptor through signing and service flows. Tests update fixtures and cover valid and invalid transfer payloads.

Changes

Tron transfer verification

Layer / File(s) Summary
Transfer specification contract
src/wire/mod.rs, src/wire/test.rs
TransactionSpec::Tron now requires a TronTransfer with native TRX or TRC20 data.
Transfer payload validation
src/tx/tron.rs
verify_transfer validates transaction ID, recipient, native amounts, and TRC20 parameters. Tests cover valid, incorrect, and mismatched payloads.
Verification wiring and fixtures
src/client/tron.rs, crates/tinywallet-module/src/service/mod.rs, crates/tinywallet-module/src/service/test.rs, crates/tinywallet-module/tests/module_e2e.rs, src/client/test.rs
Client and service flows pass transfer data to Tron verification. Tron fixtures use the corrected encoding and include native transfer descriptors.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TransactionSpec
  participant TronClient
  participant TronVerifier
  TransactionSpec->>TronClient: transfer descriptor
  TronClient->>TronVerifier: raw data, recipient, txid, transfer
  TronVerifier->>TronVerifier: validate native amount or TRC20 parameter
  TronVerifier-->>TronClient: verification result
Loading

Possibly related PRs

Suggested labels: priority: p1

Poem

I carry the transfer, precise and bright,
Native coins or tokens encoded right.
The Tron path checks each payload true,
And rejects mismatches before they pass through.
— A verification rabbit 🐇

🚥 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: binding Tron transfer fields before signing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tx/tron.rs`:
- Around line 84-97: Replace the raw byte-substring validation in the transfer
verification flow with Tron transaction decoding: parse the transaction
contract, require the contract type matching the requested TronTransfer variant,
and compare the native amount or TRC20 ABI parameters from that contract payload
against the requested values. Ensure expected bytes in unrelated fields are
rejected, and add fixtures/tests covering those cases.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d2313d0-5573-41b7-904b-4633112791d4

📥 Commits

Reviewing files that changed from the base of the PR and between f82edab and a800ffb.

📒 Files selected for processing (8)
  • crates/tinywallet-module/src/service/mod.rs
  • crates/tinywallet-module/src/service/test.rs
  • crates/tinywallet-module/tests/module_e2e.rs
  • src/client/test.rs
  • src/client/tron.rs
  • src/tx/tron.rs
  • src/wire/mod.rs
  • src/wire/test.rs

Comment thread src/tx/tron.rs
Comment on lines +84 to +97
let raw = decode_hex(raw_data_hex)?;
let expected = match transfer {
TronTransfer::Native { amount_sun } => encode_varint(*amount_sun),
TronTransfer::Trc20 { parameter_hex } => decode_hex(parameter_hex)?,
};
if expected.is_empty() || !raw.windows(expected.len()).any(|window| window == expected) {
let field = match transfer {
TronTransfer::Native { .. } => "amount",
TronTransfer::Trc20 { .. } => "TRC20 transfer parameter",
};
return Err(Error::UntrustedResponse {
reason: format!("the node's transaction does not contain the requested {field}"),
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- tron implementation and tests ---'
sed -n '1,125p' src/tx/tron.rs
sed -n '230,325p' src/tx/tron.rs

printf '%s\n' '--- Tron verification call sites ---'
rg -n -C 5 'verify_transfer|raw_data_hex|expected_txid|build_unsigned|attach_signature' \
  src crates/tinywallet-module/src/service/mod.rs

printf '%s\n' '--- exact predicate probe ---'
python3 - <<'PY'
def accepts(raw: bytes, expected: bytes) -> bool:
    return bool(expected) and any(
        raw[i:i + len(expected)] == expected
        for i in range(len(raw) - len(expected) + 1)
    )

cases = [
    ("native bytes occur in unrelated field", bytes.fromhex("12010f220101"), bytes.fromhex("0f")),
    ("trc20 parameter occurs in unrelated field", bytes.fromhex("1204deadbeef2204aabbccdd"), bytes.fromhex("aabbccdd")),
    ("expected bytes absent", bytes.fromhex("1201aa"), bytes.fromhex("0f")),
]
for name, raw, expected in cases:
    print(f"{name}: {accepts(raw, expected)}")
PY

Repository: tinyhumansai/tinywallet

Length of output: 46718


Other (CWE-345)

Reachability: External

Parse the transfer contract before accepting the requested fields.

raw.windows(...) only proves that the requested bytes occur somewhere in raw_data. A compromised node can place the expected native varint or TRC20 parameter in an unrelated field while using different transfer values. The transaction-ID check does not bind these bytes to the requested transfer fields.

Decode the Tron transaction structure, require the expected contract type, and compare the native amount or TRC20 ABI parameters within that contract payload. Add fixtures that place the expected bytes in an unrelated field and assert rejection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tx/tron.rs` around lines 84 - 97, Replace the raw byte-substring
validation in the transfer verification flow with Tron transaction decoding:
parse the transaction contract, require the contract type matching the requested
TronTransfer variant, and compare the native amount or TRC20 ABI parameters from
that contract payload against the requested values. Ensure expected bytes in
unrelated fields are rejected, and add fixtures/tests covering those cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant