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

# Splitting sign & send

> Pre-sign a sponsored intent, relay it, and poll relay status for custom transaction flows.

[`sendSponsoredTransaction`](https://docs.dynamic.xyz/docs/javascript/reference/evm/send-sponsored-transaction) bundles signing, relaying, and waiting into one call. When you need more control (pre-signing an intent to send later, relaying without blocking, or driving your own progress UI), split those steps with the functions below.

The full flow is: **sign** → **relay** (get a `requestId`) → **poll status** until the relay reports a transaction hash.

> [!TIP]
>
> To have your **backend** decide what gets sponsored, sign on the client with `signSponsoredTransaction` and relay from your server. See [EVM Server-Controlled Sponsorship](https://docs.dynamic.xyz/docs/recipes/integrations/evm-server-controlled-sponsorship.md).

## signSponsoredTransaction

Signs an EIP-712 intent for a batch of calls without sending it. Returns a serializable payload you can hand to [`sendSponsoredTransaction`](https://docs.dynamic.xyz/docs/javascript/reference/evm/send-sponsored-transaction) or [`relaySponsoredTransaction`](#relaysponsoredtransaction) later.

```javascript theme={"system"}
import {
  signSponsoredTransaction,
  sendSponsoredTransaction,
} from '@dynamic-labs-sdk/evm';

const signedTransaction = await signSponsoredTransaction({
  walletAccount,
  calls,
});

// ...later, or from another process:
const { transactionHash } = await sendSponsoredTransaction({ signedTransaction });
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `walletAccount` | `EvmWalletAccount` | The V3 MPC embedded wallet to sign with. |
| `calls` | `SponsoredTransactionCall[]` | The batch of calls to execute. |
| `authorization` | `SignAuthorizationReturnType` (optional) | A pre-signed EIP-7702 authorization. Takes priority over `autoDelegate`. |
| `autoDelegate` | `boolean` (optional) | Whether to auto-sign an EIP-7702 authorization when the wallet isn't delegated yet. Defaults to `true`. |
| `nonce` | `bigint` (optional) | A bitmap nonce to sign with. When provided, nonce generation and its on-chain check are skipped. See [Reusing a nonce](#reusing-a-nonce). |
| `validForSeconds` | `number` (optional) | How long the intent stays valid. Defaults to `600` (10 minutes). |

### Returns

`Promise<SignedSponsoredTransaction>`:

| Field | Type | Description |
| - | - | - |
| `authorization` | `SerializedAuthorization \| undefined` | The serialized EIP-7702 authorization, if one was needed. |
| `calls` | `SponsoredTransactionCall[]` | The batch of calls that was signed. |
| `chainId` | `number` | Target chain ID. |
| `deadline` | `string` | Intent expiration as a unix-timestamp string. |
| `nonce` | `string` | The bitmap nonce, as a `uint256` string. |
| `relayer` | `Hex` | The relayer address signed into the intent. |
| `signature` | `Hex` | The EIP-712 signature over the intent. |
| `walletAddress` | `Hex` | The user's wallet address. |

### Custom validity window

```javascript theme={"system"}
import { signSponsoredTransaction } from '@dynamic-labs-sdk/evm';
const signedTransaction = await signSponsoredTransaction({
  walletAccount,
  calls,
  validForSeconds: 60, // valid for 1 minute instead of the default 10
});
```

## relaySponsoredTransaction

Relays an intent to the sponsorship backend and returns a `requestId` **without waiting** for on-chain inclusion. Accepts either unsigned `calls` (it signs them for you) or a pre-signed `signedTransaction`.

```javascript theme={"system"}
import { relaySponsoredTransaction } from '@dynamic-labs-sdk/evm';

const { requestId } = await relaySponsoredTransaction({ walletAccount, calls });
```

The `requestId`, not a transaction hash, is the stable identifier for a sponsored transaction, because the relay may retry the on-chain submission. Use it to track status below.

### Parameters

Same as [`signSponsoredTransaction`](#signsponsoredtransaction) (unsigned form), or `{ signedTransaction }`.

### Returns

`Promise<{ requestId: string }>`.

## Tracking status

### getEVMSponsoredTransactionStatus

Fetches the current relay state for a `requestId`. Use it as the building block for custom polling, for example a progress indicator.

```javascript theme={"system"}
import {
  relaySponsoredTransaction,
  getEVMSponsoredTransactionStatus,
} from '@dynamic-labs-sdk/evm';

const { requestId } = await relaySponsoredTransaction({ walletAccount, calls });

const { status, transactionHash, errorMessage } =
  await getEVMSponsoredTransactionStatus({ requestId });
```

**Returns** `Promise<SponsoredTransactionStatusResult>`:

| Field | Type | Description |
| - | - | - |
| `status` | `SponsoredTransactionStatus` | One of `'pending'`, `'submitted'`, `'success'`, or `'failure'`. |
| `transactionHash` | `Hex \| undefined` | Set once the relay has broadcast the transaction. |
| `errorMessage` | `string \| undefined` | Present when `status` is the terminal `'failure'`. |

The `status` lifecycle:

| Status | Meaning |
| - | - |
| `pending` | Accepted by the relayer, not yet broadcast to the chain. |
| `submitted` | Broadcast to the chain, awaiting confirmation. |
| `success` | Finalized successfully on-chain. |
| `failure` | Terminal failure; see `errorMessage`. |

### waitForSponsoredTransaction

For the common "wait until done" case, `waitForSponsoredTransaction` polls `getEVMSponsoredTransactionStatus` every 2 seconds and resolves as soon as the relay reports a transaction hash. It throws a `SponsorTransactionError` on a terminal `failure` or after a 60-second timeout.

```javascript theme={"system"}
import { waitForSponsoredTransaction } from '@dynamic-labs-sdk/evm';

const { transactionHash } = await waitForSponsoredTransaction({ requestId });
```

**Returns** `Promise<{ transactionHash: Hex }>`.

## Reusing a nonce

By default, `signSponsoredTransaction` generates and validates a fresh single-use bitmap nonce for you. Pass your own `nonce` to reuse one across intents, so at most one can ever land on-chain (cancel-replace), or to safely retry a signing request idempotently. Read the nonce back from a signed transaction and pass it to the next signing call:

```javascript theme={"system"}
import { signSponsoredTransaction } from '@dynamic-labs-sdk/evm';

const signedTransaction = await signSponsoredTransaction({
  walletAccount,
  calls,
});

const nonce = BigInt(signedTransaction.nonce);

const replacementTransaction = await signSponsoredTransaction({
  walletAccount,
  calls: replacementCalls,
  nonce,
});
```

`nonce` works the same way on `relaySponsoredTransaction` and [`sendSponsoredTransaction`](https://docs.dynamic.xyz/docs/javascript/reference/evm/send-sponsored-transaction).

To generate a fresh, on-chain-validated nonce yourself (for example, to sign several mutually exclusive intents up front), use `generateSponsoredTransactionNonce`:

```javascript theme={"system"}
import {
  generateSponsoredTransactionNonce,
  signSponsoredTransaction,
} from '@dynamic-labs-sdk/evm';

const nonce = await generateSponsoredTransactionNonce({ walletAccount });

const signedTransaction = await signSponsoredTransaction({
  walletAccount,
  calls,
  nonce,
});
```

## Related functions

* [sendSponsoredTransaction](https://docs.dynamic.xyz/docs/javascript/reference/evm/send-sponsored-transaction.md): sign, relay, and wait in one call
* [EVM Gas Sponsorship overview](https://docs.dynamic.xyz/docs/javascript/reference/evm/evm-gas-sponsorship.md): setup and the common path
* [Managing EIP-7702 delegation](https://docs.dynamic.xyz/docs/javascript/reference/evm/managing-7702-delegation.md): control the one-time delegation step
* [EVM Server-Controlled Sponsorship](https://docs.dynamic.xyz/docs/recipes/integrations/evm-server-controlled-sponsorship.md): sign on the client, validate and relay from your backend


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.