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

# Optimized Transaction Building

> For better performance, you can build transactions synchronously using ABI data, a replay protection nonce, and the chain ID. This avoids network calls during transaction construction

## Overview

The optimized approach uses:

* **ABI (Application Binary Interface)**: Pre-loaded function signatures and parameter types.
* **Replay Protection Nonce**: A random 64-bit value embedded in the transaction payload to enable orderless transactions.
* **Chain ID**: The network identifier to prevent cross-chain replay attacks.

## Orderless Transactions

These transactions are **orderless**, meaning they can be submitted in any order without requiring sequential sequence numbers. The `replayProtectionNonce` is embedded directly in the transaction payload to provide replay protection, eliminating the need to fetch the account's current sequence number from the network.

**Benefits of orderless transactions:**

* **No sequence number fetch**: Avoids network round-trip to get account sequence number
* **Parallel execution**: Multiple transactions can be built and submitted simultaneously
* **Better performance**: Faster transaction construction without waiting for network responses
* **Improved UX**: Transactions can be prepared offline and submitted later

**Traditional (non-orderless) transactions:**

* Require fetching the account's current sequence number from the network
* Must be submitted sequentially (each transaction increments the sequence number)
* Cannot be built in parallel without coordination
* Require network calls during transaction construction

***

## Generate Replay Protection Nonce

The replay protection nonce is a random 64-bit value that enables orderless transactions. Instead of using the account's sequence number (which requires a network fetch), the nonce is embedded in the transaction payload to prevent replay attacks.

**Generate a random 64-bit nonce for replay protection:**

<CodeGroup>
  ```typescript Typescript theme={null}
  function generateRandomReplayProtectionNonce(): bigint | null {
    const buf = new Uint32Array(2);
    crypto.getRandomValues(buf);

  const valueAtIndex0 = buf[0];
  const valueAtIndex1 = buf[1];

  if (!valueAtIndex0 || !valueAtIndex1) return null;

  // Combine two 32-bit parts into a single 64-bit bigint
  return (BigInt(valueAtIndex0) << BigInt(32)) | BigInt(valueAtIndex1);
  }

  ```

  ```python Python theme={null}
  import secrets

  def generate_random_replay_protection_nonce() -> int | None:
      """Generate a random 64-bit nonce for replay protection."""
      # Generate 8 random bytes (64 bits)
      random_bytes = secrets.token_bytes(8)

      if not random_bytes:
          return None

      # Convert bytes to 64-bit integer (big-endian)
      return int.from_bytes(random_bytes, byteorder="big")
  ```
</CodeGroup>

***

## Parse ABI to EntryFunctionABI

Before building a transaction, parse the `MoveFunction` ABI to the `EntryFunctionABI` format required for transaction payload construction.

<CodeGroup>
  ```typescript Typescript theme={null}
  const parseMoveFnAbiToEntryFnABI = (
    functionAbi: MoveFunction
  ): EntryFunctionABI => {
    // Remove the signer arguments
    const numSigners = findFirstNonSignerArg(functionAbi);

  const params: TypeTag[] = [];
  for (let i = numSigners; i < functionAbi.params.length; i += 1) {
  const param = functionAbi.params[i];
  if (!param) continue;
  params.push(parseTypeTag(param, { allowGenerics: true }));
  }

  return {
  signers: numSigners,
  typeParameters: functionAbi.generic_type_params,
  parameters: params,
  };
  };

  ```

  ```python Python theme={null}
  from aptos_sdk.transactions import EntryFunctionABI
  from aptos_sdk.type_tag import TypeTag, parse_type_tag

  def parse_move_fn_abi_to_entry_fn_abi(function_abi: dict) -> EntryFunctionABI:
      """Parse MoveFunction ABI to EntryFunctionABI format."""
      # Count signer arguments (typically "&signer" at the start)
      num_signers = 0
      for param in function_abi.get("params", []):
          if param and param.startswith("&signer"):
              num_signers += 1
          else:
              break

      # Parse non-signer parameters
      params: list[TypeTag] = []
      for i in range(num_signers, len(function_abi.get("params", []))):
          param = function_abi["params"][i]
          if not param:
              continue
          params.append(parse_type_tag(param, allow_generics=True))

      return EntryFunctionABI(
          signers=num_signers,
          type_parameters=function_abi.get("generic_type_params", []),
          parameters=params,
      )
  ```
