Skip to content

Your first swap

A swap is two calls: GET /quote to see what a trade returns, POST /swap to get the transaction for your wallet. You sign and send it.

Terminal window
curl "https://uprally.co/api/v1/quote?token=0x94641b97010608c3827fb058074889f19868ff33&side=buy&amount=0.001"
  • side: buy spends ETH for the coin, sell spends the coin for ETH.
  • amount: whole units as a string: ETH for a buy ("0.001"), coins for a sale. Never wei.
  • wallet (optional): quote for that wallet exactly. A coin with a launch-time snipe tax charges by wallet.

The answer says what you get after every fee and tax (amountOut), the least the transaction will accept (minOut, 1% under by default; set slippageBps), the route it won (venue), how many routes it compared, the price impact, and for a buy, what selling it straight back would return (sellBack). Every figure comes from simulating the exact transaction against the chain as it is now.

Terminal window
curl -X POST https://uprally.co/api/v1/swap \
-H 'content-type: application/json' \
-d '{"wallet":"0xYourWallet","token":"0x94641b97010608c3827fb058074889f19868ff33","side":"buy","amount":"0.001"}'

The same fields, plus wallet. The answer is the quote, plus:

  • tx: the unsigned transaction (chainId 4663, from, to, data, value in wei, gas). Send it exactly as it is.
  • requires: anything to send first, in order. Empty for a buy. A first sale of a coin through a Uniswap pool needs two approvals (the coin to Permit2, then Permit2 to the router); through a launchpad curve, one. See Approvals.
  • expiresAt: a router swap reverts after this (10 minutes). Build again rather than sending an old one.

The build checks your real balances: INSUFFICIENT_FUNDS (ETH) or INSUFFICIENT_BALANCE (the coin) when you don’t have enough.

import { JsonRpcProvider, Wallet } from 'ethers';
const chain = await (await fetch('https://uprally.co/api/v1/chain')).json();
const wallet = new Wallet(process.env.PRIVATE_KEY, new JsonRpcProvider(chain.rpc, chain.chainId));
const res = await fetch('https://uprally.co/api/v1/swap', {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ wallet: wallet.address, token: '0x94641b97010608c3827fb058074889f19868ff33', side: 'buy', amount: '0.001' }),
});
const built = await res.json();
if (!res.ok) throw new Error(`${built.error.code}: ${built.error.message}`);
for (const step of built.requires) await (await wallet.sendTransaction(step.tx)).wait();
const sent = await wallet.sendTransaction({ ...built.tx, value: BigInt(built.tx.value), gasLimit: BigInt(built.tx.gas) });
console.log(`${chain.explorer}/tx/${sent.hash}`);

The whole file, with a sale and the approvals handled: swap.mjs. GET /tx/{hash} says when it confirmed.

Every error is { "error": { "code", "message", "fix" } }; act on code. The ones a swap meets most:

CodeMeans
NO_ROUTENo pool or curve can make the trade right now. A coin seconds old may have no pool yet.
HONEYPOTSelling it straight after buying fails through every route, in simulation.
PRICE_IMPACT_TOO_HIGHThe trade moves the price more than 50%; trade less, or send maxPriceImpactPct.
SIMULATION_FAILEDThe price moved between the quote and the check; build again.

Every error.