Build Transactions

Use buildTransaction() to create unsigned transactions for review, simulation, and custom signing workflows before execution.

buildTransaction() constructs an unsigned transaction without signing or broadcasting it. Use this when you want to inspect or display a transaction before committing, or when you need to implement a custom signing flow.

When to Use

  • Show users a preview of what will happen before they confirm
  • Custom multi-step flows (build → evaluate → sign)
  • Integrating with hardware wallets or external signers

For most cases, sendAssets() (build + sign + broadcast in one call) is simpler.

Build via Client API

import { WalletChain } from "@tatumio/wallet-sdk";

const tx = await client.buildTransaction({
  path: { chain: WalletChain.ETHEREUM_MAINNET },
  body: {
    to: "0xRecipientAddress",
    token: "NATIVE",
    amount: "0.01",
  },
});

Build via Custodian API

Build on behalf of a specific client from the custodian side:

const tx = await wallets.custodian.buildTransaction({
  path: {
    clientId: "cli_...",
    chain: WalletChain.ETHEREUM_MAINNET,
  },
  body: {
    to: "0xRecipientAddress",
    token: "NATIVE",
    amount: "0.01",
  },
});

Response Shapes

The response type depends on the chain.

EVM Chains

{
  transaction: {
    from?: string;   // sender address
    to?: string;     // recipient or contract
    data?: string;   // calldata (empty for native transfers)
    value?: string;  // amount in wei
  };
  metadata: {
    amount?: string;
    fromAddress?: string;
    toAddress?: string;
    tokenAddress?: string;
    tokenDecimals?: number;
    tokenSymbol?: string;
    rawAmount?: string;
  };
}

Solana

{
  transaction?: string;  // base64-encoded serialized transaction
  metadata: {
    amount?: string;
    fromAddress?: string;
    toAddress?: string;
    tokenMintAddress?: string;
    tokenDecimals?: number;
    tokenProgramId?: string;
    tokenSymbol?: string;
    rawAmount?: string;
    lastValidBlockHeight?: string;
    serializedTransactionBase64Encoded?: string;
    serializedTransactionBase58Encoded?: string;
  };
}

Bitcoin

{
  transaction: {
    publicKey?: string;
    rawTxHex?: string;
    signatureHashes?: string[];  // one hash per input to sign
  };
  metadata: {
    amount?: string;
    fromAddress?: string;
    toAddress?: string;
    rawAmount?: string;
    feeInSatoshis?: string;
    changeInSatoshis?: string;
  };
}

Stellar

{
  transaction: {
    xdr?: string;               // XDR-encoded transaction envelope
    networkPassphrase?: string;
  };
  metadata: {
    amount?: string;
    fromAddress?: string;
    toAddress?: string;
    assetCode?: string;
    assetIssuer?: string | null;
    rawAmount?: string;
  };
}

Tron

{
  transaction: {
    id?: string;
    network?: "mainnet" | "nile" | "shasta";
  };
  metadata: {
    amount?: string;
    fromAddress?: string;
    toAddress?: string;
    tokenSymbol?: string;
    contractAddress?: string | null;
  };
}

Build → Evaluate → Sign Flow

const chain = WalletChain.ETHEREUM_MAINNET;

// 1. Build
const tx = await client.buildTransaction({
  path: { chain },
  body: { to: "0xRecipient", token: "NATIVE", amount: "0.01" },
});

// 2. Evaluate (optional but recommended)
const evaluation = await client.evaluateTransaction({
  query: { chainId: chain },
  body: {
    network: "ethereum",
    transaction: {
      toAddress: "0xRecipient",
      value: tx.transaction?.value ?? "0",
    },
    operationType: "simulation",
  },
});

if ((evaluation.evaluation?.riskScore ?? 0) > 70) {
  throw new Error("Transaction risk score too high");
}

// 3. Sign and broadcast
const signed = await client.sign({
  body: {
    share: shares.SECP256K1.share,
    method: "eth_sendTransaction",
    params: [tx.transaction],
    chainId: chain,
    to: "0xRecipient",
  },
});

console.log(signed.data); // transaction hash