Skip to main content
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    │
                          │   (zero base fee, zero priority 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 ACCEPTED while the deposit oracle confirms each Spark transfer id against the Spark operator DB. Intents without deposits skip this wait. A failure here or an expiry transitions the intent to EXPIRED, with the reason in statusMessage.
  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.
Settlement back to SparkThe settlement layer reads finalized intents and translates SparkWithdrawal events into Spark transfers. The intent boundary is its input.
Replay protection across both sidesThe intent’s nonce binds the deposit ids, the EVM transaction, and the expiry into one signed preimage. A replay can’t reuse a deposit, a tx, or a recipient in isolation.
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 runtime sets baseFeePerGas = 0 and maxPriorityFeePerGas = 0 for every block. There is no base fee to charge, no priority fee to bid, and no gas-token economy to manage. 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.
  • The fee policy is settable. 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.