</CodeGroup>

***

## Generate Expiration Timestamp

A convenience function to compute the expiration timestamp for the transaction.

<CodeGroup>
  ```typescript Typescript theme={null}
  const generateExpireTimestamp = (aptosConfig: AptosConfig) =>
    Math.floor(Date.now() / 1000) + aptosConfig.getDefaultTxnExpirySecFromNow();
  ```

  ```python Python theme={null}
  import time

  def generate_expire_timestamp(default_txn_expiry_sec: int = 600) -> int:
      """Generate expiration timestamp for the transaction."""
      return int(time.time()) + default_txn_expiry_sec
  ```
</CodeGroup>

***

## Build Transaction Synchronously

This function builds a transaction payload and constructs a `RawTransaction` synchronously using all pre-known parameters.

<CodeGroup>
  ```typescript Typescript theme={null}
  import {
    AccountAddress,
    AccountAddressInput,
    AptosConfig,
    ChainId,
    convertPayloadToInnerPayload,
    EntryFunctionABI,
    findFirstNonSignerArg,
    generateTransactionPayloadWithABI,
    InputEntryFunctionData,
    InputEntryFunctionDataWithABI,
    MoveFunction,
    parseTypeTag,
    RawTransaction,
    SimpleTransaction,
    TypeTag,
  } from "@aptos-labs/ts-sdk";

  function buildSimpleTransactionSync(args: {
  aptosConfig: AptosConfig;
  sender: AccountAddressInput;
  data: InputEntryFunctionData;
  chainId: number;
  gasUnitPrice: number;
  abi: MoveFunction;
  withFeePayer: boolean;
  replayProtectionNonce: bigint;
  }): SimpleTransaction {
  const txnPayload = generateTransactionPayloadWithABI({
  aptosConfig: args.aptosConfig,
  function: args.data.function,
  functionArguments: args.data.functionArguments,
  typeArguments: args.data.typeArguments,
  abi: parseMoveFnAbiToEntryFnABI(args.abi),
  } as InputEntryFunctionDataWithABI);

  const expireTimestamp = generateExpireTimestamp(args.aptosConfig);

  const rawTxn = new RawTransaction(
  AccountAddress.from(args.sender),
  BigInt("0xdeadbeef"), // Default Sequence Number as it is unused when replay nonce is provided
  convertPayloadToInnerPayload(txnPayload, args.replayProtectionNonce), // Convert payload and embed replay protection nonce
  BigInt(args.aptosConfig.getDefaultMaxGasAmount()),
  BigInt(args.gasUnitPrice),
  BigInt(expireTimestamp),
  new ChainId(args.chainId)
  );

  return new SimpleTransaction(
  rawTxn,
  args.withFeePayer ? AccountAddress.ZERO : undefined
  );
  }

  ```

  ```python Python theme={null}
  from aptos_sdk.account import AccountAddress
  from aptos_sdk.transactions import (
      EntryFunction,
      RawTransaction,
      TransactionArgument,
      TransactionPayload,
      convert_payload_to_inner_payload,
  )
  from aptos_sdk.type_tag import TypeTag, StructTag
  from aptos_sdk.chain_id import ChainId

  def build_simple_transaction_sync(
      sender: AccountAddress,
      function: str,
      function_arguments: list,
      type_arguments: list[TypeTag],
      abi: dict,
      chain_id: int,
      gas_unit_price: int,
      max_gas_amount: int,
      expire_timestamp: int,
      replay_protection_nonce: int,
      with_fee_payer: bool = False,
  ) -> RawTransaction:
      """Build a transaction synchronously using ABI and replay protection nonce."""
      # Parse ABI to EntryFunctionABI
      entry_function_abi = parse_move_fn_abi_to_entry_fn_abi(abi)

      # Create entry function payload
      entry_function = EntryFunction(
          module=StructTag.from_str(function.split("::")[0] + "::" + function.split("::")[1]),
          function=function.split("::")[2],
          ty_args=type_arguments,
          args=[TransactionArgument(arg) for arg in function_arguments],
      )

      payload = TransactionPayload(entry_function)

      # Convert payload and embed replay protection nonce
      inner_payload = convert_payload_to_inner_payload(payload, replay_protection_nonce)

      # Create raw transaction
      raw_txn = RawTransaction(
          sender=sender,
          sequence_number=0xDEADBEEF,  # Default sequence number (unused when replay nonce is provided)
          payload=inner_payload,
          max_gas_amount=max_gas_amount,
          gas_unit_price=gas_unit_price,
          expiration_timestamp_secs=expire_timestamp,
          chain_id=ChainId(chain_id),
      )

      return raw_txn
  ```
