> ## 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.

# Spark tokens

> Spark assets on the Execution side

A Spark token on the Execution side is a `SparkToken` ERC20 contract that represents a Spark-native asset one-to-one. The gateway deploys it the first time anyone deposits that asset, then mints and burns through the same contract for every subsequent deposit and withdrawal.

## How it gets deployed

1. A user submits a deposit intent referencing a Spark transfer of token id `T`.
2. The gateway looks up `T` in its registry. If no contract exists, it calls `depositBtknWithDeploy` on `SparkGateway`.
3. The gateway deploys a fresh `SparkToken` ERC20 via CREATE2. The address is deterministic in `(salt = T, name, symbol, decimals)`.
4. The gateway mints the deposit amount to the recipient's EVM address. Subsequent deposits skip the deploy step and just mint.

The deployment is idempotent: if the contract already exists, the deploy step is a no-op.

## Get the contract address

```typescript theme={null}
import { querySparkTokenAddress } from "@flashnet/sdk";

const tokenIdHex = "...";  // 64-char hex token id (decoded from bech32m)
const tokenAddress = await querySparkTokenAddress(
  rpcUrl,
  gatewayAddress,
  tokenIdHex
);

if (!tokenAddress) {
  // Token not deployed yet. Submit a deposit (or depositBtknWithDeploy) first.
}
```

The bech32m form (`btknrt1...` / `btkn1...`) is what users see; the gateway indexes by the underlying 32-byte hex id. To convert:

```typescript theme={null}
import { decodeSparkHumanReadableTokenIdentifier } from "@flashnet/sdk";

const { tokenIdentifier } = decodeSparkHumanReadableTokenIdentifier(
  "btknrt1...",
  "REGTEST"
);
```

## Wait for first deployment

A first-deposit intent deploys the contract atomically with the first mint. If you submit a deposit and want the address back as soon as it lands, poll:

```typescript theme={null}
import { waitForSparkTokenAddress } from "@flashnet/sdk";

const address = await waitForSparkTokenAddress(
  rpcUrl,
  gatewayAddress,
  tokenIdHex,
  20_000  // timeout ms
);
```

Returns `null` on timeout. Adjust the timeout based on how long your gateway takes to reach finality on first-deposit intents (usually a few seconds).

## Properties

`SparkToken` is a standard ERC20 with three notable differences:

| Feature             | Behavior                                                                                                             |
| ------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Decimals**        | Set at deploy time from Spark token metadata. Not always 18. Always read with `decimals()` before doing amount math. |
| **EIP-2612 Permit** | Implemented. Lets `TradingClient` swap your tokens without a standing allowance.                                     |
| **Mint and burn**   | Restricted to the gateway. The token's `OnlyGateway()` error fires if anyone else tries.                             |

Standard ERC20 calls (`balanceOf`, `transfer`, `approve`, `transferFrom`) work as expected. Use the regular [reading-state helpers](/products/execution/reading-state) to query.

## Bytecode determinism

Because `SparkToken` is deployed via CREATE2 with the Spark token id as salt, the resulting EVM address is the same on every Flashnet deployment that shares the same SparkGateway proxy. You can compute it off-chain if you need to reference the address before the first deposit. In practice, query `tokenBySparkId` or `querySparkTokenAddress` instead. The gateway is the source of truth.

## Listing all deployed tokens

`SparkGateway.getDeployedTokens()` returns every Spark token contract the gateway has spawned. For paginated listing, use `getDeployedTokensPaginated(offset, limit)`. Off-chain indexers (Blockscout, the `/network/info` endpoint) are the better path for production UIs. Chain reads of `getDeployedTokens()` aren't bounded.
