> ## Documentation Index
> Fetch the complete documentation index at: https://docs.privy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign a Tron transaction

> Sign a Tron transaction without broadcasting it using Privy

Sign a Tron transaction without broadcasting it. Use this when you need to broadcast via a custom RPC or gas sponsor like [Transatron](/recipes/tron/transatron).

<Info>
  To sign and broadcast in a single call, use
  [`tron_sendTransaction`](/wallets/using-wallets/tron/send-a-transaction) instead.
</Info>

<View title="REST API" icon="terminal">
  To sign a transaction, make a `POST` request to

  ```bash theme={"system"} theme={"system"}
  https://api.privy.io/v1/wallets/<wallet_id>/rpc
  ```

  Block reference fields (`ref_block_bytes`, `ref_block_hash`, `expiration`) are **required** for `tron_signTransaction` — fetch them fresh using `TronWeb.trx.getCurrentRefBlockParams()` before every request. They expire in about 60 seconds.

  ### Usage

  ```bash theme={"system"} theme={"system"}
  $ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
  -u "<your-privy-app-id>:<your-privy-app-secret>" \
  -H "privy-app-id: <your-privy-app-id>" \
  -H "privy-authorization-signature: <authorization-signature>" \
  -H 'Content-Type: application/json' \
  -d '{
    "method": "tron_signTransaction",
    "params": {
      "raw_data": {
        "contract": [
          {
            "type": "TransferContract",
            "owner_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c",
            "to_address": "41e552f6487585c2b58bc2c9bb4492bc1f17132cd0",
            "amount": 1000000
          }
        ],
        "ref_block_bytes": "a2b4",
        "ref_block_hash": "1234567890abcdef",
        "expiration": 1735689600000,
        "timestamp": 1735689540000
      }
    }
  }'
  ```

  A successful response looks like:

  ```json theme={"system"} theme={"system"}
  {
    "method": "tron_signTransaction",
    "data": {
      "signed_transaction": "0a02a2b42208...",
      "encoding": "hex"
    }
  }
  ```

  The `signed_transaction` is `rawDataHex + signatureHex` (signature = last 130 hex chars / 65 bytes). To broadcast, pass it to `POST /wallet/broadcasthex` on any Tron full node.

  ### Parameters

  <ParamField body="method" type="string" required>
    Must be `"tron_signTransaction"`.
  </ParamField>

  <ParamField body="params.raw_data.contract" type="array" required>
    Array of exactly one contract — `TransferContract` (TRX) or `TriggerSmartContract` (TRC-20 / smart
    contract call). All addresses must be 41-prefixed hex.
  </ParamField>

  <ParamField body="params.raw_data.ref_block_bytes" type="string" required>
    Block reference bytes — 4 hex characters. Must be fetched fresh from chain before signing.
  </ParamField>

  <ParamField body="params.raw_data.ref_block_hash" type="string" required>
    Block reference hash — 16 hex characters. Fetched alongside `ref_block_bytes`.
  </ParamField>

  <ParamField body="params.raw_data.expiration" type="number" required>
    Transaction expiration in Unix milliseconds.
  </ParamField>

  <ParamField body="params.raw_data.fee_limit" type="number">
    Maximum energy fee in sun. Required for `TriggerSmartContract`. `100_000_000` (100 TRX) is a safe
    default for TRC-20 transfers.
  </ParamField>

  <ParamField body="params.raw_data.timestamp" type="number">
    Transaction creation timestamp in Unix milliseconds. Defaults to `Date.now()` if omitted.
  </ParamField>

  ### Returns

  <ResponseField name="data.signed_transaction" type="string">
    The signed transaction hex: `rawDataHex + signatureHex` (65 bytes). Pass directly to
    `/wallet/broadcasthex` on a Tron full node.
  </ResponseField>

  <ResponseField name="data.encoding" type="string">
    Always `"hex"`.
  </ResponseField>

  Check out the [API reference](/api-reference/wallets/tron/tron-sign-transaction) for more details.
</View>

<View title="NodeJS" icon="node-js">
  Use the typed `wallets().tron().signTransaction()` method to sign a transaction. It returns the fully signed transaction hex — broadcast it yourself via `/wallet/broadcasthex`.

  ```typescript theme={"system"} theme={"system"}
  import {PrivyClient} from '@privy-io/node';
  import {TronWeb} from 'tronweb';

  const privy = new PrivyClient({
    appId: process.env.PRIVY_APP_ID,
    appSecret: process.env.PRIVY_APP_SECRET
  });

  const tronWeb = new TronWeb({fullHost: 'https://api.trongrid.io'});

  // Build a transaction to source fresh block reference fields — they expire in ~60 seconds
  const tx = await tronWeb.transactionBuilder.sendTrx(
    'insert-recipient-address',
    1_000_000, // 1 TRX in sun
    'insert-wallet-address'
  );

  const {signed_transaction, encoding} = await privy
    .wallets()
    .tron()
    .signTransaction('insert-wallet-id', {
      params: {
        raw_data: {
          contract: [
            {
              type: 'TransferContract',
              owner_address: TronWeb.address.toHex('insert-wallet-address'),
              to_address: TronWeb.address.toHex('insert-recipient-address'),
              amount: 1_000_000 // 1 TRX in sun
            }
          ],
          ref_block_bytes: tx.raw_data.ref_block_bytes,
          ref_block_hash: tx.raw_data.ref_block_hash,
          expiration: tx.raw_data.expiration
        }
      }
    });

  // signed_transaction is `rawDataHex + signatureHex` — broadcast via POST /wallet/broadcasthex
  console.log(signed_transaction, encoding);
  ```

  <Note>
    Block reference fields (`ref_block_bytes`, `ref_block_hash`, `expiration`) are required for
    `tron_signTransaction`. Fetch them fresh before every request — they expire in about 60 seconds.
  </Note>

  ### Parameters and Returns

  Check out the [API reference](/api-reference/wallets/tron/tron-sign-transaction) for more details.
