Skip to main content

Documentation Index

Fetch the complete documentation index at: https://flashnet-build.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

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

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

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

interface ExecuteResponse {
  submissionId: string;
  intentId: string;
  status: IntentStatus; // "accepted" | "oracle_pending" | "included_pending_finality" | "finalized" | "rejected" | "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.

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.