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.

Flashnet Execution is the programmable settlement layer between Spark and your contract code. The runtime is EVM-compatible, so contracts compile with Solidity and standard tooling. The integration model is intent-based: you sign an intent, the sequencer includes it, validators sign the finality certificate, and settlement dispatches results back to Spark.

Components

                          ┌──────────────────────────────────────┐
                          │              Spark                    │
                          │   wallets · MPC custody · L1 anchor   │
                          └──────────────┬───────────────────────┘

                            send_sats / send_token (Spark transfers)

                          ┌──────────────▼───────────────────────┐
                          │           SparkGateway                │
                          │   deposit / withdrawal contract       │
                          └──────────────┬───────────────────────┘

                          ┌──────────────▼───────────────────────┐
                          │            Sequencer                  │
                          │   admits intents, orders the block,   │
                          │   pays the operator-funded base fee   │
                          └──────────────┬───────────────────────┘

                          ┌──────────────▼───────────────────────┐
                          │     Validators + sequencer signers    │
                          │   keys live in TEE (Nitro Enclaves    │
                          │   in production); finality cert       │
                          │   signed inside the enclave           │
                          └──────────────┬───────────────────────┘

                          ┌──────────────▼───────────────────────┐
                          │           Settlement                  │
                          │   dispatch SparkWithdrawal events     │
                          │   back to Spark via send_sats /       │
                          │   send_token                          │
                          └──────────────────────────────────────┘

The intent path

  1. Client signs. The SDK builds a canonical intent message (chain id, transfers, action, expiry), SHA-256 hashes it, and signs with the identity key. See Intents.
  2. Gateway admits. A REST gateway authenticates the signer, validates the expiry, checks the intent isn’t a replay, and forwards to the sequencer.
  3. Sequencer admission and deposit oracle. The sequencer holds deposit-shaped intents in oracle_pending while the deposit oracle confirms each Spark transfer id against the Spark operator DB. Intents without deposits skip this stage. Failure here transitions to rejected; expiry transitions to expired.
  4. Sequencer includes. Once admitted, the sequencer orders the intent into the next block as one or more EIP-1559 transactions: deposit calls to SparkGateway plus the user’s signed transaction.
  5. Validators finalize. Validators run the block, compare state roots, and sign a finality certificate inside their TEE. Quorum advances the chain head.
  6. Settlement dispatches. Finalized SparkWithdrawal events are translated into Spark transfers and dispatched back to the user’s Spark wallet.
The user signs once. Everything else is the operator’s responsibility.

Why TEEs

All consensus signing and Spark wallet operations run inside a TEE signing server (tee-server). Validator and sequencer host processes talk to it over VSock and never hold keys themselves. In production the TEE is an AWS Nitro Enclave, with the signing key sealed via KMS and unsealed only on PCR-attested startup. Two things this buys:
  • Key isolation. Finality-certificate signing keys, deposit-oracle signing keys, and Spark wallet signing keys all live inside the enclave. A compromised validator or sequencer host can’t forge a signature.
  • Attestable code. The enclave produces a remote attestation that proves the running binary matches a known measurement. Operators publish the expected measurement; clients can verify the validator they’re talking to is running the code they expect.
The sequencer is in scope here too: it signs Spark deposit transactions and consensus messages from inside its own TEE-backed signer. Its ordering authority is checked independently by validators, but the keys it uses to act on Spark are still enclave-bound.

Why intents instead of transactions

Three things plain transactions can’t express:
NeedWhy intents
Atomicity across Spark and EVMAn intent commits Spark deposits and an EVM action together. Either both apply or neither does.
Operator-paid executionThe intent boundary is where the sequencer authorizes paying the base fee on behalf of the user.
Settlement back to SparkThe settlement layer reads finalized intents and translates SparkWithdrawal events into Spark transfers. The intent boundary is its input.
For read-only access or tooling that only speaks JSON-RPC, the gateway exposes a standard EVM RPC endpoint. Writes go through intents.

Why zero gas

The operator runs the sequencer and pays for inclusion. The runtime sets baseFeePerGas = 0 and maxPriorityFeePerGas = 0 for every block. The fee model is on the operator side, not on the user side. This means:
  • No gas token. Native sats are usable, but you don’t need to hold them just to call a contract.
  • No fee market. Transactions are ordered by sequencer policy, not by bid.
  • Operator policy can change. The integration is forward-compatible: fetchEip1559Fees(rpcUrl) returns whatever the node currently reports, so a future fee change doesn’t break clients that read it.

Replay safety

Two layers of replay protection:
  • Spark transfer ids are recorded on SparkGateway after first use. A second intent claiming the same transfer id is rejected at admission.
  • Withdrawal nonces are monotonic on SparkGateway. The settlement layer reconciles by nonce, so a finalized withdrawal never settles twice on Spark even if the EVM transaction is replayed.
The standard EVM nonce on the user’s signed transaction is the third layer for execute intents.

What’s not on chain

  • The signed intent message. It’s the input the gateway and validators verify against. Only the resulting EVM transactions land on the chain.
  • Spark transfer ids in their original form. They’re embedded in the deposit call’s calldata as 32-byte values for replay protection but don’t appear as chain events outside that.
  • Spark addresses. Withdrawals carry the 33-byte compressed pubkey of the recipient in calldata. The chain doesn’t know it’s a Spark address; the settlement layer does.
The chain’s role is execution and finality. Everything Spark-aware lives at the gateway and settlement boundaries.