Skip to main content

Guide: Native Swap Example

This guide provides a complete, code-first walkthrough for creating and submitting a swap transaction using the API. We will build a real-world example: swapping USD to cBTC on the Citrea blockchain backed by Sepolia ETH as collateral, using Crest as a liquidity source.

The Goal

Our goal is to create an “intent” that performs the following actions:
  1. On Sepolia Testnet: A user deposits 0.0001 Sepolia ETH into an escrow EOA.
  2. On Citrea Testnet: Using the value from the deposit, execute a swap for cBTC via crest contract.
  3. Finally: The solver sends the principal amount of the deposit back to the user on Citrea.
This entire process will be defined in a single intent, signed by the user once, and submitted to the API.

Prerequisites

You’ll need viem to interact with chains, create authorizations, and sign messages. For frontend applications, you would need to use privy SDK to work with embedded wallets.

Step 1: Setting up Accounts and Clients

First, we define the accounts and blockchain clients we’ll be working with. In a real application, the user would be the end-user interacting with your application, and their private key would be managed by their wallet.

Step 2: Define the Intent Parameters

We’ll define the amounts and generate a quote for the swap part of our intent.

Step 3: Create EIP-7702 Authorizations

The core of the process is the user granting our system one-time authority on each chain. The user’s wallet will sign an EIP-7702 authorization for each delegate contract on each chain.
These authorization objects are what a solver will use to execute transactions on the user’s behalf.

Step 4: Construct the Chain Batches

Now we define the specific on-chain actions. Each object in the chainBatches array represents a set of calls to be executed on a specific blockchain, in order. Import the hashing helpers from @spicenet-io/spiceflow-core. Do not hand-roll them, and do not add a recentBlock field: the current chain-batch shape is { chainId, calls }, and the request schema rejects unknown keys.
hashChainBatches returns each batch as { hash, chainId, calls }.

Step 5: Sign the Intent and Build the Request

The user signs the intent hash. getIntentHash takes the signature type, a not-before timestamp (nbf), an expiry (exp), and the hashed chain batches:
Assemble the POST /actions request body. chainAuthorizations are the EIP-7702 authorizations from Step 3, each { r, s, yParity, address, chainId, nonce } (drop the legacy v field). Each chain batch also carries its tokenTransfers (how the solver moves tokens):
Send it to POST /actions. See the POST /actions reference for the full request and response schema.

What Happens Next: The Solver

After you submit the intent, the API makes it available to a network of solvers. A solver will:
  1. Pick up your intent.
  2. Execute Step 0 by sending a transaction to the Delegate contract on Sepolia, using your signed authorization. This deposits your funds to escrow.
  3. Wait for the required block confirmations.
  4. Execute Step 1 by sending a transaction to the Delegate contract on Citrea, which performs the swap.
  5. As part of the final transaction, the solver also transfers the principal deposit amount (tokenAmount) back to your address (address) on the destination chain (Citrea).
Your application can track each step using the GET /actions/{actionId}/intents/{intentIndex}/steps/{stepIndex} endpoint. You have successfully orchestrated a cross-chain action without requiring the user to switch networks or manage gas on the destination chain.