useWriteContract
Invoke state-changing Soroban contract methods from React, powered by TanStack Query.
useWriteContract is the React wrapper around writeContract. It invokes a state-changing Soroban contract method, prompting the connected user to sign, and exposes the call as a TanStack Query mutation — giving you mutate/mutateAsync, plus isPending, isSuccess, and error states.
Import
import { useWriteContract } from "@bluxcc/react";Native contract arguments
Pass ordinary JavaScript values in the same order as the contract function's parameters. Blux reads the deployed contract spec and encodes each value as the expected Soroban type, so args does not require ToScVal.
Use strings for addresses, strings, and symbols; booleans for bool; Uint8Array for bytes; and arrays for vectors or tuples. Integers accept safe numbers, bigint values, or decimal strings. Prefer bigint or a decimal string for wide integers such as i128.
The contract address and every ABI-declared Address argument accept .xlm
names and SEP-2 federation addresses, including address values nested in
contract-defined structures. See address resolution.
Pre-encoded xdr.ScVal arguments remain supported for existing integrations, but manual encoding is optional.
Usage
Call a token's transfer method when the user clicks a button:
import { useWriteContract, useBlux } from "@bluxcc/react";
const TOKEN = "CB64D3G7SM2RTH6JSGG34DDTFTQ5CFDKVDZJZSODMCX4NJ2HV2KN7OG";
function TransferButton() {
const { user } = useBlux();
const { mutate, isPending } = useWriteContract<null>();
const transfer = () => {
if (!user) return;
mutate({
call: {
address: TOKEN,
fn: "transfer",
args: [
user.address, // from: Address
"bob.xlm", // to: Address
"1000000000", // amount: i128
],
},
});
};
return (
<button onClick={transfer} disabled={isPending}>
{isPending ? "Sending…" : "Transfer"}
</button>
);
}root.render(
<BluxProvider
config={{
appId: "your-app-id",
appName: "MyApp",
networks: [networks.testnet, networks.mainnet],
}}
>
<App />
</BluxProvider>
);The mutation variables are { call, options }, where call is the contract call and options can carry a network. Use mutateAsync if you prefer to await the result. Pass the decoded contract return type as the hook generic:
const { mutateAsync } = useWriteContract<bigint>();
const result = await mutateAsync({
call: {
address: TOKEN,
fn: "mint",
args: ["alice.xlm", "1000000000"],
},
options: { network: networks.mainnet },
});
const minted = await result.returnValue(); // bigint | nullBecause the ABI is discovered at runtime, TypeScript cannot infer this value
from address, fn, and network strings. Without a generic,
returnValue() is unknown | null; it is null for a void function.
A user must be connected before calling the mutation — the connected account is the transaction source. Handle rejection and simulation failures via the mutation's onError callback or a try/catch around mutateAsync.