Skip to content

Tron: Spend a prebuilt TriggerSmartContract call - #1088

Open
j0ntz wants to merge 2 commits into
masterfrom
jon/rango-tron-contract-call
Open

Tron: Spend a prebuilt TriggerSmartContract call#1088
j0ntz wants to merge 2 commits into
masterfrom
jon/rango-tron-contract-call

Conversation

@j0ntz

@j0ntz j0ntz commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

Asana: https://app.asana.com/0/1215088146871429/1216839790397157

TronEngine.makeSpend only read otherParams for the four staking actions. Everything
else fell through to makeTransferJson / encodeTRC20Transfer, so a DEX swap that
arrives as a finished TriggerSmartContract call was silently rewritten into a plain
transfer and never executed the swap.

What changed

  • asTronContractCallOtherParams (tronTypes.ts) recognizes { contractJson, feeLimit?, note? }
    where contractJson is a TriggerSmartContract. Every level uses .withRest, so the payload
    reaches the transaction builder byte-identical to what the provider sent — parameter.type_url
    is load-bearing here, it is serialized into the signed raw data.
  • makeContractCallTransaction builds the transaction through the existing
    txBuilder({ contractJson, feeLimit, note }) and returns otherParams unchanged, so signTx
    (getOtherParamstxBuilder → sign) needed no change. It refuses a payload whose
    owner_address is not this wallet.
  • Amount accounting follows the transfer path: a token call reports the caller's amount with the
    fee as parentNetworkFee; a mainnet call reports the contract's own call_value plus the fee,
    since that is the TRX the chain actually moves.
  • calcTxFee gained contractCallOpts. The existing energy estimate dry-runs a canonical
    transfer(address,uint256), which says nothing about a swap router, so a contract call is
    estimated from its own data and call_value. A failed dry run falls back to the existing
    default rather than blocking the spend, because a call that depends on an approval which has
    not been broadcast yet cannot be simulated. The existing token-transfer estimate is untouched.
  • The CLI make-spend command takes --otherParams <json>, so the new path can be driven
    outside a swap plugin.

Testing

Unit tests (test/tron/tronContractCall.test.ts) use the real Rango payload from the task:
the cleaner accepts it, rejects staking and transfer payloads, and the built raw data matches
the provider's raw_data_hex and txID byte-for-byte.

Driven end to end on the iOS sim against edge-exchange-plugins#484:
a TRX → USDT swap through Rango reached the success scene, and on-chain
42fd4970…9650
is a TriggerSmartContract with contractRet: SUCCESS, call_value 39.148 TRX, selector
cef95229 against the Sun Swap router, and the same transaction delivered 13.004043 USDT.
Screenshots in a comment below.


Note

Medium Risk
Changes the Tron spend path for otherParams contract calls and fee math; guards reduce silent mis-sends, but wrong validation or accounting could still affect real swap spends and TRX balances.

Overview
Tron DEX swaps no longer get rewritten into plain TRX/TRC20 transfers when a swap plugin passes a finished TriggerSmartContract in otherParams. makeSpend now routes valid payloads through makeContractCallTransaction, which signs the provider’s contractJson byte-identical via the existing txBuilder path.

Fee estimation adds contractCallOpts to calcTxFee: energy is dry-run with /wallet/triggerconstantcontract using the call’s own data and call_value, with revert detection on ret and result.message, and a default fallback when simulation fails (e.g. pending approval). Malformed contract-call attempts are blocked by asTronContractCallIntent so they error instead of falling through to a transfer to the contract address.

The CLI make-spend command accepts --otherParams JSON for testing this path outside swap plugins.

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

Lets the CLI hand an engine a prebuilt payload, which is how a TRON
contract call reaches makeSpend outside of a swap plugin.
@j0ntz

j0ntz commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence: Rango TRX → USDT swap on iOS sim

rango trx usdt quote

rango trx usdt quote

rango trx swap success

rango trx swap success

rango trx tx details

rango trx tx details

Captured by the agent's in-app test run (build-and-test).

@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from 6536d5e to c5df3b5 Compare August 14, 2026 17:24
@j0ntz
j0ntz marked this pull request as ready for review August 14, 2026 17:24
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Comment thread src/tron/TronEngine.ts
@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from c5df3b5 to 3e34fb7 Compare August 14, 2026 17:34
Comment thread src/tron/TronEngine.ts
Comment thread src/tron/tronTypes.ts
Comment thread src/tron/TronEngine.ts
@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from 3e34fb7 to 7650f82 Compare August 14, 2026 17:46
Comment thread src/tron/TronEngine.ts
Comment thread src/tron/tronTypes.ts
@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from 7650f82 to 599badd Compare August 14, 2026 18:01
Comment thread src/tron/tronTypes.ts
@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from 599badd to 43377eb Compare August 14, 2026 18:17

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 43377eb. Configure here.

Comment thread src/tron/TronEngine.ts
makeSpend only read otherParams for the staking actions, so a DEX swap
that arrives as a finished contract call fell through to the transfer
encoders and was signed as a transfer instead. Detect the payload and
hand it to the transaction builder untouched, keeping signTx unchanged.

Energy is estimated by dry-running the call's own data, since the
canonical TRC20 transfer estimate says nothing about an arbitrary
contract call.
@j0ntz
j0ntz force-pushed the jon/rango-tron-contract-call branch from 43377eb to f265426 Compare August 14, 2026 18:25
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