Documentation

Build on Prism

Plug split routing into your wallet, bot or dApp. Quotes, live market data and ready-to-sign swap transactions over a keyless REST API on ROBINHOOD TESTNET.

Overview

Prism is a split-routing DEX deployed on ROBINHOOD TESTNET. Instead of routing your entire order through a single liquidity pool, Prism atomically fans the trade across multiple venues, finding the allocation that minimises slippage and maximises output in a single transaction.

The router enforces one minAmountOut floor across all legs simultaneously. If the total output falls short at execution time, the entire transaction reverts — you are never partially filled at a bad price.

⛡
Split routing

Orders are fanned across multiple constant-product pools. The API finds the allocation that minimises price impact.

🔑
Keyless API

No API key, no sign-up. CORS is open. Call it directly from a browser, a trading bot or any backend.

☕
Non-custodial

The server returns calldata only. Your wallet signs. Prism never touches keys or holds funds.

Network details

Prism runs on ROBINHOOD TESTNET — Coinbase’s EVM-compatible L2 testnet. Gas is paid in ETH.

NetworkROBINHOOD TESTNET
Chain ID46630
RPChttps://robinhood-testnet.drpc.org
Gas tokenETH
Explorerhttps://robinhood-testnet.drpc.org
ETH faucethttps://faucet.zalalena.com/base
ⓘ
Prism asks your wallet to add ROBINHOOD TESTNET automatically. You can also add it manually using the network details above.

Router API

All endpoints return JSON over HTTPS. Amounts in responses are integer strings in the token’s smallest unit — tUSD has 6 decimals, instruments have 18. No authentication is required.

GET /api/health

Returns the latest indexed block number and whether the on-chain market contracts are deployed and responding. Use this to verify the server is live before making trade calls.

// Response { "ok": true, "blockNumber": "63992259", "contracts": "deployed" }
GET /api/tokens

Every address you need in one call: the router contract, the tUSD cash token and each instrument with its decimals and associated pool addresses.

GET /api/markets

Every instrument with its liquidity-weighted price, total liquidity and per-venue reserves, read at the latest ROBINHOOD TESTNET block.

POST /api/quote

Plans a split route for an order and returns estimated output, price impact and the individual legs. Does not build a transaction.

symbol string Instrument ticker, e.g. tSPY
side string buy to pay tUSD  ·  sell to pay the instrument
amount string Decimal in the input token (e.g. "25000" for 25,000 tUSD)
// Request body { "symbol": "tSPY", "side": "buy", "amount": "25000" } // Response { "blockNumber": "63992259", "symbol": "tSPY", "side": "buy", "amountIn": "25000000000", "amountOut": "32350000000000000000", "priceImpact": "0.12", "legs": [ { "venue": "Deep", "pool": "0x...", "amountIn": "13000...", "amountOut": "..." }, { "venue": "Core", "pool": "0x...", "amountIn": "7750...", "amountOut": "..." } ] }
POST /api/swap

The full integration in one call: a split route plus a ready-to-sign transaction. Returns to (router address and calldata for swapSplit), approval (the token and amount to approve first) and minAmountOut, the floor the router enforces on-chain.

symbol string Instrument ticker
side string buy or sell
amount string Decimal in the input token
from address Sender wallet address (for calldata encoding)
slippageBps number Slippage tolerance in basis points (default 50)
deadline number Transaction deadline in seconds (default 600)
POST /api/faucet/claim

Mints 1,000,000 tUSD to the requesting wallet. Subject to a 24-hour cooldown per wallet address. The faucet contract enforces the cooldown on-chain.

address address Recipient wallet address
// Response { "txHash": "0x...", "amount": "1000000000000000000000000", "nextClaimAt": 1727654400 }

Contracts

Three Solidity contracts are deployed on ROBINHOOD TESTNET (chain 46630). All source code is compiled and deployed via Foundry.

PrismRouter
ROBINHOOD TESTNET
0x08C46606Df8bd37B43b5B5B224E829D7713feE61
View on Basescan ↗

Pulls the input once, fans it out across legs, and enforces one minimum on the total output. All legs fill or the transaction reverts.

Faucet
ROBINHOOD TESTNET
0x01E80eCc557bB6872cc6Cb8A30E65a81D0c6FC57
View on Basescan ↗

Public mint entrypoint with a 24-hour per-wallet cooldown enforced on-chain. Mints 1,000,000 tUSD per claim.

tUSD
ROBINHOOD TESTNET
0x1e3A65977FCe77c9F6dD82B994e75Cb2bCaBeD95
View on Basescan ↗

Minimal ERC-20 with 6 decimals used as the quote/settlement currency. All instruments are priced in tUSD.

ⓘ
These contracts are deployed to testnet only. tUSD tokens have no monetary value. Do not send mainnet funds to these addresses.

Examples

The examples below show how to call the API from a browser or Node.js application using the native Fetch API.

1. Get a quote

Call POST /api/quote to preview a split route before committing to a swap.

const res = await fetch('http://localhost:8080/api/quote', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: 'tSPY', side: 'buy', amount: '25000' }) }) const quote = await res.json() console.log(`Out: ${quote.amountOut} — impact: ${quote.priceImpact}%`) console.log('Legs:', quote.legs)
2. Execute a swap with viem

Call POST /api/swap to get a fully-encoded transaction, then submit it with your wallet library.

import { createWalletClient, custom, erc20Abi } from 'viem' const wallet = createWalletClient({ transport: custom(window.ethereum) }) const [account] = await wallet.getAddresses() // 1. get a ready-to-sign transaction from the router API const route = await fetch('http://localhost:8080/api/swap', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: 'tSPY', side: 'buy', amount: '25000', from: account, slippageBps: 50, deadline: 600 }) }).then(r => r.json()) // 2. approve the router once for the input token await wallet.writeContract({ abi: erc20Abi, address: route.approval.token, functionName: 'approve', args: [route.to.address, BigInt(route.approval.amount)] }) // 3. send the split swap — every leg fills in one tx, or none do await wallet.sendTransaction({ account, chain: null, to: route.to.address, data: route.to.calldata })
3. Claim tUSD from the faucet
const claim = await fetch('http://localhost:8080/api/faucet/claim', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: account }) }).then(r => r.json()) console.log('tx:', claim.txHash) console.log('Next claim:', new Date(claim.nextClaimAt * 1000).toLocaleString())