Trade on the Exchange
Interlude Exchange is an order book any program can trade on. A key of its own, one grant, a seat of demo balances, then orders that each answer in one round trip. Twenty lines.
Interlude Exchange is a spot order book, DEMO/USD, whose matching runs on an Interlude node. Anyone can trade on it, a program as well as a person: the house agents you see on the page are programs like this one, running in visitors’ browsers. Your agent makes a key of its own, signs one grant with it, joins for a seat and trades. No wallet, no gas, no sign-up.
import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { createInterludeClient } from "@interludelayer-sdk/sdk";
const app = "0x69b1Ff7d02fb9fc48FD0Abe39801D45D0984d5A6"; // the book
const node = "https://il2-eu-69b1ff7d02fb9fc4.fly.dev"; // its node
const monad = http("https://testnet-rpc.monad.xyz");
const abi = parseAbi([
"function join() returns (uint256)",
"function buy(uint256 quoteIn) returns (uint256)",
"function sell(uint256 baseIn) returns (uint256)",
]);
const book = createInterludeClient({ app, abi, node, base: createPublicClient({ transport: monad }) });
const wallet = createWalletClient({ account: privateKeyToAccount(generatePrivateKey()), transport: monad });
const session = await book.openSession({ wallet, scope: ["join", "buy", "sell"] });
await session.send("join"); // a new seat: 1,000 DEMO and 1,000 USD, demo balances
for (const side of ["buy", "sell", "buy", "sell"]) {
const { result, latencyMs } = await session.send(side, [10n]); // spend 10 USD, or sell 10 DEMO
console.log(side, String(result), Math.round(latencyMs), "ms");
}
process.exit(0); // the SDK keeps a connection to the node open
npm i @interludelayer-sdk/sdk viem
node agent.mjsEach line it prints is one market order: the side, what it got back, and the round trip from sending the order to holding its fill. Its fills show on the page’s tape as OTHER TRADER: only the sender can time its own order.
Which book
The snippet trades on the Paris book, 0x69b1Ff7d02fb9fc48FD0Abe39801D45D0984d5A6 on https://il2-eu-69b1ff7d02fb9fc4.fly.dev. The New York book, 0x181343e34cF598cf8EE4ae6a47c191730F4Bf83e on https://il2-ny-181343e34cf598cf.fly.dev, is a separate market with its own seats. The page opens the book nearest you, and its Plug your agent shows the same twenty lines for that book. A node serves one book: change both lines together.
What an agent can do
Name the functions it needs in the grant’s scope: the book refuses the rest, and the grant expires after an hour by default. The calls:
- join()
- Once per address: a seat of 1,000 DEMO and 1,000 USD, dealt from the book's house float. Demo balances, not tokens: nothing to withdraw or bridge. A second join is refused (AlreadySeated).
- buy(quoteIn) · sell(baseIn)
- Market orders. buy spends quoteIn USD up the asks, sell sells baseIn DEMO down the bids, at the resting prices, best first. There is no price limit, so size them to the book. An empty side refuses them (NoLiquidity).
- place(isBuy, priceE6, size)
- A limit order: it fills what it crosses at the resting prices, then rests the rest. The price is in millionths of a USD (1.0 is 1000000). Returns the order's id.
- replace(id, seq, priceE6, size)
- Moves one of your resting orders in one call. It counts as a new arrival at its new price.
- cancel(id, seq)
- Takes one of your orders off the book and frees what it locked.
- openOrders() · cashOf(who) · invOf(who) · midE6()
- Reads, free, from the node: every resting order with its id and seq, a seat's free USD and DEMO, the last trade's price.
The limits are the contract’s, the same for every seat. A seat rests at most 32 orders, and the book 128 (BookFull). On a full book a new order rests by evicting a worst quote: the other side’s while its own side holds under half the book, else its own side’s, which it has to beat. An order is worth at least 0.5 USD (DustOrder). One call fills at most 32 resting orders, and never your own: those it cancels. Ids are reused, so cancel and replace take the id and its seq, from openOrders() or the Placed event; a stale pair is refused (NotLive). Seats are dealt 240 at once, then one every 2 s (SeatRateLimited, with the seconds to wait).
Fair use
Every call lands in a batch the book commits to Monad every 2 s, and the commits are paid from one gas budget an hour that everybody on the book shares. The house agents in every open tab hold themselves to 12 calls a second together. The node refuses a signer past 100 transactions a second (-32005) and a caller past 6,000 calls in 10 s (HTTP 429). An agent that sends a few calls a second trades all day; one that floods the book spends the hour’s budget, and the book halts for everybody until the hour frees it (limits).
Trust
The node is Interlude’s and answers each order in one round trip, but it cannot keep the state: every batch lands on Monad with its signed transactions, anyone can replay it, and a wrong one can be challenged by the session’s bench, whose three seats are all Interlude’s in v1 (what is live).
More agents, longer
The SDK repo’s examples/agent-tap.mjs is the same program for several agents and a set time: each joins, trades market orders and the run ends with how many filled and their round trips. It trades on the Paris book by default, two agents for a minute; INTERLUDE_TAP and INTERLUDE_NODE name another.
git clone https://github.com/Veenoway/interlude-sdk
cd interlude-sdk/sdk && npm i && npm run build
AGENT_COUNT=2 AGENT_SECONDS=20 node examples/agent-tap.mjs