Advanced Transfers
Start with the single-flow approach in Send a Transaction. The features on this page are useful when your product needs batch payments, separate confirmation stages, or recovery after an interruption.
Multiple recipients
Pass transfers instead of the single-recipient fields. The two input forms are mutually exclusive.
const prepared = await prepareTransfer({
transfers: [
{ tokenAddress: USDC, recipientAddress: ALICE, amount: parseUnits("100", 6) },
{ tokenAddress: USDC, recipientAddress: BOB, amount: parseUnits("250", 6) },
],
walletClient,
publicClient,
network: networks.ethereum,
});Every transfer uses an EscrowBatch, including a transaction with one recipient. Row order is preserved while the SDK groups compatible rows for execution.
Staged execution
Use staged execution when your interface needs separate approval and deployment actions. Otherwise, prefer execute().
const approvals = prepared.approve(walletClient);
let checkpoint;
while (true) {
const next = await approvals.next();
if (next.done) {
checkpoint = next.value;
break;
}
console.log(next.value.hash);
}
const deployed = await prepared.deploy(walletClient, checkpoint);
await saveSecrets(deployed.secrets);
for await (const event of prepared.complete(walletClient, deployed.secrets)) {
console.log(event.step);
}ApprovalCheckpoint and TransferSecrets are the serializable boundaries between stages. Persist the secrets before rendering the next action because a reload between stages is an expected product state.
Updating a quote
Before approval begins, you can refresh pricing or replace recipients and amounts.
const fresh = await prepared.refreshFees();
const updated = await prepared.updateTransfers(newRows);Both methods throw INVALID_STAGE after an approval is broadcast, a checkpoint exists, or the escrow is deployed. At that point the operation is bound to its quote.
Canceling an in-progress operation
Pass an AbortSignal when preparing the transaction.
const controller = new AbortController();
const prepared = await prepareTransfer({
// transaction parameters
abortSignal: controller.signal,
});
controller.abort();Before any wallet transaction, aborting only stops the operation. After escrow deployment, TransferAbortedError includes the escrow address and the saved secrets determine the available recovery path.
Resuming after interruption
Recreate the prepared transfer with the same parameters and the saved secrets.
const prepared = await prepareTransfer({
// same transaction parameters
resume: savedTransferSecrets,
});
for await (const event of prepared.execute(walletClient)) {
console.log(event.step);
}The SDK resumes at the appropriate post-deployment stage. It requires the saved blinding scalar and sealed pricing authorization.
For recovery branches and typed failures, continue to Error Handling.