Swap Token - Integration Guide

This guide explains how to implement token swaps in your application. The process includes: requesting a quote, then executing the swap via the SWAP_FROM_QUOTE operation.

📊 View Flow Diagram

1. Get a Quote

Before executing a swap, you must obtain a quote that indicates the amount of tokens you will receive in exchange, as well as the associated fees.

Endpoint : GET /v1.2/safes/swap/quote

Headers :

Query Parameters :

Request Example :

GET /v1.2/safes/swap/quote?sellTokenAddress=0xcb444e90d8198415266c6a2724b7900fb12fc56e&buyTokenAddress=0xEURE12345678901234567890123456789012345678&amount=100.0&chainId=421614&provider=BOTH
Authorization: Bearer <access_token>

Response (200 OK) :

{
  "quoteId": "abc123-def456-ghi789",
  "sellToken": "0xcb444e90d8198415266c6a2724b7900fb12fc56e",
  "sellTokenDecimals": 18,
  "buyToken": "0xEURE12345678901234567890123456789012345678",
  "buyTokenDecimals": 18,
  "sellAmount": "100.0",
  "feeAmount": "0.5",
  "buyAmount": "9950.25",
  "validTo": 1735689600,
  "comparisons": {
    "cowswap": {
      "provider": "COWSWAP",
      "buyAmount": "9950.25",
      "feeAmount": "0.5",
      "validTo": 1735689600
    },
    "oneinch": {
      "provider": "1INCH",
      "buyAmount": "9948.50",
      "estimatedGas": "150000"
    }
  },
  "bestProvider": "COWSWAP"
}
💾 To Store :
💡 Note : The quote is valid for a limited duration (usually 5 minutes). Make sure to execute the swap before expiration. If the quote expires, you will need to request a new one.

Balance Verification

Before executing the swap, verify that the user has sufficient tokens to sell. The API automatically checks the balance when requesting a quote, but you can also verify manually via:

Endpoint : GET /v1.2/bcreader/balances?address={safeAddress}

2. Execute Swap via SWAP_FROM_QUOTE

Once the quote is obtained, you can execute the swap using the SWAP_FROM_QUOTE operation.

Endpoint : POST /v1.2/safes/operations

Headers :

Body (JSON) :

SWAP_FROM_QUOTE Operation :

Request Example :

POST /v1.2/safes/operations
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "safeAddress": "0xd676c6188195372EC269E9C2cAf815C56436A679",
  "operations": [
    {
      "type": "SWAP_FROM_QUOTE",
      "quoteId": "abc123-def456-ghi789"
    }
  ]
}

Response (200 OK) :

{
  "credentialRequestOptions": {
    "challenge": "<base64url_encoded_userOpHash>",
    "rpId": "foo.domain",
    "userVerification": "required"
  }
}
⚠️ Important : After receiving credentialRequestOptions, you must:
  1. Use navigator.credentials.get() with these options to obtain a credential
  2. Send a PUT /v1.2/safes/operations request with the credential to finalize swap execution

Finalize Execution (PUT)

Endpoint : PUT /v1.2/safes/operations

Body (JSON) :

Request Example :

PUT /v1.2/safes/operations
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "credential": {
    "id": "AVZs0qRCBSmfThZWu37g...",
    "rawId": "AVZs0qRCBSmfThZWu37g...",
    "type": "public-key",
    "response": {
      "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MFAAAAAQ...",
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoi...",
      "signature": "MEUCIQC..."
    }
  }
}

Response (200 OK) :

{
  "userOpHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "status": "SIGNED"
}
💾 To Store :

3. Track Operation Status

Once the operation is submitted, you can track its status. Possible statuses are:

Check Operation Status

Endpoint : GET /v1.2/safes/operations/{userOpHash}

Request Example :

GET /v1.2/safes/operations/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Authorization: Bearer <access_token>

Response (200 OK) :

{
  "userOpHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "status": "CONFIRMED",
  "transactionHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
  "createdAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T10:35:00.000Z"
}

Track Swap Order (v1.1 - Optional)

For CoW Protocol swaps, you can also track the swap order status via BCReader after execution:

Endpoint : POST /v1.1/swap/order/create (BCReader API)

Note : This endpoint is automatically called by the IBEX API after a CoW Protocol swap is signed. You can also call it manually to track swap orders.

Request Body :

Request Example :

POST /v1.1/swap/order/create
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "safeAddress": "0xd676c6188195372EC269E9C2cAf815C56436A679",
  "uid": "0xd9c6...69069a35",
  "provider": "COWSWAP",
  "blockchainId": "100"
}

Response (200 OK) :

{
  "message": "Order surveillé créé",
  "order": {
    "id": 1,
    "uid": "0xd9c6...69069a35",
    "blockchainId": "100",
    "safeAddress": "0xfaa672c06e4abdcb4a1513e9a31c3c498a321468",
    "provider": "COWSWAP",
    "status": "fulfilled",
    "type": "traded",
    "executedSell": "8999454",
    "executedBuy": "7704892248123160929",
    "surplus": "0",
    "lastCheckedAt": "2025-11-02T12:10:35.000Z",
    "createdAt": "2025-11-02T12:10:34.000Z",
    "updatedAt": "2025-11-02T12:10:35.000Z"
  }
}

