Skip to content

Liquidity API

The /v1/liquidity/* endpoints abstract the Snowside subnet (Avalanche L1) behind https://ecashfarm.com/v1 so that front-ends — our own /liquidity page and 3rd-party partners such as alpha.pecx.shop — never talk to Snowside directly. The server is a read + broadcast relay only (AGENTS.md rule 5): it holds no funds, no keys, and never signs. Transaction building and signing stay 100% client-side.

https://ecashfarm.com/v1/liquidity

All responses are JSON, CORS-enabled (Access-Control-Allow-Origin: *), and require no authentication on reads.

Every response carries a mode field:

  • preview — Snowside Uniswap is not yet deployed. Contract addresses are placeholders; stats / pools / quote return deterministic mocked values so integrators can build the full flow now.
  • live — Snowside Uniswap is deployed. config returns real addresses; stats/pools/quote relay real on-chain reads from Snowside.

Detect mode from GET /v1/liquidity/config → contractsDeployed (or mode). Do not hardcode addresses — always read them from /config.

Rule 5 boundary (important for integrators)

Section titled “Rule 5 boundary (important for integrators)”
Operation Where it happens
Reads (config, stats, pools, quote) Server relays from Snowside / D1
Transaction building (calldata) Client-side
Signing Client-side (browser wallet)
Broadcast Relay of pre-signed raw txs only (server never signs)

The server never sees private keys or holds funds. This is the same read/broadcast-relay shape the API uses for Solana today, applied to Snowside.


Chain, token, and Uniswap contract metadata. D1-backed (singleton row, updateable without a worker redeploy). This is the single source of truth — both ecashfarm.com/liquidity and 3rd-party front-ends consume it.

{
"ok": true,
"mode": "preview",
"chain": { "chainId": 0, "name": "Snowside", "rpcUrl": "" },
"tokens": {
"PECX": { "symbol": "pECX", "decimals": 8, "address": "" },
"USDC": { "symbol": "USDC", "decimals": 6, "address": "" },
"BTCB": { "symbol": "BTC.b", "decimals": 8, "address": "" }
},
"v2": { "factory": "", "router": "", "feeBps": 30 },
"v3": {
"factory": "", "router": "",
"nonfungiblePositionManager": "", "quoter": "",
"feeTiers": [
{ "fee": 500, "bps": 5, "label": "0.05%", "hint": "Stable pairs (USDC↔BTC.b)" },
{ "fee": 3000, "bps": 30, "label": "0.30%", "hint": "Moderate volatility (USDC↔pECX)" },
{ "fee": 10000,"bps": 100, "label": "1%", "hint": "Exotic / volatile pairs" }
]
},
"pairs": [
{ "id": "PECX-USDC", "a": "PECX", "b": "USDC", "label": "pECX / USDC" },
{ "id": "BTCB-PECX", "a": "BTCB", "b": "PECX", "label": "BTC.b / pECX" }
],
"contractsDeployed": false,
"updatedAt": 1717600000
}
  • pECX: 8 decimals (follows Bitcoin — 1 pECX = 10⁸ base units)
  • USDC: 6 decimals (Circle standard)
  • BTC.b: 8 decimals (Avalanche wrapped BTC)

Two pairs only — the platform focuses on pECX:

  • pECX / USDC — primary pair (trade pECX against the stablecoin)
  • BTC.b / pECX — BTC bridge pair (move BTC into/out of the pECX ecosystem)

Volatile-left convention (base / quote): price reads as “1 base = ? quote”.

  1. Fetch /config on load.
  2. If mode === 'preview', render the UI in preview mode (no real wallet reads needed — use the mocked stats/pools/quote endpoints).
  3. If mode === 'live', use the returned addresses + chainId to build Uniswap router calls client-side; the user signs in their browser wallet.

Cache-Control: public, max-age=60 — cache for up to 60s.


Network-wide aggregates across all pECX liquidity pools. Mocked (deterministic placeholders) while mode=preview; backed by real Snowside reads aggregated into D1 when mode=live. Responses carry mocked: true so integrators can detect placeholder data.

{
"ok": true,
"mode": "preview",
"mocked": true,
"network": {
"tvlUsd": 402000,
"volume24hUsd": 20700,
"volume7dUsd": 129700,
"fees24hUsd": 62.1,
"fees7dUsd": 389.1,
"aprPct": 5.05,
"liquidityProviders": 60,
"poolCount": 2,
"activePairs": ["PECX-USDC", "BTCB-PECX"]
},
"updatedAt": null
}

aprPct is the blended network APR annualized from fees7dUsd / tvlUsd.


Per-pair aggregates. Accepts both orderings — PECX-USDC and USDC-PECX resolve to the same pair (Uniswap orders token0/token1 by address on-chain; the id is a display convention only).

Name In Required Values
pair path yes PECX-USDC, BTCB-PECX (reverse orderings accepted)
{
"ok": true,
"mode": "preview",
"mocked": true,
"pair": "PECX-USDC",
"label": "pECX / USDC",
"version": "v2",
"feeBps": 30,
"price": 0.9,
"priceChange24hPct": 2.4,
"reserves": { "a": "50000.00000000", "b": "45000.000000" },
"reservesUsd": { "a": 45000, "b": 45000 },
"tvlUsd": 90000,
"volume24hUsd": 12500,
"volume7dUsd": 78400,
"fees24hUsd": 37.5,
"fees7dUsd": 235.2,
"aprPct": 13.6,
"liquidityProviders": 42,
"updatedAt": null
}
  • version: which Uniswap version the pool uses (v2 = Basic Provider, v3 = Advanced Provider).
  • reserves.a / reserves.b: raw reserves as decimal strings respecting token decimals (pECX 8dp, USDC 6dp, BTC.b 8dp). Parse as strings; do not assume integer base units.
  • price: quote per base (b per a), e.g. 0.9 USDC per pECX.
  • aprPct: annualized from fees7dUsd / tvlUsd.
  • 404 — unknown pair (lists available pairs).

Raw Uniswap pool fields for every pair — what an integrator needs to render positions, chart ticks, and compute swap math client-side. Mocked (deterministic placeholders) while mode=preview; backed by real Snowside reads when mode=live.

{
"ok": true,
"mode": "preview",
"mocked": true,
"pools": [
{
"pair": "PECX-USDC",
"label": "pECX / USDC",
"version": "v2",
"feeBps": 30,
"fee": 3000,
"token0": "PECX", "token1": "USDC",
"reserves": { "token0": "50000.00000000", "token1": "45000.000000" },
"lpTotalSupply": "47434.165012496",
"price": 0.9,
"kLast": "2250000000.000000000000000000"
},
{
"pair": "BTCB-PECX",
"label": "BTC.b / pECX",
"version": "v3",
"feeBps": 30,
"fee": 3000,
"tickSpacing": 60,
"token0": "BTCB", "token1": "PECX",
"slot0": {
"sqrtPriceX96": "79228162514264337593543950336",
"tick": 0,
"observationCardinality": 1,
"unlocked": true
},
"liquidity": "17333333333333",
"price": 86666.67,
"tickCurrent": 0
}
],
"count": 2,
"updatedAt": null
}
  • v2 pools expose reserves (token0/token1 as decimal strings respecting token decimals), lpTotalSupply (LP token total supply), kLast (reserve0 * reserve1). LP tokens are fungible ERC-20s.
  • v3 pools expose slot0 (sqrtPriceX96 as a Q64.96 big-int string, tick as an integer, plus the observation cardinals), liquidity (active in-range uint128 as a string), fee (tier), tickSpacing. Positions are ERC-721 NFTs.
  • token0/token1 are display symbols; on-chain Uniswap orders by raw address (whichever address is numerically smaller becomes token0). When live, the response will also carry token0Address/token1Address; map them via GET /v1/liquidity/config.

Single pool state — same fields as the matching entry in /pools, for one pair. Accepts both orderings (PECX-USDC and USDC-PECX resolve to the same pool).

Name In Required Values
pair path yes PECX-USDC, BTCB-PECX (reverse orderings accepted)
  • 404 — unknown pair (lists available pairs).

Expected swap output (like the Uniswap Quoter). Mocked (deterministic) in preview mode; when mode=live the v2 path relays the real getAmountOut computation and the v3 path relays the Snowside Quoter contract.

Name In Required Default Values / format
pair query yes — PECX-USDC, BTCB-PECX (reverse orderings accepted)
tokenIn query yes — PECX, USDC, BTCB (must be in the pair)
amountIn query yes — decimal string, e.g. 1000 or 0.1
slippageBps query no 50 (0.50%) integer basis points
{
"ok": true,
"mode": "preview",
"mocked": true,
"pair": "PECX-USDC",
"label": "pECX / USDC",
"version": "v2",
"tokenIn": "PECX",
"tokenOut": "USDC",
"amountIn": "1000",
"amountOut": "879.757633",
"minimumAmountOut": "875.358845",
"feeBps": 30,
"priceImpactPct": 1.9608,
"priceImpactModeled": true,
"slippageBps": 50,
"updatedAt": null
}
  • v2 uses the exact Uniswap v2 getAmountOut constant-product formula (fee on input). priceImpactPct excludes the protocol fee (Uniswap UI convention). priceImpactModeled: true.
  • v3 uses a linear quote at the current price in preview mode — the concentrated-liquidity tick walk is not modeled (no real tick structure). priceImpactPct: 0 and priceImpactModeled: false until live (then it relays the Snowside Quoter, which walks ticks for real impact).
  • amountOut / minimumAmountOut are decimal strings respecting the output token’s decimals (pECX 8dp, USDC 6dp, BTC.b 8dp).
  • minimumAmountOut = amountOut × (1 - slippageBps/10000).
  • This endpoint is not cached (Cache-Control: no-store) because quotes are trade-sized and time-sensitive.
  • 400 — missing pair/tokenIn/amountIn, tokenIn not in pair, or amountIn not a positive finite number.
  • 404 — unknown pair.

Relay a pre-signed raw EVM transaction to Snowside RPC via eth_sendRawTransaction. This is the only write endpoint in the liquidity API, and it is rule-5-safe: the server holds no keys, builds no calldata, and signs nothing. Calldata construction + signing stay 100% client-side (project decision). The server is a pure broadcast relay — same trust model as POST /v1/rpc, for the EVM/Snowside side.

In preview mode this endpoint returns 503 — broadcast is unavailable until Snowside RPC is configured. Detect the mode via GET /v1/liquidity/config first (mode: 'live' + a non-empty chain.rpcUrl).

{ "rawTx": "0x02f87201048459682f00850746a5288282520894..." }
Field Type Required Notes
rawTx string yes 0x-prefixed hex of the signed raw tx (built + signed client-side). Max 10,000 chars.
{
"ok": true,
"mode": "live",
"txHash": "0xabcdef1234567890...",
"method": "eth_sendRawTransaction"
}
  • 400 — bad rawTx (not a 0x hex string), or Snowside RPC rejected the transaction (insufficient funds, bad nonce, already-known, etc.). The upstream JSON-RPC error is forwarded in rpcError.
  • 405 — non-POST method.
  • 413 — rawTx exceeds 10,000 chars.
  • 429 — per-IP rate limit exceeded (same guard as /v1/rpc + intake).
  • 503 — preview mode (Snowside RPC not configured).
  • 502 — relay fetch to Snowside failed.

No further liquidity endpoints are planned — the surface is complete (config, stats, pools, quote, broadcast). The remaining work is operational: seed the D1 liquidity_config row with real Snowside Uniswap addresses (flipping mode from preview to live) once the Snowside engineers deploy the contracts.