Skip to content

Buy or sell from your wallet

Example

This is an example. Every value in it (names, amounts, addresses) is there to show you how; change any of them to suit you. It’s swap.mjs from developers/examples, as it is. Anything that sends waits for SEND=1: there is no testnet, so a sent transaction spends real ETH.

swap.mjs
// Buy or sell a coin from your own wallet. The API finds the best route and simulates the exact transaction; your
// key signs it here and never leaves this process. Without SEND=1 it only builds and prints.
// PRIVATE_KEY=0x… COIN=0x… SIDE=buy AMOUNT=0.001 SEND=1 node swap.mjs
import { JsonRpcProvider, Wallet } from 'ethers';
const API = process.env.UPRALLY_API ?? 'https://uprally.co/api/v1';
const chain = await (await fetch(`${API}/chain`)).json(); // the network and its node: never hard-coded
const wallet = new Wallet(process.env.PRIVATE_KEY, new JsonRpcProvider(chain.rpc, chain.chainId));
async function post(path, body) {
const res = await fetch(`${API}${path}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
const json = await res.json();
if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message} ${json.error.fix ?? ''}`);
return json;
}
async function send(tx) {
const sent = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: tx.gas ? BigInt(tx.gas) : undefined, chainId: tx.chainId });
const receipt = await sent.wait();
if (receipt.status !== 1) throw new Error(`reverted: ${chain.explorer}/tx/${sent.hash}`);
return sent.hash;
}
const order = { wallet: wallet.address, token: process.env.COIN, side: process.env.SIDE ?? 'buy', amount: process.env.AMOUNT ?? '0.001', slippageBps: 100 };
let built = await post('/swap', order);
console.log(`${built.amountIn.amount} ${built.amountIn.symbol} → ${built.amountOut.amount} ${built.amountOut.symbol} (at least ${built.minOut.amount})`);
if (process.env.SEND !== '1') {
console.log('Built, not sent (set SEND=1 to send).', built.requires.length ? `First: ${built.requires.map((r) => r.step).join(', ')}.` : '');
console.log('RESULT built');
process.exit(0);
}
// A sale's first time: the approvals, in order, each confirmed. Then built again: the swap is simulated once they are in place.
if (built.requires.length) {
for (const step of built.requires) console.log(step.step, await send(step.tx));
built = await post('/swap', order);
}
const hash = await send(built.tx);
console.log(`done: ${chain.explorer}/tx/${hash}`);
console.log(`RESULT ${hash}`);