13 · Trade with your AI agent
Trade with your AI agent
Everything the website does, your own AI agent can do by chatting with it. Paste a prompt, say what you want, and the agent reads the venue, shows you what it will do, and signs only with your say-so.
What an agent needs#
| Thing | How it works |
|---|---|
| Your wallet | Your wallet signs every act. The key stays in your own environment, never in the chat. |
| A venue key | None. The agent never holds a venue key and there is none to give it. |
| Gas | The venue submits your signed act and pays the gas. Your wallet needs no native coin. |
| Money | USDC on your own HyperCore testnet account (Perps balance). One signed transfer moves it to the venue; the venue credits your ledger cash within a minute or two. |
| Base URL | https://protect.temporal.exchange/api/venue |
There are two kinds of call. A read needs nothing: it is a plain web request. An act is authorised by a signature from your wallet over a ledger call (an intent): the venue checks the signature, submits the transaction and pays for it. If an act cannot be done, the venue answers with a named reason and nothing moves.
The reads#
Public, no key, no sign-in. Replace the wallet with your own address.
| Route | What it answers |
|---|---|
GET /health | Is the venue up, and is it testnet. |
GET /chain/health | Chain id, ledger address, assets, fees, freshness of prices. |
GET /chain/quote | The price the front quotes for a size, with the fee. |
GET /chain/state | Your free cash and every account, leg and perp. |
GET /chain/fills | Your own fills, newest first. |
GET /chain/deposits | Where to send USDC, and what has arrived. |
GET /chain/withdrawals | Your withdrawals and the limits. |
GET /chain/nonce | The next number your signed request must carry. |
GET /chain/rpc | A read-only chain call (a receipt, a block number). |
GET /hypercore/balance | Your HyperCore testnet balance. |
POST /perp/plan | The protection structure for a floor. Reads the book, changes nothing. |
POST /chain/dryrun | What an act would do, before you sign. Nothing moves. |
POST /chain/snapshot | A fresh signed price for the act you are about to send. |
POST /earn/plan | Preview a maker's curve. Reads the book, sends nothing. |
curl -s https://protect.temporal.exchange/api/venue/health{"ok":true,"ready":true,"phase":"testnet","seq":2155967,"wallets":210, ...}curl -s https://protect.temporal.exchange/api/venue/chain/health{"ok":true,"chainId":99801,"ledger":"0x5dc52db2…51cc","intentRelay":true,
"pricedAssets":["BTC","HYPE"],"assetIds":{"BTC":0,"HYPE":1,"SPX":2},
"fees":{...},"front":{...},"venueVersion":"elysium-testnet-21", ...}curl -s "https://protect.temporal.exchange/api/venue/chain/state?wallet=0xYOUR_WALLET"{"ok":true,"wallet":"0x…","connected":false,"cashUSD":0,"accounts":{},
"perpMark":{"BTC":79892.5,"HYPE":76.2105}, ...}Once you have accounts, accounts holds one entry per account, keyed T1 (OPTIONS), P1 (PROTECT) or E1 (EARN). Each carries its ledger id, kind, depositUSD, heldUSD, legs[] (each with legIndex, wing, strikeUSD, qty), perps[] and a margin block with equity and maintenance. You see yourself only: no other trader or maker appears anywhere.
curl -s "https://protect.temporal.exchange/api/venue/chain/nonce?wallet=0xYOUR_WALLET"{"ok":true,"source":"elysium-testnet-1","nonce":2}The act list#
Each act below has its own section, with the command beside the explanation. All of them are signed by your wallet; none needs a venue key.
| Act | What it does | Where |
|---|---|---|
| Fund | Move USDC from your HyperCore account to the venue | Wallet & accounts |
| Open an account, deposit | OPTIONS, PROTECT or EARN account; put cash behind it | Wallet & accounts |
| Read a price | The front's price and fee for a size | Pricing |
| Buy or sell an option | One option at the front | How it works |
| PROTECT | A perp with its floor, in one signed request | Wallet & accounts |
| Close a leg, CLOSE ACCOUNT | Leave a position at the front | Leaving a position |
| Withdraw | Account to free cash to your HyperCore wallet | Fees & liquidation |
| Make a market (LP) | Start AUTO, TLP or CUSTOM quoting; post your own curve | Earn (making) |
| Check your own numbers | Re-derive fees, fills and equity from public reads | Verify it yourself |
The toolkit#
One small file does the signing for every act. Save it as temporal.mjs beside the others, run npm i ethers, and set WALLET_KEY in your own shell. It builds the ledger calls exactly as the website does and signs the intent with the wallet; the typed data it signs is the one the website signs, field for field. An act is valid for 10 minutes after you sign it.
// temporal.mjs: the whole toolkit an agent needs to act on the Temporal TESTNET venue.
// Needs Node 22+ and `npm i ethers`. The key stays in YOUR environment (WALLET_KEY); the venue never sees it.
import { Wallet, Interface, keccak256 } from "ethers";
export const BASE = process.env.TEMPORAL_BASE ?? "https://protect.temporal.exchange/api/venue";
export const wallet = new Wallet(process.env.WALLET_KEY);
const json = (r) => r.json();
export const get = (path, headers = {}) => fetch(BASE + path, { headers }).then(json);
export const post = (path, body, headers = {}) =>
fetch(BASE + path, { method: "POST", headers: { "content-type": "application/json", ...headers }, body: JSON.stringify(body) }).then(json);
// The ledger calls, exactly as the website builds them.
export const ledger = new Interface([
"function connect()",
"function mintAccount(uint8 kind)",
"function deposit(uint256 account, uint256 usd)",
"function withdraw(uint256 account, uint256 usd)",
"function openLegAtFront(uint256 account, (uint8 asset, uint8 side, uint8 wing, uint256 strikeK, uint256 decay) spec, uint256 qty, uint256 consent)",
"function closeLegAtFront(uint256 account, uint256 legIndex, uint256 qty)",
"function closeAccountAtFront(uint256 account)",
"function openPerpWithLegs(uint256 account, uint8 asset, uint8 side, uint256 qty, uint8 leverage, uint256 margin, (uint8 wing, uint8 side, uint256 strikeK, uint256 qty, uint256 decay, uint256 bound, uint256 consent)[] legs)",
"function requestClosePerp(uint256 account, uint256 perpId)",
]);
export const call = (name, ...args) => ledger.encodeFunctionData(name, args);
// Units: dollars have 6 decimals, coins and strikes 18. `up` rounds a dollar amount UP (a consent never authorises less than asked).
export const KIND = { trade: 0, protect: 1, earn: 3 };
export const ASSET = { BTC: 0, HYPE: 1 };
export const usd = (x, up = false) => BigInt(up ? Math.ceil(x * 1e6 - 1e-6) : Math.round(x * 1e6));
export const coin = (x) => BigInt(Math.round(x * 1e6)) * 10n ** 12n;
export const strike = (dollars) => BigInt(Math.round(dollars * 100)) * 10n ** 16n;
// A decay is signed as its rate per year (12 / months) in 18 decimals. A whole month is exact.
export const decay = (months) =>
Number.isInteger(months) ? (12n * 10n ** 18n) / BigInt(months) : BigInt(Math.round((12 / months) * 1e6)) * 10n ** 12n;
// Ask the venue what the act would do. Nothing is signed or sent.
export const check = (data) => post("/chain/dryrun", { user: wallet.address, call: data, extraCashUSD: 0 });
// Sign ONE intent for a ledger call and hand it to the venue, which submits it and pays the gas.
export async function act(data) {
const health = await get("/chain/health");
const { nonce } = await get(`/chain/nonce?wallet=${wallet.address}`);
const deadline = Math.floor(Date.now() / 1000) + 600;
const domain = { name: "VenueLedger", version: "1", chainId: health.chainId, verifyingContract: health.ledger };
const types = {
VenueIntent: [
{ name: "user", type: "address" },
{ name: "callHash", type: "bytes32" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
};
const message = { user: wallet.address, callHash: keccak256(data), nonce: String(nonce), deadline };
const sig = await wallet.signTypedData(domain, types, message);
// Acts that read a price carry a fresh signed price snapshot (it lives 5 seconds, so fetch it right before sending).
const snap = await post("/chain/snapshot", { call: data, wallet: wallet.address });
return post("/chain/intent", { user: wallet.address, call: data, nonce: String(nonce), deadline, sig, ...(snap.ok ? { snaps: snap.snaps } : {}) });
}
// Poll a read until it says what you expect (the index trails the chain by a few seconds).
export async function until(read, ok, seconds = 90) {
for (let t = 0; t < seconds; t += 3) {
const v = await read();
if (ok(v)) return v;
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timed out waiting for the venue to show the change");
}Every act first asks the venue for a dry run (POST /chain/dryrun), which prices the exact call on a fresh snapshot and says what it would do. Nothing is signed or moved. Only then does the script ask you to run it again with CONFIRM=yes.
The ready prompt#
Paste this to Claude, ChatGPT or any agent that can run code. Then say what you want in your own words.
You are my trading assistant for the Temporal perp-options venue, TESTNET only. Read https://protect.temporal.exchange/docs/agents first, then the section that matches what I ask (https://protect.temporal.exchange/docs/wallet-and-accounts, /docs/how-it-works, /docs/settlement, /docs/earn, /docs/fees). A machine-readable index is at https://protect.temporal.exchange/llms.txt. Rules: 1. Base URL: https://protect.temporal.exchange/api/venue. It is testnet; say so in every summary. There is no mainnet URL yet. 2. My wallet signs every act. Never ask me to paste a private key into this chat. Use the WALLET_KEY environment variable on my own machine, and the files temporal.mjs, fund.mjs, setup.mjs, open_option.mjs, protect.mjs, close.mjs, withdraw.mjs, lp.mjs from the docs. 3. Before ANY act: read the venue (GET /chain/state, GET /chain/quote), run the dry run (POST /chain/dryrun), and tell me in plain English what will happen, what it costs (premium, fee, margin) and the worst case. Wait for my yes. Only then send with CONFIRM=yes. 4. If the venue refuses, quote its reason to me word for word. Do not retry with different numbers unless I ask. 5. Keep a running list of what you did: act, size, price, fee, transaction hash, and the account's balance before and after. 6. Never use any route that is not listed in the docs. Never use an admin or oracle route. Start by checking the venue is up, then show me my cash and accounts.
When the venue says no#
A refusal is a named reason, never a silent failure, and a refused act changes nothing.
{"ok":false,"code":"intent_reverted","errorName":"NoSuchAccount","reason":"No such account on this wallet.","dry":true}The common ones: no maker stands at that size or strike (NoMakerStands), the account needs more margin (BelowRequirement), the consent is below what the act needs (ConsentShort), prices are frozen for that asset, or a test session is pausing new trades (the /health reply says when it ends).
Then check the numbers#
An agent that trades can also audit. Verify it yourself lays out the testnet testing protocol as checks you can run from the public reads: fees, fills, equity and the money trail, with the number each should show and how to change the size, strike or asset.
Kept in lockstep with the code: a check fails if this page drifts.