Shape
How signing works
The SDK serializes the message in canonical camelCase JSON, takes a SHA-256 hash, and signs it with the identity key (DER-encoded secp256k1 ECDSA). The validator’s signature check uses the same preimage, so any deviation between client and gateway invalidates the intent. You don’t construct this message by hand.ExecutionClient.deposit / withdraw / withdrawToken / execute all build and sign it for you.
Expiry
The default TTL is 15 minutes. Override per-call withexpiresAt:
- Short TTL (1-5 min) for interactive UIs where the user should retry if something stalls.
- Default (15 min) for batch flows that need to survive transient gateway hiccups.
- Long (1-24h) for offline-signed intents you plan to submit later.
Composition
A single intent can carry many deposits and one execute action. The pattern most flows follow:TradingClient.swap (deposit + swap + withdraw) and the lower-level execClient.execute(...) (any deposits + any pre-signed tx).
Status lifecycle
SCREAMING_SNAKE_CASE.
For most flows, wait for
FINALIZED before reading downstream balances. For optimistic UIs, INCLUDED_PENDING_FINALITY is enough.
Replay protection
Two layers:- Spark transfer ids. Each Spark transfer can only fund one intent. A second intent referencing the same id is rejected at admission.
- EVM nonce. The signed transaction inside an execute intent has the standard EVM nonce, so the runtime rejects a replayed transaction even if the intent itself reaches the chain twice.
Why intents instead of transactions
Three reasons the SDK doesn’t expose raw EVM transactions as the unit of work:- Cross-chain atomicity. Spark deposits and the EVM action commit together. Plain transactions can’t reference Spark transfer state.
- Settlement dispatch. Withdrawals need to translate
SparkWithdrawalevents back into Spark transfers. The intent boundary is what the settlement layer reads. - Replay protection across Spark and EVM. The intent’s nonce binds the deposit ids, the EVM transaction, and the expiry into one preimage so a partial replay isn’t possible.
rpcUrl. Writes go through intents.