Get Swap Order Status : GET /v1.1/swap/order/{id}

You can retrieve a tracked swap order by UID or transaction hash:

Request Example (by UID) :

GET /v1.1/swap/order/0xd9c6...69069a35
Authorization: Bearer <access_token>

Request Example (by txHash) :

GET /v1.1/swap/order/0xswapTxHashReturnedAfterExecution
Authorization: Bearer <access_token>

4. Available Providers

The IBEX API supports two swap providers:

COWSWAP

1INCH

💡 Note : By specifying provider: "BOTH" (default), the API automatically compares both providers and returns the best quote. The bestProvider field in the response indicates which one is recommended.

5. Error Handling

Expired Quote

If the quote has expired, you will receive an error during execution. In this case, request a new quote.

Insufficient Balance

If the user does not have sufficient tokens to sell, the API will return an error. Check the balance before executing the swap.

Invalid Quote

If the quoteId is invalid or no longer exists, the API will return an error. Make sure to use a recent and valid quote.

Complete Flow Summary

  1. Get a quote : GET /v1.2/safes/swap/quote with swap parameters
  2. Store the quoteId : Store the quoteId received in the response
  3. Prepare the swap : POST /v1.2/safes/operations with SWAP_FROM_QUOTE operation and the quoteId
  4. Sign with passkey : Use navigator.credentials.get() with the credentialRequestOptions
  5. Finalize execution : PUT /v1.2/safes/operations with the credential
  6. Track status : Check status via GET /v1.2/safes/operations/{userOpHash}
  7. Verify result : Once status = "CONFIRMED", the swap is complete
⚠️ Important Points :

Technical Deep Dive - For AI Integration

This section provides detailed technical information for AI systems integrating the IBEX token swap flow, including architecture patterns, data models, and implementation details.

Quote Request Flow - Technical Details

GET /v1.2/safes/swap/quote

Database Schema - UserQuote:

UserQuote {
  id: String (PK, UUID)
  userId: String (FK to User)
  provider: String (COWSWAP | 1INCH)
  sellToken: String (address)
  buyToken: String (address)
  receiver: String (Safe address)
  sellAmount: String (wei, BigInt as string)
  buyAmount: String (wei, BigInt as string)
  validTo: Int (Unix timestamp)
  appData: String (JSON string)
  appDataHash: String
  kind: String (sell | buy)
  partiallyFillable: Boolean
  sellTokenBalance: String (erc20 | eth)
  buyTokenBalance: String (erc20 | eth)
  signingScheme: String (presign | eip712)
  createdAt: DateTime
  updatedAt: DateTime
}

SWAP_FROM_QUOTE Operation - Technical Details

POST /v1.2/safes/operations

1INCH Execution Flow:

CoW Protocol Execution Flow:

PUT /v1.2/safes/operations/{userOpHash}

Provider Comparison - Technical Details

Quote Response Structure:

{
  "quoteId": "uuid",
  "sellToken": "0x...",
  "sellTokenDecimals": 18,
  "buyToken": "0x...",
  "buyTokenDecimals": 18,
  "sellAmount": "1000000000000000000",  // Human-readable amount
  "feeAmount": "5000000000000000",      // CoW fee (if applicable)
  "buyAmount": "2000000000000000000",   // Expected output
  "validTo": 1234567890,                // Unix timestamp
  "comparisons": {
    "cowswap": {
      "provider": "COWSWAP",
      "buyAmount": "2000000000000000000",
      "feeAmount": "5000000000000000",
      "validTo": 1234567890
    },
    "oneinch": {
      "provider": "1INCH",
      "buyAmount": "1950000000000000000",
      "estimatedGas": "150000"
    }
  },
  "bestProvider": "COWSWAP"            // Selected provider
}

Provider Selection Logic:

Idempotency and Concurrency Control

Per-Safe Execution Locks:

Quote Idempotency:

Operation Status Tracking

Status Flow:

Status Polling:

Error Handling

Key Implementation Files

Complete Flow - Technical Sequence

  1. Request quote : GET /v1.2/safes/swap/quote → returns quoteId, amounts, provider comparison
  2. Store quoteId : Client stores quoteId (valid for ~5 minutes)
  3. Prepare swap : POST /v1.2/safes/operations with { type: "SWAP_FROM_QUOTE", quoteId }
  4. Load quote : Server loads UserQuote from database
  5. Create operation : Server creates Safe user operation (approve + swap/setPreSignature)
  6. Get credential options : Server returns credentialRequestOptions with userOpHash
  7. Sign with passkey : Client uses WebAuthn to sign challenge
  8. Finalize execution : PUT /v1.2/safes/operations/{userOpHash} with credential
  9. Operation signed : Server updates status to SIGNED, notifies BCReader (CoW only)
  10. Bundler execution : Bundler picks up signed operation, submits to blockchain
  11. Status tracking : Poll GET /v1.2/safes/operations/{userOpHash} until CONFIRMED
  12. Swap complete : Once CONFIRMED, tokens have been swapped on-chain
← Back to Main Guide