Open app
Reference / Liquidity API
Docs/Reference

Liquidity API

Add and manage liquidity with one API and a local wallet signer.

One flow across supported pools

Flea handles pool discovery, paired amounts, wrapping, approvals, transaction preparation, submission and receipt checks through the same API for supported V2, V3 and V4 markets on Robinhood. Your integration supplies a pool, amount and wallet signer, without implementing a different contract flow for each pool version.

The initial API supports Robinhood, chain ID 4663. It uses existing verified pools and the same eligibility checks as the app. Both assets must be available in the wallet; Flea can wrap ETH into WETH, but does not swap assets, create a new pool or permanently lock a position.

Find a market and preview amounts

The API is public and does not require a Privy login or API key. Discover markets using the token contract, then explicitly select an eligible pool. The default listing is ranked by indexed pool liquidity; pass nextCursor back as cursor to load the next page.

This example discovers CASHCAT markets. Check pool eligibility, paired assets, fee rights and available liquidity before choosing. A token can have several pools.

const base = 'https://flea.trade/api/v1';
const token = '0x020bfc650a365f8bb26819deaabf3e21291018b4';
const { data } = await fetch(base + '/pools?token=' + token)
  .then(response => response.json());
console.log(data.pools); // Choose a pool explicitly.

const quote = await fetch(base + '/quote', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    poolId, token, amount: '100', range: 'full', slippageBps: 50
  })
}).then(response => response.json());

Run a deposit

Download client.mjs as flea-v1.mjs and install viem for the local signer. The example uses Node 22 or newer. Keep the private key in your own process; never send it in an API request or put it in browser code.

Persist a unique idempotency key before starting and save the operation ID as soon as it is returned. Use that same key to retry the same intended deposit. Reuse the operation ID to resume after a restart. Changing the input with the same key returns a conflict.

import { FleaClient } from './flea-v1.mjs';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const flea = new FleaClient();
const result = await flea.execute({
  input: {
    action: 'deposit', owner: account.address,
    poolId, token, amount: '100',
    maxNetworkFeeWei: '10000000000000000'
  },
  idempotencyKey: savedRequestKey,
  signTransaction: tx => account.signTransaction(tx),
  onOperation: op => saveOperationId(op.id),
  onStep: step => reviewTransactionPolicy(step)
});
console.log(result.result.positionIds);

Review what gets signed

An operation returns one prepared transaction at a time. The signer receives its chain, recipient, calldata, value, nonce, gas limit and fee fields. Flea validates the signed transaction against those fields before broadcasting. The position is minted to the signing wallet.

Approval steps also expose token, spender, amountRaw, unlimited and any Permit2 expiry. Your onStep callback can reject a permission before signing. Some compatible tokens require an unlimited ERC20 allowance to Permit2; the separate Permit2 manager allowance remains bounded by amount and time. Do not treat an unlimited allowance as an exact-amount permission.

maxNetworkFeeWei caps gas limit multiplied by maximum fee per gas for each transaction, excluding the ETH value being deposited or wrapped. The default is 0.01 ETH per transaction. It is a ceiling, not an estimate of the final charge or a total operation budget.

Collect and withdraw

Use an opaque position ID returned by Flea. Wallet discovery is partial, so import an externally created position when necessary. V2 positions use v2: followed by the pool address; V3 and V4 use their NFT token ID. Ownership is checked before preparation.

The same execute method handles collect and withdraw. V2 fees accrue inside LP tokens and have no separate collect action. Withdrawal percent is an integer from 1 to 100; the existing withdrawal adapter applies a 0.5% amount tolerance.

await flea.execute({
  input: { action: 'withdraw', owner: account.address,
    positionId, percent: 100 },
  idempotencyKey: savedWithdrawalKey,
  signTransaction: tx => account.signTransaction(tx)
});
// To collect, use action: 'collect' and omit percent.

Resume and recover

The client retries transient requests with the same idempotency key or identical signed bytes. It polls only while execute is running, and does not automatically increase fees. If it times out, the error includes operationId and idempotencyKey; the transaction may still be pending. Resume that operation before creating another deposit.

A broadcastState of unknown means the RPC response was inconclusive. Retry the exact signed bytes or poll the operation. After a process restart, use reprice to obtain a replacement for the same nonce and action if it is still pending, sign it locally and submit it. A successfully confirmed external replacement can be reported through reconcile. A different replacement action marks the operation cancelled.

Two confirmations are required before advancing to the next step. This is a confirmation policy, not a guarantee of absolute chain finality. A failed final transaction does not undo earlier approvals or wrapping. Keep the operation ID and transaction hashes.