Skip to main content
WalletConnect Pay supports Tron payments with USDT (TRC-20). Tron is a sign-only relay chain: WalletConnect Pay builds the transaction, commits to its txID, and broadcasts the signed bytes itself. Your wallet only verifies what it was given and signs it — it never rebuilds, re-serializes, or submits the transaction.
This guide applies whether you integrate with the Wallet Pay SDK or directly with the Gateway API (API-first). The signing requirements are identical — Tron actions arrive as walletRpc actions, and the signed result is returned in the results array. The code samples below use SDK method names; if you are integrating API-first, the equivalents are:Everything else in this guide — advertising Tron accounts, routing by namespace, the tron_signTransaction payload, and returning the { raw_data_hex, signature } object — is the same in both integrations.

Requirements

Object results in data require these minimum SDK versions: Earlier versions type the confirm results as strings only and cannot carry the Tron result object.

Tron payment flow

A Tron payment follows the same three-call flow as any other WalletConnect Pay payment. The Tron-specific parts are the signing method (tron_signTransaction), the verification your wallet performs before signing, the object it returns, and the asynchronous settlement.
The data[] you submit on confirm must match the option’s actions[] in order and length. The Tron result is a single JSON object — do not wrap it in an extra array and do not stringify it into a plain signature string.

Key differences from other chains

  1. Sign-only relayraw_data_hex is opaque. Refreshing the expiration, re-deriving the TAPOS reference block, adjusting fee_limit, or re-encoding raw_data all change the hash and get the payment rejected with tx_id_mismatch.
  2. Object result — the confirm result is { raw_data_hex, signature }, not a bare signature string. This is why confirmPayment takes data rather than signatures.
  3. The buyer pays energy — there is no fee payer and no fee bump on Tron. WalletConnect Pay offers a Tron option only to accounts holding USDT and enough TRX for energy (currently 14 TRX). An unfunded account is not offered Tron at all.
  4. Mainnet only — WalletConnect Pay settles Tron on mainnet (tron:0x2b6653dc).
  5. Settlement takes a few seconds — the gateway broadcasts the transaction and waits for inclusion. confirmPayment keeps polling and resolves with succeeded or failed, exactly as on other chains; nothing extra to handle.

Implementation requirements

Include the wallet’s Tron mainnet account when calling getPaymentOptions, using the CAIP-10 format:
For example:
accounts.ts
Only advertise a Tron account if your wallet holds Tron keys. The gateway checks the account’s USDT and TRX balances and omits the Tron option when either is insufficient — this is expected, not an integration error.

Route actions by namespace

Extract the namespace from actions[i].walletRpc.chainId and route tron actions to the Tron signer:
routeActions.ts

Parse the tron_signTransaction action

The action’s params is a JSON string. It may be array-wrapped, and the transaction may be nested once more under transaction — accept both shapes, exactly as the WalletConnect Sign tron_signTransaction request handler does:
params.json
parseTronAction.ts

Verify before signing

Verify the payload before asking the user to approve, so a bad payload surfaces as a readable wallet-side error instead of an opaque gateway rejection at confirm:
  1. txID must equal sha256(raw_data_hex) — anything else means the bytes were altered and the gateway would reject the payment with tx_id_mismatch.
  2. The transaction owner must be the quoted buyerraw_data.contract[0].parameter.value.owner_address must match the account the option was quoted against, or the gateway rejects with owner_mismatch.

Sign the digest verbatim

Sign sha256(raw_data_hex) with the account’s secp256k1 key and return the 65-byte recoverable signature (r ‖ s ‖ v) as 130 hex characters. Do not pass the transaction through a helper that re-serializes raw_data from JSON (such as TronWeb’s trx.sign) — it can change the bytes and therefore the hash.
handleTronAction.ts
Return the object, not a bare signature. The gateway needs both raw_data_hex and signature to broadcast. On React Native, Web and Flutter pass the object directly; on Kotlin and Swift pass it JSON-encoded as a string — the SDK detects JSON objects in data and forwards them as objects.

Do not broadcast

Do not implement tron_sendTransaction for Pay flows and do not call sendRawTransaction. WalletConnect Pay broadcasts the signed transaction; a wallet that also broadcasts causes a duplicate submission.

Complete action handler

approvePayment.ts

Validate your integration

1

Funded Tron account

Import a mainnet account holding USDT and at least 14 TRX. Open a payment link whose merchant accepts USDT on Tron and verify that:
  • The Tron option is presented
  • The wallet verifies txID and the owner, then signs
  • The confirm request carries { raw_data_hex, signature } as an object in data
  • confirmPayment resolves with succeeded and the transaction appears in a Tron explorer
2

Tampered payload

Alter one byte of raw_data_hex in a test harness and verify the wallet fails with a txID mismatch before signing, rather than at confirm.
3

Regression on other chains

Confirm that EVM and Solana payments still work — their results stay plain strings in the same data array.

Sample implementations

React Native

wallets/rn_cli_wallet — see TronLib.signPaymentTransaction for the verification and signing, PaymentStore.approvePayment for the tron route, and usePairing for advertising the Tron mainnet account.

Web

advanced/wallets/react-wallet-v2 — see TronLib.signPaymentTransaction and the tron_signTransaction branch in PaymentStore.