</CodeGroup>

***

## Complete Example: Building a Transaction

Below is a complete example of building and submitting a transaction using the optimized (orderless, synchronous) approach.

<CodeGroup>
  ```typescript Typescript theme={null}
  // Example: Build and submit a transaction synchronously using ABI and replay nonce.
  import {
    Aptos,
    AptosConfig,
    AccountAddress,
    SimpleTransaction,
    MoveFunction,
  } from "@aptos-labs/ts-sdk";

  const subaccountAddr = "0x..."; // Your subaccount address
  const accountToDelegateTo = "0x..."; // Address to delegate trading to
  const expirationTimestamp = undefined; // Optional: expiration timestamp in seconds

  // Initialize Aptos config
  const aptosConfig = new AptosConfig({
  network: "mainnet",
  fullnode: "https://fullnode.mainnet.aptoslabs.com",
  });

  const aptos = new Aptos(aptosConfig);

  // ABI for delegate_trading_to function
  const functionAbi: MoveFunction = {
  name: "delegate_trading_to_for_subaccount",
  visibility: "friend",
  is_entry: true,
  is_view: false,
  generic_type_params: [],
  params: ["&signer", "address", "address", "0x1::option::Option<u64>"],
  return: [],
  };

  const replayProtectionNonce = generateRandomReplayProtectionNonce();

  // Get gas price (from cache or network)
  const gasUnitPrice = await aptos
  .getGasPriceEstimation()
  .then((r) => r.gas_estimate);

  // Build transaction synchronously
  const transaction = buildSimpleTransactionSync({
  aptosConfig: aptos.config,
  sender: account.accountAddress,
  data: {
  function: `${PACKAGE}::dex_accounts_entry::delegate_trading_to_for_subaccount`,
  typeArguments: [],
  functionArguments: [
  subaccountAddr, // Subaccount address
  accountToDelegateTo, // Address to delegate trading to
  expirationTimestamp, // Optional expiration timestamp (can be undefined)
  ],
  },
  chainId: 1, // Mainnet chain ID
  gasUnitPrice,
  abi: functionAbi,
  withFeePayer: false,
  replayProtectionNonce,
  });

  // Sign and submit the transaction
  const senderAuthenticator = aptos.transaction.sign({
  signer: account,
  transaction,
  });

  const pendingTransaction = await aptos.transaction.submit.simple({
  transaction,
  senderAuthenticator,
  });

  // Wait for transaction confirmation
  const committedTransaction = await aptos.waitForTransaction({
  transactionHash: pendingTransaction.hash,
  });

  console.log("Transaction confirmed:", committedTransaction.hash);

  ```

  ```python Python theme={null}
  # Example: Build and submit a transaction synchronously using ABI and replay nonce.
  from aptos_sdk.account import Account, AccountAddress
  from aptos_sdk.client import RestClient
  from aptos_sdk.transactions import SignedTransaction
  from aptos_sdk.type_tag import TypeTag

  PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06"
  subaccount_addr = "0x..."  # Your subaccount address
  account_to_delegate_to = "0x..."  # Address to delegate trading to
  expiration_timestamp = None  # Optional: expiration timestamp in seconds

  # Initialize Aptos client
  rest_client = RestClient("https://fullnode.mainnet.aptoslabs.com")

  # ABI for delegate_trading_to function
  function_abi = {
      "name": "delegate_trading_to_for_subaccount",
      "visibility": "friend",
      "is_entry": True,
      "is_view": False,
      "generic_type_params": [],
      "params": ["&signer", "address", "address", "0x1::option::Option<u64>"],
      "return": [],
  }

  # Generate replay protection nonce
  replay_protection_nonce = generate_random_replay_protection_nonce()

  # Get gas price (from cache or network)
  gas_unit_price = rest_client.estimate_gas_price()

  # Build transaction synchronously
  transaction = build_simple_transaction_sync(
      sender=account.address(),
      function=f"{PACKAGE}::dex_accounts_entry::delegate_trading_to_for_subaccount",
      function_arguments=[
          AccountAddress.from_str(subaccount_addr),  # Subaccount address
          AccountAddress.from_str(account_to_delegate_to),  # Address to delegate trading to
          expiration_timestamp,  # Optional expiration timestamp (can be None)
      ],
      type_arguments=[],
      abi=function_abi,
      chain_id=1,  # Mainnet chain ID
      gas_unit_price=gas_unit_price,
      max_gas_amount=100000,  # Default max gas amount
      expire_timestamp=generate_expire_timestamp(),
      replay_protection_nonce=replay_protection_nonce,
      with_fee_payer=False,
  )

  # Sign the transaction
  signed_transaction = account.sign(transaction)

  # Submit the transaction
  pending_transaction = rest_client.submit_transaction(signed_transaction)

  # Wait for transaction confirmation
  committed_transaction = rest_client.wait_for_transaction(pending_transaction)

  print(f"Transaction confirmed: {committed_transaction['hash']}")
  ```