</View>

<View title="Go" icon="golang">
  Use the typed `Wallets.Tron.SignTransaction` method to sign a transaction. It returns the fully signed transaction hex — broadcast it yourself via `/wallet/broadcasthex`.

  ```go theme={"system"} theme={"system"}
  data, err := client.Wallets.Tron.SignTransaction(context.Background(), walletID,
      privy.TronSignTransactionRpcInputParams{
          RawData: privy.TronRawDataForSign{
              Contract: []privy.TronContractUnion{
                  {
                      OfTransferContract: &privy.TronTransferContract{
                          Type:         privy.TronTransferContractTypeTransferContract,
                          OwnerAddress: ownerAddressHex,     // 41-prefixed hex
                          ToAddress:    recipientAddressHex, // 41-prefixed hex
                          Amount:       1_000_000,           // 1 TRX in sun
                      },
                  },
              },
              RefBlockBytes: refBlockBytes, // fetched fresh from chain
              RefBlockHash:  refBlockHash,
              Expiration:    time.Now().UnixMilli() + 60_000,
          },
      },
  )
  if err != nil {
      log.Fatalf("failed to sign transaction: %v", err)
  }

  // data.SignedTransaction is `rawDataHex + signatureHex` — broadcast via POST /wallet/broadcasthex
  fmt.Println(data.SignedTransaction, data.Encoding)
  ```

  ### Parameters and Returns

  See the [API reference](/api-reference/wallets/tron/tron-sign-transaction) for more details.
</View>

<View title="Ruby" icon="gem">
  Use the typed `wallets.tron.sign_transaction` method to sign a transaction. It returns the fully signed transaction hex — broadcast it yourself via `/wallet/broadcasthex`.

  ```ruby theme={"system"} theme={"system"}
  response = client.wallets.tron.sign_transaction(
    wallet_id,
    params: {
      raw_data: {
        contract: [
          {
            type: "TransferContract",
            owner_address: owner_hex_address,     # 41-prefixed hex
            to_address: recipient_hex_address,    # 41-prefixed hex
            amount: 1_000_000                     # 1 TRX in sun
          }
        ],
        ref_block_bytes: ref_block_bytes,         # fetched fresh from chain
        ref_block_hash: ref_block_hash,
        expiration: (Time.now.to_i * 1000) + 60_000
      }
    }
  )

  # response.signed_transaction is `rawDataHex + signatureHex` — broadcast via POST /wallet/broadcasthex
  puts(response.signed_transaction, response.encoding)
  ```

  ### Parameters and Returns

  See the [API reference](/api-reference/wallets/tron/tron-sign-transaction) for more details.
</View>

<View title="React" icon="react">
  Use `useSignRawHash` from `@privy-io/react-auth/extended-chains` to sign the transaction's `txID` in the browser. Send the 64-byte signature to your server to attach the recovery byte and broadcast.

  ```tsx theme={"system"} theme={"system"}
  import {useSignRawHash} from '@privy-io/react-auth/extended-chains';

  const {signRawHash} = useSignRawHash();

  const signTronTxId = async (address: string, txId: string) => {
    const txIdHex = txId.startsWith('0x') ? txId : `0x${txId}`;

    const {signature} = await signRawHash({
      address,
      chainType: 'tron',
      hash: txIdHex as `0x${string}`
    });

    return signature; // 64-byte hex — send to your server to attach recovery byte
  };
  ```

  On the server, attach the correct recovery byte before broadcasting:

  ```typescript theme={"system"} theme={"system"}
  import type {TronWeb, Types} from 'tronweb';

  function attachRecoveryByte(
    tronWeb: TronWeb,
    walletAddress: string,
    transaction: Types.SignedTransaction,
    signature: string
  ): Types.SignedTransaction {
    const baseSig = signature.replace(/^0x/, '');
    transaction.signature = [`${baseSig}1b`];
    if (tronWeb.trx.ecRecover(transaction) !== walletAddress) {
      transaction.signature = [`${baseSig}1c`];
    }
    return transaction;
  }
  ```

  For a complete gas-sponsored Tron flow, see the [Transatron recipe](/recipes/tron/transatron).
</View>

<View title="Python" icon="python">
  Use the `sign_transaction` method on the Tron wallet service.

  ```python theme={"system"}
  response = client.wallets.tron.sign_transaction(
      wallet_id,
      params={"raw_data": raw_data},
  )

  signed_transaction = response.signed_transaction
  ```
</View>
