suprafx-agent-sdk 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +452 -0
- package/dist/bin/suprafx-mcp.d.ts +15 -0
- package/dist/bin/suprafx-mcp.js +238 -0
- package/dist/bin/suprafx-mcp.js.map +1 -0
- package/dist/src/asset-registry.d.ts +61 -0
- package/dist/src/asset-registry.js +118 -0
- package/dist/src/asset-registry.js.map +1 -0
- package/dist/src/client.d.ts +227 -0
- package/dist/src/client.js +282 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/derive-ids.d.ts +112 -0
- package/dist/src/derive-ids.js +361 -0
- package/dist/src/derive-ids.js.map +1 -0
- package/dist/src/event-bcs.d.ts +341 -0
- package/dist/src/event-bcs.js +767 -0
- package/dist/src/event-bcs.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/config.d.ts +32 -0
- package/dist/src/mcp/config.js +101 -0
- package/dist/src/mcp/config.js.map +1 -0
- package/dist/src/mcp/lifecycle.d.ts +109 -0
- package/dist/src/mcp/lifecycle.js +170 -0
- package/dist/src/mcp/lifecycle.js.map +1 -0
- package/dist/src/mcp/preflight.d.ts +36 -0
- package/dist/src/mcp/preflight.js +291 -0
- package/dist/src/mcp/preflight.js.map +1 -0
- package/dist/src/mcp/server.d.ts +20 -0
- package/dist/src/mcp/server.js +235 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +51 -0
- package/dist/src/mcp/tools.js +1022 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/sign-event.d.ts +185 -0
- package/dist/src/sign-event.js +331 -0
- package/dist/src/sign-event.js.map +1 -0
- package/dist/src/signer.d.ts +89 -0
- package/dist/src/signer.js +226 -0
- package/dist/src/signer.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `suprafx-mcp` CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Two modes:
|
|
6
|
+
* - `suprafx-mcp init` — interactive setup wizard. Writes
|
|
7
|
+
* `~/.suprafx/config.json` with the user's delegate priv key
|
|
8
|
+
* after they paste it in or point to a JSON file the dApp
|
|
9
|
+
* downloaded.
|
|
10
|
+
* - `suprafx-mcp` (no args) — runs the MCP server over stdio.
|
|
11
|
+
* Designed to be invoked by Claude Desktop / Cursor / Continue
|
|
12
|
+
* as a subprocess. Reads stdin for JSON-RPC, writes stdout for
|
|
13
|
+
* responses, stderr for log lines.
|
|
14
|
+
*/
|
|
15
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync, chmodSync, renameSync } from "node:fs";
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { createInterface } from "node:readline";
|
|
19
|
+
import { runMCPServer } from "../src/mcp/server.js";
|
|
20
|
+
import { loadConfig, resolveMode, resolveToolGroups } from "../src/mcp/config.js";
|
|
21
|
+
/** Read the real version from the installed package.json.
|
|
22
|
+
* A hard-coded string silently goes stale and then LIES about which
|
|
23
|
+
* build is running — exactly the thing `--version` exists to answer. */
|
|
24
|
+
function packageVersion() {
|
|
25
|
+
try {
|
|
26
|
+
const here = new URL("../package.json", import.meta.url);
|
|
27
|
+
const pkg = JSON.parse(readFileSync(here, "utf-8"));
|
|
28
|
+
if (pkg.version)
|
|
29
|
+
return pkg.version;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* fall through */
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const here = new URL("../../package.json", import.meta.url);
|
|
36
|
+
const pkg = JSON.parse(readFileSync(here, "utf-8"));
|
|
37
|
+
if (pkg.version)
|
|
38
|
+
return pkg.version;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
/* fall through */
|
|
42
|
+
}
|
|
43
|
+
return "unknown";
|
|
44
|
+
}
|
|
45
|
+
async function main() {
|
|
46
|
+
const cmd = process.argv[2];
|
|
47
|
+
if (cmd === "init") {
|
|
48
|
+
await initWizard();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (cmd === "--help" || cmd === "-h" || cmd === "help") {
|
|
52
|
+
printHelp();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
56
|
+
console.log(`suprafx-agent-sdk ${packageVersion()}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const cfg = loadConfig();
|
|
60
|
+
const mode = resolveMode();
|
|
61
|
+
const groups = resolveToolGroups();
|
|
62
|
+
if (!cfg.delegatePrivKeyHex) {
|
|
63
|
+
process.stderr.write("[suprafx-mcp] no delegate key configured. Running in READ-ONLY mode.\n" +
|
|
64
|
+
"[suprafx-mcp] To enable trading tools, run: `suprafx-mcp init`\n");
|
|
65
|
+
}
|
|
66
|
+
else if (mode === "autonomous") {
|
|
67
|
+
process.stderr.write("[suprafx-mcp] AUTONOMOUS mode: money tools will NOT ask for per-call\n" +
|
|
68
|
+
"[suprafx-mcp] acknowledgement. Every write is real money.\n");
|
|
69
|
+
}
|
|
70
|
+
if (!cfg.masterAddress) {
|
|
71
|
+
process.stderr.write("[suprafx-mcp] no master address set — balance, lock and open-order reads\n" +
|
|
72
|
+
"[suprafx-mcp] need it. Set SUPRAFX_MASTER_ADDRESS or re-run `suprafx-mcp init`.\n");
|
|
73
|
+
}
|
|
74
|
+
await runMCPServer({
|
|
75
|
+
baseUrl: cfg.baseUrl,
|
|
76
|
+
delegatePrivKeyHex: cfg.delegatePrivKeyHex,
|
|
77
|
+
masterAddress: cfg.masterAddress,
|
|
78
|
+
mode,
|
|
79
|
+
groups,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function printHelp() {
|
|
83
|
+
console.log(`
|
|
84
|
+
suprafx-mcp — Model Context Protocol server for SupraFX
|
|
85
|
+
|
|
86
|
+
Usage:
|
|
87
|
+
suprafx-mcp Run the MCP server over stdio (default for Claude Desktop)
|
|
88
|
+
suprafx-mcp init Interactive setup wizard — writes ~/.suprafx/config.json
|
|
89
|
+
suprafx-mcp --help Show this help
|
|
90
|
+
suprafx-mcp --version Print the installed package version
|
|
91
|
+
|
|
92
|
+
Flags:
|
|
93
|
+
--tools=read Expose ONLY read tools, even with a key loaded
|
|
94
|
+
(a keyed monitor agent that cannot trade).
|
|
95
|
+
Also: --tools=read,cancel (cancel-only)
|
|
96
|
+
--tools=read,trade (no cancel class)
|
|
97
|
+
Default: every class the key entitles you to.
|
|
98
|
+
--allow-dangerous AUTONOMOUS mode: money tools stop requiring a
|
|
99
|
+
per-call 'acknowledged:true'. Without this the
|
|
100
|
+
server is GUARDED — every write asks once.
|
|
101
|
+
|
|
102
|
+
Environment overrides:
|
|
103
|
+
SUPRAFX_DELEGATE_PRIV_HEX Hex of delegate ed25519 private key (32 bytes)
|
|
104
|
+
SUPRAFX_MASTER_ADDRESS Your MASTER StarKey address — balances, locks and
|
|
105
|
+
open orders all live there, not on the delegate
|
|
106
|
+
SUPRAFX_BASE_URL Override the dApp base URL (default https://suprafx.ai)
|
|
107
|
+
SUPRAFX_ALLOW_DANGEROUS=1 Same as --allow-dangerous
|
|
108
|
+
SUPRAFX_TOOLS=read,cancel Same as --tools=
|
|
109
|
+
|
|
110
|
+
One-line install (Claude Code):
|
|
111
|
+
|
|
112
|
+
npm install -g suprafx-agent-sdk
|
|
113
|
+
claude mcp add --scope user suprafx -- suprafx-mcp
|
|
114
|
+
|
|
115
|
+
Configure Claude Desktop by adding this to your claude_desktop_config.json:
|
|
116
|
+
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"suprafx": {
|
|
120
|
+
"command": "suprafx-mcp"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Then restart Claude Desktop. Tools will appear in the model's tool palette.
|
|
126
|
+
|
|
127
|
+
Documentation: https://github.com/jtobkin/suprafx-agent-sdk
|
|
128
|
+
`);
|
|
129
|
+
}
|
|
130
|
+
async function initWizard() {
|
|
131
|
+
console.log("\nSupraFX MCP setup wizard\n========================\n");
|
|
132
|
+
console.log("Before you start, you need a delegate keypair authorized");
|
|
133
|
+
console.log("on chain by your master StarKey wallet.");
|
|
134
|
+
console.log("");
|
|
135
|
+
console.log("If you haven't done that yet:");
|
|
136
|
+
console.log(" 1. Go to https://suprafx.ai");
|
|
137
|
+
console.log(" 2. Connect StarKey, open Profile → Delegates");
|
|
138
|
+
console.log(" 3. Click 'Create Delegate'");
|
|
139
|
+
console.log(" 4. Click 'Generate' — a JSON file downloads to your machine.");
|
|
140
|
+
console.log(" KEEP THIS FILE SAFE. The private key inside controls trading.");
|
|
141
|
+
console.log(" 5. Set per-asset caps, sign the policy with StarKey.");
|
|
142
|
+
console.log("");
|
|
143
|
+
console.log("Now paste the 32-byte hex private key (or a path to the");
|
|
144
|
+
console.log("downloaded JSON file). Press enter when done.");
|
|
145
|
+
console.log("");
|
|
146
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
147
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
148
|
+
const input = await ask("Delegate private key (hex or path to JSON): ");
|
|
149
|
+
let privHex;
|
|
150
|
+
if (input.startsWith("/") || input.startsWith("~") || input.startsWith("./")) {
|
|
151
|
+
const path = input.startsWith("~") ? join(homedir(), input.slice(1)) : input;
|
|
152
|
+
if (!existsSync(path)) {
|
|
153
|
+
throw new Error(`File not found: ${path}`);
|
|
154
|
+
}
|
|
155
|
+
const j = JSON.parse(readFileSync(path, "utf-8"));
|
|
156
|
+
const key = j.delegatePrivKeyHex ?? j.privateKeyHex ?? j.privateKey ?? j.priv;
|
|
157
|
+
if (!key) {
|
|
158
|
+
throw new Error(`JSON at ${path} did not contain a recognized private-key field`);
|
|
159
|
+
}
|
|
160
|
+
privHex = String(key);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
privHex = input;
|
|
164
|
+
}
|
|
165
|
+
privHex = privHex.replace(/^0x/i, "").toLowerCase();
|
|
166
|
+
if (!/^[0-9a-f]{64}$/.test(privHex)) {
|
|
167
|
+
throw new Error(`Expected a 32-byte hex private key (64 hex chars). Got ${privHex.length} chars.`);
|
|
168
|
+
}
|
|
169
|
+
console.log("");
|
|
170
|
+
console.log("Now your MASTER StarKey address — the wallet you connected to");
|
|
171
|
+
console.log("suprafx.ai with, that holds the funds. Your agent needs it to read");
|
|
172
|
+
console.log("balances and locks; the delegate has no balances of its own.");
|
|
173
|
+
console.log("Saving it here means the agent never has to be told it again.");
|
|
174
|
+
console.log("");
|
|
175
|
+
let masterAddress = await ask("Master StarKey address (0x…, or enter to skip): ");
|
|
176
|
+
masterAddress = masterAddress.trim().toLowerCase();
|
|
177
|
+
if (masterAddress.length > 0) {
|
|
178
|
+
const m = masterAddress.startsWith("0x") ? masterAddress.slice(2) : masterAddress;
|
|
179
|
+
if (!/^[0-9a-f]{64}$/.test(m)) {
|
|
180
|
+
rl.close();
|
|
181
|
+
throw new Error(`Expected a 32-byte hex address (64 hex chars, 0x-prefixed). Got ${m.length} chars.`);
|
|
182
|
+
}
|
|
183
|
+
masterAddress = "0x" + m;
|
|
184
|
+
}
|
|
185
|
+
const baseUrl = await ask("SupraFX base URL (press enter for https://suprafx.ai): ");
|
|
186
|
+
rl.close();
|
|
187
|
+
const cfg = { delegatePrivKeyHex: privHex };
|
|
188
|
+
if (masterAddress.length > 0)
|
|
189
|
+
cfg.masterAddress = masterAddress;
|
|
190
|
+
if (baseUrl.length > 0)
|
|
191
|
+
cfg.baseUrl = baseUrl;
|
|
192
|
+
const cfgDir = join(homedir(), ".suprafx");
|
|
193
|
+
mkdirSync(cfgDir, { recursive: true });
|
|
194
|
+
const cfgPath = join(cfgDir, "config.json");
|
|
195
|
+
// Atomic write (temp + rename): a running suprafx-mcp hot-reloads this
|
|
196
|
+
// file, so a truncate-then-write could be read mid-rotation as a partial
|
|
197
|
+
// (invalid JSON) and flip the server to read-only. Write to a temp file
|
|
198
|
+
// with 0600 first, then rename into place (atomic on the same filesystem).
|
|
199
|
+
const tmpPath = `${cfgPath}.tmp`;
|
|
200
|
+
writeFileSync(tmpPath, JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
201
|
+
chmodSync(tmpPath, 0o600);
|
|
202
|
+
renameSync(tmpPath, cfgPath);
|
|
203
|
+
console.log(`\n✓ Saved to ${cfgPath} (mode 600 — owner read/write only)`);
|
|
204
|
+
console.log("");
|
|
205
|
+
if (!cfg.masterAddress) {
|
|
206
|
+
console.log("⚠ No master address saved. Balance and open-order reads will need");
|
|
207
|
+
console.log(" one passed by hand every session. Re-run `suprafx-mcp init` to add it.");
|
|
208
|
+
console.log("");
|
|
209
|
+
}
|
|
210
|
+
console.log("Next — Claude Code, one line:");
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log(" claude mcp add --scope user suprafx -- suprafx-mcp");
|
|
213
|
+
console.log("");
|
|
214
|
+
console.log("Or add this to your Claude Desktop config:");
|
|
215
|
+
console.log("");
|
|
216
|
+
console.log(" ~/Library/Application Support/Claude/claude_desktop_config.json");
|
|
217
|
+
console.log("");
|
|
218
|
+
console.log(` {
|
|
219
|
+
"mcpServers": {
|
|
220
|
+
"suprafx": {
|
|
221
|
+
"command": "suprafx-mcp"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}`);
|
|
225
|
+
console.log("");
|
|
226
|
+
console.log("Restart / reconnect. SupraFX tools will appear in the tool palette —");
|
|
227
|
+
console.log("the key is read at STARTUP, so a running server will not see it until then.");
|
|
228
|
+
console.log("");
|
|
229
|
+
console.log("The server starts GUARDED: every money tool asks for an explicit");
|
|
230
|
+
console.log("acknowledgement per call. For an unattended loop, launch it with");
|
|
231
|
+
console.log("--allow-dangerous. For a monitor that must never trade: --tools=read.");
|
|
232
|
+
console.log("");
|
|
233
|
+
}
|
|
234
|
+
main().catch((e) => {
|
|
235
|
+
process.stderr.write(`[suprafx-mcp] fatal: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
});
|
|
238
|
+
//# sourceMappingURL=suprafx-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suprafx-mcp.js","sourceRoot":"","sources":["../../bin/suprafx-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAElF;;yEAEyE;AACzE,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAyB,CAAC;QAC5E,IAAI,GAAG,CAAC,OAAO;YAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAyB,CAAC;QAC5E,IAAI,GAAG,CAAC,OAAO;YAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,MAAM,UAAU,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACvD,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,qBAAqB,cAAc,EAAE,EAAE,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wEAAwE;YACtE,kEAAkE,CACrE,CAAC;IACJ,CAAC;SAAM,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wEAAwE;YACtE,6DAA6D,CAChE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4EAA4E;YAC1E,mFAAmF,CACtF,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,CAAC;QACjB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;QAC1C,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,IAAI;QACJ,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6Cb,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU;IACvB,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CACxB,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAE7E,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,8CAA8C,CAAC,CAAC;IACxE,IAAI,OAAe,CAAC;IACpB,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAClD,MAAM,GAAG,GACP,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC;QACpE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,iDAAiD,CACjE,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,KAAK,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,0DAA0D,OAAO,CAAC,MAAM,SAAS,CAClF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IAC5E,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,aAAa,GAAG,MAAM,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAClF,aAAa,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QAClF,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,mEAAmE,CAAC,CAAC,MAAM,SAAS,CACrF,CAAC;QACJ,CAAC;QACD,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,GAAG,CACvB,yDAAyD,CAC1D,CAAC;IACF,EAAE,CAAC,KAAK,EAAE,CAAC;IAEX,MAAM,GAAG,GAIL,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;IACpC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,aAAa,GAAG,aAAa,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IAE9C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;IAC3C,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC5C,uEAAuE;IACvE,yEAAyE;IACzE,wEAAwE;IACxE,2EAA2E;IAC3E,MAAM,OAAO,GAAG,GAAG,OAAO,MAAM,CAAC;IACjC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1B,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE7B,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,qCAAqC,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;IAMV,CAAC,CAAC;IACJ,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;IACpF,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;IAC3F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wBAAwB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CACvE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BFT `Amount` encoding math.
|
|
3
|
+
*
|
|
4
|
+
* The council-rust protocol denominates token amounts in `Amount`
|
|
5
|
+
* (u128) using **native per-asset decimals** — an asset with `D`
|
|
6
|
+
* on-chain decimals is carried at the `10^D` scale, exactly as the
|
|
7
|
+
* token contract reports it. See the `council-amount-decimals`
|
|
8
|
+
* decision and council-rust `chain::eth::u256_to_native_amount`.
|
|
9
|
+
* Rates are scaled by `PRICE_SCALE = 10^18` (council-rust `fees.rs`).
|
|
10
|
+
*
|
|
11
|
+
* ## This module is pure math — it embeds NO asset table
|
|
12
|
+
*
|
|
13
|
+
* Every function takes explicit `decimals` values. Per-(chain, asset)
|
|
14
|
+
* decimals are the single responsibility of the `supported_assets`
|
|
15
|
+
* registry, verified against each token's on-chain `decimals()` by
|
|
16
|
+
* `scripts/verify-asset-decimals.ts`. There is deliberately no symbol
|
|
17
|
+
* table here to drift as assets land on new chains — e.g. USDT is 6
|
|
18
|
+
* decimals on Ethereum but 18 on BNB Smart Chain.
|
|
19
|
+
*
|
|
20
|
+
* Sourcing decimals:
|
|
21
|
+
* - server: `getAssetDecimals(chain, symbol)` — `lib/council/asset-decimals.ts`
|
|
22
|
+
* - client: `clientAssetDecimals(chain, symbol)` — `lib/council/client-asset-decimals.ts`
|
|
23
|
+
* (both read the `supported_assets` registry; client via `GET /api/assets`)
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Convert a display-unit amount to a BFT `Amount` (u128) at the asset's
|
|
27
|
+
* native scale: `displayAmount × 10^decimals`.
|
|
28
|
+
*
|
|
29
|
+
* `decimals` is the asset's on-chain decimal precision on its chain
|
|
30
|
+
* (from `supported_assets`). High-decimal assets split through 10^9 to
|
|
31
|
+
* stay within IEEE-754 safe-integer range.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toMicroUnits(amountDisplay: number, decimals: number): bigint;
|
|
34
|
+
/**
|
|
35
|
+
* Convert a display exchange rate (quote per base) to the BFT-scaled
|
|
36
|
+
* `rate` (u128).
|
|
37
|
+
*
|
|
38
|
+
* Protocol definition (council-rust `fees.rs`):
|
|
39
|
+
* `rate / PRICE_SCALE = quote-micro-units per base-micro-unit`
|
|
40
|
+
*
|
|
41
|
+
* With native per-asset decimals on both legs:
|
|
42
|
+
* `rate_BFT = rateDisplay × 10^(18 + quoteDecimals − baseDecimals)`
|
|
43
|
+
*/
|
|
44
|
+
export declare function toRateBFT(rateDisplay: number, baseDecimals: number, quoteDecimals: number): bigint;
|
|
45
|
+
/**
|
|
46
|
+
* Parse a `"BASE/QUOTE"` pair string into its two uppercase symbols.
|
|
47
|
+
* @throws if the format is invalid.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parsePair(pair: string): {
|
|
50
|
+
base: string;
|
|
51
|
+
quote: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Encode `PlaceQuote` amounts: `fill_size` in base-asset native
|
|
55
|
+
* micro-units, `rate` BFT-scaled. Caller supplies the base/quote
|
|
56
|
+
* decimals (from the `supported_assets` registry).
|
|
57
|
+
*/
|
|
58
|
+
export declare function encodePlaceQuoteAmounts(sizeDisplay: number, rateDisplay: number, baseDecimals: number, quoteDecimals: number): {
|
|
59
|
+
fillSizeMicro: bigint;
|
|
60
|
+
rateBFT: bigint;
|
|
61
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BFT `Amount` encoding math.
|
|
3
|
+
*
|
|
4
|
+
* The council-rust protocol denominates token amounts in `Amount`
|
|
5
|
+
* (u128) using **native per-asset decimals** — an asset with `D`
|
|
6
|
+
* on-chain decimals is carried at the `10^D` scale, exactly as the
|
|
7
|
+
* token contract reports it. See the `council-amount-decimals`
|
|
8
|
+
* decision and council-rust `chain::eth::u256_to_native_amount`.
|
|
9
|
+
* Rates are scaled by `PRICE_SCALE = 10^18` (council-rust `fees.rs`).
|
|
10
|
+
*
|
|
11
|
+
* ## This module is pure math — it embeds NO asset table
|
|
12
|
+
*
|
|
13
|
+
* Every function takes explicit `decimals` values. Per-(chain, asset)
|
|
14
|
+
* decimals are the single responsibility of the `supported_assets`
|
|
15
|
+
* registry, verified against each token's on-chain `decimals()` by
|
|
16
|
+
* `scripts/verify-asset-decimals.ts`. There is deliberately no symbol
|
|
17
|
+
* table here to drift as assets land on new chains — e.g. USDT is 6
|
|
18
|
+
* decimals on Ethereum but 18 on BNB Smart Chain.
|
|
19
|
+
*
|
|
20
|
+
* Sourcing decimals:
|
|
21
|
+
* - server: `getAssetDecimals(chain, symbol)` — `lib/council/asset-decimals.ts`
|
|
22
|
+
* - client: `clientAssetDecimals(chain, symbol)` — `lib/council/client-asset-decimals.ts`
|
|
23
|
+
* (both read the `supported_assets` registry; client via `GET /api/assets`)
|
|
24
|
+
*/
|
|
25
|
+
/** `rate` fixed-point exponent. council-rust `fees.rs` PRICE_SCALE = 10^18. */
|
|
26
|
+
const PRICE_SCALE_EXP = 18;
|
|
27
|
+
/** Upper bound on plausible token decimals — guards against bad registry data. */
|
|
28
|
+
const MAX_DECIMALS = 36;
|
|
29
|
+
/** bigint exponentiation (avoids `**` for older TS lib targets). */
|
|
30
|
+
function bigintPow(base, exp) {
|
|
31
|
+
if (exp < 0)
|
|
32
|
+
throw new Error(`bigintPow: negative exponent ${exp}`);
|
|
33
|
+
let result = BigInt(1);
|
|
34
|
+
for (let i = 0; i < exp; i++)
|
|
35
|
+
result *= base;
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function assertValidDecimals(decimals, label) {
|
|
39
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_DECIMALS) {
|
|
40
|
+
throw new Error(`${label}: invalid decimals ${decimals} (expected integer 0..${MAX_DECIMALS})`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Convert a display-unit amount to a BFT `Amount` (u128) at the asset's
|
|
45
|
+
* native scale: `displayAmount × 10^decimals`.
|
|
46
|
+
*
|
|
47
|
+
* `decimals` is the asset's on-chain decimal precision on its chain
|
|
48
|
+
* (from `supported_assets`). High-decimal assets split through 10^9 to
|
|
49
|
+
* stay within IEEE-754 safe-integer range.
|
|
50
|
+
*/
|
|
51
|
+
export function toMicroUnits(amountDisplay, decimals) {
|
|
52
|
+
assertValidDecimals(decimals, "toMicroUnits");
|
|
53
|
+
if (!Number.isFinite(amountDisplay) || amountDisplay < 0) {
|
|
54
|
+
throw new Error(`toMicroUnits: invalid amount ${amountDisplay}`);
|
|
55
|
+
}
|
|
56
|
+
if (decimals <= 15) {
|
|
57
|
+
// 10^15 < 2^53 — exact in float.
|
|
58
|
+
return BigInt(Math.round(amountDisplay * 10 ** decimals));
|
|
59
|
+
}
|
|
60
|
+
// Split at 9 to stay within safe float range (2^53 ≈ 9×10^15).
|
|
61
|
+
const lower = BigInt(Math.round(amountDisplay * 1e9));
|
|
62
|
+
return lower * bigintPow(BigInt(10), decimals - 9);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Convert a display exchange rate (quote per base) to the BFT-scaled
|
|
66
|
+
* `rate` (u128).
|
|
67
|
+
*
|
|
68
|
+
* Protocol definition (council-rust `fees.rs`):
|
|
69
|
+
* `rate / PRICE_SCALE = quote-micro-units per base-micro-unit`
|
|
70
|
+
*
|
|
71
|
+
* With native per-asset decimals on both legs:
|
|
72
|
+
* `rate_BFT = rateDisplay × 10^(18 + quoteDecimals − baseDecimals)`
|
|
73
|
+
*/
|
|
74
|
+
export function toRateBFT(rateDisplay, baseDecimals, quoteDecimals) {
|
|
75
|
+
assertValidDecimals(baseDecimals, "toRateBFT base");
|
|
76
|
+
assertValidDecimals(quoteDecimals, "toRateBFT quote");
|
|
77
|
+
if (!Number.isFinite(rateDisplay) || rateDisplay < 0) {
|
|
78
|
+
throw new Error(`toRateBFT: invalid rate ${rateDisplay}`);
|
|
79
|
+
}
|
|
80
|
+
const totalExp = PRICE_SCALE_EXP + quoteDecimals - baseDecimals;
|
|
81
|
+
if (totalExp < 0) {
|
|
82
|
+
// Quote asset has far fewer decimals than base — encoding here
|
|
83
|
+
// would truncate sub-unit precision. Refuse rather than silently
|
|
84
|
+
// lose money-precision; this is unreachable for realistic pairs.
|
|
85
|
+
throw new Error(`toRateBFT: negative scale exponent ${totalExp} (baseDec ${baseDecimals}, quoteDec ${quoteDecimals})`);
|
|
86
|
+
}
|
|
87
|
+
if (totalExp >= 9) {
|
|
88
|
+
const lower = BigInt(Math.round(rateDisplay * 1e9));
|
|
89
|
+
return lower * bigintPow(BigInt(10), totalExp - 9);
|
|
90
|
+
}
|
|
91
|
+
return BigInt(Math.round(rateDisplay * 10 ** totalExp));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Parse a `"BASE/QUOTE"` pair string into its two uppercase symbols.
|
|
95
|
+
* @throws if the format is invalid.
|
|
96
|
+
*/
|
|
97
|
+
export function parsePair(pair) {
|
|
98
|
+
const parts = pair.split("/");
|
|
99
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
100
|
+
throw new Error(`parsePair: expected "BASE/QUOTE", got "${pair}"`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
base: parts[0].trim().toUpperCase(),
|
|
104
|
+
quote: parts[1].trim().toUpperCase(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Encode `PlaceQuote` amounts: `fill_size` in base-asset native
|
|
109
|
+
* micro-units, `rate` BFT-scaled. Caller supplies the base/quote
|
|
110
|
+
* decimals (from the `supported_assets` registry).
|
|
111
|
+
*/
|
|
112
|
+
export function encodePlaceQuoteAmounts(sizeDisplay, rateDisplay, baseDecimals, quoteDecimals) {
|
|
113
|
+
return {
|
|
114
|
+
fillSizeMicro: toMicroUnits(sizeDisplay, baseDecimals),
|
|
115
|
+
rateBFT: toRateBFT(rateDisplay, baseDecimals, quoteDecimals),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=asset-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-registry.js","sourceRoot":"","sources":["../../src/asset-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin HTTP client over the SupraFX dApp's public endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the read + write surfaces documented in
|
|
5
|
+
* `docs/INTEGRATING-AGENTS.md`. No auth required for reads; writes
|
|
6
|
+
* carry their own ed25519 signature inside the BCS envelope (see
|
|
7
|
+
* `./signer.ts`).
|
|
8
|
+
*
|
|
9
|
+
* Pure fetch — no global state, no caching beyond the chain-info
|
|
10
|
+
* lookup. Safe to use from the MCP server, from a cookbook script,
|
|
11
|
+
* or as a library inside a larger agent codebase.
|
|
12
|
+
*/
|
|
13
|
+
export interface SupraFxClientOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Base URL of the SupraFX dApp. Defaults to `https://suprafx.ai`.
|
|
16
|
+
* Override for staging or for direct validator HTTP submit.
|
|
17
|
+
*/
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
/** Per-request timeout in ms. Defaults to 15000. */
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ChainInfo {
|
|
23
|
+
chainId: string;
|
|
24
|
+
chainIdHashHex: string;
|
|
25
|
+
threshold: number;
|
|
26
|
+
/** Live venue also returns these; optional so older deployments parse. */
|
|
27
|
+
validatorCount?: number;
|
|
28
|
+
stateMachineVersion?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface AssetInfo {
|
|
31
|
+
chain_id: string;
|
|
32
|
+
asset_symbol: string;
|
|
33
|
+
contract_address: string | null;
|
|
34
|
+
decimals: number;
|
|
35
|
+
}
|
|
36
|
+
export interface PlatformBalance {
|
|
37
|
+
asset: string;
|
|
38
|
+
available: number;
|
|
39
|
+
locked_in_orders: number;
|
|
40
|
+
locked_in_rfq: number;
|
|
41
|
+
total: number;
|
|
42
|
+
}
|
|
43
|
+
/** One deposit claim as `GET /api/platform/deposit` summarises it. */
|
|
44
|
+
export interface DepositClaimSummary {
|
|
45
|
+
claim_id: string;
|
|
46
|
+
claimer_address: string;
|
|
47
|
+
chain: string;
|
|
48
|
+
tx_hash: string;
|
|
49
|
+
asset: string;
|
|
50
|
+
/** Decimal string, never a float. */
|
|
51
|
+
amount: string;
|
|
52
|
+
/** Raw venue status, e.g. `awaiting_council`, `rejected_wrong_vault`. */
|
|
53
|
+
status: string;
|
|
54
|
+
state: "pending" | "credited" | "rejected" | "expired";
|
|
55
|
+
created_at: string;
|
|
56
|
+
credited_at: string | null;
|
|
57
|
+
credited_batch_number: number | null;
|
|
58
|
+
rejection_reason: string | null;
|
|
59
|
+
age_seconds: number;
|
|
60
|
+
/** Pending for longer than the venue's fresh-wallet threshold. NOT a failure. */
|
|
61
|
+
stale: boolean;
|
|
62
|
+
next_step: string;
|
|
63
|
+
/**
|
|
64
|
+
* True when `state` came from the venue's ledger rather than the claim
|
|
65
|
+
* record — the money provably arrived while the record still says
|
|
66
|
+
* otherwise. `status` keeps the raw record value, so the two can disagree
|
|
67
|
+
* in one response; `state` is the one to act on.
|
|
68
|
+
*/
|
|
69
|
+
reconciled_from_ledger?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* What the chain actually credited, when the venue matched a ledger entry.
|
|
72
|
+
* May differ from `amount`, which is what the depositor claimed to send.
|
|
73
|
+
*/
|
|
74
|
+
credited_amount?: string | null;
|
|
75
|
+
}
|
|
76
|
+
/** Single-claim lookup. `found:false` is a normal answer, not an error. */
|
|
77
|
+
export type DepositStatusLookup = {
|
|
78
|
+
found: true;
|
|
79
|
+
claim: DepositClaimSummary;
|
|
80
|
+
} | {
|
|
81
|
+
found: false;
|
|
82
|
+
chain: string;
|
|
83
|
+
tx_hash: string;
|
|
84
|
+
state: "unclaimed";
|
|
85
|
+
next_step: string;
|
|
86
|
+
};
|
|
87
|
+
export interface DepositClaimList {
|
|
88
|
+
address: string;
|
|
89
|
+
claims: DepositClaimSummary[];
|
|
90
|
+
counts: {
|
|
91
|
+
pending: number;
|
|
92
|
+
stale: number;
|
|
93
|
+
credited: number;
|
|
94
|
+
rejected: number;
|
|
95
|
+
expired: number;
|
|
96
|
+
/** How many of these were only known credited via the ledger. */
|
|
97
|
+
reconciled_from_ledger?: number;
|
|
98
|
+
};
|
|
99
|
+
truncated: boolean;
|
|
100
|
+
}
|
|
101
|
+
/** Public delegate-policy response. Additional venue fields are preserved. */
|
|
102
|
+
export interface DelegatePolicy {
|
|
103
|
+
active?: boolean;
|
|
104
|
+
master?: string;
|
|
105
|
+
master_address?: string;
|
|
106
|
+
[key: string]: unknown;
|
|
107
|
+
}
|
|
108
|
+
export interface OrderbookRfq {
|
|
109
|
+
id: string;
|
|
110
|
+
taker_address: string;
|
|
111
|
+
pair: string;
|
|
112
|
+
size: number;
|
|
113
|
+
remaining_size: number;
|
|
114
|
+
source_chain: string;
|
|
115
|
+
dest_chain: string;
|
|
116
|
+
reference_price: number;
|
|
117
|
+
status: string;
|
|
118
|
+
settlement_mode: string;
|
|
119
|
+
allow_partial_fills: boolean;
|
|
120
|
+
min_fill_size: number;
|
|
121
|
+
expires_at: string;
|
|
122
|
+
created_at: string;
|
|
123
|
+
}
|
|
124
|
+
export interface SubmitResult {
|
|
125
|
+
ok: boolean;
|
|
126
|
+
batch?: number;
|
|
127
|
+
event_hash_hex?: string;
|
|
128
|
+
code?: string;
|
|
129
|
+
detail?: string;
|
|
130
|
+
per_validator?: unknown[];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Stable, machine-readable error categories. An agent can branch on
|
|
134
|
+
* `code` without parsing prose, and `action` names the one thing that
|
|
135
|
+
* clears it. Mirrors the envelope Kraken ships on every command.
|
|
136
|
+
*/
|
|
137
|
+
export type SupraFxErrorCode = "auth" | "rate_limit" | "validation" | "not_found" | "api" | "network" | "timeout" | "seq_desync" | "needs_acknowledgement" | "read_only";
|
|
138
|
+
export type SupraFxErrorAction = "authenticate" | "backoff" | "fix_input" | "reconnect" | "configure_key" | "acknowledge" | "retry" | "report";
|
|
139
|
+
/** An error carrying a stable category and the action that clears it. */
|
|
140
|
+
export declare class SupraFxError extends Error {
|
|
141
|
+
readonly code: SupraFxErrorCode;
|
|
142
|
+
readonly action: SupraFxErrorAction;
|
|
143
|
+
readonly status?: number;
|
|
144
|
+
readonly detail?: unknown;
|
|
145
|
+
constructor(code: SupraFxErrorCode, action: SupraFxErrorAction, message: string, opts?: {
|
|
146
|
+
status?: number;
|
|
147
|
+
detail?: unknown;
|
|
148
|
+
});
|
|
149
|
+
/** The JSON body an MCP handler returns on failure. */
|
|
150
|
+
toEnvelope(): {
|
|
151
|
+
error: SupraFxErrorCode;
|
|
152
|
+
action: SupraFxErrorAction;
|
|
153
|
+
message: string;
|
|
154
|
+
status?: number;
|
|
155
|
+
detail?: unknown;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export interface OracleQuote {
|
|
159
|
+
pair: string;
|
|
160
|
+
conversionRate: number | null;
|
|
161
|
+
updatedAt: number | null;
|
|
162
|
+
/** Age of the quote in ms at read time. */
|
|
163
|
+
ageMs: number | null;
|
|
164
|
+
}
|
|
165
|
+
export declare class SupraFxClient {
|
|
166
|
+
private readonly baseUrl;
|
|
167
|
+
private readonly timeoutMs;
|
|
168
|
+
private cachedChainInfo;
|
|
169
|
+
private cachedClockOffset;
|
|
170
|
+
constructor(opts?: SupraFxClientOptions);
|
|
171
|
+
/**
|
|
172
|
+
* Fetch the canonical chain-id hash and validator threshold.
|
|
173
|
+
* Cached for the lifetime of the client — these values are
|
|
174
|
+
* constant per chain genesis.
|
|
175
|
+
*/
|
|
176
|
+
getChainInfo(): Promise<ChainInfo>;
|
|
177
|
+
/**
|
|
178
|
+
* Difference between the venue's HTTP clock and the local clock.
|
|
179
|
+
* Best-effort only: expiry calculation must remain available when the
|
|
180
|
+
* header or endpoint is unavailable.
|
|
181
|
+
*/
|
|
182
|
+
getVenueClockOffsetMs(): Promise<number>;
|
|
183
|
+
/** Current committed batch height. Useful for `expires_at_batch` math. */
|
|
184
|
+
getCurrentBatch(): Promise<number>;
|
|
185
|
+
/**
|
|
186
|
+
* Next strictly-monotonic sequence number this address must use
|
|
187
|
+
* for its next signed event. `0` for a brand-new account.
|
|
188
|
+
*/
|
|
189
|
+
getSequenceNumber(address: string): Promise<number>;
|
|
190
|
+
/** All supported assets with canonical chain id + decimals. */
|
|
191
|
+
listAssets(): Promise<AssetInfo[]>;
|
|
192
|
+
/**
|
|
193
|
+
* Available + locked balances for `address` (a master Supra account).
|
|
194
|
+
* Returns an empty array if the address has no balance rows.
|
|
195
|
+
*/
|
|
196
|
+
getBalances(address: string): Promise<PlatformBalance[]>;
|
|
197
|
+
/**
|
|
198
|
+
* Status of one deposit claim, keyed on the chain and the L1 transaction
|
|
199
|
+
* hash. Answers "still crediting, or failed?" — see `state`, `stale` and
|
|
200
|
+
* `next_step`. An unknown transaction is `found:false`, not an error: a
|
|
201
|
+
* deposit made without recording a claim still credits through the
|
|
202
|
+
* validator bridge, it is just not visible here.
|
|
203
|
+
*/
|
|
204
|
+
getDepositStatus(chain: string, txHash: string): Promise<DepositStatusLookup>;
|
|
205
|
+
/** Every deposit claim recorded by `address` (a master account), newest first. */
|
|
206
|
+
listDepositClaims(address: string, limit?: number): Promise<DepositClaimList>;
|
|
207
|
+
/** On-chain policy currently associated with a delegate address. */
|
|
208
|
+
getDelegatePolicy(address: string): Promise<DelegatePolicy | null>;
|
|
209
|
+
/**
|
|
210
|
+
* Public orderbook: open RFQs. Filters as documented in
|
|
211
|
+
* `INTEGRATING-AGENTS.md` §2.
|
|
212
|
+
*/
|
|
213
|
+
getOrderbook(filters?: {
|
|
214
|
+
pair?: string;
|
|
215
|
+
status?: string;
|
|
216
|
+
limit?: number;
|
|
217
|
+
}): Promise<OrderbookRfq[]>;
|
|
218
|
+
/**
|
|
219
|
+
* Venue oracle quote for `pair` (e.g. `"ETH/USDC"`), with the quote's
|
|
220
|
+
* age computed at read time. Quote against THIS, never an external
|
|
221
|
+
* price — and never against a stale one (see `ORACLE_STALE_MS`).
|
|
222
|
+
*/
|
|
223
|
+
getOracle(pair: string): Promise<OracleQuote>;
|
|
224
|
+
submitEnvelope(endpoint: "submit-rfq" | "place-quote" | "accept-quote" | "withdraw-quote" | "cancel-rfq", bodyFieldName: string, envelopeBcsHex: string): Promise<SubmitResult>;
|
|
225
|
+
private get;
|
|
226
|
+
private post;
|
|
227
|
+
}
|