</CodeGroup>

***

## Benefits

* **Performance**: No network calls during transaction construction
* **Reliability**: Deterministic transaction building with pre-loaded ABI
* **Security**: Replay protection nonce prevents transaction replay attacks
* **Efficiency**: Can build multiple transactions in parallel without blocking

***

## When to Use

Use the optimized synchronous approach when:

* You have ABI data available locally
* You know the chain ID
* You want to build transactions without network latency
* You're building multiple transactions in batch

***

## Fallback to Async Building

If ABI or chain ID is not available, the SDK falls back to async transaction building, which may require a network fetch to get the account's sequence number for replay protection.

<CodeGroup>
  ```typescript Typescript theme={null}
  // Fallback: Build a transaction asynchronously when ABI or chainId are missing
  // This will fetch the account's sequence number from the network.
  const transaction = await aptos.transaction.build.simple({
    sender,
    data: payload,
    withFeePayer,
    options: {
      replayProtectionNonce, // Still uses nonce if provided, but may also fetch sequence number
    },
  });
  ```

  ```python Python theme={null}
  # Fallback: Build a transaction asynchronously when ABI or chainId are missing
  # This will fetch the account's sequence number from the network.
  from aptos_sdk.transactions import TransactionBuilder

  transaction = TransactionBuilder.build_transaction(
      sender=account.address(),
      payload=payload,
      options={
          "replay_protection_nonce": replay_protection_nonce,  # Still uses nonce if provided, but may also fetch sequence number
      },
  )
  ```
</CodeGroup>

**What happens without orderless transactions:**

* The SDK makes a network request to fetch the account's current sequence number when you call `aptos.transaction.build.simple()`
* The sequence number is used for replay protection instead of (or in addition to) the nonce
* Transactions must be submitted sequentially
* Each transaction increments the sequence number, preventing parallel submission
