use-truapi
Transactions

useTx

Sign, submit and watch a transaction

useTx submits transactions built against the typed PAPI api. Call submit(build, options?): it signs with the connected account, broadcasts, and resolves once the transaction reaches a best block (or finality with waitFor: "finalized"). phase reports where the transaction is: "idle" → "signing" → "broadcasting" → "in-block" → "finalized" | "error".

On first submit the hook requests the ChainSubmit permission and connects the signer if needed. No manual pre-flight.

The resolved TxResult reports dispatch failures as data: check result.ok, a failed dispatch carries the decoded dispatchError. Thrown errors (TxSigningRejectedError, TxError) mean the transaction never made it into a block.

Usage

import { useTx } from "@use-truapi/react";
import { MultiAddress } from "@polkadot-api/descriptors";

function Transfer({ dest, value }: { dest: string; value: bigint }) {
  const { submit, phase, isPending, error } = useTx();

  async function onSend() {
    const result = await submit((api) =>
      api.tx.Balances.transfer_keep_alive({
        dest: MultiAddress.Id(dest),
        value,
      }),
    );
    if (!result.ok) console.error("dispatch failed", result.dispatchError);
  }

  return (
    <>
      <button type="button" onClick={onSend} disabled={isPending}>
        {isPending ? phase : "Send"}
      </button>
      {error && <p role="alert">{error.message}</p>}
    </>
  );
}
<script setup lang="ts">
import { useTx } from "@use-truapi/vue";
import { MultiAddress } from "@polkadot-api/descriptors";

const props = defineProps<{ dest: string; value: bigint }>();
const { submit, phase, isPending, error } = useTx();

async function onSend() {
  const result = await submit((api) =>
    api.tx.Balances.transfer_keep_alive({
      dest: MultiAddress.Id(props.dest),
      value: props.value,
    }),
  );
  if (!result.ok) console.error("dispatch failed", result.dispatchError);
}
</script>

<template>
  <button type="button" :disabled="isPending" @click="onSend">
    {{ isPending ? phase : "Send" }}
  </button>
  <p v-if="error" role="alert">{{ error.message }}</p>
</template>

To wait for finality, or observe each phase transition:

const result = await submit(
  (api) => api.tx.System.remark({ remark: Binary.fromText("hello") }),
  {
    waitFor: "finalized",
    onStatus: (status) => console.log("tx phase:", status),
  },
);

To build against a specific chain, pass its key; the build callback then receives that chain's typed api:

const { submit } = useTx({ chain: "people" });

reset() clears the mutation state and returns phase to "idle".

See also

  • useBatchTx submits several calls atomically via Utility.batch_all.
  • useContractTx is the same lifecycle for contract calls.

API reference

React

function useTx<K>(options?): UseTxResult<K>;

Transaction lifecycle as a TanStack mutation with a granular phase. Permission (ChainSubmit) and signer connection are handled automatically on first submit.

const { submit, phase } = useTx();
await submit((api) => api.tx.Balances.transfer_keep_alive({ dest, value }));

Type Parameters

Type ParameterDefault type
K extends stringstring

Parameters

ParameterType
options?{ chain?: K; mutation?: MutationOptions<TxResult, TxVariables<K, SubmittableTransaction, SubmitOptions>>; }
options.chain?K
options.mutation?MutationOptions<TxResult, TxVariables<K, SubmittableTransaction, SubmitOptions>>

Returns

UseTxResult<K>

Extends

  • Omit<NamedMutation<TxResult, TxVariables<K, AnyTx, SubmitOptions>>, "reset">

Type Parameters

Type Parameter
K extends ChainKey

Properties

context

context: unknown;
Inherited from
Omit.context

data

data: TxResult | undefined;

The last successfully resolved data for the mutation.

Inherited from
Omit.data

error

error: Error | null;

The error object for the mutation, if an error was encountered.

  • Defaults to null.
Inherited from
Omit.error

failureCount

failureCount: number;
Inherited from
Omit.failureCount

failureReason

failureReason: Error | null;
Inherited from
Omit.failureReason

isError

isError: boolean;

A boolean variable derived from status.

  • true if the last mutation attempt resulted in an error.
Inherited from
Omit.isError

isIdle

isIdle: boolean;

A boolean variable derived from status.

  • true if the mutation is in its initial state prior to executing.
Inherited from
Omit.isIdle

isPaused

isPaused: boolean;
Inherited from
Omit.isPaused

isPending

isPending: boolean;

A boolean variable derived from status.

  • true if the mutation is currently executing.
Inherited from
Omit.isPending

isSuccess

isSuccess: boolean;

A boolean variable derived from status.

  • true if the last mutation attempt was successful.
Inherited from
Omit.isSuccess

phase

phase: TxPhase;

"idle" → "signing" → "broadcasting" → "in-block" → "finalized" | "error".


reset

reset: () => void;
Returns

void


status

status: "idle" | "success" | "error" | "pending";

The status of the mutation.

  • Will be:
    • idle initial status prior to the mutation function executing.
    • pending if the mutation is currently executing.
    • error if the last mutation attempt resulted in an error.
    • success if the last mutation attempt was successful.
Inherited from
Omit.status

submit

submit: (build, options?) => Promise<TxResult>;

Build against the typed api and submit; resolves when the tx reaches best-block (or waitFor: "finalized").

Parameters
ParameterType
build(api) => SubmittableTransaction | Promise<SubmittableTransaction>
options?SubmitOptions
Returns

Promise<TxResult>


submittedAt

submittedAt: number;
Inherited from
Omit.submittedAt

variables

variables: 
  | TxVariables<K, SubmittableTransaction, SubmitOptions>
  | undefined;

The variables object passed to the mutationFn.

Inherited from
Omit.variables

Vue

function useTx<K>(options?): UseTxResult<K>;

Transaction lifecycle as a TanStack mutation with a granular phase. Permission (ChainSubmit) and signer connection are handled automatically on first submit.

Type Parameters

Type ParameterDefault type
K extends stringstring

Parameters

ParameterType
options?{ chain?: K; mutation?: MutationOptions<TxResult, TxVariables<K, SubmittableTransaction, SubmitOptions>>; }
options.chain?K
options.mutation?MutationOptions<TxResult, TxVariables<K, SubmittableTransaction, SubmitOptions>>

Returns

UseTxResult<K>

On this page