FS
FirmSwap

API Reference

The FirmSwap API is a self-hosted quote aggregator built on Fastify. Anyone can run an instance — it is not a centralized service.

Endpoints

MethodPathDescriptionRate Limit
GET/healthHealth check
GET/metricsPrometheus metricsAuth optional
POST/v1/:chainId/quoteRequest a swap quote30/min
GET/v1/:chainId/order/:orderIdGet on-chain order status60/min
POST/v1/:chainId/solvers/registerRegister a solver5/min
DELETE/v1/:chainId/solvers/:addressUnregister a solver10/min
GET/v1/:chainId/solversList active solvers60/min
GET/v1/wsWebSocket for real-time events

All routes scoped to :chainId return 404 if the chain is not supported.

Quote Request

POST /v1/:chainId/quote

{
  "inputToken": "0x...",
  "outputToken": "0x...",
  "orderType": "EXACT_INPUT",
  "amount": "1000000000000000000",
  "userAddress": "0x...",
  "originChainId": 100,
  "destinationChainId": 100,
  "depositMode": "CONTRACT"
}

Fields

FieldTypeDescription
inputTokenaddressToken the user is selling
outputTokenaddressToken the user is buying
orderTypestringEXACT_INPUT or EXACT_OUTPUT
amountstringAmount in the token's smallest unit
userAddressaddressUser's wallet address
originChainIdnumberChain ID for the deposit
destinationChainIdnumberChain ID for the output
depositModestringCONTRACT or ADDRESS
depositWindownumberOptional: deposit deadline in seconds (default: 300)

Quote Response

{
  "quote": {
    "solver": "0x...",
    "user": "0x...",
    "inputToken": "0x...",
    "inputAmount": "1000000000000000000",
    "outputToken": "0x...",
    "outputAmount": "200000000",
    "orderType": 0,
    "outputChainId": 100,
    "depositDeadline": 1700000000,
    "fillDeadline": 1700000120,
    "nonce": "123456"
  },
  "solverSignature": "0x...",
  "depositAddress": "0x...",
  "alternativeQuotes": []
}

The quote fields map directly to the on-chain FirmSwapQuote struct. The solverSignature is an EIP-712 typed data signature.

Solver Registration

POST /v1/:chainId/solvers/register

{
  "address": "0xSolverAddress...",
  "endpointUrl": "https://solver.example.com",
  "name": "My Solver",
  "signature": "0x...",
  "timestamp": 1700000000000
}

The signature is an EIP-191 personal message signature over:

FirmSwap Solver Registration
Address: 0xsolveraddress...
Endpoint: https://solver.example.com
Timestamp: 1700000000000

Requirements:

  • The solver must be registered on-chain with a bond >= 1,000 USDC
  • The timestamp must be within 5 minutes of the server's clock
  • In production, the endpoint URL must be HTTPS with a public IP (SSRF protection)

Solver Unregistration

DELETE /v1/:chainId/solvers/:address

Requires an EIP-191 signature in the request body proving address ownership.

WebSocket Events

GET /v1/ws

Events are broadcast for all supported chains:

{ "type": "connected", "supportedChains": [100, 10200] }
{
  "type": "Deposited",
  "chainId": 100,
  "orderId": "0x...",
  "user": "0x...",
  "solver": "0x...",
  "inputToken": "0x...",
  "inputAmount": "1000000000000000000",
  "outputToken": "0x...",
  "outputAmount": "200000000",
  "fillDeadline": 1700000120,
  "blockNumber": 12345
}
{ "type": "Settled", "chainId": 100, "orderId": "0x...", "blockNumber": 12346 }
{
  "type": "Refunded",
  "chainId": 100,
  "orderId": "0x...",
  "user": "0x...",
  "inputAmount": "1000000000000000000",
  "bondSlashed": "10000000",
  "blockNumber": 12347
}

Configuration

VariableDefaultDescription
SUPPORTED_CHAINSComma-separated chain IDs (e.g., 100,10200,8453)
RPC_URL_<chainId>JSON-RPC endpoint per chain
FIRMSWAP_ADDRESS_<chainId>Contract address per chain
PORT3000HTTP server port
HOST0.0.0.0Bind address
DB_PATH./firmswap-api.dbSQLite path (:memory: to disable)
QUOTE_TIMEOUT_MS2000Max wait for solver quotes
DEFAULT_DEPOSIT_WINDOW300Deposit deadline (seconds)
DEFAULT_FILL_WINDOW120Fill window after deposit deadline
MIN_SOLVER_BOND1000000000Minimum bond (1000 USDC, 6 decimals)
MAX_SOLVERS_PER_CHAIN50Max registered solvers per chain
MAX_QUOTE_FAN_OUT10Max solvers queried per quote
RATE_LIMIT_MAX100Requests per window (global)
RATE_LIMIT_WINDOW_MS60000Rate limit window (ms)
CORS_ORIGINS*Allowed origins
NODE_ENVproduction enforces HTTPS solver URLs

Self-Hosting

git clone https://github.com/purybr365/firmswap.git
cd firmswap/api
cp .env.example .env
# Configure SUPPORTED_CHAINS, RPC_URL_*, FIRMSWAP_ADDRESS_*
npm install
npm start

Multiple API instances can coexist, each with their own solver set. The smart contract is the source of truth — the API never holds funds.