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

# Withdrawals

> Sweep balances back to Spark

Withdrawals move assets from the Execution side back to your Spark wallet. The user signs an EIP-1559 transaction calling `withdrawSats` or `withdrawBtkn` on `SparkGateway`. The contract emits a `SparkWithdrawal` event; the consensus layer reads finalized events and the sequencer dispatches the matching Spark transfer back to the recipient. One intent per withdrawal.

## Native sats

```typescript theme={null}
await execClient.authenticate();

const result = await execClient.withdraw({
  amount: 50_000n, // satoshis
});
```

`amount` is in sats. The contract rejects `0` (`ZeroAmount()`) and any value that doesn't divide evenly by `WEI_PER_SAT = 10^10` (`SubSatWithdrawal()`). The output lands at the Spark address derived from the same identity key that controls the EVM balance. The user pays no gas. Flashnet runs zero base fee and zero priority fee.

## Spark tokens

```typescript theme={null}
const result = await execClient.withdrawToken({
  tokenAddress: "0x...",       // Spark ERC20 contract on Execution
  amount: 1_000_000n,          // base units (matches the token's decimals)
});
```

`withdrawBtkn` calls `SparkToken.burnFrom` (gateway-only burn authority) and emits a `SparkWithdrawal` event with the Spark token id and recipient. The consensus layer scans finalized logs and the sequencer dispatches the matching Spark token transfer.

Both `withdrawSats` and `withdrawBtkn` are gated by a `whenNotPaused` modifier. When the operator pauses the gateway, withdrawals revert.

## What gets returned

```typescript theme={null}
interface ExecuteResponse {
  submissionId: string;
  intentId: string;
  status: IntentStatus; // "ACCEPTED" | "INCLUDED_PENDING_FINALITY" | "FINALIZED" | "EXPIRED"
}
```

The Spark-side transfer id is not in the response. To follow the output, subscribe to your Spark wallet's incoming transfers or query the gateway's intent status endpoint until `FINALIZED`. See [Intents → Status lifecycle](/products/execution/intents#status-lifecycle).

## Replay safety

Each withdrawal carries a monotonically increasing nonce on `SparkGateway`. The settlement layer reconciles by withdrawal id, so a finalized withdrawal never settles twice on Spark even if the EVM transaction is replayed.

## Failure modes

* **Zero amount.** Calling `withdrawSats` with `msg.value == 0` reverts with `ZeroAmount()`.
* **Sub-sat amount.** A `msg.value` that isn't a whole number of sats reverts with `SubSatWithdrawal()`.
* **Unregistered token.** Withdrawing through a contract address the gateway didn't deploy reverts with `UnregisteredToken()`. Check the address came from `tokenBySparkId(...)` or `querySparkTokenAddress`.
* **Gateway paused.** Both withdraw functions are `whenNotPaused`; calls during a pause window revert.
* **Recipient encoding.** The Spark recipient is encoded automatically from the identity key. If you call the contract directly (bypassing the SDK), pass the 33-byte compressed pubkey.

## Combining with other actions

A withdrawal does not have to stand alone. The standard pattern is to bundle it with whatever action produced the balance: a swap, a deploy, a contract call. `TradingClient.swap({ withdraw: true })` is one example. For arbitrary contract calls, see [Executing intents](/products/execution/executing).
