@orkid-labs/sdk 0.1.0
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/README.md +689 -0
- package/dist/chains-QHQI25WO.mjs +20 -0
- package/dist/chunk-3UAOMCO3.mjs +227 -0
- package/dist/chunk-7T23KZR4.mjs +122 -0
- package/dist/chunk-PMDWMIGW.mjs +164 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +856 -0
- package/dist/cli.mjs +324 -0
- package/dist/index.d.mts +542 -0
- package/dist/index.d.ts +542 -0
- package/dist/index.js +640 -0
- package/dist/index.mjs +140 -0
- package/dist/viem-CZMIEVIX.mjs +23 -0
- package/openapi.yaml +522 -0
- package/package.json +66 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
OrkidClient
|
|
4
|
+
} from "./chunk-PMDWMIGW.mjs";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
function parseArgs(argv) {
|
|
8
|
+
const positional = [];
|
|
9
|
+
const flags = {};
|
|
10
|
+
let command;
|
|
11
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12
|
+
const arg = argv[i];
|
|
13
|
+
if (arg === "-h" || arg === "--help") {
|
|
14
|
+
flags.help = true;
|
|
15
|
+
} else if (arg === "--json") {
|
|
16
|
+
flags.json = true;
|
|
17
|
+
} else if (arg === "--execute") {
|
|
18
|
+
flags.execute = true;
|
|
19
|
+
} else if (arg === "--dry-run") {
|
|
20
|
+
flags.dryRun = true;
|
|
21
|
+
} else if (arg.startsWith("--")) {
|
|
22
|
+
const key = arg.slice(2);
|
|
23
|
+
const next = argv[i + 1];
|
|
24
|
+
if (next !== void 0 && !next.startsWith("-")) {
|
|
25
|
+
flags[key] = next;
|
|
26
|
+
i++;
|
|
27
|
+
} else {
|
|
28
|
+
flags[key] = true;
|
|
29
|
+
}
|
|
30
|
+
} else if (!command) {
|
|
31
|
+
command = arg;
|
|
32
|
+
} else {
|
|
33
|
+
positional.push(arg);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { command, positional, flags };
|
|
37
|
+
}
|
|
38
|
+
function flag(flags, ...names) {
|
|
39
|
+
for (const n of names) {
|
|
40
|
+
const v = flags[n];
|
|
41
|
+
if (typeof v === "string") return v;
|
|
42
|
+
}
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
function num(flags, ...names) {
|
|
46
|
+
const v = flag(flags, ...names);
|
|
47
|
+
return v === void 0 ? void 0 : Number(v);
|
|
48
|
+
}
|
|
49
|
+
function die(message, code = 1) {
|
|
50
|
+
console.error(`error: ${message}`);
|
|
51
|
+
process.exit(code);
|
|
52
|
+
}
|
|
53
|
+
function print(data, json, formatter) {
|
|
54
|
+
if (json || !formatter) {
|
|
55
|
+
console.log(JSON.stringify(data, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
formatter(data);
|
|
59
|
+
}
|
|
60
|
+
var HELP = `orkid \u2014 Orkid swap API CLI
|
|
61
|
+
|
|
62
|
+
Commands:
|
|
63
|
+
quote Get an executable swap quote
|
|
64
|
+
--from <sym> --to <sym> --amount <n> [--chain base]
|
|
65
|
+
[--from-address 0x.. --from-decimals n --to-address 0x.. --to-decimals n]
|
|
66
|
+
solve Sign + submit a gasless swap (needs viem + ORKID_PRIVATE_KEY)
|
|
67
|
+
same flags as quote, plus --user 0x.. --execute (default: dry-run)
|
|
68
|
+
tokens List tokens for a chain
|
|
69
|
+
[--chain base] [--search <q>] [--limit n]
|
|
70
|
+
account Show the partner account for this API key
|
|
71
|
+
usage List usage events for this API key's account
|
|
72
|
+
[--period YYYY-MM] [--event-type route|solve] [--limit n]
|
|
73
|
+
rebates List rebate ledger entries for this API key's account
|
|
74
|
+
[--period YYYY-MM]
|
|
75
|
+
confirm Confirm a user-submitted swap tx (counts it toward volume/rebates)
|
|
76
|
+
orkid confirm <txHash> [--chain base]
|
|
77
|
+
status API health check
|
|
78
|
+
|
|
79
|
+
Global flags:
|
|
80
|
+
--api-key <40-hex> Orkid API key (or ORKID_API_KEY env)
|
|
81
|
+
--base-url <url> API base URL (or ORKID_API_URL env, default https://orkidlabs.xyz)
|
|
82
|
+
--test Operator test mode (requires ORKID_OPERATOR_SECRET)
|
|
83
|
+
--json Raw JSON output
|
|
84
|
+
-h, --help This help
|
|
85
|
+
|
|
86
|
+
Environment:
|
|
87
|
+
ORKID_API_KEY Partner API key
|
|
88
|
+
ORKID_API_URL Override API base URL
|
|
89
|
+
ORKID_PRIVATE_KEY Wallet private key for 'solve' signing (hex, 0x-prefixed)
|
|
90
|
+
ORKID_OPERATOR_SECRET Operator test mode \u2014 marks usage as test (no rebate impact)
|
|
91
|
+
`;
|
|
92
|
+
async function main() {
|
|
93
|
+
const { command, positional, flags } = parseArgs(process.argv.slice(2));
|
|
94
|
+
if (!command || flags.help) {
|
|
95
|
+
console.log(HELP);
|
|
96
|
+
process.exit(command ? 0 : 1);
|
|
97
|
+
}
|
|
98
|
+
const apiKey = flag(flags, "api-key", "apiKey") || process.env.ORKID_API_KEY;
|
|
99
|
+
const baseUrl = flag(flags, "base-url", "baseUrl", "url") || process.env.ORKID_API_URL;
|
|
100
|
+
const json = Boolean(flags.json);
|
|
101
|
+
const testMode = Boolean(flags.test);
|
|
102
|
+
const operatorSecret = process.env.ORKID_OPERATOR_SECRET;
|
|
103
|
+
if (testMode && !operatorSecret) {
|
|
104
|
+
console.error("warning: --test without ORKID_OPERATOR_SECRET will record normal volume");
|
|
105
|
+
}
|
|
106
|
+
if (testMode && operatorSecret) {
|
|
107
|
+
console.error("test mode: usage events marked is_test \u2014 excluded from rebates");
|
|
108
|
+
}
|
|
109
|
+
const client = new OrkidClient({ apiKey, baseUrl, operatorSecret: testMode ? operatorSecret : void 0 });
|
|
110
|
+
switch (command) {
|
|
111
|
+
case "quote": {
|
|
112
|
+
const req = routeRequest(flags);
|
|
113
|
+
const res = await client.getQuote(req);
|
|
114
|
+
print(res, json, (r) => {
|
|
115
|
+
if (!r.ok) return die(r.error || "quote failed");
|
|
116
|
+
const q = r.quote;
|
|
117
|
+
console.log(`${req.amount} ${req.from} -> ${q.amountOut} ${req.to} (${q.rate})`);
|
|
118
|
+
console.log(`protocol: ${q.protocol}`);
|
|
119
|
+
console.log(`volume: $${q.volumeUsd}`);
|
|
120
|
+
if (r.savings) {
|
|
121
|
+
console.log(`savings: ${r.savings.savingsBps} bps vs MetaMask ($${r.savings.savingsUsd})`);
|
|
122
|
+
console.log(`orkid fee: ${r.savings.orkidBps} bps`);
|
|
123
|
+
}
|
|
124
|
+
if (q.priceImpactBps !== void 0) console.log(`impact: ${q.priceImpactBps} bps`);
|
|
125
|
+
console.log(`compute: ${r.computeMs}ms`);
|
|
126
|
+
});
|
|
127
|
+
if (!res.ok) process.exit(1);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case "solve": {
|
|
131
|
+
const res = await cmdSolve(client, flags);
|
|
132
|
+
print(res, json, (r) => {
|
|
133
|
+
if (!r.ok) return die(r.error || "solve failed");
|
|
134
|
+
if (r.transaction?.txHash) console.log(`tx: ${r.transaction.txHash}`);
|
|
135
|
+
else console.log(`calldata ready: to=${r.transaction?.to}`);
|
|
136
|
+
if (r.savings) console.log(`savings: ${r.savings.savingsBps} bps ($${r.savings.savingsUsd})`);
|
|
137
|
+
});
|
|
138
|
+
if (!res.ok) process.exit(1);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case "tokens": {
|
|
142
|
+
const res = await client.listTokens({
|
|
143
|
+
chain: flag(flags, "chain") || "base",
|
|
144
|
+
search: flag(flags, "search"),
|
|
145
|
+
limit: num(flags, "limit")
|
|
146
|
+
});
|
|
147
|
+
print(res, json, (r) => {
|
|
148
|
+
if (!r.ok) return die(r.error || "token lookup failed");
|
|
149
|
+
for (const t of r.tokens || []) {
|
|
150
|
+
console.log(`${t.symbol.padEnd(10)} ${t.address} (${t.decimals} decimals, ${t.chain})`);
|
|
151
|
+
}
|
|
152
|
+
if (!r.tokens?.length) console.log("no tokens found");
|
|
153
|
+
});
|
|
154
|
+
if (!res.ok) process.exit(1);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "account": {
|
|
158
|
+
const res = await client.getAccount();
|
|
159
|
+
print(res, json, (r) => {
|
|
160
|
+
if (!r.ok || !r.account) return die(r.error || "account lookup failed");
|
|
161
|
+
const a = r.account;
|
|
162
|
+
console.log(`${a.name} (${a.slug})`);
|
|
163
|
+
console.log(`id: ${a.id}`);
|
|
164
|
+
console.log(`rebate: ${a.rebate_bps} bps ${a.rebate_active ? "(active)" : "(inactive)"}`);
|
|
165
|
+
if (a.contact_email) console.log(`contact: ${a.contact_email}`);
|
|
166
|
+
});
|
|
167
|
+
if (!res.ok) process.exit(1);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "usage": {
|
|
171
|
+
const res = await client.getUsage({
|
|
172
|
+
period: flag(flags, "period", "month"),
|
|
173
|
+
eventType: flag(flags, "event-type", "eventType", "type"),
|
|
174
|
+
limit: num(flags, "limit")
|
|
175
|
+
});
|
|
176
|
+
print(res, json, (r) => {
|
|
177
|
+
if (r.error) return die(r.error);
|
|
178
|
+
for (const e of r.events || []) {
|
|
179
|
+
const vol = e.volume_usd != null ? `$${e.volume_usd}` : "-";
|
|
180
|
+
const dry = e.is_dry_run ? " [dry-run]" : "";
|
|
181
|
+
console.log(`${e.created_at} ${e.event_type.padEnd(6)} ${String(e.token_in || "-").padEnd(6)}->${String(e.token_out || "-").padEnd(6)} ${vol}${dry}`);
|
|
182
|
+
}
|
|
183
|
+
console.log(`---
|
|
184
|
+
total volume: $${r.total_volume_usd ?? 0} total savings: $${r.total_savings_usd ?? 0}`);
|
|
185
|
+
});
|
|
186
|
+
if (res.error) process.exit(1);
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case "rebates": {
|
|
190
|
+
const res = await client.getRebates({ period: flag(flags, "period", "month") });
|
|
191
|
+
print(res, json, (r) => {
|
|
192
|
+
if (r.error) return die(r.error);
|
|
193
|
+
for (const b of r.rebates || []) {
|
|
194
|
+
const month = String(b.period_start).slice(0, 7);
|
|
195
|
+
console.log(`${month} volume=$${b.volume_usd} rate=${b.rebate_bps}bps rebate=$${b.rebate_usd} [${b.status}]`);
|
|
196
|
+
}
|
|
197
|
+
if (!r.rebates?.length) console.log("no rebates accrued yet");
|
|
198
|
+
});
|
|
199
|
+
if (res.error) process.exit(1);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
case "confirm": {
|
|
203
|
+
const txHash = flag(flags, "tx-hash", "txHash", "tx") || positional[0];
|
|
204
|
+
if (!txHash) die("confirm requires a tx hash: orkid confirm 0x...");
|
|
205
|
+
const res = await client.confirmTransaction(txHash, flag(flags, "chain"));
|
|
206
|
+
print(res, json, (r) => {
|
|
207
|
+
if (r.confirmed) {
|
|
208
|
+
console.log(`confirmed \u2014 event ${r.eventId} now counts toward volume/rebates`);
|
|
209
|
+
} else {
|
|
210
|
+
die(r.error || "not confirmed");
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
if (!res.confirmed) process.exit(1);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "status": {
|
|
217
|
+
const res = await client.getStatus();
|
|
218
|
+
print(res, json, (r) => console.log(r.ok === false ? "API unreachable" : JSON.stringify(r)));
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
default:
|
|
222
|
+
console.error(`unknown command: ${command}
|
|
223
|
+
`);
|
|
224
|
+
console.log(HELP);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function routeRequest(flags) {
|
|
229
|
+
const from = flag(flags, "from");
|
|
230
|
+
const to = flag(flags, "to");
|
|
231
|
+
const amount = flag(flags, "amount");
|
|
232
|
+
if (!from || !to || !amount) die("quote requires --from, --to, and --amount");
|
|
233
|
+
return {
|
|
234
|
+
from,
|
|
235
|
+
to,
|
|
236
|
+
amount,
|
|
237
|
+
chain: flag(flags, "chain") || "base",
|
|
238
|
+
fromAddress: flag(flags, "from-address", "fromAddress"),
|
|
239
|
+
fromDecimals: num(flags, "from-decimals", "fromDecimals"),
|
|
240
|
+
toAddress: flag(flags, "to-address", "toAddress"),
|
|
241
|
+
toDecimals: num(flags, "to-decimals", "toDecimals")
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async function cmdSolve(client, flags) {
|
|
245
|
+
const req = routeRequest(flags);
|
|
246
|
+
if (!req.fromAddress || req.fromDecimals === void 0) {
|
|
247
|
+
die("solve requires --from-address and --from-decimals (token-in contract + decimals)");
|
|
248
|
+
}
|
|
249
|
+
const privateKey = flag(flags, "private-key", "privateKey") || process.env.ORKID_PRIVATE_KEY;
|
|
250
|
+
if (!privateKey) die("solve requires --private-key or ORKID_PRIVATE_KEY");
|
|
251
|
+
let viem, accounts, chainsMod;
|
|
252
|
+
try {
|
|
253
|
+
viem = await import("viem");
|
|
254
|
+
accounts = await import("viem/accounts");
|
|
255
|
+
chainsMod = await import("viem/chains");
|
|
256
|
+
} catch {
|
|
257
|
+
die("solve requires viem \u2014 run: npm install viem");
|
|
258
|
+
}
|
|
259
|
+
const { OrkidViemPermitSigner } = await import("./viem-CZMIEVIX.mjs");
|
|
260
|
+
const { chainConfigFromName } = await import("./chains-QHQI25WO.mjs");
|
|
261
|
+
const chainConfig = chainConfigFromName(req.chain || "base");
|
|
262
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
263
|
+
const viemChain = Object.values(chainsMod).find((c) => c.id === chainConfig.id);
|
|
264
|
+
if (!viemChain) die(`no viem chain config for chain id ${chainConfig.id}`);
|
|
265
|
+
const walletClient = viem.createWalletClient({
|
|
266
|
+
account,
|
|
267
|
+
chain: viemChain,
|
|
268
|
+
transport: viem.http(chainConfig.rpcUrl)
|
|
269
|
+
});
|
|
270
|
+
const publicClient = viem.createPublicClient({
|
|
271
|
+
chain: viemChain,
|
|
272
|
+
transport: viem.http(chainConfig.rpcUrl)
|
|
273
|
+
});
|
|
274
|
+
const user = flag(flags, "user") || account.address;
|
|
275
|
+
const signer = new OrkidViemPermitSigner(walletClient, publicClient);
|
|
276
|
+
const { permit, signature } = await signer.signSwap({
|
|
277
|
+
user,
|
|
278
|
+
fromToken: req.fromAddress,
|
|
279
|
+
fromDecimals: req.fromDecimals,
|
|
280
|
+
amount: req.amount,
|
|
281
|
+
chain: req.chain || "base"
|
|
282
|
+
});
|
|
283
|
+
const dryRun = !flags.execute;
|
|
284
|
+
if (!dryRun) {
|
|
285
|
+
console.error("submitting live swap...");
|
|
286
|
+
}
|
|
287
|
+
const res = await client.solve({
|
|
288
|
+
...req,
|
|
289
|
+
user,
|
|
290
|
+
permit,
|
|
291
|
+
signature,
|
|
292
|
+
dryRun,
|
|
293
|
+
slippageBps: num(flags, "slippage-bps", "slippageBps")
|
|
294
|
+
});
|
|
295
|
+
if (flags.execute && !res.ok && res.gaslessEligible === false) {
|
|
296
|
+
console.error("below gasless minimum \u2014 submitting user-paid transaction...");
|
|
297
|
+
const encoded = await client.solve({
|
|
298
|
+
...req,
|
|
299
|
+
user,
|
|
300
|
+
permit,
|
|
301
|
+
signature,
|
|
302
|
+
dryRun: true,
|
|
303
|
+
slippageBps: num(flags, "slippage-bps", "slippageBps")
|
|
304
|
+
});
|
|
305
|
+
if (!encoded.ok || !encoded.transaction?.data) return encoded;
|
|
306
|
+
const txHash = await walletClient.sendTransaction({
|
|
307
|
+
to: encoded.transaction.to,
|
|
308
|
+
data: encoded.transaction.data,
|
|
309
|
+
value: BigInt(encoded.transaction.value || "0")
|
|
310
|
+
});
|
|
311
|
+
console.error(`user-paid tx submitted: ${txHash} \u2014 waiting for confirmation...`);
|
|
312
|
+
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
313
|
+
const confirm = await client.confirmTransaction(txHash, req.chain || "base");
|
|
314
|
+
if (!confirm.confirmed) {
|
|
315
|
+
console.error(`warning: swap settled on-chain but not recorded (${confirm.error || "confirm failed"})`);
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
...encoded,
|
|
319
|
+
transaction: { ...encoded.transaction, txHash }
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return res;
|
|
323
|
+
}
|
|
324
|
+
main().catch((e) => die(e instanceof Error ? e.message : String(e)));
|