@openfort/cli 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/dist/bin.js +24 -0
- package/dist/chunk-SZO4OB6U.js +23 -0
- package/dist/cli.js +2886 -0
- package/package.json +30 -0
- package/src/bin.ts +25 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2886 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CREDENTIALS_PATH,
|
|
3
|
+
ensureConfigDir
|
|
4
|
+
} from "./chunk-SZO4OB6U.js";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
import { Cli as Cli12, z as z14, Errors as Errors4 } from "incur";
|
|
8
|
+
import Openfort from "@openfort/openfort-node";
|
|
9
|
+
|
|
10
|
+
// src/vars.ts
|
|
11
|
+
import { z } from "incur";
|
|
12
|
+
var varsSchema = z.object({
|
|
13
|
+
openfort: z.custom()
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// src/constants.ts
|
|
17
|
+
var API_BASE_URL = process.env.OPENFORT_BASE_URL || "https://api.openfort.io";
|
|
18
|
+
var OPENFORT_SHIELD_URL = process.env.OPENFORT_SHIELD_URL || "https://shield.openfort.io";
|
|
19
|
+
var AUTH_PAGE_URL = process.env.OPENFORT_AUTH_PAGE_URL || "https://dashboard.openfort.io";
|
|
20
|
+
var CLI_CALLBACK_PORT = Number(process.env.OPENFORT_CLI_CALLBACK_PORT) || 8271;
|
|
21
|
+
|
|
22
|
+
// src/commands/login.ts
|
|
23
|
+
import { randomBytes } from "crypto";
|
|
24
|
+
import { createServer } from "http";
|
|
25
|
+
import { z as z2 } from "incur";
|
|
26
|
+
|
|
27
|
+
// src/env.ts
|
|
28
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
29
|
+
function loadEnvFile(envPath) {
|
|
30
|
+
const entries = /* @__PURE__ */ new Map();
|
|
31
|
+
if (!existsSync(envPath)) return entries;
|
|
32
|
+
const content = readFileSync(envPath, "utf-8");
|
|
33
|
+
for (const line of content.split("\n")) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
36
|
+
const eqIndex = trimmed.indexOf("=");
|
|
37
|
+
if (eqIndex === -1) continue;
|
|
38
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
39
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
40
|
+
entries.set(key, value);
|
|
41
|
+
}
|
|
42
|
+
return entries;
|
|
43
|
+
}
|
|
44
|
+
function writeEnvKey(envPath, key, value) {
|
|
45
|
+
const entries = loadEnvFile(envPath);
|
|
46
|
+
entries.set(key, value);
|
|
47
|
+
const lines = [];
|
|
48
|
+
for (const [k, v] of entries) {
|
|
49
|
+
lines.push(`${k}=${v}`);
|
|
50
|
+
}
|
|
51
|
+
writeFileSync(envPath, `${lines.join("\n")}
|
|
52
|
+
`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/commands/login.ts
|
|
56
|
+
function base64url(buffer) {
|
|
57
|
+
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
58
|
+
}
|
|
59
|
+
function generateState() {
|
|
60
|
+
return base64url(randomBytes(16));
|
|
61
|
+
}
|
|
62
|
+
function callbackPage(title, description, variant = "success") {
|
|
63
|
+
const iconColor = variant === "success" ? "hsl(142 71% 45%)" : "hsl(0 84% 60%)";
|
|
64
|
+
const icon = variant === "success" ? `<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>` : `<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>`;
|
|
65
|
+
return `<!DOCTYPE html>
|
|
66
|
+
<html lang="en">
|
|
67
|
+
<head>
|
|
68
|
+
<meta charset="UTF-8">
|
|
69
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
70
|
+
<title>${title} - Openfort CLI</title>
|
|
71
|
+
<style>
|
|
72
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
73
|
+
:root {
|
|
74
|
+
--background: hsl(0 0% 100%);
|
|
75
|
+
--foreground: hsl(20 14.3% 4.1%);
|
|
76
|
+
--card: hsl(0 0% 100%);
|
|
77
|
+
--card-foreground: hsl(20 14.3% 4.1%);
|
|
78
|
+
--border: hsl(20 5.9% 90%);
|
|
79
|
+
--muted-foreground: hsl(25 5.3% 44.7%);
|
|
80
|
+
--radius: 0.3rem;
|
|
81
|
+
}
|
|
82
|
+
@media (prefers-color-scheme: dark) {
|
|
83
|
+
:root {
|
|
84
|
+
--background: hsl(20 14.3% 4.1%);
|
|
85
|
+
--foreground: hsl(60 9.1% 97.8%);
|
|
86
|
+
--card: hsl(20 14.3% 4.1%);
|
|
87
|
+
--card-foreground: hsl(60 9.1% 97.8%);
|
|
88
|
+
--border: hsl(12 6.5% 15.1%);
|
|
89
|
+
--muted-foreground: hsl(24 5.4% 63.9%);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
body {
|
|
93
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
94
|
+
background-color: var(--background);
|
|
95
|
+
color: var(--foreground);
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
min-height: 100vh;
|
|
100
|
+
padding: 1rem;
|
|
101
|
+
}
|
|
102
|
+
.card {
|
|
103
|
+
background-color: var(--card);
|
|
104
|
+
color: var(--card-foreground);
|
|
105
|
+
border: 1px solid var(--border);
|
|
106
|
+
border-radius: var(--radius);
|
|
107
|
+
width: 100%;
|
|
108
|
+
max-width: 28rem;
|
|
109
|
+
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
110
|
+
}
|
|
111
|
+
.card-header {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
align-items: center;
|
|
115
|
+
gap: 0.5rem;
|
|
116
|
+
padding: 1.5rem;
|
|
117
|
+
text-align: center;
|
|
118
|
+
}
|
|
119
|
+
.card-icon { margin-bottom: 0.5rem; }
|
|
120
|
+
.card-title {
|
|
121
|
+
font-size: 1.5rem;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
line-height: 1.2;
|
|
124
|
+
letter-spacing: -0.025em;
|
|
125
|
+
}
|
|
126
|
+
.card-description {
|
|
127
|
+
font-size: 0.875rem;
|
|
128
|
+
color: var(--muted-foreground);
|
|
129
|
+
line-height: 1.5;
|
|
130
|
+
}
|
|
131
|
+
</style>
|
|
132
|
+
</head>
|
|
133
|
+
<body>
|
|
134
|
+
<div class="card">
|
|
135
|
+
<div class="card-header">
|
|
136
|
+
<div class="card-icon">${icon}</div>
|
|
137
|
+
<h1 class="card-title">${title}</h1>
|
|
138
|
+
<p class="card-description">${description}</p>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</body>
|
|
142
|
+
</html>`;
|
|
143
|
+
}
|
|
144
|
+
function waitForCallback(port, state) {
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const timeout = setTimeout(() => {
|
|
147
|
+
server.close();
|
|
148
|
+
reject(new Error("Login timed out after 5 minutes. Please try again."));
|
|
149
|
+
}, 5 * 60 * 1e3);
|
|
150
|
+
const server = createServer((req, res) => {
|
|
151
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
152
|
+
if (url.pathname === "/callback") {
|
|
153
|
+
const apiKey = url.searchParams.get("api_key");
|
|
154
|
+
const publishableKey = url.searchParams.get("publishable_key");
|
|
155
|
+
const projectId = url.searchParams.get("project_id");
|
|
156
|
+
const project = url.searchParams.get("project");
|
|
157
|
+
const returnedState = url.searchParams.get("state");
|
|
158
|
+
const error = url.searchParams.get("error");
|
|
159
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
160
|
+
if (error) {
|
|
161
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
162
|
+
res.end(callbackPage("Login failed", "Something went wrong. You can close this window.", "error"));
|
|
163
|
+
clearTimeout(timeout);
|
|
164
|
+
server.close();
|
|
165
|
+
reject(new Error(errorDescription || error));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!apiKey || returnedState !== state) {
|
|
169
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
170
|
+
res.end(callbackPage("Invalid callback", "Missing API key or state mismatch. Please try logging in again.", "error"));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
174
|
+
res.end(callbackPage("Login successful!", "You can close this window and return to your terminal."));
|
|
175
|
+
clearTimeout(timeout);
|
|
176
|
+
server.close();
|
|
177
|
+
resolve({ apiKey, publishableKey: publishableKey || void 0, projectId: projectId || void 0, project: project || "unknown" });
|
|
178
|
+
} else {
|
|
179
|
+
res.writeHead(404);
|
|
180
|
+
res.end();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
server.listen(port);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
var loginConfig = {
|
|
187
|
+
description: "Log in to Openfort via browser and save your API key.",
|
|
188
|
+
output: z2.object({
|
|
189
|
+
apiKey: z2.string().describe("The API key saved to credentials"),
|
|
190
|
+
project: z2.string().describe("The project name"),
|
|
191
|
+
credentialsPath: z2.string().describe("Path to the credentials file")
|
|
192
|
+
}),
|
|
193
|
+
async run(c) {
|
|
194
|
+
const state = generateState();
|
|
195
|
+
const port = CLI_CALLBACK_PORT;
|
|
196
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
197
|
+
const authUrl = new URL(`${AUTH_PAGE_URL}/oauth/consent`);
|
|
198
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
199
|
+
authUrl.searchParams.set("state", state);
|
|
200
|
+
console.log("\nOpen this URL in your browser to log in:\n");
|
|
201
|
+
console.log(` ${authUrl.toString()}
|
|
202
|
+
`);
|
|
203
|
+
console.log("Waiting for authentication...\n");
|
|
204
|
+
const { apiKey, publishableKey, projectId, project } = await waitForCallback(port, state);
|
|
205
|
+
ensureConfigDir();
|
|
206
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_API_KEY", apiKey);
|
|
207
|
+
if (publishableKey) {
|
|
208
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_PUBLISHABLE_KEY", publishableKey);
|
|
209
|
+
}
|
|
210
|
+
if (projectId) {
|
|
211
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_PROJECT_ID", projectId);
|
|
212
|
+
}
|
|
213
|
+
console.log(`Saved API key for project "${project}" to ${CREDENTIALS_PATH}`);
|
|
214
|
+
return c.ok(
|
|
215
|
+
{ apiKey, project, credentialsPath: CREDENTIALS_PATH },
|
|
216
|
+
{
|
|
217
|
+
cta: {
|
|
218
|
+
description: "Next steps:",
|
|
219
|
+
commands: [
|
|
220
|
+
{ command: `wallet-keys create`, description: "Create and save wallet keys necessary for backend wallet creation" }
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// src/commands/accounts.ts
|
|
229
|
+
import { Cli, z as z3, Errors } from "incur";
|
|
230
|
+
function requireWalletCredentials() {
|
|
231
|
+
const missing = [];
|
|
232
|
+
if (!process.env.OPENFORT_WALLET_SECRET) missing.push("OPENFORT_WALLET_SECRET");
|
|
233
|
+
if (!process.env.OPENFORT_PUBLISHABLE_KEY) missing.push("OPENFORT_PUBLISHABLE_KEY");
|
|
234
|
+
if (missing.length > 0) {
|
|
235
|
+
throw new Errors.IncurError({
|
|
236
|
+
code: "MISSING_CREDENTIALS",
|
|
237
|
+
message: `Missing required credentials: ${missing.join(", ")}`,
|
|
238
|
+
hint: "Run: openfort wallet-keys create"
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
var evm = Cli.create("evm", {
|
|
243
|
+
description: "EVM wallet management.",
|
|
244
|
+
vars: varsSchema
|
|
245
|
+
});
|
|
246
|
+
evm.command("create", {
|
|
247
|
+
description: "Create a new EVM backend wallet.",
|
|
248
|
+
examples: [
|
|
249
|
+
{ description: "Create a new EVM wallet" }
|
|
250
|
+
],
|
|
251
|
+
output: z3.object({
|
|
252
|
+
id: z3.string().describe("Account ID"),
|
|
253
|
+
address: z3.string().describe("Wallet address"),
|
|
254
|
+
custody: z3.string().describe("Custody type")
|
|
255
|
+
}),
|
|
256
|
+
async run(c) {
|
|
257
|
+
requireWalletCredentials();
|
|
258
|
+
const account = await c.var.openfort.accounts.evm.backend.create();
|
|
259
|
+
return c.ok(
|
|
260
|
+
{ id: account.id, address: account.address, custody: account.custody },
|
|
261
|
+
{
|
|
262
|
+
cta: {
|
|
263
|
+
description: "Next steps:",
|
|
264
|
+
commands: [
|
|
265
|
+
{ command: `accounts evm get ${account.id}`, description: "View this account" },
|
|
266
|
+
{ command: "policies create", description: "Create an access policy" }
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
evm.command("list", {
|
|
274
|
+
description: "List EVM backend wallets.",
|
|
275
|
+
options: z3.object({
|
|
276
|
+
limit: z3.number().optional().describe("Max results"),
|
|
277
|
+
skip: z3.number().optional().describe("Offset")
|
|
278
|
+
}),
|
|
279
|
+
alias: { limit: "l" },
|
|
280
|
+
examples: [
|
|
281
|
+
{ description: "List all EVM backend wallets" },
|
|
282
|
+
{ options: { limit: 5 }, description: "Show first 5 wallets" }
|
|
283
|
+
],
|
|
284
|
+
output: z3.object({
|
|
285
|
+
accounts: z3.array(z3.object({
|
|
286
|
+
id: z3.string(),
|
|
287
|
+
address: z3.string(),
|
|
288
|
+
custody: z3.string()
|
|
289
|
+
})),
|
|
290
|
+
total: z3.number().optional()
|
|
291
|
+
}),
|
|
292
|
+
async run(c) {
|
|
293
|
+
const res = await c.var.openfort.accounts.evm.backend.list({
|
|
294
|
+
limit: c.options.limit,
|
|
295
|
+
skip: c.options.skip
|
|
296
|
+
});
|
|
297
|
+
return c.ok({
|
|
298
|
+
accounts: res.accounts.map((a) => ({
|
|
299
|
+
id: a.id,
|
|
300
|
+
address: a.address,
|
|
301
|
+
custody: a.custody
|
|
302
|
+
})),
|
|
303
|
+
total: res.total
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
evm.command("list-delegated", {
|
|
308
|
+
description: "List EVM delegated accounts.",
|
|
309
|
+
options: z3.object({
|
|
310
|
+
limit: z3.number().optional().describe("Max results"),
|
|
311
|
+
skip: z3.number().optional().describe("Offset")
|
|
312
|
+
}),
|
|
313
|
+
alias: { limit: "l" },
|
|
314
|
+
examples: [
|
|
315
|
+
{ description: "List all EVM delegated accounts" },
|
|
316
|
+
{ options: { limit: 5 }, description: "Show first 5 accounts" }
|
|
317
|
+
],
|
|
318
|
+
output: z3.object({
|
|
319
|
+
accounts: z3.array(z3.object({
|
|
320
|
+
id: z3.string(),
|
|
321
|
+
address: z3.string(),
|
|
322
|
+
custody: z3.string()
|
|
323
|
+
})),
|
|
324
|
+
total: z3.number().optional()
|
|
325
|
+
}),
|
|
326
|
+
async run(c) {
|
|
327
|
+
const res = await c.var.openfort.accounts.evm.list({
|
|
328
|
+
accountType: "Delegated Account",
|
|
329
|
+
limit: c.options.limit,
|
|
330
|
+
skip: c.options.skip
|
|
331
|
+
});
|
|
332
|
+
return c.ok({
|
|
333
|
+
accounts: res.data.map((a) => ({
|
|
334
|
+
id: a.id,
|
|
335
|
+
address: a.address,
|
|
336
|
+
custody: a.custody
|
|
337
|
+
})),
|
|
338
|
+
total: res.total
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
evm.command("list-smart", {
|
|
343
|
+
description: "List EVM smart accounts.",
|
|
344
|
+
options: z3.object({
|
|
345
|
+
limit: z3.number().optional().describe("Max results"),
|
|
346
|
+
skip: z3.number().optional().describe("Offset")
|
|
347
|
+
}),
|
|
348
|
+
alias: { limit: "l" },
|
|
349
|
+
examples: [
|
|
350
|
+
{ description: "List all EVM smart accounts" },
|
|
351
|
+
{ options: { limit: 5 }, description: "Show first 5 accounts" }
|
|
352
|
+
],
|
|
353
|
+
output: z3.object({
|
|
354
|
+
accounts: z3.array(z3.object({
|
|
355
|
+
id: z3.string(),
|
|
356
|
+
address: z3.string(),
|
|
357
|
+
custody: z3.string()
|
|
358
|
+
})),
|
|
359
|
+
total: z3.number().optional()
|
|
360
|
+
}),
|
|
361
|
+
async run(c) {
|
|
362
|
+
const res = await c.var.openfort.accounts.evm.list({
|
|
363
|
+
accountType: "Smart Account",
|
|
364
|
+
limit: c.options.limit,
|
|
365
|
+
skip: c.options.skip
|
|
366
|
+
});
|
|
367
|
+
return c.ok({
|
|
368
|
+
accounts: res.data.map((a) => ({
|
|
369
|
+
id: a.id,
|
|
370
|
+
address: a.address,
|
|
371
|
+
custody: a.custody
|
|
372
|
+
})),
|
|
373
|
+
total: res.total
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
evm.command("get", {
|
|
378
|
+
description: "Get an EVM backend wallet by ID or address.",
|
|
379
|
+
args: z3.object({
|
|
380
|
+
id: z3.string().describe("Account ID or address")
|
|
381
|
+
}),
|
|
382
|
+
examples: [
|
|
383
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Get wallet by ID" }
|
|
384
|
+
],
|
|
385
|
+
output: z3.object({
|
|
386
|
+
id: z3.string(),
|
|
387
|
+
address: z3.string(),
|
|
388
|
+
custody: z3.string()
|
|
389
|
+
}),
|
|
390
|
+
async run(c) {
|
|
391
|
+
const a = await c.var.openfort.accounts.evm.backend.get({ id: c.args.id });
|
|
392
|
+
return c.ok({
|
|
393
|
+
id: a.id,
|
|
394
|
+
address: a.address,
|
|
395
|
+
custody: a.custody
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
evm.command("sign", {
|
|
400
|
+
description: "Sign data with an EVM backend wallet.",
|
|
401
|
+
args: z3.object({
|
|
402
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
403
|
+
}),
|
|
404
|
+
options: z3.object({
|
|
405
|
+
data: z3.string().describe("Data to sign (hex-encoded)")
|
|
406
|
+
}),
|
|
407
|
+
alias: { data: "d" },
|
|
408
|
+
output: z3.object({
|
|
409
|
+
account: z3.string(),
|
|
410
|
+
signature: z3.string()
|
|
411
|
+
}),
|
|
412
|
+
examples: [
|
|
413
|
+
{
|
|
414
|
+
args: { id: "acc_abc123" },
|
|
415
|
+
options: { data: "0x1234abcd" },
|
|
416
|
+
description: "Sign a message hash with a backend wallet"
|
|
417
|
+
}
|
|
418
|
+
],
|
|
419
|
+
async run(c) {
|
|
420
|
+
requireWalletCredentials();
|
|
421
|
+
const signature = await c.var.openfort.accounts.evm.backend.sign({
|
|
422
|
+
id: c.args.id,
|
|
423
|
+
data: c.options.data
|
|
424
|
+
});
|
|
425
|
+
return c.ok({ account: c.args.id, signature });
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
evm.command("delete", {
|
|
429
|
+
description: "Delete an EVM backend wallet.",
|
|
430
|
+
args: z3.object({
|
|
431
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
432
|
+
}),
|
|
433
|
+
examples: [
|
|
434
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Delete a wallet" }
|
|
435
|
+
],
|
|
436
|
+
output: z3.object({
|
|
437
|
+
id: z3.string(),
|
|
438
|
+
deleted: z3.boolean()
|
|
439
|
+
}),
|
|
440
|
+
async run(c) {
|
|
441
|
+
const res = await c.var.openfort.accounts.evm.backend.delete(c.args.id);
|
|
442
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
evm.command("update", {
|
|
446
|
+
description: "Upgrade an EVM backend wallet to a delegated account (EIP-7702).",
|
|
447
|
+
args: z3.object({
|
|
448
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
449
|
+
}),
|
|
450
|
+
options: z3.object({
|
|
451
|
+
chainId: z3.number().describe("Chain ID to deploy on"),
|
|
452
|
+
implementationType: z3.string().describe("Smart account implementation type we will update to")
|
|
453
|
+
}),
|
|
454
|
+
examples: [
|
|
455
|
+
{ args: { id: "acc_1a2b3c4d" }, options: { chainId: 8453, implementationType: "CaliburV9" }, description: "Upgrade to delegated account on Base" }
|
|
456
|
+
],
|
|
457
|
+
output: z3.object({
|
|
458
|
+
id: z3.string(),
|
|
459
|
+
address: z3.string(),
|
|
460
|
+
accountType: z3.string(),
|
|
461
|
+
chainId: z3.number().optional(),
|
|
462
|
+
chainType: z3.string()
|
|
463
|
+
}),
|
|
464
|
+
async run(c) {
|
|
465
|
+
const account = await c.var.openfort.accounts.evm.backend.get({ id: c.args.id });
|
|
466
|
+
const res = await c.var.openfort.accounts.evm.backend.update({
|
|
467
|
+
walletId: account.walletId,
|
|
468
|
+
chainId: c.options.chainId,
|
|
469
|
+
accountId: account.id,
|
|
470
|
+
implementationType: c.options.implementationType
|
|
471
|
+
});
|
|
472
|
+
return c.ok(
|
|
473
|
+
{
|
|
474
|
+
id: res.id,
|
|
475
|
+
address: res.address,
|
|
476
|
+
accountType: res.accountType,
|
|
477
|
+
chainId: res.chainId,
|
|
478
|
+
chainType: res.chainType
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
cta: {
|
|
482
|
+
description: "Next steps:",
|
|
483
|
+
commands: [
|
|
484
|
+
{ command: `accounts evm list-delegated`, description: "To see all accounts which were updated to delegated ones" }
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
evm.command("sign", {
|
|
492
|
+
description: "Sign data with an EVM backend wallet.",
|
|
493
|
+
args: z3.object({
|
|
494
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
495
|
+
}),
|
|
496
|
+
options: z3.object({
|
|
497
|
+
data: z3.string().describe("Hex-encoded data to sign")
|
|
498
|
+
}),
|
|
499
|
+
examples: [
|
|
500
|
+
{ args: { id: "acc_1a2b3c4d" }, options: { data: "0xdeadbeef" }, description: "Sign a message hash" }
|
|
501
|
+
],
|
|
502
|
+
output: z3.object({
|
|
503
|
+
signature: z3.string()
|
|
504
|
+
}),
|
|
505
|
+
async run(c) {
|
|
506
|
+
requireWalletCredentials();
|
|
507
|
+
const signature = await c.var.openfort.accounts.evm.backend.sign({
|
|
508
|
+
id: c.args.id,
|
|
509
|
+
data: c.options.data
|
|
510
|
+
});
|
|
511
|
+
return c.ok({ signature });
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
evm.command("import", {
|
|
515
|
+
description: "Import a private key as an EVM backend wallet.",
|
|
516
|
+
options: z3.object({
|
|
517
|
+
privateKey: z3.string().describe("Private key (hex string)")
|
|
518
|
+
}),
|
|
519
|
+
examples: [
|
|
520
|
+
{ options: { privateKey: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" }, description: "Import a private key" }
|
|
521
|
+
],
|
|
522
|
+
output: z3.object({
|
|
523
|
+
id: z3.string(),
|
|
524
|
+
address: z3.string(),
|
|
525
|
+
custody: z3.string()
|
|
526
|
+
}),
|
|
527
|
+
async run(c) {
|
|
528
|
+
requireWalletCredentials();
|
|
529
|
+
const account = await c.var.openfort.accounts.evm.backend.import({
|
|
530
|
+
privateKey: c.options.privateKey
|
|
531
|
+
});
|
|
532
|
+
return c.ok({
|
|
533
|
+
id: account.id,
|
|
534
|
+
address: account.address,
|
|
535
|
+
custody: account.custody
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
evm.command("export", {
|
|
540
|
+
description: "Export an EVM backend wallet private key.",
|
|
541
|
+
args: z3.object({
|
|
542
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
543
|
+
}),
|
|
544
|
+
examples: [
|
|
545
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Export private key" }
|
|
546
|
+
],
|
|
547
|
+
output: z3.object({
|
|
548
|
+
privateKey: z3.string()
|
|
549
|
+
}),
|
|
550
|
+
async run(c) {
|
|
551
|
+
requireWalletCredentials();
|
|
552
|
+
const privateKey = await c.var.openfort.accounts.evm.backend.export({
|
|
553
|
+
id: c.args.id
|
|
554
|
+
});
|
|
555
|
+
return c.ok({ privateKey });
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
evm.command("send-transaction", {
|
|
559
|
+
description: "Send a gasless EVM transaction (auto-delegates via EIP-7702 if needed).",
|
|
560
|
+
args: z3.object({
|
|
561
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
562
|
+
}),
|
|
563
|
+
options: z3.object({
|
|
564
|
+
chainId: z3.number().describe("Chain ID"),
|
|
565
|
+
interactions: z3.string().describe('Interactions as JSON: [{"to":"0x...","data":"0x...","value":"0"}]'),
|
|
566
|
+
policy: z3.string().optional().describe("Policy ID for gas sponsorship (pol_...)")
|
|
567
|
+
}),
|
|
568
|
+
examples: [
|
|
569
|
+
{
|
|
570
|
+
args: { id: "acc_1a2b3c4d" },
|
|
571
|
+
options: {
|
|
572
|
+
chainId: 8453,
|
|
573
|
+
interactions: '[{"to":"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359","data":"0xa9059cbb...","value":"0"}]'
|
|
574
|
+
},
|
|
575
|
+
description: "Send a gasless transaction on Base"
|
|
576
|
+
}
|
|
577
|
+
],
|
|
578
|
+
output: z3.object({
|
|
579
|
+
id: z3.string(),
|
|
580
|
+
chainId: z3.number(),
|
|
581
|
+
transactionHash: z3.string().optional()
|
|
582
|
+
}),
|
|
583
|
+
async run(c) {
|
|
584
|
+
const account = await c.var.openfort.accounts.evm.backend.get({ id: c.args.id });
|
|
585
|
+
const interactions = JSON.parse(c.options.interactions);
|
|
586
|
+
const res = await c.var.openfort.accounts.evm.backend.sendTransaction({
|
|
587
|
+
account,
|
|
588
|
+
chainId: c.options.chainId,
|
|
589
|
+
interactions,
|
|
590
|
+
policy: c.options.policy
|
|
591
|
+
});
|
|
592
|
+
return c.ok({
|
|
593
|
+
id: res.id,
|
|
594
|
+
chainId: res.chainId,
|
|
595
|
+
transactionHash: res.response?.transactionHash
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
var solana = Cli.create("solana", {
|
|
600
|
+
description: "Solana wallet management.",
|
|
601
|
+
vars: varsSchema
|
|
602
|
+
});
|
|
603
|
+
solana.command("create", {
|
|
604
|
+
description: "Create a new Solana backend wallet.",
|
|
605
|
+
examples: [
|
|
606
|
+
{ description: "Create a new Solana wallet" }
|
|
607
|
+
],
|
|
608
|
+
output: z3.object({
|
|
609
|
+
id: z3.string().describe("Account ID"),
|
|
610
|
+
address: z3.string().describe("Wallet address"),
|
|
611
|
+
custody: z3.string().describe("Custody type")
|
|
612
|
+
}),
|
|
613
|
+
async run(c) {
|
|
614
|
+
requireWalletCredentials();
|
|
615
|
+
const account = await c.var.openfort.accounts.solana.backend.create();
|
|
616
|
+
return c.ok(
|
|
617
|
+
{ id: account.id, address: account.address, custody: account.custody },
|
|
618
|
+
{
|
|
619
|
+
cta: {
|
|
620
|
+
description: "Next steps:",
|
|
621
|
+
commands: [
|
|
622
|
+
{ command: `accounts solana get ${account.id}`, description: "View this account" }
|
|
623
|
+
]
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
solana.command("list", {
|
|
630
|
+
description: "List Solana backend wallets.",
|
|
631
|
+
options: z3.object({
|
|
632
|
+
limit: z3.number().optional().describe("Max results"),
|
|
633
|
+
skip: z3.number().optional().describe("Offset")
|
|
634
|
+
}),
|
|
635
|
+
alias: { limit: "l" },
|
|
636
|
+
examples: [
|
|
637
|
+
{ description: "List all Solana wallets" }
|
|
638
|
+
],
|
|
639
|
+
output: z3.object({
|
|
640
|
+
accounts: z3.array(z3.object({
|
|
641
|
+
id: z3.string(),
|
|
642
|
+
address: z3.string(),
|
|
643
|
+
custody: z3.string()
|
|
644
|
+
})),
|
|
645
|
+
total: z3.number().optional()
|
|
646
|
+
}),
|
|
647
|
+
async run(c) {
|
|
648
|
+
const res = await c.var.openfort.accounts.solana.backend.list({
|
|
649
|
+
limit: c.options.limit,
|
|
650
|
+
skip: c.options.skip
|
|
651
|
+
});
|
|
652
|
+
return c.ok({
|
|
653
|
+
accounts: res.accounts.map((a) => ({
|
|
654
|
+
id: a.id,
|
|
655
|
+
address: a.address,
|
|
656
|
+
custody: a.custody
|
|
657
|
+
})),
|
|
658
|
+
total: res.total
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
solana.command("get", {
|
|
663
|
+
description: "Get a Solana backend wallet by ID or address.",
|
|
664
|
+
args: z3.object({
|
|
665
|
+
id: z3.string().describe("Account ID or address")
|
|
666
|
+
}),
|
|
667
|
+
examples: [
|
|
668
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Get wallet by ID" }
|
|
669
|
+
],
|
|
670
|
+
output: z3.object({
|
|
671
|
+
id: z3.string(),
|
|
672
|
+
address: z3.string(),
|
|
673
|
+
custody: z3.string()
|
|
674
|
+
}),
|
|
675
|
+
async run(c) {
|
|
676
|
+
const a = await c.var.openfort.accounts.solana.backend.get({ id: c.args.id });
|
|
677
|
+
return c.ok({
|
|
678
|
+
id: a.id,
|
|
679
|
+
address: a.address,
|
|
680
|
+
custody: a.custody
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
solana.command("sign", {
|
|
685
|
+
description: "Sign data with a Solana backend wallet.",
|
|
686
|
+
args: z3.object({
|
|
687
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
688
|
+
}),
|
|
689
|
+
options: z3.object({
|
|
690
|
+
data: z3.string().describe("Data to sign (base64-encoded)")
|
|
691
|
+
}),
|
|
692
|
+
alias: { data: "d" },
|
|
693
|
+
output: z3.object({
|
|
694
|
+
account: z3.string(),
|
|
695
|
+
signature: z3.string()
|
|
696
|
+
}),
|
|
697
|
+
examples: [
|
|
698
|
+
{
|
|
699
|
+
args: { id: "acc_abc123" },
|
|
700
|
+
options: { data: "SGVsbG8gV29ybGQ=" },
|
|
701
|
+
description: "Sign a message with a Solana backend wallet"
|
|
702
|
+
}
|
|
703
|
+
],
|
|
704
|
+
async run(c) {
|
|
705
|
+
requireWalletCredentials();
|
|
706
|
+
const signature = await c.var.openfort.accounts.solana.backend.sign(c.args.id, c.options.data);
|
|
707
|
+
return c.ok({ account: c.args.id, signature });
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
solana.command("delete", {
|
|
711
|
+
description: "Delete a Solana backend wallet.",
|
|
712
|
+
args: z3.object({
|
|
713
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
714
|
+
}),
|
|
715
|
+
examples: [
|
|
716
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Delete a wallet" }
|
|
717
|
+
],
|
|
718
|
+
output: z3.object({
|
|
719
|
+
id: z3.string(),
|
|
720
|
+
deleted: z3.boolean()
|
|
721
|
+
}),
|
|
722
|
+
async run(c) {
|
|
723
|
+
const res = await c.var.openfort.accounts.solana.backend.delete(c.args.id);
|
|
724
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
solana.command("sign", {
|
|
728
|
+
description: "Sign data with a Solana backend wallet.",
|
|
729
|
+
args: z3.object({
|
|
730
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
731
|
+
}),
|
|
732
|
+
options: z3.object({
|
|
733
|
+
data: z3.string().describe("Data to sign")
|
|
734
|
+
}),
|
|
735
|
+
examples: [
|
|
736
|
+
{ args: { id: "acc_1a2b3c4d" }, options: { data: "hello" }, description: "Sign a message" }
|
|
737
|
+
],
|
|
738
|
+
output: z3.object({
|
|
739
|
+
signature: z3.string()
|
|
740
|
+
}),
|
|
741
|
+
async run(c) {
|
|
742
|
+
requireWalletCredentials();
|
|
743
|
+
const signature = await c.var.openfort.accounts.solana.backend.sign(c.args.id, c.options.data);
|
|
744
|
+
return c.ok({ signature });
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
solana.command("import", {
|
|
748
|
+
description: "Import a private key as a Solana backend wallet.",
|
|
749
|
+
options: z3.object({
|
|
750
|
+
privateKey: z3.string().describe("Private key (hex-encoded 32 bytes or base58)")
|
|
751
|
+
}),
|
|
752
|
+
examples: [
|
|
753
|
+
{ options: { privateKey: "abc123..." }, description: "Import a Solana private key" }
|
|
754
|
+
],
|
|
755
|
+
output: z3.object({
|
|
756
|
+
id: z3.string(),
|
|
757
|
+
address: z3.string(),
|
|
758
|
+
custody: z3.string()
|
|
759
|
+
}),
|
|
760
|
+
async run(c) {
|
|
761
|
+
requireWalletCredentials();
|
|
762
|
+
const account = await c.var.openfort.accounts.solana.backend.import({
|
|
763
|
+
privateKey: c.options.privateKey
|
|
764
|
+
});
|
|
765
|
+
return c.ok({
|
|
766
|
+
id: account.id,
|
|
767
|
+
address: account.address,
|
|
768
|
+
custody: account.custody
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
solana.command("export", {
|
|
773
|
+
description: "Export a Solana backend wallet private key.",
|
|
774
|
+
args: z3.object({
|
|
775
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
776
|
+
}),
|
|
777
|
+
examples: [
|
|
778
|
+
{ args: { id: "acc_1a2b3c4d" }, description: "Export private key" }
|
|
779
|
+
],
|
|
780
|
+
output: z3.object({
|
|
781
|
+
privateKey: z3.string()
|
|
782
|
+
}),
|
|
783
|
+
async run(c) {
|
|
784
|
+
requireWalletCredentials();
|
|
785
|
+
const privateKey = await c.var.openfort.accounts.solana.backend.export({
|
|
786
|
+
id: c.args.id
|
|
787
|
+
});
|
|
788
|
+
return c.ok({ privateKey });
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
solana.command("transfer", {
|
|
792
|
+
description: "Transfer SOL or SPL tokens.",
|
|
793
|
+
args: z3.object({
|
|
794
|
+
id: z3.string().describe("Account ID (acc_...)")
|
|
795
|
+
}),
|
|
796
|
+
options: z3.object({
|
|
797
|
+
to: z3.string().describe("Destination address (base58)"),
|
|
798
|
+
amount: z3.string().describe("Amount in base units (lamports for SOL)"),
|
|
799
|
+
token: z3.string().optional().describe('Token: "sol" (default), "usdc", or mint address'),
|
|
800
|
+
cluster: z3.enum(["devnet", "mainnet-beta"]).default("mainnet-beta").describe("Cluster: devnet or mainnet-beta")
|
|
801
|
+
}),
|
|
802
|
+
examples: [
|
|
803
|
+
{
|
|
804
|
+
args: { id: "acc_1a2b3c4d" },
|
|
805
|
+
options: { to: "FDx9mf...", amount: "1000000", cluster: "devnet" },
|
|
806
|
+
description: "Transfer 0.001 SOL on devnet"
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
args: { id: "acc_1a2b3c4d" },
|
|
810
|
+
options: { to: "FDx9mf...", amount: "1000000", token: "usdc", cluster: "devnet" },
|
|
811
|
+
description: "Transfer 1 USDC on devnet"
|
|
812
|
+
}
|
|
813
|
+
],
|
|
814
|
+
output: z3.object({
|
|
815
|
+
signature: z3.string()
|
|
816
|
+
}),
|
|
817
|
+
async run(c) {
|
|
818
|
+
const account = await c.var.openfort.accounts.solana.backend.get({ id: c.args.id });
|
|
819
|
+
const res = await c.var.openfort.accounts.solana.backend.transfer({
|
|
820
|
+
account,
|
|
821
|
+
to: c.options.to,
|
|
822
|
+
amount: BigInt(c.options.amount),
|
|
823
|
+
token: c.options.token,
|
|
824
|
+
cluster: c.options.cluster
|
|
825
|
+
});
|
|
826
|
+
return c.ok({ signature: res.signature });
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
var accounts = Cli.create("accounts", {
|
|
830
|
+
description: "Manage wallets and accounts.",
|
|
831
|
+
vars: varsSchema
|
|
832
|
+
});
|
|
833
|
+
accounts.command("list", {
|
|
834
|
+
description: "List all accounts across chains.",
|
|
835
|
+
options: z3.object({
|
|
836
|
+
limit: z3.number().optional().describe("Max results"),
|
|
837
|
+
skip: z3.number().optional().describe("Offset"),
|
|
838
|
+
chainType: z3.enum(["EVM", "SVM"]).optional().describe("Filter by chain type"),
|
|
839
|
+
custody: z3.enum(["Developer", "User"]).optional().describe("Filter by custody")
|
|
840
|
+
}),
|
|
841
|
+
alias: { limit: "l" },
|
|
842
|
+
examples: [
|
|
843
|
+
{ description: "List all accounts across chains" },
|
|
844
|
+
{ options: { chainType: "EVM" }, description: "Filter to EVM accounts only" },
|
|
845
|
+
{ options: { custody: "Developer", limit: 10 }, description: "List developer-custody wallets" }
|
|
846
|
+
],
|
|
847
|
+
output: z3.object({
|
|
848
|
+
data: z3.array(z3.object({
|
|
849
|
+
id: z3.string(),
|
|
850
|
+
wallet: z3.string().describe("Wallet ID"),
|
|
851
|
+
accountType: z3.string().describe("Account type"),
|
|
852
|
+
address: z3.string(),
|
|
853
|
+
ownerAddress: z3.string().optional(),
|
|
854
|
+
chainType: z3.string(),
|
|
855
|
+
chainId: z3.number().optional(),
|
|
856
|
+
custody: z3.string(),
|
|
857
|
+
createdAt: z3.number(),
|
|
858
|
+
updatedAt: z3.number()
|
|
859
|
+
})),
|
|
860
|
+
total: z3.number()
|
|
861
|
+
}),
|
|
862
|
+
async run(c) {
|
|
863
|
+
const res = await c.var.openfort.accounts.list({
|
|
864
|
+
limit: c.options.limit,
|
|
865
|
+
skip: c.options.skip,
|
|
866
|
+
chainType: c.options.chainType,
|
|
867
|
+
custody: c.options.custody
|
|
868
|
+
});
|
|
869
|
+
return c.ok({
|
|
870
|
+
data: res.data.map((a) => ({
|
|
871
|
+
id: a.id,
|
|
872
|
+
wallet: a.wallet,
|
|
873
|
+
accountType: a.accountType,
|
|
874
|
+
address: a.address,
|
|
875
|
+
ownerAddress: a.ownerAddress,
|
|
876
|
+
chainType: a.chainType,
|
|
877
|
+
chainId: a.chainId,
|
|
878
|
+
custody: a.custody,
|
|
879
|
+
createdAt: a.createdAt,
|
|
880
|
+
updatedAt: a.updatedAt
|
|
881
|
+
})),
|
|
882
|
+
total: res.total
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
accounts.command(evm);
|
|
887
|
+
accounts.command(solana);
|
|
888
|
+
|
|
889
|
+
// src/commands/contracts.ts
|
|
890
|
+
import { Cli as Cli2, z as z4 } from "incur";
|
|
891
|
+
var contractItem = z4.object({
|
|
892
|
+
id: z4.string(),
|
|
893
|
+
createdAt: z4.number(),
|
|
894
|
+
name: z4.string().nullable(),
|
|
895
|
+
chainId: z4.number(),
|
|
896
|
+
address: z4.string(),
|
|
897
|
+
deleted: z4.boolean(),
|
|
898
|
+
abi: z4.array(z4.any()),
|
|
899
|
+
publicVerification: z4.boolean()
|
|
900
|
+
});
|
|
901
|
+
var contracts = Cli2.create("contracts", {
|
|
902
|
+
description: "Manage smart contracts.",
|
|
903
|
+
vars: varsSchema
|
|
904
|
+
});
|
|
905
|
+
contracts.command("list", {
|
|
906
|
+
description: "List registered contracts.",
|
|
907
|
+
options: z4.object({
|
|
908
|
+
limit: z4.number().optional().describe("Max results"),
|
|
909
|
+
skip: z4.number().optional().describe("Offset")
|
|
910
|
+
}),
|
|
911
|
+
alias: { limit: "l" },
|
|
912
|
+
examples: [
|
|
913
|
+
{ description: "List all contracts" },
|
|
914
|
+
{ options: { limit: 5 }, description: "List first 5 contracts" }
|
|
915
|
+
],
|
|
916
|
+
output: z4.object({
|
|
917
|
+
data: z4.array(contractItem),
|
|
918
|
+
total: z4.number()
|
|
919
|
+
}),
|
|
920
|
+
async run(c) {
|
|
921
|
+
const res = await c.var.openfort.contracts.list({
|
|
922
|
+
limit: c.options.limit,
|
|
923
|
+
skip: c.options.skip
|
|
924
|
+
});
|
|
925
|
+
return c.ok({
|
|
926
|
+
data: res.data.map((ct) => ({
|
|
927
|
+
id: ct.id,
|
|
928
|
+
createdAt: ct.createdAt,
|
|
929
|
+
name: ct.name,
|
|
930
|
+
chainId: ct.chainId,
|
|
931
|
+
address: ct.address,
|
|
932
|
+
deleted: ct.deleted,
|
|
933
|
+
abi: ct.abi,
|
|
934
|
+
publicVerification: ct.publicVerification
|
|
935
|
+
})),
|
|
936
|
+
total: res.total
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
contracts.command("create", {
|
|
941
|
+
description: "Register a smart contract.",
|
|
942
|
+
options: z4.object({
|
|
943
|
+
name: z4.string().describe("Contract name"),
|
|
944
|
+
address: z4.string().describe("Contract address"),
|
|
945
|
+
chainId: z4.number().describe("Chain ID"),
|
|
946
|
+
abi: z4.string().optional().describe("Contract ABI as JSON string")
|
|
947
|
+
}),
|
|
948
|
+
output: contractItem,
|
|
949
|
+
examples: [
|
|
950
|
+
{
|
|
951
|
+
options: { name: "USDC", address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", chainId: 137 },
|
|
952
|
+
description: "Register USDC on Polygon"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
options: { name: "My NFT", address: "0x1234...", chainId: 1, abi: '[{"type":"function","name":"mint",...}]' },
|
|
956
|
+
description: "Register contract with ABI"
|
|
957
|
+
}
|
|
958
|
+
],
|
|
959
|
+
async run(c) {
|
|
960
|
+
const res = await c.var.openfort.contracts.create({
|
|
961
|
+
name: c.options.name,
|
|
962
|
+
address: c.options.address,
|
|
963
|
+
chainId: c.options.chainId,
|
|
964
|
+
abi: c.options.abi ? JSON.parse(c.options.abi) : void 0
|
|
965
|
+
});
|
|
966
|
+
return c.ok(
|
|
967
|
+
{
|
|
968
|
+
id: res.id,
|
|
969
|
+
createdAt: res.createdAt,
|
|
970
|
+
name: res.name,
|
|
971
|
+
chainId: res.chainId,
|
|
972
|
+
address: res.address,
|
|
973
|
+
deleted: res.deleted,
|
|
974
|
+
abi: res.abi,
|
|
975
|
+
publicVerification: res.publicVerification
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
cta: {
|
|
979
|
+
description: "Next steps:",
|
|
980
|
+
commands: [
|
|
981
|
+
{ command: `contracts get ${res.id}`, description: "View this contract" },
|
|
982
|
+
{ command: "policies create", description: "Create a policy for this contract" }
|
|
983
|
+
]
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
contracts.command("get", {
|
|
990
|
+
description: "Get a contract by ID.",
|
|
991
|
+
args: z4.object({
|
|
992
|
+
id: z4.string().describe("Contract ID (con_...)")
|
|
993
|
+
}),
|
|
994
|
+
examples: [
|
|
995
|
+
{ args: { id: "con_1a2b3c4d" }, description: "Get contract details" }
|
|
996
|
+
],
|
|
997
|
+
output: contractItem,
|
|
998
|
+
async run(c) {
|
|
999
|
+
const ct = await c.var.openfort.contracts.get(c.args.id);
|
|
1000
|
+
return c.ok({
|
|
1001
|
+
id: ct.id,
|
|
1002
|
+
createdAt: ct.createdAt,
|
|
1003
|
+
name: ct.name,
|
|
1004
|
+
chainId: ct.chainId,
|
|
1005
|
+
address: ct.address,
|
|
1006
|
+
deleted: ct.deleted,
|
|
1007
|
+
abi: ct.abi,
|
|
1008
|
+
publicVerification: ct.publicVerification
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
contracts.command("update", {
|
|
1013
|
+
description: "Update a contract.",
|
|
1014
|
+
args: z4.object({
|
|
1015
|
+
id: z4.string().describe("Contract ID (con_...)")
|
|
1016
|
+
}),
|
|
1017
|
+
options: z4.object({
|
|
1018
|
+
name: z4.string().optional().describe("New name"),
|
|
1019
|
+
address: z4.string().optional().describe("New address"),
|
|
1020
|
+
chainId: z4.number().optional().describe("New chain ID"),
|
|
1021
|
+
abi: z4.string().optional().describe("New ABI as JSON string")
|
|
1022
|
+
}),
|
|
1023
|
+
examples: [
|
|
1024
|
+
{ args: { id: "con_1a2b3c4d" }, options: { name: "USDC v2" }, description: "Rename a contract" }
|
|
1025
|
+
],
|
|
1026
|
+
output: contractItem,
|
|
1027
|
+
async run(c) {
|
|
1028
|
+
const res = await c.var.openfort.contracts.update(c.args.id, {
|
|
1029
|
+
name: c.options.name,
|
|
1030
|
+
address: c.options.address,
|
|
1031
|
+
chainId: c.options.chainId,
|
|
1032
|
+
abi: c.options.abi ? JSON.parse(c.options.abi) : void 0
|
|
1033
|
+
});
|
|
1034
|
+
return c.ok({
|
|
1035
|
+
id: res.id,
|
|
1036
|
+
createdAt: res.createdAt,
|
|
1037
|
+
name: res.name,
|
|
1038
|
+
chainId: res.chainId,
|
|
1039
|
+
address: res.address,
|
|
1040
|
+
deleted: res.deleted,
|
|
1041
|
+
abi: res.abi,
|
|
1042
|
+
publicVerification: res.publicVerification
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
contracts.command("delete", {
|
|
1047
|
+
description: "Delete a contract.",
|
|
1048
|
+
args: z4.object({
|
|
1049
|
+
id: z4.string().describe("Contract ID (con_...)")
|
|
1050
|
+
}),
|
|
1051
|
+
examples: [
|
|
1052
|
+
{ args: { id: "con_1a2b3c4d" }, description: "Delete a contract" }
|
|
1053
|
+
],
|
|
1054
|
+
output: z4.object({
|
|
1055
|
+
id: z4.string(),
|
|
1056
|
+
deleted: z4.boolean()
|
|
1057
|
+
}),
|
|
1058
|
+
async run(c) {
|
|
1059
|
+
const res = await c.var.openfort.contracts.delete(c.args.id);
|
|
1060
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
// src/commands/paymasters.ts
|
|
1065
|
+
import { Cli as Cli3, z as z5 } from "incur";
|
|
1066
|
+
var paymasterItem = z5.object({
|
|
1067
|
+
id: z5.string(),
|
|
1068
|
+
createdAt: z5.number(),
|
|
1069
|
+
address: z5.string(),
|
|
1070
|
+
url: z5.string().optional(),
|
|
1071
|
+
context: z5.record(z5.string(), z5.unknown()).optional()
|
|
1072
|
+
});
|
|
1073
|
+
var paymasters = Cli3.create("paymasters", {
|
|
1074
|
+
description: "Manage ERC-4337 paymasters.",
|
|
1075
|
+
vars: varsSchema
|
|
1076
|
+
});
|
|
1077
|
+
paymasters.command("create", {
|
|
1078
|
+
description: "Create a paymaster.",
|
|
1079
|
+
options: z5.object({
|
|
1080
|
+
address: z5.string().describe("Paymaster contract address"),
|
|
1081
|
+
name: z5.string().optional().describe("Paymaster name"),
|
|
1082
|
+
url: z5.string().optional().describe("Paymaster URL")
|
|
1083
|
+
}),
|
|
1084
|
+
examples: [
|
|
1085
|
+
{ options: { address: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", name: "EntryPoint v0.6 Paymaster" }, description: "Create a paymaster for ERC-4337 v0.6" }
|
|
1086
|
+
],
|
|
1087
|
+
output: paymasterItem,
|
|
1088
|
+
async run(c) {
|
|
1089
|
+
const res = await c.var.openfort.paymasters.create({
|
|
1090
|
+
address: c.options.address,
|
|
1091
|
+
name: c.options.name,
|
|
1092
|
+
url: c.options.url
|
|
1093
|
+
});
|
|
1094
|
+
return c.ok(
|
|
1095
|
+
{
|
|
1096
|
+
id: res.id,
|
|
1097
|
+
createdAt: res.createdAt,
|
|
1098
|
+
address: res.address,
|
|
1099
|
+
url: res.url,
|
|
1100
|
+
context: res.context
|
|
1101
|
+
},
|
|
1102
|
+
{
|
|
1103
|
+
cta: {
|
|
1104
|
+
description: "Next steps:",
|
|
1105
|
+
commands: [
|
|
1106
|
+
{ command: `paymasters get ${res.id}`, description: "View this paymaster" },
|
|
1107
|
+
{ command: "sponsorship create", description: "Create a fee sponsorship" }
|
|
1108
|
+
]
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
paymasters.command("get", {
|
|
1115
|
+
description: "Get a paymaster by ID.",
|
|
1116
|
+
args: z5.object({
|
|
1117
|
+
id: z5.string().describe("Paymaster ID (pay_...)")
|
|
1118
|
+
}),
|
|
1119
|
+
examples: [
|
|
1120
|
+
{ args: { id: "pay_1a2b3c4d" }, description: "Get paymaster details" }
|
|
1121
|
+
],
|
|
1122
|
+
output: paymasterItem,
|
|
1123
|
+
async run(c) {
|
|
1124
|
+
const p = await c.var.openfort.paymasters.get(c.args.id);
|
|
1125
|
+
return c.ok({
|
|
1126
|
+
id: p.id,
|
|
1127
|
+
createdAt: p.createdAt,
|
|
1128
|
+
address: p.address,
|
|
1129
|
+
url: p.url,
|
|
1130
|
+
context: p.context
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
paymasters.command("update", {
|
|
1135
|
+
description: "Update a paymaster.",
|
|
1136
|
+
args: z5.object({
|
|
1137
|
+
id: z5.string().describe("Paymaster ID (pay_...)")
|
|
1138
|
+
}),
|
|
1139
|
+
options: z5.object({
|
|
1140
|
+
address: z5.string().describe("Paymaster address"),
|
|
1141
|
+
name: z5.string().optional().describe("New name"),
|
|
1142
|
+
url: z5.string().optional().describe("New URL")
|
|
1143
|
+
}),
|
|
1144
|
+
examples: [
|
|
1145
|
+
{ args: { id: "pay_1a2b3c4d" }, options: { address: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", name: "Updated Paymaster" }, description: "Update paymaster name" }
|
|
1146
|
+
],
|
|
1147
|
+
output: paymasterItem,
|
|
1148
|
+
async run(c) {
|
|
1149
|
+
const res = await c.var.openfort.paymasters.update(c.args.id, {
|
|
1150
|
+
address: c.options.address,
|
|
1151
|
+
name: c.options.name,
|
|
1152
|
+
url: c.options.url
|
|
1153
|
+
});
|
|
1154
|
+
return c.ok({
|
|
1155
|
+
id: res.id,
|
|
1156
|
+
createdAt: res.createdAt,
|
|
1157
|
+
address: res.address,
|
|
1158
|
+
url: res.url,
|
|
1159
|
+
context: res.context
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
paymasters.command("delete", {
|
|
1164
|
+
description: "Delete a paymaster.",
|
|
1165
|
+
args: z5.object({
|
|
1166
|
+
id: z5.string().describe("Paymaster ID (pay_...)")
|
|
1167
|
+
}),
|
|
1168
|
+
examples: [
|
|
1169
|
+
{ args: { id: "pay_1a2b3c4d" }, description: "Delete a paymaster" }
|
|
1170
|
+
],
|
|
1171
|
+
output: z5.object({
|
|
1172
|
+
id: z5.string(),
|
|
1173
|
+
deleted: z5.boolean()
|
|
1174
|
+
}),
|
|
1175
|
+
async run(c) {
|
|
1176
|
+
const res = await c.var.openfort.paymasters.delete(c.args.id);
|
|
1177
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
// src/commands/policies.ts
|
|
1182
|
+
import { Cli as Cli4, z as z6 } from "incur";
|
|
1183
|
+
var policyScopes = ["project", "account", "transaction"];
|
|
1184
|
+
var policies = Cli4.create("policies", {
|
|
1185
|
+
description: "Manage access-control policies.",
|
|
1186
|
+
vars: varsSchema
|
|
1187
|
+
});
|
|
1188
|
+
policies.command("list", {
|
|
1189
|
+
description: "List policies.",
|
|
1190
|
+
options: z6.object({
|
|
1191
|
+
limit: z6.number().optional().describe("Max results"),
|
|
1192
|
+
skip: z6.number().optional().describe("Offset"),
|
|
1193
|
+
scope: z6.enum(policyScopes).optional().describe("Filter by scope"),
|
|
1194
|
+
enabled: z6.boolean().optional().describe("Filter by enabled status")
|
|
1195
|
+
}),
|
|
1196
|
+
alias: { limit: "l" },
|
|
1197
|
+
examples: [
|
|
1198
|
+
{ description: "List all policies" },
|
|
1199
|
+
{ options: { scope: "project", enabled: true }, description: "List enabled project-scope policies" }
|
|
1200
|
+
],
|
|
1201
|
+
output: z6.object({
|
|
1202
|
+
data: z6.array(z6.object({
|
|
1203
|
+
id: z6.string(),
|
|
1204
|
+
createdAt: z6.number(),
|
|
1205
|
+
scope: z6.string(),
|
|
1206
|
+
description: z6.string().nullable(),
|
|
1207
|
+
accountId: z6.string().nullable(),
|
|
1208
|
+
enabled: z6.boolean(),
|
|
1209
|
+
priority: z6.number()
|
|
1210
|
+
})),
|
|
1211
|
+
total: z6.number()
|
|
1212
|
+
}),
|
|
1213
|
+
async run(c) {
|
|
1214
|
+
const scopeFilter = c.options.scope ? [c.options.scope] : void 0;
|
|
1215
|
+
const res = await c.var.openfort.policies.list({
|
|
1216
|
+
limit: c.options.limit,
|
|
1217
|
+
skip: c.options.skip,
|
|
1218
|
+
scope: scopeFilter,
|
|
1219
|
+
enabled: c.options.enabled
|
|
1220
|
+
});
|
|
1221
|
+
return c.ok({
|
|
1222
|
+
data: res.data.map((p) => ({
|
|
1223
|
+
id: p.id,
|
|
1224
|
+
createdAt: p.createdAt,
|
|
1225
|
+
scope: p.scope,
|
|
1226
|
+
description: p.description,
|
|
1227
|
+
accountId: p.accountId,
|
|
1228
|
+
enabled: p.enabled,
|
|
1229
|
+
priority: p.priority
|
|
1230
|
+
})),
|
|
1231
|
+
total: res.total
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
policies.command("create", {
|
|
1236
|
+
description: "Create a policy with criteria-based rules.",
|
|
1237
|
+
options: z6.object({
|
|
1238
|
+
scope: z6.enum(policyScopes).describe("Policy scope"),
|
|
1239
|
+
description: z6.string().optional().describe("Policy description"),
|
|
1240
|
+
priority: z6.number().optional().describe("Priority (higher = evaluated first)"),
|
|
1241
|
+
rules: z6.string().describe("Rules as JSON string")
|
|
1242
|
+
}),
|
|
1243
|
+
output: z6.object({
|
|
1244
|
+
id: z6.string(),
|
|
1245
|
+
createdAt: z6.number(),
|
|
1246
|
+
scope: z6.string(),
|
|
1247
|
+
description: z6.string().nullable(),
|
|
1248
|
+
enabled: z6.boolean(),
|
|
1249
|
+
priority: z6.number()
|
|
1250
|
+
}),
|
|
1251
|
+
examples: [
|
|
1252
|
+
{
|
|
1253
|
+
options: {
|
|
1254
|
+
scope: "project",
|
|
1255
|
+
rules: '[{"action":"accept","operation":"sponsorEvmTransaction","criteria":[{"type":"evmNetwork","operator":"in","chainIds":[137]}]}]'
|
|
1256
|
+
},
|
|
1257
|
+
description: "Create a policy to sponsor transactions on Polygon"
|
|
1258
|
+
}
|
|
1259
|
+
],
|
|
1260
|
+
async run(c) {
|
|
1261
|
+
const rules = JSON.parse(c.options.rules);
|
|
1262
|
+
const scope = c.options.scope;
|
|
1263
|
+
const res = await c.var.openfort.policies.create({
|
|
1264
|
+
scope,
|
|
1265
|
+
description: c.options.description,
|
|
1266
|
+
priority: c.options.priority,
|
|
1267
|
+
rules
|
|
1268
|
+
});
|
|
1269
|
+
return c.ok(
|
|
1270
|
+
{
|
|
1271
|
+
id: res.id,
|
|
1272
|
+
createdAt: res.createdAt,
|
|
1273
|
+
scope: res.scope,
|
|
1274
|
+
description: res.description,
|
|
1275
|
+
enabled: res.enabled,
|
|
1276
|
+
priority: res.priority
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
cta: {
|
|
1280
|
+
description: "Next steps:",
|
|
1281
|
+
commands: [
|
|
1282
|
+
{ command: `policies get ${res.id}`, description: "View this policy" },
|
|
1283
|
+
{ command: `sponsorship create --policyId ${res.id}`, description: "Create a fee sponsorship" }
|
|
1284
|
+
]
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
policies.command("get", {
|
|
1291
|
+
description: "Get a policy by ID.",
|
|
1292
|
+
args: z6.object({
|
|
1293
|
+
id: z6.string().describe("Policy ID (ply_...)")
|
|
1294
|
+
}),
|
|
1295
|
+
examples: [
|
|
1296
|
+
{ args: { id: "ply_1a2b3c4d" }, description: "Get policy details with rules" }
|
|
1297
|
+
],
|
|
1298
|
+
output: z6.object({
|
|
1299
|
+
id: z6.string(),
|
|
1300
|
+
createdAt: z6.number(),
|
|
1301
|
+
scope: z6.string(),
|
|
1302
|
+
description: z6.string().nullable(),
|
|
1303
|
+
accountId: z6.string().nullable(),
|
|
1304
|
+
enabled: z6.boolean(),
|
|
1305
|
+
priority: z6.number(),
|
|
1306
|
+
rules: z6.array(z6.any())
|
|
1307
|
+
}),
|
|
1308
|
+
async run(c) {
|
|
1309
|
+
const p = await c.var.openfort.policies.get(c.args.id);
|
|
1310
|
+
return c.ok({
|
|
1311
|
+
id: p.id,
|
|
1312
|
+
createdAt: p.createdAt,
|
|
1313
|
+
scope: p.scope,
|
|
1314
|
+
description: p.description,
|
|
1315
|
+
accountId: p.accountId,
|
|
1316
|
+
enabled: p.enabled,
|
|
1317
|
+
priority: p.priority,
|
|
1318
|
+
rules: p.rules
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
policies.command("update", {
|
|
1323
|
+
description: "Update a policy.",
|
|
1324
|
+
args: z6.object({
|
|
1325
|
+
id: z6.string().describe("Policy ID (ply_...)")
|
|
1326
|
+
}),
|
|
1327
|
+
options: z6.object({
|
|
1328
|
+
description: z6.string().optional().describe("New description"),
|
|
1329
|
+
enabled: z6.boolean().optional().describe("Enable or disable"),
|
|
1330
|
+
priority: z6.number().optional().describe("New priority"),
|
|
1331
|
+
rules: z6.string().optional().describe("New rules as JSON string")
|
|
1332
|
+
}),
|
|
1333
|
+
examples: [
|
|
1334
|
+
{ args: { id: "ply_1a2b3c4d" }, options: { enabled: false }, description: "Disable a policy" },
|
|
1335
|
+
{ args: { id: "ply_1a2b3c4d" }, options: { priority: 10 }, description: "Change policy priority" }
|
|
1336
|
+
],
|
|
1337
|
+
output: z6.object({
|
|
1338
|
+
id: z6.string(),
|
|
1339
|
+
createdAt: z6.number(),
|
|
1340
|
+
scope: z6.string(),
|
|
1341
|
+
description: z6.string().nullable(),
|
|
1342
|
+
enabled: z6.boolean(),
|
|
1343
|
+
priority: z6.number()
|
|
1344
|
+
}),
|
|
1345
|
+
async run(c) {
|
|
1346
|
+
const res = await c.var.openfort.policies.update(c.args.id, {
|
|
1347
|
+
description: c.options.description,
|
|
1348
|
+
enabled: c.options.enabled,
|
|
1349
|
+
priority: c.options.priority,
|
|
1350
|
+
rules: c.options.rules ? JSON.parse(c.options.rules) : void 0
|
|
1351
|
+
});
|
|
1352
|
+
return c.ok({
|
|
1353
|
+
id: res.id,
|
|
1354
|
+
createdAt: res.createdAt,
|
|
1355
|
+
scope: res.scope,
|
|
1356
|
+
description: res.description,
|
|
1357
|
+
enabled: res.enabled,
|
|
1358
|
+
priority: res.priority
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
policies.command("delete", {
|
|
1363
|
+
description: "Delete a policy.",
|
|
1364
|
+
args: z6.object({
|
|
1365
|
+
id: z6.string().describe("Policy ID (ply_...)")
|
|
1366
|
+
}),
|
|
1367
|
+
examples: [
|
|
1368
|
+
{ args: { id: "ply_1a2b3c4d" }, description: "Delete a policy" }
|
|
1369
|
+
],
|
|
1370
|
+
output: z6.object({
|
|
1371
|
+
id: z6.string(),
|
|
1372
|
+
deleted: z6.boolean()
|
|
1373
|
+
}),
|
|
1374
|
+
async run(c) {
|
|
1375
|
+
const res = await c.var.openfort.policies.delete(c.args.id);
|
|
1376
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
policies.command("evaluate", {
|
|
1380
|
+
description: "Pre-flight check if an operation would be allowed.",
|
|
1381
|
+
options: z6.object({
|
|
1382
|
+
operation: z6.string().describe("Operation to evaluate (e.g. signEvmTransaction)"),
|
|
1383
|
+
accountId: z6.string().optional().describe("Account ID")
|
|
1384
|
+
}),
|
|
1385
|
+
examples: [
|
|
1386
|
+
{ options: { operation: "signEvmTransaction", accountId: "acc_1a2b3c4d" }, description: "Check if EVM signing is allowed" },
|
|
1387
|
+
{ options: { operation: "sponsorEvmTransaction" }, description: "Check if gas sponsorship is allowed" }
|
|
1388
|
+
],
|
|
1389
|
+
output: z6.object({
|
|
1390
|
+
allowed: z6.boolean(),
|
|
1391
|
+
reason: z6.string(),
|
|
1392
|
+
operation: z6.string(),
|
|
1393
|
+
accountId: z6.string().optional(),
|
|
1394
|
+
matchedPolicyId: z6.string().optional(),
|
|
1395
|
+
matchedRuleId: z6.string().optional()
|
|
1396
|
+
}),
|
|
1397
|
+
async run(c) {
|
|
1398
|
+
const res = await c.var.openfort.policies.evaluate({
|
|
1399
|
+
operation: c.options.operation,
|
|
1400
|
+
accountId: c.options.accountId
|
|
1401
|
+
});
|
|
1402
|
+
return c.ok({
|
|
1403
|
+
allowed: res.allowed,
|
|
1404
|
+
reason: res.reason,
|
|
1405
|
+
operation: res.operation,
|
|
1406
|
+
accountId: res.accountId,
|
|
1407
|
+
matchedPolicyId: res.matchedPolicyId,
|
|
1408
|
+
matchedRuleId: res.matchedRuleId
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
// src/commands/sponsorship.ts
|
|
1414
|
+
import { Cli as Cli5, z as z7 } from "incur";
|
|
1415
|
+
var sponsorSchemas = ["pay_for_user", "charge_custom_tokens", "fixed_rate"];
|
|
1416
|
+
var sponsorshipItem = z7.object({
|
|
1417
|
+
id: z7.string(),
|
|
1418
|
+
createdAt: z7.number(),
|
|
1419
|
+
name: z7.string().nullable(),
|
|
1420
|
+
chainId: z7.number().nullable(),
|
|
1421
|
+
enabled: z7.boolean(),
|
|
1422
|
+
strategy: z7.object({
|
|
1423
|
+
sponsorSchema: z7.string(),
|
|
1424
|
+
tokenContract: z7.string().optional(),
|
|
1425
|
+
tokenContractAmount: z7.string().optional(),
|
|
1426
|
+
dynamicExchangeRate: z7.boolean().optional()
|
|
1427
|
+
}),
|
|
1428
|
+
paymasterId: z7.string().nullable(),
|
|
1429
|
+
policyId: z7.string().nullable()
|
|
1430
|
+
});
|
|
1431
|
+
var sponsorship = Cli5.create("sponsorship", {
|
|
1432
|
+
description: "Manage fee sponsorships for gas costs.",
|
|
1433
|
+
vars: varsSchema
|
|
1434
|
+
});
|
|
1435
|
+
sponsorship.command("list", {
|
|
1436
|
+
description: "List fee sponsorships.",
|
|
1437
|
+
options: z7.object({
|
|
1438
|
+
limit: z7.number().optional().describe("Max results"),
|
|
1439
|
+
skip: z7.number().optional().describe("Offset"),
|
|
1440
|
+
enabled: z7.boolean().optional().describe("Filter by enabled status")
|
|
1441
|
+
}),
|
|
1442
|
+
alias: { limit: "l" },
|
|
1443
|
+
examples: [
|
|
1444
|
+
{ description: "List all sponsorships" },
|
|
1445
|
+
{ options: { enabled: true }, description: "List active sponsorships only" }
|
|
1446
|
+
],
|
|
1447
|
+
output: z7.object({
|
|
1448
|
+
data: z7.array(sponsorshipItem),
|
|
1449
|
+
total: z7.number()
|
|
1450
|
+
}),
|
|
1451
|
+
async run(c) {
|
|
1452
|
+
const res = await c.var.openfort.feeSponsorship.list({
|
|
1453
|
+
limit: c.options.limit,
|
|
1454
|
+
skip: c.options.skip,
|
|
1455
|
+
enabled: c.options.enabled
|
|
1456
|
+
});
|
|
1457
|
+
return c.ok({
|
|
1458
|
+
data: res.data.map((s) => ({
|
|
1459
|
+
id: s.id,
|
|
1460
|
+
createdAt: s.createdAt,
|
|
1461
|
+
name: s.name,
|
|
1462
|
+
chainId: s.chainId,
|
|
1463
|
+
enabled: s.enabled,
|
|
1464
|
+
strategy: s.strategy,
|
|
1465
|
+
paymasterId: s.paymasterId,
|
|
1466
|
+
policyId: s.policyId
|
|
1467
|
+
})),
|
|
1468
|
+
total: res.total
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
sponsorship.command("create", {
|
|
1473
|
+
description: "Create a fee sponsorship linked to a policy.",
|
|
1474
|
+
options: z7.object({
|
|
1475
|
+
policyId: z7.string().describe("Policy ID to link (ply_...)"),
|
|
1476
|
+
name: z7.string().optional().describe("Sponsorship name"),
|
|
1477
|
+
strategy: z7.enum(sponsorSchemas).default("pay_for_user").describe("Sponsorship strategy"),
|
|
1478
|
+
chainId: z7.number().optional().describe("Chain ID")
|
|
1479
|
+
}),
|
|
1480
|
+
output: sponsorshipItem,
|
|
1481
|
+
examples: [
|
|
1482
|
+
{
|
|
1483
|
+
options: { policyId: "ply_1a2b3c4d", strategy: "pay_for_user", name: "Polygon Gas Sponsor" },
|
|
1484
|
+
description: "Sponsor gas fees for users on Polygon"
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
options: { policyId: "ply_1a2b3c4d", strategy: "charge_custom_tokens", chainId: 137 },
|
|
1488
|
+
description: "Pay gas with custom tokens on chain 137"
|
|
1489
|
+
}
|
|
1490
|
+
],
|
|
1491
|
+
async run(c) {
|
|
1492
|
+
const strategy = { sponsorSchema: c.options.strategy };
|
|
1493
|
+
const res = await c.var.openfort.feeSponsorship.create({
|
|
1494
|
+
policyId: c.options.policyId,
|
|
1495
|
+
name: c.options.name,
|
|
1496
|
+
strategy,
|
|
1497
|
+
chainId: c.options.chainId
|
|
1498
|
+
});
|
|
1499
|
+
return c.ok(
|
|
1500
|
+
{
|
|
1501
|
+
id: res.id,
|
|
1502
|
+
createdAt: res.createdAt,
|
|
1503
|
+
name: res.name,
|
|
1504
|
+
chainId: res.chainId,
|
|
1505
|
+
enabled: res.enabled,
|
|
1506
|
+
strategy: res.strategy,
|
|
1507
|
+
paymasterId: res.paymasterId,
|
|
1508
|
+
policyId: res.policyId
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
cta: {
|
|
1512
|
+
description: "Next steps:",
|
|
1513
|
+
commands: [
|
|
1514
|
+
{ command: `sponsorship get ${res.id}`, description: "View this sponsorship" },
|
|
1515
|
+
{ command: "transactions create", description: "Create a sponsored transaction" }
|
|
1516
|
+
]
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
sponsorship.command("get", {
|
|
1523
|
+
description: "Get a fee sponsorship by ID.",
|
|
1524
|
+
args: z7.object({
|
|
1525
|
+
id: z7.string().describe("Fee sponsorship ID (pol_...)")
|
|
1526
|
+
}),
|
|
1527
|
+
examples: [
|
|
1528
|
+
{ args: { id: "pol_1a2b3c4d" }, description: "Get sponsorship details" }
|
|
1529
|
+
],
|
|
1530
|
+
output: sponsorshipItem,
|
|
1531
|
+
async run(c) {
|
|
1532
|
+
const s = await c.var.openfort.feeSponsorship.get(c.args.id);
|
|
1533
|
+
return c.ok({
|
|
1534
|
+
id: s.id,
|
|
1535
|
+
createdAt: s.createdAt,
|
|
1536
|
+
name: s.name,
|
|
1537
|
+
chainId: s.chainId,
|
|
1538
|
+
enabled: s.enabled,
|
|
1539
|
+
strategy: s.strategy,
|
|
1540
|
+
paymasterId: s.paymasterId,
|
|
1541
|
+
policyId: s.policyId
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
sponsorship.command("update", {
|
|
1546
|
+
description: "Update a fee sponsorship.",
|
|
1547
|
+
args: z7.object({
|
|
1548
|
+
id: z7.string().describe("Fee sponsorship ID (pol_...)")
|
|
1549
|
+
}),
|
|
1550
|
+
options: z7.object({
|
|
1551
|
+
name: z7.string().optional().describe("New name"),
|
|
1552
|
+
strategy: z7.enum(sponsorSchemas).optional().describe("New strategy"),
|
|
1553
|
+
policyId: z7.string().optional().describe("New policy ID")
|
|
1554
|
+
}),
|
|
1555
|
+
examples: [
|
|
1556
|
+
{ args: { id: "pol_1a2b3c4d" }, options: { name: "Mainnet Gas Sponsor" }, description: "Rename a sponsorship" }
|
|
1557
|
+
],
|
|
1558
|
+
output: sponsorshipItem,
|
|
1559
|
+
async run(c) {
|
|
1560
|
+
const strategy = c.options.strategy ? { sponsorSchema: c.options.strategy } : void 0;
|
|
1561
|
+
const res = await c.var.openfort.feeSponsorship.update(c.args.id, {
|
|
1562
|
+
name: c.options.name,
|
|
1563
|
+
strategy,
|
|
1564
|
+
policyId: c.options.policyId
|
|
1565
|
+
});
|
|
1566
|
+
return c.ok({
|
|
1567
|
+
id: res.id,
|
|
1568
|
+
createdAt: res.createdAt,
|
|
1569
|
+
name: res.name,
|
|
1570
|
+
chainId: res.chainId,
|
|
1571
|
+
enabled: res.enabled,
|
|
1572
|
+
strategy: res.strategy,
|
|
1573
|
+
paymasterId: res.paymasterId,
|
|
1574
|
+
policyId: res.policyId
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
sponsorship.command("enable", {
|
|
1579
|
+
description: "Enable a fee sponsorship.",
|
|
1580
|
+
args: z7.object({
|
|
1581
|
+
id: z7.string().describe("Fee sponsorship ID (pol_...)")
|
|
1582
|
+
}),
|
|
1583
|
+
examples: [
|
|
1584
|
+
{ args: { id: "pol_1a2b3c4d" }, description: "Enable a sponsorship" }
|
|
1585
|
+
],
|
|
1586
|
+
output: sponsorshipItem,
|
|
1587
|
+
async run(c) {
|
|
1588
|
+
const res = await c.var.openfort.feeSponsorship.enable(c.args.id);
|
|
1589
|
+
return c.ok({
|
|
1590
|
+
id: res.id,
|
|
1591
|
+
createdAt: res.createdAt,
|
|
1592
|
+
name: res.name,
|
|
1593
|
+
chainId: res.chainId,
|
|
1594
|
+
enabled: res.enabled,
|
|
1595
|
+
strategy: res.strategy,
|
|
1596
|
+
paymasterId: res.paymasterId,
|
|
1597
|
+
policyId: res.policyId
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
});
|
|
1601
|
+
sponsorship.command("disable", {
|
|
1602
|
+
description: "Disable a fee sponsorship.",
|
|
1603
|
+
args: z7.object({
|
|
1604
|
+
id: z7.string().describe("Fee sponsorship ID (pol_...)")
|
|
1605
|
+
}),
|
|
1606
|
+
examples: [
|
|
1607
|
+
{ args: { id: "pol_1a2b3c4d" }, description: "Disable a sponsorship" }
|
|
1608
|
+
],
|
|
1609
|
+
output: sponsorshipItem,
|
|
1610
|
+
async run(c) {
|
|
1611
|
+
const res = await c.var.openfort.feeSponsorship.disable(c.args.id);
|
|
1612
|
+
return c.ok({
|
|
1613
|
+
id: res.id,
|
|
1614
|
+
createdAt: res.createdAt,
|
|
1615
|
+
name: res.name,
|
|
1616
|
+
chainId: res.chainId,
|
|
1617
|
+
enabled: res.enabled,
|
|
1618
|
+
strategy: res.strategy,
|
|
1619
|
+
paymasterId: res.paymasterId,
|
|
1620
|
+
policyId: res.policyId
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
sponsorship.command("delete", {
|
|
1625
|
+
description: "Delete a fee sponsorship.",
|
|
1626
|
+
args: z7.object({
|
|
1627
|
+
id: z7.string().describe("Fee sponsorship ID (pol_...)")
|
|
1628
|
+
}),
|
|
1629
|
+
examples: [
|
|
1630
|
+
{ args: { id: "pol_1a2b3c4d" }, description: "Delete a sponsorship" }
|
|
1631
|
+
],
|
|
1632
|
+
output: z7.object({
|
|
1633
|
+
id: z7.string(),
|
|
1634
|
+
deleted: z7.boolean()
|
|
1635
|
+
}),
|
|
1636
|
+
async run(c) {
|
|
1637
|
+
const res = await c.var.openfort.feeSponsorship.delete(c.args.id);
|
|
1638
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
// src/commands/subscriptions.ts
|
|
1643
|
+
import { Cli as Cli6, z as z8 } from "incur";
|
|
1644
|
+
var apiTopics = [
|
|
1645
|
+
"transaction_intent.broadcast",
|
|
1646
|
+
"transaction_intent.successful",
|
|
1647
|
+
"transaction_intent.cancelled",
|
|
1648
|
+
"transaction_intent.failed",
|
|
1649
|
+
"balance.project",
|
|
1650
|
+
"balance.contract",
|
|
1651
|
+
"balance.dev_account",
|
|
1652
|
+
"test",
|
|
1653
|
+
"user.created",
|
|
1654
|
+
"user.updated",
|
|
1655
|
+
"user.deleted",
|
|
1656
|
+
"account.created"
|
|
1657
|
+
];
|
|
1658
|
+
var apiTriggerTypes = ["webhook", "email"];
|
|
1659
|
+
var triggers = Cli6.create("triggers", {
|
|
1660
|
+
description: "Manage subscription triggers.",
|
|
1661
|
+
vars: varsSchema
|
|
1662
|
+
});
|
|
1663
|
+
triggers.command("list", {
|
|
1664
|
+
description: "List triggers for a subscription.",
|
|
1665
|
+
args: z8.object({
|
|
1666
|
+
subscriptionId: z8.string().describe("Subscription ID (sub_...)")
|
|
1667
|
+
}),
|
|
1668
|
+
examples: [
|
|
1669
|
+
{ args: { subscriptionId: "sub_1a2b3c4d" }, description: "List triggers" }
|
|
1670
|
+
],
|
|
1671
|
+
output: z8.object({
|
|
1672
|
+
data: z8.array(z8.object({
|
|
1673
|
+
id: z8.string(),
|
|
1674
|
+
createdAt: z8.number(),
|
|
1675
|
+
target: z8.string(),
|
|
1676
|
+
type: z8.string()
|
|
1677
|
+
}))
|
|
1678
|
+
}),
|
|
1679
|
+
async run(c) {
|
|
1680
|
+
const res = await c.var.openfort.triggers.list(c.args.subscriptionId);
|
|
1681
|
+
return c.ok({
|
|
1682
|
+
data: res.data.map((t) => ({
|
|
1683
|
+
id: t.id,
|
|
1684
|
+
createdAt: t.createdAt,
|
|
1685
|
+
target: t.target,
|
|
1686
|
+
type: t.type
|
|
1687
|
+
}))
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
triggers.command("create", {
|
|
1692
|
+
description: "Create a trigger for a subscription.",
|
|
1693
|
+
args: z8.object({
|
|
1694
|
+
subscriptionId: z8.string().describe("Subscription ID (sub_...)")
|
|
1695
|
+
}),
|
|
1696
|
+
options: z8.object({
|
|
1697
|
+
target: z8.string().describe("Webhook URL or email address"),
|
|
1698
|
+
type: z8.enum(apiTriggerTypes).default("webhook").describe("Trigger type: webhook or email")
|
|
1699
|
+
}),
|
|
1700
|
+
examples: [
|
|
1701
|
+
{
|
|
1702
|
+
args: { subscriptionId: "sub_1a2b3c4d" },
|
|
1703
|
+
options: { target: "https://myapp.com/webhooks", type: "webhook" },
|
|
1704
|
+
description: "Create a webhook trigger"
|
|
1705
|
+
}
|
|
1706
|
+
],
|
|
1707
|
+
output: z8.object({
|
|
1708
|
+
id: z8.string(),
|
|
1709
|
+
createdAt: z8.number(),
|
|
1710
|
+
target: z8.string(),
|
|
1711
|
+
type: z8.string()
|
|
1712
|
+
}),
|
|
1713
|
+
async run(c) {
|
|
1714
|
+
const res = await c.var.openfort.triggers.create(c.args.subscriptionId, {
|
|
1715
|
+
target: c.options.target,
|
|
1716
|
+
type: c.options.type
|
|
1717
|
+
});
|
|
1718
|
+
return c.ok({
|
|
1719
|
+
id: res.id,
|
|
1720
|
+
createdAt: res.createdAt,
|
|
1721
|
+
target: res.target,
|
|
1722
|
+
type: res.type
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
triggers.command("get", {
|
|
1727
|
+
description: "Get a trigger by ID.",
|
|
1728
|
+
args: z8.object({
|
|
1729
|
+
subscriptionId: z8.string().describe("Subscription ID (sub_...)"),
|
|
1730
|
+
triggerId: z8.string().describe("Trigger ID (tri_...)")
|
|
1731
|
+
}),
|
|
1732
|
+
examples: [
|
|
1733
|
+
{ args: { subscriptionId: "sub_1a2b3c4d", triggerId: "tri_1a2b3c4d" }, description: "Get trigger details" }
|
|
1734
|
+
],
|
|
1735
|
+
output: z8.object({
|
|
1736
|
+
id: z8.string(),
|
|
1737
|
+
createdAt: z8.number(),
|
|
1738
|
+
target: z8.string(),
|
|
1739
|
+
type: z8.string()
|
|
1740
|
+
}),
|
|
1741
|
+
async run(c) {
|
|
1742
|
+
const t = await c.var.openfort.triggers.get(c.args.subscriptionId, c.args.triggerId);
|
|
1743
|
+
return c.ok({
|
|
1744
|
+
id: t.id,
|
|
1745
|
+
createdAt: t.createdAt,
|
|
1746
|
+
target: t.target,
|
|
1747
|
+
type: t.type
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
triggers.command("delete", {
|
|
1752
|
+
description: "Delete a trigger.",
|
|
1753
|
+
args: z8.object({
|
|
1754
|
+
subscriptionId: z8.string().describe("Subscription ID (sub_...)"),
|
|
1755
|
+
triggerId: z8.string().describe("Trigger ID (tri_...)")
|
|
1756
|
+
}),
|
|
1757
|
+
examples: [
|
|
1758
|
+
{ args: { subscriptionId: "sub_1a2b3c4d", triggerId: "tri_1a2b3c4d" }, description: "Delete a trigger" }
|
|
1759
|
+
],
|
|
1760
|
+
output: z8.object({
|
|
1761
|
+
id: z8.string(),
|
|
1762
|
+
deleted: z8.boolean()
|
|
1763
|
+
}),
|
|
1764
|
+
async run(c) {
|
|
1765
|
+
const res = await c.var.openfort.triggers.delete(c.args.subscriptionId, c.args.triggerId);
|
|
1766
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1767
|
+
}
|
|
1768
|
+
});
|
|
1769
|
+
var subscriptions = Cli6.create("subscriptions", {
|
|
1770
|
+
description: "Manage webhook subscriptions.",
|
|
1771
|
+
vars: varsSchema
|
|
1772
|
+
});
|
|
1773
|
+
subscriptions.command("list", {
|
|
1774
|
+
description: "List webhook subscriptions.",
|
|
1775
|
+
examples: [
|
|
1776
|
+
{ description: "List all subscriptions" }
|
|
1777
|
+
],
|
|
1778
|
+
output: z8.object({
|
|
1779
|
+
data: z8.array(z8.object({
|
|
1780
|
+
id: z8.string(),
|
|
1781
|
+
createdAt: z8.number(),
|
|
1782
|
+
topic: z8.string(),
|
|
1783
|
+
triggers: z8.array(z8.object({
|
|
1784
|
+
id: z8.string(),
|
|
1785
|
+
target: z8.string(),
|
|
1786
|
+
type: z8.string()
|
|
1787
|
+
}))
|
|
1788
|
+
})),
|
|
1789
|
+
total: z8.number()
|
|
1790
|
+
}),
|
|
1791
|
+
async run(c) {
|
|
1792
|
+
const res = await c.var.openfort.subscriptions.list();
|
|
1793
|
+
return c.ok({
|
|
1794
|
+
data: res.data.map((s) => ({
|
|
1795
|
+
id: s.id,
|
|
1796
|
+
createdAt: s.createdAt,
|
|
1797
|
+
topic: s.topic,
|
|
1798
|
+
triggers: s.triggers
|
|
1799
|
+
})),
|
|
1800
|
+
total: res.total
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1804
|
+
subscriptions.command("create", {
|
|
1805
|
+
description: "Create a webhook subscription.",
|
|
1806
|
+
options: z8.object({
|
|
1807
|
+
topic: z8.enum(apiTopics).describe("Event topic (e.g. transaction_intent.successful, user.created)"),
|
|
1808
|
+
triggers: z8.string().describe('Triggers as JSON: [{"type":"webhook","target":"https://..."}]')
|
|
1809
|
+
}),
|
|
1810
|
+
examples: [
|
|
1811
|
+
{
|
|
1812
|
+
options: {
|
|
1813
|
+
topic: "transaction_intent.successful",
|
|
1814
|
+
triggers: '[{"type":"webhook","target":"https://myapp.com/webhooks/openfort"}]'
|
|
1815
|
+
},
|
|
1816
|
+
description: "Get notified when transactions succeed"
|
|
1817
|
+
}
|
|
1818
|
+
],
|
|
1819
|
+
output: z8.object({
|
|
1820
|
+
id: z8.string(),
|
|
1821
|
+
createdAt: z8.number(),
|
|
1822
|
+
topic: z8.string(),
|
|
1823
|
+
triggers: z8.array(z8.object({
|
|
1824
|
+
id: z8.string(),
|
|
1825
|
+
target: z8.string(),
|
|
1826
|
+
type: z8.string()
|
|
1827
|
+
}))
|
|
1828
|
+
}),
|
|
1829
|
+
async run(c) {
|
|
1830
|
+
const parsedTriggers = JSON.parse(c.options.triggers);
|
|
1831
|
+
const res = await c.var.openfort.subscriptions.create({
|
|
1832
|
+
topic: c.options.topic,
|
|
1833
|
+
triggers: parsedTriggers
|
|
1834
|
+
});
|
|
1835
|
+
return c.ok(
|
|
1836
|
+
{
|
|
1837
|
+
id: res.id,
|
|
1838
|
+
createdAt: res.createdAt,
|
|
1839
|
+
topic: res.topic,
|
|
1840
|
+
triggers: res.triggers
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
cta: {
|
|
1844
|
+
description: "Next steps:",
|
|
1845
|
+
commands: [
|
|
1846
|
+
{ command: `subscriptions get ${res.id}`, description: "View this subscription" },
|
|
1847
|
+
{ command: "subscriptions list", description: "List all subscriptions" }
|
|
1848
|
+
]
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
subscriptions.command("get", {
|
|
1855
|
+
description: "Get a subscription by ID.",
|
|
1856
|
+
args: z8.object({
|
|
1857
|
+
id: z8.string().describe("Subscription ID (sub_...)")
|
|
1858
|
+
}),
|
|
1859
|
+
examples: [
|
|
1860
|
+
{ args: { id: "sub_1a2b3c4d" }, description: "Get subscription details" }
|
|
1861
|
+
],
|
|
1862
|
+
output: z8.object({
|
|
1863
|
+
id: z8.string(),
|
|
1864
|
+
createdAt: z8.number(),
|
|
1865
|
+
topic: z8.string(),
|
|
1866
|
+
triggers: z8.array(z8.object({
|
|
1867
|
+
id: z8.string(),
|
|
1868
|
+
target: z8.string(),
|
|
1869
|
+
type: z8.string()
|
|
1870
|
+
}))
|
|
1871
|
+
}),
|
|
1872
|
+
async run(c) {
|
|
1873
|
+
const s = await c.var.openfort.subscriptions.get(c.args.id);
|
|
1874
|
+
return c.ok({
|
|
1875
|
+
id: s.id,
|
|
1876
|
+
createdAt: s.createdAt,
|
|
1877
|
+
topic: s.topic,
|
|
1878
|
+
triggers: s.triggers
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
});
|
|
1882
|
+
subscriptions.command("delete", {
|
|
1883
|
+
description: "Delete a subscription.",
|
|
1884
|
+
args: z8.object({
|
|
1885
|
+
id: z8.string().describe("Subscription ID (sub_...)")
|
|
1886
|
+
}),
|
|
1887
|
+
examples: [
|
|
1888
|
+
{ args: { id: "sub_1a2b3c4d" }, description: "Delete a subscription" }
|
|
1889
|
+
],
|
|
1890
|
+
output: z8.object({
|
|
1891
|
+
id: z8.string(),
|
|
1892
|
+
deleted: z8.boolean()
|
|
1893
|
+
}),
|
|
1894
|
+
async run(c) {
|
|
1895
|
+
const res = await c.var.openfort.subscriptions.delete(c.args.id);
|
|
1896
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1899
|
+
subscriptions.command(triggers);
|
|
1900
|
+
|
|
1901
|
+
// src/commands/sessions.ts
|
|
1902
|
+
import { Cli as Cli7, z as z9 } from "incur";
|
|
1903
|
+
var sessionItem = z9.object({
|
|
1904
|
+
id: z9.string(),
|
|
1905
|
+
createdAt: z9.number(),
|
|
1906
|
+
updatedAt: z9.number(),
|
|
1907
|
+
address: z9.string(),
|
|
1908
|
+
validAfter: z9.string(),
|
|
1909
|
+
validUntil: z9.string(),
|
|
1910
|
+
whitelist: z9.array(z9.string()).optional(),
|
|
1911
|
+
isActive: z9.boolean(),
|
|
1912
|
+
nextAction: z9.object({
|
|
1913
|
+
type: z9.string(),
|
|
1914
|
+
payload: z9.any().optional()
|
|
1915
|
+
}).optional()
|
|
1916
|
+
});
|
|
1917
|
+
var sessions = Cli7.create("sessions", {
|
|
1918
|
+
description: "Manage session keys.",
|
|
1919
|
+
vars: varsSchema
|
|
1920
|
+
});
|
|
1921
|
+
sessions.command("list", {
|
|
1922
|
+
description: "List session keys for a player.",
|
|
1923
|
+
options: z9.object({
|
|
1924
|
+
player: z9.string().describe("Player ID (pla_...)"),
|
|
1925
|
+
limit: z9.number().optional().describe("Max results"),
|
|
1926
|
+
skip: z9.number().optional().describe("Offset")
|
|
1927
|
+
}),
|
|
1928
|
+
alias: { limit: "l" },
|
|
1929
|
+
examples: [
|
|
1930
|
+
{ options: { player: "pla_1a2b3c4d" }, description: "List sessions for a player" }
|
|
1931
|
+
],
|
|
1932
|
+
output: z9.object({
|
|
1933
|
+
data: z9.array(z9.object({
|
|
1934
|
+
id: z9.string(),
|
|
1935
|
+
createdAt: z9.number(),
|
|
1936
|
+
address: z9.string(),
|
|
1937
|
+
isActive: z9.boolean()
|
|
1938
|
+
})),
|
|
1939
|
+
total: z9.number()
|
|
1940
|
+
}),
|
|
1941
|
+
async run(c) {
|
|
1942
|
+
const res = await c.var.openfort.sessions.list({
|
|
1943
|
+
player: c.options.player,
|
|
1944
|
+
limit: c.options.limit,
|
|
1945
|
+
skip: c.options.skip
|
|
1946
|
+
});
|
|
1947
|
+
return c.ok({
|
|
1948
|
+
data: res.data.map((s) => ({
|
|
1949
|
+
id: s.id,
|
|
1950
|
+
createdAt: s.createdAt,
|
|
1951
|
+
address: s.address,
|
|
1952
|
+
isActive: s.isActive
|
|
1953
|
+
})),
|
|
1954
|
+
total: res.total
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
sessions.command("create", {
|
|
1959
|
+
description: "Create a session key.",
|
|
1960
|
+
options: z9.object({
|
|
1961
|
+
address: z9.string().describe("Session key address"),
|
|
1962
|
+
chainId: z9.number().describe("Chain ID"),
|
|
1963
|
+
validAfter: z9.number().describe("Valid after (unix timestamp in seconds)"),
|
|
1964
|
+
validUntil: z9.number().describe("Valid until (unix timestamp in seconds)"),
|
|
1965
|
+
player: z9.string().optional().describe("Player ID (pla_...)"),
|
|
1966
|
+
account: z9.string().optional().describe("Account ID (acc_...)"),
|
|
1967
|
+
limit: z9.number().optional().describe("Max session uses"),
|
|
1968
|
+
policy: z9.string().optional().describe("Policy ID for gas sponsorship (pol_...)"),
|
|
1969
|
+
whitelist: z9.string().optional().describe("Whitelisted contract addresses as JSON array")
|
|
1970
|
+
}),
|
|
1971
|
+
examples: [
|
|
1972
|
+
{
|
|
1973
|
+
options: {
|
|
1974
|
+
address: "0x1234...",
|
|
1975
|
+
chainId: 137,
|
|
1976
|
+
validAfter: 17e8,
|
|
1977
|
+
validUntil: 1700086400,
|
|
1978
|
+
player: "pla_1a2b3c4d"
|
|
1979
|
+
},
|
|
1980
|
+
description: "Create a 24h session key on Polygon"
|
|
1981
|
+
}
|
|
1982
|
+
],
|
|
1983
|
+
output: sessionItem,
|
|
1984
|
+
async run(c) {
|
|
1985
|
+
const res = await c.var.openfort.sessions.create({
|
|
1986
|
+
address: c.options.address,
|
|
1987
|
+
chainId: c.options.chainId,
|
|
1988
|
+
validAfter: c.options.validAfter,
|
|
1989
|
+
validUntil: c.options.validUntil,
|
|
1990
|
+
player: c.options.player,
|
|
1991
|
+
account: c.options.account,
|
|
1992
|
+
limit: c.options.limit,
|
|
1993
|
+
policy: c.options.policy,
|
|
1994
|
+
whitelist: c.options.whitelist ? JSON.parse(c.options.whitelist) : void 0
|
|
1995
|
+
});
|
|
1996
|
+
return c.ok(
|
|
1997
|
+
{
|
|
1998
|
+
id: res.id,
|
|
1999
|
+
createdAt: res.createdAt,
|
|
2000
|
+
updatedAt: res.updatedAt,
|
|
2001
|
+
address: res.address,
|
|
2002
|
+
validAfter: res.validAfter,
|
|
2003
|
+
validUntil: res.validUntil,
|
|
2004
|
+
whitelist: res.whitelist,
|
|
2005
|
+
isActive: res.isActive,
|
|
2006
|
+
nextAction: res.nextAction
|
|
2007
|
+
},
|
|
2008
|
+
{
|
|
2009
|
+
cta: {
|
|
2010
|
+
description: "Next steps:",
|
|
2011
|
+
commands: [
|
|
2012
|
+
{ command: `sessions get ${res.id}`, description: "View this session" }
|
|
2013
|
+
]
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
sessions.command("get", {
|
|
2020
|
+
description: "Get a session key by ID.",
|
|
2021
|
+
args: z9.object({
|
|
2022
|
+
id: z9.string().describe("Session ID (ses_...)")
|
|
2023
|
+
}),
|
|
2024
|
+
examples: [
|
|
2025
|
+
{ args: { id: "ses_1a2b3c4d" }, description: "Get session details" }
|
|
2026
|
+
],
|
|
2027
|
+
output: sessionItem,
|
|
2028
|
+
async run(c) {
|
|
2029
|
+
const s = await c.var.openfort.sessions.get(c.args.id);
|
|
2030
|
+
return c.ok({
|
|
2031
|
+
id: s.id,
|
|
2032
|
+
createdAt: s.createdAt,
|
|
2033
|
+
updatedAt: s.updatedAt,
|
|
2034
|
+
address: s.address,
|
|
2035
|
+
validAfter: s.validAfter,
|
|
2036
|
+
validUntil: s.validUntil,
|
|
2037
|
+
whitelist: s.whitelist,
|
|
2038
|
+
isActive: s.isActive,
|
|
2039
|
+
nextAction: s.nextAction
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
});
|
|
2043
|
+
sessions.command("revoke", {
|
|
2044
|
+
description: "Revoke a session key.",
|
|
2045
|
+
options: z9.object({
|
|
2046
|
+
address: z9.string().describe("Session key address to revoke"),
|
|
2047
|
+
chainId: z9.number().describe("Chain ID"),
|
|
2048
|
+
player: z9.string().optional().describe("Player ID (pla_...)"),
|
|
2049
|
+
policy: z9.string().optional().describe("Policy ID (pol_...)")
|
|
2050
|
+
}),
|
|
2051
|
+
examples: [
|
|
2052
|
+
{ options: { address: "0x1234...", chainId: 137 }, description: "Revoke a session key" }
|
|
2053
|
+
],
|
|
2054
|
+
output: sessionItem,
|
|
2055
|
+
async run(c) {
|
|
2056
|
+
const res = await c.var.openfort.sessions.revoke({
|
|
2057
|
+
address: c.options.address,
|
|
2058
|
+
chainId: c.options.chainId,
|
|
2059
|
+
player: c.options.player,
|
|
2060
|
+
policy: c.options.policy
|
|
2061
|
+
});
|
|
2062
|
+
return c.ok({
|
|
2063
|
+
id: res.id,
|
|
2064
|
+
createdAt: res.createdAt,
|
|
2065
|
+
updatedAt: res.updatedAt,
|
|
2066
|
+
address: res.address,
|
|
2067
|
+
validAfter: res.validAfter,
|
|
2068
|
+
validUntil: res.validUntil,
|
|
2069
|
+
whitelist: res.whitelist,
|
|
2070
|
+
isActive: res.isActive,
|
|
2071
|
+
nextAction: res.nextAction
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
sessions.command("sign", {
|
|
2076
|
+
description: "Sign and broadcast a session userOperationHash.",
|
|
2077
|
+
args: z9.object({
|
|
2078
|
+
id: z9.string().describe("Session ID (ses_...)")
|
|
2079
|
+
}),
|
|
2080
|
+
options: z9.object({
|
|
2081
|
+
signature: z9.string().describe("Hex signature"),
|
|
2082
|
+
optimistic: z9.boolean().optional().describe("Return before on-chain confirmation")
|
|
2083
|
+
}),
|
|
2084
|
+
examples: [
|
|
2085
|
+
{ args: { id: "ses_1a2b3c4d" }, options: { signature: "0xabcd1234..." }, description: "Sign a session" }
|
|
2086
|
+
],
|
|
2087
|
+
output: sessionItem,
|
|
2088
|
+
async run(c) {
|
|
2089
|
+
const res = await c.var.openfort.sessions.signature(c.args.id, {
|
|
2090
|
+
signature: c.options.signature,
|
|
2091
|
+
optimistic: c.options.optimistic
|
|
2092
|
+
});
|
|
2093
|
+
return c.ok({
|
|
2094
|
+
id: res.id,
|
|
2095
|
+
createdAt: res.createdAt,
|
|
2096
|
+
updatedAt: res.updatedAt,
|
|
2097
|
+
address: res.address,
|
|
2098
|
+
validAfter: res.validAfter,
|
|
2099
|
+
validUntil: res.validUntil,
|
|
2100
|
+
whitelist: res.whitelist,
|
|
2101
|
+
isActive: res.isActive,
|
|
2102
|
+
nextAction: res.nextAction
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
});
|
|
2106
|
+
|
|
2107
|
+
// src/commands/transactions.ts
|
|
2108
|
+
import { Cli as Cli8, z as z10 } from "incur";
|
|
2109
|
+
var transactionIntentItem = z10.object({
|
|
2110
|
+
id: z10.string(),
|
|
2111
|
+
createdAt: z10.number(),
|
|
2112
|
+
updatedAt: z10.number(),
|
|
2113
|
+
chainId: z10.number(),
|
|
2114
|
+
abstractionType: z10.string().describe("e.g. accountAbstractionV6, standard"),
|
|
2115
|
+
userOperationHash: z10.string().optional(),
|
|
2116
|
+
response: z10.object({
|
|
2117
|
+
createdAt: z10.number(),
|
|
2118
|
+
blockNumber: z10.number().optional(),
|
|
2119
|
+
transactionHash: z10.string().optional(),
|
|
2120
|
+
gasUsed: z10.string().optional(),
|
|
2121
|
+
gasFee: z10.string().optional(),
|
|
2122
|
+
status: z10.number().optional(),
|
|
2123
|
+
to: z10.string().optional(),
|
|
2124
|
+
error: z10.any().optional()
|
|
2125
|
+
}).optional(),
|
|
2126
|
+
interactions: z10.array(z10.object({
|
|
2127
|
+
to: z10.string().optional(),
|
|
2128
|
+
data: z10.string().optional(),
|
|
2129
|
+
value: z10.string().optional()
|
|
2130
|
+
})).optional(),
|
|
2131
|
+
nextAction: z10.object({
|
|
2132
|
+
type: z10.string(),
|
|
2133
|
+
payload: z10.any().optional()
|
|
2134
|
+
}).optional()
|
|
2135
|
+
});
|
|
2136
|
+
var transactions = Cli8.create("transactions", {
|
|
2137
|
+
description: "Manage transaction intents.",
|
|
2138
|
+
vars: varsSchema
|
|
2139
|
+
});
|
|
2140
|
+
transactions.command("list", {
|
|
2141
|
+
description: "List transaction intents.",
|
|
2142
|
+
options: z10.object({
|
|
2143
|
+
limit: z10.number().optional().describe("Max results"),
|
|
2144
|
+
skip: z10.number().optional().describe("Offset")
|
|
2145
|
+
}),
|
|
2146
|
+
alias: { limit: "l" },
|
|
2147
|
+
examples: [
|
|
2148
|
+
{ description: "List all transactions" },
|
|
2149
|
+
{ options: { limit: 10 }, description: "List last 10 transactions" }
|
|
2150
|
+
],
|
|
2151
|
+
output: z10.object({
|
|
2152
|
+
data: z10.array(z10.object({
|
|
2153
|
+
id: z10.string(),
|
|
2154
|
+
createdAt: z10.number(),
|
|
2155
|
+
updatedAt: z10.number(),
|
|
2156
|
+
chainId: z10.number(),
|
|
2157
|
+
abstractionType: z10.string()
|
|
2158
|
+
})),
|
|
2159
|
+
total: z10.number()
|
|
2160
|
+
}),
|
|
2161
|
+
async run(c) {
|
|
2162
|
+
const res = await c.var.openfort.transactionIntents.list({
|
|
2163
|
+
limit: c.options.limit,
|
|
2164
|
+
skip: c.options.skip
|
|
2165
|
+
});
|
|
2166
|
+
return c.ok({
|
|
2167
|
+
data: res.data.map((t) => ({
|
|
2168
|
+
id: t.id,
|
|
2169
|
+
createdAt: t.createdAt,
|
|
2170
|
+
updatedAt: t.updatedAt,
|
|
2171
|
+
chainId: t.chainId,
|
|
2172
|
+
abstractionType: t.abstractionType
|
|
2173
|
+
})),
|
|
2174
|
+
total: res.total
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2177
|
+
});
|
|
2178
|
+
transactions.command("create", {
|
|
2179
|
+
description: "Create a transaction intent.",
|
|
2180
|
+
options: z10.object({
|
|
2181
|
+
account: z10.string().describe("Account ID (acc_...)"),
|
|
2182
|
+
chainId: z10.number().describe("Chain ID"),
|
|
2183
|
+
interactions: z10.string().describe('Interactions as JSON: [{"to":"0x...","data":"0x...","value":"0"}]'),
|
|
2184
|
+
policy: z10.string().optional().describe("Policy ID for gas sponsorship"),
|
|
2185
|
+
signedAuthorization: z10.string().optional().describe("Signed EIP-7702 authorization hex (for delegated accounts)")
|
|
2186
|
+
}),
|
|
2187
|
+
output: transactionIntentItem,
|
|
2188
|
+
examples: [
|
|
2189
|
+
{
|
|
2190
|
+
options: {
|
|
2191
|
+
account: "acc_1a2b3c4d",
|
|
2192
|
+
chainId: 137,
|
|
2193
|
+
interactions: '[{"to":"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359","data":"0xa9059cbb000000...","value":"0"}]'
|
|
2194
|
+
},
|
|
2195
|
+
description: "Transfer USDC on Polygon"
|
|
2196
|
+
},
|
|
2197
|
+
{
|
|
2198
|
+
options: {
|
|
2199
|
+
account: "acc_1a2b3c4d",
|
|
2200
|
+
chainId: 137,
|
|
2201
|
+
interactions: '[{"to":"0x742d35Cc6634C0532925a3b844Bc9e7595f92cD5","value":"1000000000000000000"}]',
|
|
2202
|
+
policy: "ply_1a2b3c4d"
|
|
2203
|
+
},
|
|
2204
|
+
description: "Send 1 MATIC with gas sponsorship"
|
|
2205
|
+
}
|
|
2206
|
+
],
|
|
2207
|
+
async run(c) {
|
|
2208
|
+
const interactions = JSON.parse(c.options.interactions);
|
|
2209
|
+
const res = await c.var.openfort.transactionIntents.create({
|
|
2210
|
+
account: c.options.account,
|
|
2211
|
+
chainId: c.options.chainId,
|
|
2212
|
+
interactions,
|
|
2213
|
+
policy: c.options.policy,
|
|
2214
|
+
signedAuthorization: c.options.signedAuthorization
|
|
2215
|
+
});
|
|
2216
|
+
return c.ok(
|
|
2217
|
+
{
|
|
2218
|
+
id: res.id,
|
|
2219
|
+
createdAt: res.createdAt,
|
|
2220
|
+
updatedAt: res.updatedAt,
|
|
2221
|
+
chainId: res.chainId,
|
|
2222
|
+
abstractionType: res.abstractionType,
|
|
2223
|
+
userOperationHash: res.userOperationHash,
|
|
2224
|
+
response: res.response,
|
|
2225
|
+
interactions: res.interactions,
|
|
2226
|
+
nextAction: res.nextAction
|
|
2227
|
+
},
|
|
2228
|
+
{
|
|
2229
|
+
cta: {
|
|
2230
|
+
description: "Next steps:",
|
|
2231
|
+
commands: [
|
|
2232
|
+
{ command: `transactions get ${res.id}`, description: "Check transaction status" }
|
|
2233
|
+
]
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
transactions.command("get", {
|
|
2240
|
+
description: "Get a transaction intent by ID.",
|
|
2241
|
+
args: z10.object({
|
|
2242
|
+
id: z10.string().describe("Transaction intent ID (tin_...)")
|
|
2243
|
+
}),
|
|
2244
|
+
examples: [
|
|
2245
|
+
{ args: { id: "tin_1a2b3c4d" }, description: "Get transaction status and receipt" }
|
|
2246
|
+
],
|
|
2247
|
+
output: transactionIntentItem,
|
|
2248
|
+
async run(c) {
|
|
2249
|
+
const t = await c.var.openfort.transactionIntents.get(c.args.id);
|
|
2250
|
+
return c.ok({
|
|
2251
|
+
id: t.id,
|
|
2252
|
+
createdAt: t.createdAt,
|
|
2253
|
+
updatedAt: t.updatedAt,
|
|
2254
|
+
chainId: t.chainId,
|
|
2255
|
+
abstractionType: t.abstractionType,
|
|
2256
|
+
userOperationHash: t.userOperationHash,
|
|
2257
|
+
response: t.response,
|
|
2258
|
+
interactions: t.interactions,
|
|
2259
|
+
nextAction: t.nextAction
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
});
|
|
2263
|
+
transactions.command("sign", {
|
|
2264
|
+
description: "Sign and broadcast a transaction intent.",
|
|
2265
|
+
args: z10.object({
|
|
2266
|
+
id: z10.string().describe("Transaction intent ID (tin_...)")
|
|
2267
|
+
}),
|
|
2268
|
+
options: z10.object({
|
|
2269
|
+
signature: z10.string().describe("Hex signature"),
|
|
2270
|
+
optimistic: z10.boolean().optional().describe("Return before on-chain confirmation")
|
|
2271
|
+
}),
|
|
2272
|
+
examples: [
|
|
2273
|
+
{ args: { id: "tin_1a2b3c4d" }, options: { signature: "0xabcd1234..." }, description: "Sign and broadcast a transaction" },
|
|
2274
|
+
{ args: { id: "tin_1a2b3c4d" }, options: { signature: "0xabcd1234...", optimistic: true }, description: "Sign without waiting for on-chain confirmation" }
|
|
2275
|
+
],
|
|
2276
|
+
output: transactionIntentItem,
|
|
2277
|
+
async run(c) {
|
|
2278
|
+
const res = await c.var.openfort.transactionIntents.signature(c.args.id, {
|
|
2279
|
+
signature: c.options.signature,
|
|
2280
|
+
optimistic: c.options.optimistic
|
|
2281
|
+
});
|
|
2282
|
+
return c.ok(
|
|
2283
|
+
{
|
|
2284
|
+
id: res.id,
|
|
2285
|
+
createdAt: res.createdAt,
|
|
2286
|
+
updatedAt: res.updatedAt,
|
|
2287
|
+
chainId: res.chainId,
|
|
2288
|
+
abstractionType: res.abstractionType,
|
|
2289
|
+
userOperationHash: res.userOperationHash,
|
|
2290
|
+
response: res.response,
|
|
2291
|
+
interactions: res.interactions,
|
|
2292
|
+
nextAction: res.nextAction
|
|
2293
|
+
},
|
|
2294
|
+
{
|
|
2295
|
+
cta: {
|
|
2296
|
+
description: "Next steps:",
|
|
2297
|
+
commands: [
|
|
2298
|
+
{ command: `transactions get ${res.id}`, description: "Check transaction status" }
|
|
2299
|
+
]
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
});
|
|
2305
|
+
transactions.command("estimate", {
|
|
2306
|
+
description: "Estimate gas cost for a transaction.",
|
|
2307
|
+
options: z10.object({
|
|
2308
|
+
account: z10.string().describe("Account ID (acc_...)"),
|
|
2309
|
+
chainId: z10.number().describe("Chain ID"),
|
|
2310
|
+
interactions: z10.string().describe("Interactions as JSON"),
|
|
2311
|
+
policy: z10.string().optional().describe("Policy ID for gas sponsorship")
|
|
2312
|
+
}),
|
|
2313
|
+
examples: [
|
|
2314
|
+
{
|
|
2315
|
+
options: { account: "acc_1a2b3c4d", chainId: 137, interactions: '[{"to":"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359","data":"0xa9059cbb...","value":"0"}]' },
|
|
2316
|
+
description: "Estimate gas for a USDC transfer on Polygon"
|
|
2317
|
+
}
|
|
2318
|
+
],
|
|
2319
|
+
output: z10.object({
|
|
2320
|
+
estimatedTXGas: z10.string(),
|
|
2321
|
+
estimatedTXGasFee: z10.string(),
|
|
2322
|
+
estimatedTXGasFeeUSD: z10.string(),
|
|
2323
|
+
estimatedTXGasFeeToken: z10.string().optional(),
|
|
2324
|
+
gasPrice: z10.string()
|
|
2325
|
+
}),
|
|
2326
|
+
async run(c) {
|
|
2327
|
+
const interactions = JSON.parse(c.options.interactions);
|
|
2328
|
+
const res = await c.var.openfort.transactionIntents.estimateCost({
|
|
2329
|
+
account: c.options.account,
|
|
2330
|
+
chainId: c.options.chainId,
|
|
2331
|
+
interactions,
|
|
2332
|
+
policy: c.options.policy
|
|
2333
|
+
});
|
|
2334
|
+
return c.ok({
|
|
2335
|
+
estimatedTXGas: res.estimatedTXGas,
|
|
2336
|
+
estimatedTXGasFee: res.estimatedTXGasFee,
|
|
2337
|
+
estimatedTXGasFeeUSD: res.estimatedTXGasFeeUSD,
|
|
2338
|
+
estimatedTXGasFeeToken: res.estimatedTXGasFeeToken,
|
|
2339
|
+
gasPrice: res.gasPrice
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
});
|
|
2343
|
+
|
|
2344
|
+
// src/commands/shield.ts
|
|
2345
|
+
import { Cli as Cli9, z as z11, Errors as Errors2 } from "incur";
|
|
2346
|
+
var SHIELD_API_URL = OPENFORT_SHIELD_URL;
|
|
2347
|
+
var shield = Cli9.create("shield", {
|
|
2348
|
+
description: "Manage Shield (embedded wallet) API keys.",
|
|
2349
|
+
vars: varsSchema
|
|
2350
|
+
});
|
|
2351
|
+
shield.command("create", {
|
|
2352
|
+
description: "Create Shield API keys for embedded wallets.",
|
|
2353
|
+
options: z11.object({
|
|
2354
|
+
project: z11.string().optional().describe("Project ID (pro_...). Defaults to OPENFORT_PROJECT_ID env var.")
|
|
2355
|
+
}),
|
|
2356
|
+
alias: { project: "p" },
|
|
2357
|
+
output: z11.object({
|
|
2358
|
+
message: z11.string(),
|
|
2359
|
+
credentialsPath: z11.string()
|
|
2360
|
+
}),
|
|
2361
|
+
examples: [
|
|
2362
|
+
{
|
|
2363
|
+
options: { project: "pro_abc123" },
|
|
2364
|
+
description: "Create Shield keys for a project"
|
|
2365
|
+
}
|
|
2366
|
+
],
|
|
2367
|
+
async run(c) {
|
|
2368
|
+
const publishableKey = process.env.OPENFORT_PUBLISHABLE_KEY;
|
|
2369
|
+
if (!publishableKey) {
|
|
2370
|
+
throw new Errors2.IncurError({
|
|
2371
|
+
code: "MISSING_PUBLISHABLE_KEY",
|
|
2372
|
+
message: "OPENFORT_PUBLISHABLE_KEY environment variable is required to create Shield keys.",
|
|
2373
|
+
hint: "Run: openfort login"
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
const apiKey = process.env.OPENFORT_API_KEY;
|
|
2377
|
+
const environment = apiKey.startsWith("sk_live_") ? "live" : "test";
|
|
2378
|
+
const projectId = c.options.project || process.env.OPENFORT_PROJECT_ID;
|
|
2379
|
+
if (!projectId) {
|
|
2380
|
+
throw new Errors2.IncurError({
|
|
2381
|
+
code: "MISSING_PROJECT_ID",
|
|
2382
|
+
message: "Project ID is required. Pass --project or set OPENFORT_PROJECT_ID.",
|
|
2383
|
+
hint: "Run: openfort login"
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
const registerRes = await fetch(`${SHIELD_API_URL}/register`, {
|
|
2387
|
+
method: "POST",
|
|
2388
|
+
headers: {
|
|
2389
|
+
"Content-Type": "application/json",
|
|
2390
|
+
"x-api-key": publishableKey
|
|
2391
|
+
},
|
|
2392
|
+
body: JSON.stringify({
|
|
2393
|
+
name: `${projectId}-${environment}`,
|
|
2394
|
+
generate_encryption_key: true,
|
|
2395
|
+
enable_2fa: false
|
|
2396
|
+
})
|
|
2397
|
+
});
|
|
2398
|
+
if (!registerRes.ok) {
|
|
2399
|
+
const text = await registerRes.text();
|
|
2400
|
+
throw new Errors2.IncurError({
|
|
2401
|
+
code: "SHIELD_REGISTER_FAILED",
|
|
2402
|
+
message: `Shield registration failed: ${text}`
|
|
2403
|
+
});
|
|
2404
|
+
}
|
|
2405
|
+
const shieldData = await registerRes.json();
|
|
2406
|
+
if (shieldData.error) {
|
|
2407
|
+
throw new Errors2.IncurError({
|
|
2408
|
+
code: "SHIELD_REGISTER_ERROR",
|
|
2409
|
+
message: `Shield registration error: ${shieldData.error}`
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
const persistKey = async (type, uuid) => {
|
|
2413
|
+
const res = await fetch(`${API_BASE_URL}/v1/project/apikey`, {
|
|
2414
|
+
method: "PUT",
|
|
2415
|
+
headers: {
|
|
2416
|
+
"Content-Type": "application/json",
|
|
2417
|
+
Authorization: `Bearer ${apiKey}`
|
|
2418
|
+
},
|
|
2419
|
+
body: JSON.stringify({ type, uuid })
|
|
2420
|
+
});
|
|
2421
|
+
if (!res.ok) {
|
|
2422
|
+
const text = await res.text();
|
|
2423
|
+
throw new Errors2.IncurError({
|
|
2424
|
+
code: "PERSIST_KEY_FAILED",
|
|
2425
|
+
message: `Failed to persist ${type} key: ${text}`
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
await Promise.all([
|
|
2430
|
+
persistKey("pk_shield", shieldData.api_key),
|
|
2431
|
+
persistKey("sk_shield", shieldData.api_secret)
|
|
2432
|
+
]);
|
|
2433
|
+
const linkRes = await fetch(`${SHIELD_API_URL}/project/providers`, {
|
|
2434
|
+
method: "POST",
|
|
2435
|
+
headers: {
|
|
2436
|
+
"Content-Type": "application/json",
|
|
2437
|
+
"x-api-key": shieldData.api_key,
|
|
2438
|
+
"x-api-secret": shieldData.api_secret
|
|
2439
|
+
},
|
|
2440
|
+
body: JSON.stringify({
|
|
2441
|
+
providers: {
|
|
2442
|
+
openfort: {
|
|
2443
|
+
publishable_key: `pk_${environment}_${publishableKey}`
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
})
|
|
2447
|
+
});
|
|
2448
|
+
if (!linkRes.ok) {
|
|
2449
|
+
const text = await linkRes.text();
|
|
2450
|
+
throw new Errors2.IncurError({
|
|
2451
|
+
code: "SHIELD_LINK_FAILED",
|
|
2452
|
+
message: `Failed to link Openfort provider to Shield: ${text}`
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
ensureConfigDir();
|
|
2456
|
+
writeEnvKey(CREDENTIALS_PATH, "SHIELD_PUBLISHABLE_KEY", shieldData.api_key);
|
|
2457
|
+
writeEnvKey(CREDENTIALS_PATH, "SHIELD_SECRET_KEY", shieldData.api_secret);
|
|
2458
|
+
writeEnvKey(CREDENTIALS_PATH, "SHIELD_ENCRYPTION_SHARE", shieldData.encryption_part);
|
|
2459
|
+
return c.ok(
|
|
2460
|
+
{ message: `Shield keys were created and saved to ${CREDENTIALS_PATH}`, credentialsPath: CREDENTIALS_PATH },
|
|
2461
|
+
{
|
|
2462
|
+
cta: {
|
|
2463
|
+
description: "Next steps:",
|
|
2464
|
+
commands: [
|
|
2465
|
+
{ command: "accounts evm list", description: "List your accounts" },
|
|
2466
|
+
{ command: "contracts list", description: "List your contracts" },
|
|
2467
|
+
{ command: "policies list", description: "List your policies" }
|
|
2468
|
+
]
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2473
|
+
});
|
|
2474
|
+
|
|
2475
|
+
// src/commands/users.ts
|
|
2476
|
+
import { Cli as Cli10, z as z12 } from "incur";
|
|
2477
|
+
var userItem = z12.object({
|
|
2478
|
+
id: z12.string(),
|
|
2479
|
+
createdAt: z12.number(),
|
|
2480
|
+
name: z12.string(),
|
|
2481
|
+
email: z12.string().nullable(),
|
|
2482
|
+
emailVerified: z12.boolean(),
|
|
2483
|
+
phoneNumber: z12.string().nullable(),
|
|
2484
|
+
phoneNumberVerified: z12.boolean(),
|
|
2485
|
+
isAnonymous: z12.boolean().optional(),
|
|
2486
|
+
linkedAccounts: z12.array(z12.object({
|
|
2487
|
+
provider: z12.string(),
|
|
2488
|
+
createdAt: z12.number(),
|
|
2489
|
+
updatedAt: z12.number(),
|
|
2490
|
+
accountId: z12.string().optional(),
|
|
2491
|
+
chainType: z12.string().optional(),
|
|
2492
|
+
connectorType: z12.string().optional(),
|
|
2493
|
+
walletClientType: z12.string().optional()
|
|
2494
|
+
}))
|
|
2495
|
+
});
|
|
2496
|
+
var users = Cli10.create("users", {
|
|
2497
|
+
description: "Manage authenticated users.",
|
|
2498
|
+
vars: varsSchema
|
|
2499
|
+
});
|
|
2500
|
+
users.command("list", {
|
|
2501
|
+
description: "List users.",
|
|
2502
|
+
options: z12.object({
|
|
2503
|
+
limit: z12.number().optional().describe("Max results"),
|
|
2504
|
+
skip: z12.number().optional().describe("Offset"),
|
|
2505
|
+
email: z12.string().optional().describe("Filter by email"),
|
|
2506
|
+
name: z12.string().optional().describe("Filter by name")
|
|
2507
|
+
}),
|
|
2508
|
+
alias: { limit: "l" },
|
|
2509
|
+
examples: [
|
|
2510
|
+
{ description: "List all users" },
|
|
2511
|
+
{ options: { email: "user@example.com" }, description: "Find user by email" }
|
|
2512
|
+
],
|
|
2513
|
+
output: z12.object({
|
|
2514
|
+
data: z12.array(userItem),
|
|
2515
|
+
total: z12.number()
|
|
2516
|
+
}),
|
|
2517
|
+
async run(c) {
|
|
2518
|
+
const res = await c.var.openfort.iam.users.list({
|
|
2519
|
+
limit: c.options.limit,
|
|
2520
|
+
skip: c.options.skip,
|
|
2521
|
+
email: c.options.email,
|
|
2522
|
+
name: c.options.name
|
|
2523
|
+
});
|
|
2524
|
+
return c.ok({
|
|
2525
|
+
data: res.data.map((u) => ({
|
|
2526
|
+
id: u.id,
|
|
2527
|
+
createdAt: u.createdAt,
|
|
2528
|
+
name: u.name,
|
|
2529
|
+
email: u.email,
|
|
2530
|
+
emailVerified: u.emailVerified,
|
|
2531
|
+
phoneNumber: u.phoneNumber,
|
|
2532
|
+
phoneNumberVerified: u.phoneNumberVerified,
|
|
2533
|
+
isAnonymous: u.isAnonymous,
|
|
2534
|
+
linkedAccounts: u.linkedAccounts
|
|
2535
|
+
})),
|
|
2536
|
+
total: res.total
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
});
|
|
2540
|
+
users.command("get", {
|
|
2541
|
+
description: "Get a user by ID.",
|
|
2542
|
+
args: z12.object({
|
|
2543
|
+
id: z12.string().describe("User ID (usr_...)")
|
|
2544
|
+
}),
|
|
2545
|
+
examples: [
|
|
2546
|
+
{ args: { id: "usr_1a2b3c4d" }, description: "Get user profile and linked accounts" }
|
|
2547
|
+
],
|
|
2548
|
+
output: userItem,
|
|
2549
|
+
async run(c) {
|
|
2550
|
+
const u = await c.var.openfort.iam.users.get(c.args.id);
|
|
2551
|
+
return c.ok({
|
|
2552
|
+
id: u.id,
|
|
2553
|
+
createdAt: u.createdAt,
|
|
2554
|
+
name: u.name,
|
|
2555
|
+
email: u.email,
|
|
2556
|
+
emailVerified: u.emailVerified,
|
|
2557
|
+
phoneNumber: u.phoneNumber,
|
|
2558
|
+
phoneNumberVerified: u.phoneNumberVerified,
|
|
2559
|
+
isAnonymous: u.isAnonymous,
|
|
2560
|
+
linkedAccounts: u.linkedAccounts
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2563
|
+
});
|
|
2564
|
+
users.command("delete", {
|
|
2565
|
+
description: "Delete a user.",
|
|
2566
|
+
args: z12.object({
|
|
2567
|
+
id: z12.string().describe("User ID (usr_...)")
|
|
2568
|
+
}),
|
|
2569
|
+
examples: [
|
|
2570
|
+
{ args: { id: "usr_1a2b3c4d" }, description: "Delete a user and their accounts" }
|
|
2571
|
+
],
|
|
2572
|
+
output: z12.object({
|
|
2573
|
+
id: z12.string(),
|
|
2574
|
+
deleted: z12.boolean()
|
|
2575
|
+
}),
|
|
2576
|
+
async run(c) {
|
|
2577
|
+
const res = await c.var.openfort.iam.users.delete(c.args.id);
|
|
2578
|
+
return c.ok({ id: res.id, deleted: res.deleted });
|
|
2579
|
+
}
|
|
2580
|
+
});
|
|
2581
|
+
|
|
2582
|
+
// src/commands/wallet-keys.ts
|
|
2583
|
+
import { randomBytes as randomBytes2, subtle } from "crypto";
|
|
2584
|
+
import { Cli as Cli11, z as z13, Errors as Errors3 } from "incur";
|
|
2585
|
+
function arrayBufferToBase64(buffer) {
|
|
2586
|
+
return Buffer.from(buffer).toString("base64");
|
|
2587
|
+
}
|
|
2588
|
+
function arrayBufferToBase64Url(buffer) {
|
|
2589
|
+
return Buffer.from(buffer).toString("base64url");
|
|
2590
|
+
}
|
|
2591
|
+
function stringToArrayBuffer(str) {
|
|
2592
|
+
return new TextEncoder().encode(str).buffer;
|
|
2593
|
+
}
|
|
2594
|
+
function formatPEMBody(base64) {
|
|
2595
|
+
return base64.match(/.{1,64}/g)?.join("\n") || base64;
|
|
2596
|
+
}
|
|
2597
|
+
function sortObjectKeys(obj) {
|
|
2598
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
2599
|
+
if (Array.isArray(obj)) return obj.map(sortObjectKeys);
|
|
2600
|
+
const sorted = {};
|
|
2601
|
+
for (const key of Object.keys(obj).sort()) {
|
|
2602
|
+
sorted[key] = sortObjectKeys(obj[key]);
|
|
2603
|
+
}
|
|
2604
|
+
return sorted;
|
|
2605
|
+
}
|
|
2606
|
+
async function importPrivateKey(base64) {
|
|
2607
|
+
const binaryDer = Buffer.from(base64, "base64");
|
|
2608
|
+
return subtle.importKey(
|
|
2609
|
+
"pkcs8",
|
|
2610
|
+
binaryDer,
|
|
2611
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
2612
|
+
false,
|
|
2613
|
+
["sign"]
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2616
|
+
async function generateKeyPair() {
|
|
2617
|
+
const keyPair = await subtle.generateKey(
|
|
2618
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
2619
|
+
true,
|
|
2620
|
+
["sign", "verify"]
|
|
2621
|
+
);
|
|
2622
|
+
const spki = await subtle.exportKey("spki", keyPair.publicKey);
|
|
2623
|
+
const pkcs8 = await subtle.exportKey("pkcs8", keyPair.privateKey);
|
|
2624
|
+
return {
|
|
2625
|
+
publicKey: formatPEMBody(arrayBufferToBase64(spki)),
|
|
2626
|
+
privateKey: formatPEMBody(arrayBufferToBase64(pkcs8)),
|
|
2627
|
+
privateKeyCrypto: keyPair.privateKey
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
async function signWalletAuthJwt(privateKey, method, path, body) {
|
|
2631
|
+
const sortedJson = JSON.stringify(sortObjectKeys(body));
|
|
2632
|
+
const hashBuffer = await subtle.digest("SHA-256", stringToArrayBuffer(sortedJson));
|
|
2633
|
+
const reqHash = Buffer.from(hashBuffer).toString("hex");
|
|
2634
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2635
|
+
const jti = randomBytes2(16).toString("hex");
|
|
2636
|
+
const header = { alg: "ES256", typ: "JWT" };
|
|
2637
|
+
const payload = {
|
|
2638
|
+
uris: [`${method.toUpperCase()} ${path}`],
|
|
2639
|
+
reqHash,
|
|
2640
|
+
iat: now,
|
|
2641
|
+
nbf: now,
|
|
2642
|
+
jti
|
|
2643
|
+
};
|
|
2644
|
+
const headerB64 = arrayBufferToBase64Url(stringToArrayBuffer(JSON.stringify(header)));
|
|
2645
|
+
const payloadB64 = arrayBufferToBase64Url(stringToArrayBuffer(JSON.stringify(payload)));
|
|
2646
|
+
const signingInput = `${headerB64}.${payloadB64}`;
|
|
2647
|
+
const signature = await subtle.sign(
|
|
2648
|
+
{ name: "ECDSA", hash: { name: "SHA-256" } },
|
|
2649
|
+
privateKey,
|
|
2650
|
+
stringToArrayBuffer(signingInput)
|
|
2651
|
+
);
|
|
2652
|
+
return `${signingInput}.${arrayBufferToBase64Url(signature)}`;
|
|
2653
|
+
}
|
|
2654
|
+
var walletKeys = Cli11.create("wallet-keys", {
|
|
2655
|
+
description: "Manage backend wallet keys.",
|
|
2656
|
+
vars: varsSchema
|
|
2657
|
+
});
|
|
2658
|
+
walletKeys.command("create", {
|
|
2659
|
+
description: "Create backend wallet keys (ECDSA P-256).",
|
|
2660
|
+
output: z13.object({
|
|
2661
|
+
message: z13.string(),
|
|
2662
|
+
credentialsPath: z13.string()
|
|
2663
|
+
}),
|
|
2664
|
+
examples: [
|
|
2665
|
+
{
|
|
2666
|
+
description: "Create backend wallet keys and save to credentials"
|
|
2667
|
+
}
|
|
2668
|
+
],
|
|
2669
|
+
async run(c) {
|
|
2670
|
+
const apiKey = process.env.OPENFORT_API_KEY;
|
|
2671
|
+
const { publicKey, privateKey, privateKeyCrypto } = await generateKeyPair();
|
|
2672
|
+
const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
|
|
2673
|
+
${publicKey}
|
|
2674
|
+
-----END PUBLIC KEY-----`;
|
|
2675
|
+
const path = "/v2/accounts/backend/register-secret";
|
|
2676
|
+
const keyId = `ws_${Date.now()}`;
|
|
2677
|
+
const bodyWithoutToken = { publicKey: publicKeyPEM, keyId };
|
|
2678
|
+
const jwt = await signWalletAuthJwt(privateKeyCrypto, "POST", path, bodyWithoutToken);
|
|
2679
|
+
const registerRes = await fetch(`${API_BASE_URL}${path}`, {
|
|
2680
|
+
method: "POST",
|
|
2681
|
+
headers: {
|
|
2682
|
+
"Content-Type": "application/json",
|
|
2683
|
+
Authorization: `Bearer ${apiKey}`
|
|
2684
|
+
},
|
|
2685
|
+
body: JSON.stringify({
|
|
2686
|
+
...bodyWithoutToken,
|
|
2687
|
+
walletAuthToken: jwt
|
|
2688
|
+
})
|
|
2689
|
+
});
|
|
2690
|
+
if (!registerRes.ok) {
|
|
2691
|
+
const text = await registerRes.text();
|
|
2692
|
+
throw new Errors3.IncurError({
|
|
2693
|
+
code: "REGISTER_SECRET_FAILED",
|
|
2694
|
+
message: `Failed to register wallet secret: ${text}`
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2697
|
+
const storeRes = await fetch(`${API_BASE_URL}/v1/project/apikey`, {
|
|
2698
|
+
method: "PUT",
|
|
2699
|
+
headers: {
|
|
2700
|
+
"Content-Type": "application/json",
|
|
2701
|
+
Authorization: `Bearer ${apiKey}`
|
|
2702
|
+
},
|
|
2703
|
+
body: JSON.stringify({ type: "pk_wallet", uuid: publicKey })
|
|
2704
|
+
});
|
|
2705
|
+
if (!storeRes.ok) {
|
|
2706
|
+
const text = await storeRes.text();
|
|
2707
|
+
throw new Errors3.IncurError({
|
|
2708
|
+
code: "STORE_KEY_FAILED",
|
|
2709
|
+
message: `Failed to store wallet key reference: ${text}`
|
|
2710
|
+
});
|
|
2711
|
+
}
|
|
2712
|
+
ensureConfigDir();
|
|
2713
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_PUBLIC_KEY", publicKey.replaceAll("\n", ""));
|
|
2714
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_SECRET", privateKey.replaceAll("\n", ""));
|
|
2715
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_KEY_ID", keyId);
|
|
2716
|
+
return c.ok(
|
|
2717
|
+
{ message: `Backend wallet keys were created and saved to ${CREDENTIALS_PATH}`, credentialsPath: CREDENTIALS_PATH },
|
|
2718
|
+
{
|
|
2719
|
+
cta: {
|
|
2720
|
+
description: "Next steps:",
|
|
2721
|
+
commands: [
|
|
2722
|
+
{ command: `shield create`, description: "Create and save Shield API keys" }
|
|
2723
|
+
]
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
});
|
|
2729
|
+
walletKeys.command("revoke", {
|
|
2730
|
+
description: "Revoke the current backend wallet secret.",
|
|
2731
|
+
output: z13.object({
|
|
2732
|
+
keyId: z13.string(),
|
|
2733
|
+
revoked: z13.boolean(),
|
|
2734
|
+
revokedAt: z13.number()
|
|
2735
|
+
}),
|
|
2736
|
+
examples: [
|
|
2737
|
+
{
|
|
2738
|
+
description: "Revoke the current wallet secret"
|
|
2739
|
+
}
|
|
2740
|
+
],
|
|
2741
|
+
async run(c) {
|
|
2742
|
+
const apiKey = process.env.OPENFORT_API_KEY;
|
|
2743
|
+
const keyId = process.env.OPENFORT_WALLET_KEY_ID;
|
|
2744
|
+
const privateKeyBase64 = process.env.OPENFORT_WALLET_SECRET;
|
|
2745
|
+
if (!keyId || !privateKeyBase64) {
|
|
2746
|
+
throw new Errors3.IncurError({
|
|
2747
|
+
code: "MISSING_WALLET_KEY",
|
|
2748
|
+
message: "OPENFORT_WALLET_KEY_ID and OPENFORT_WALLET_SECRET must be set. Create a wallet secret first with `wallet-keys create`."
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
const privateKeyCrypto = await importPrivateKey(privateKeyBase64);
|
|
2752
|
+
const path = "/v2/accounts/backend/revoke-secret";
|
|
2753
|
+
const body = { keyId };
|
|
2754
|
+
const jwt = await signWalletAuthJwt(privateKeyCrypto, "POST", path, body);
|
|
2755
|
+
const res = await fetch(`${API_BASE_URL}${path}`, {
|
|
2756
|
+
method: "POST",
|
|
2757
|
+
headers: {
|
|
2758
|
+
"Content-Type": "application/json",
|
|
2759
|
+
Authorization: `Bearer ${apiKey}`,
|
|
2760
|
+
"x-wallet-auth": jwt
|
|
2761
|
+
},
|
|
2762
|
+
body: JSON.stringify(body)
|
|
2763
|
+
});
|
|
2764
|
+
if (!res.ok) {
|
|
2765
|
+
const text = await res.text();
|
|
2766
|
+
throw new Errors3.IncurError({
|
|
2767
|
+
code: "REVOKE_SECRET_FAILED",
|
|
2768
|
+
message: `Failed to revoke wallet secret: ${text}`
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
const data = await res.json();
|
|
2772
|
+
return c.ok(data);
|
|
2773
|
+
}
|
|
2774
|
+
});
|
|
2775
|
+
walletKeys.command("rotate", {
|
|
2776
|
+
description: "Rotate backend wallet secret (generates new ECDSA P-256 key pair).",
|
|
2777
|
+
output: z13.object({
|
|
2778
|
+
message: z13.string(),
|
|
2779
|
+
credentialsPath: z13.string()
|
|
2780
|
+
}),
|
|
2781
|
+
examples: [
|
|
2782
|
+
{
|
|
2783
|
+
description: "Rotate wallet secret and save new keys to credentials"
|
|
2784
|
+
}
|
|
2785
|
+
],
|
|
2786
|
+
async run(c) {
|
|
2787
|
+
const apiKey = process.env.OPENFORT_API_KEY;
|
|
2788
|
+
const { publicKey, privateKey, privateKeyCrypto } = await generateKeyPair();
|
|
2789
|
+
const newPublicKeyPEM = `-----BEGIN PUBLIC KEY-----
|
|
2790
|
+
${publicKey}
|
|
2791
|
+
-----END PUBLIC KEY-----`;
|
|
2792
|
+
const path = "/v2/accounts/backend/rotate-secrets";
|
|
2793
|
+
const newKeyId = `ws_${Date.now()}`;
|
|
2794
|
+
const bodyWithoutToken = { newPublicKey: newPublicKeyPEM, newKeyId };
|
|
2795
|
+
const jwt = await signWalletAuthJwt(privateKeyCrypto, "POST", path, bodyWithoutToken);
|
|
2796
|
+
const rotateRes = await fetch(`${API_BASE_URL}${path}`, {
|
|
2797
|
+
method: "POST",
|
|
2798
|
+
headers: {
|
|
2799
|
+
"Content-Type": "application/json",
|
|
2800
|
+
Authorization: `Bearer ${apiKey}`
|
|
2801
|
+
},
|
|
2802
|
+
body: JSON.stringify({
|
|
2803
|
+
...bodyWithoutToken,
|
|
2804
|
+
walletAuthToken: jwt
|
|
2805
|
+
})
|
|
2806
|
+
});
|
|
2807
|
+
if (!rotateRes.ok) {
|
|
2808
|
+
const text = await rotateRes.text();
|
|
2809
|
+
throw new Errors3.IncurError({
|
|
2810
|
+
code: "ROTATE_SECRET_FAILED",
|
|
2811
|
+
message: `Failed to rotate wallet secret: ${text}`
|
|
2812
|
+
});
|
|
2813
|
+
}
|
|
2814
|
+
const storeRes = await fetch(`${API_BASE_URL}/v1/project/apikey`, {
|
|
2815
|
+
method: "PUT",
|
|
2816
|
+
headers: {
|
|
2817
|
+
"Content-Type": "application/json",
|
|
2818
|
+
Authorization: `Bearer ${apiKey}`
|
|
2819
|
+
},
|
|
2820
|
+
body: JSON.stringify({ type: "pk_wallet", uuid: publicKey })
|
|
2821
|
+
});
|
|
2822
|
+
if (!storeRes.ok) {
|
|
2823
|
+
const text = await storeRes.text();
|
|
2824
|
+
throw new Errors3.IncurError({
|
|
2825
|
+
code: "STORE_KEY_FAILED",
|
|
2826
|
+
message: `Failed to store rotated wallet key reference: ${text}`
|
|
2827
|
+
});
|
|
2828
|
+
}
|
|
2829
|
+
ensureConfigDir();
|
|
2830
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_PUBLIC_KEY", publicKey.replaceAll("\n", ""));
|
|
2831
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_SECRET", privateKey.replaceAll("\n", ""));
|
|
2832
|
+
writeEnvKey(CREDENTIALS_PATH, "OPENFORT_WALLET_KEY_ID", newKeyId);
|
|
2833
|
+
return c.ok({ message: `Wallet secret rotated and new keys saved to ${CREDENTIALS_PATH}`, credentialsPath: CREDENTIALS_PATH });
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
|
|
2837
|
+
// src/cli.ts
|
|
2838
|
+
var cli = Cli12.create("openfort", {
|
|
2839
|
+
version: "0.1.0",
|
|
2840
|
+
description: "Openfort CLI \u2014 manage wallets, policies, and transactions. If you are LLM read this doc first https://www.openfort.io/docs/overview/building-with-cli",
|
|
2841
|
+
vars: varsSchema,
|
|
2842
|
+
env: z14.object({
|
|
2843
|
+
OPENFORT_API_KEY: z14.string().optional().describe("Openfort secret API key (sk_test_... or sk_live_...)"),
|
|
2844
|
+
OPENFORT_WALLET_SECRET: z14.string().optional().describe("Wallet encryption secret"),
|
|
2845
|
+
OPENFORT_PUBLISHABLE_KEY: z14.string().optional().describe("Publishable key for client-side ops"),
|
|
2846
|
+
OPENFORT_BASE_URL: z14.string().optional().describe("Custom API base URL")
|
|
2847
|
+
}),
|
|
2848
|
+
sync: {
|
|
2849
|
+
depth: 2,
|
|
2850
|
+
include: ["accounts", "transactions", "policies", "sponsorship", "contracts", "users", "sessions", "subscriptions"],
|
|
2851
|
+
suggestions: [
|
|
2852
|
+
"create an EVM backend wallet",
|
|
2853
|
+
"list all accounts",
|
|
2854
|
+
"create a gas sponsorship policy",
|
|
2855
|
+
"list users",
|
|
2856
|
+
"estimate transaction gas cost"
|
|
2857
|
+
]
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
cli.command("login", loginConfig);
|
|
2861
|
+
cli.use(async (c, next) => {
|
|
2862
|
+
const isLoginCommand = process.argv.slice(2).some((arg) => arg === "login");
|
|
2863
|
+
if (isLoginCommand) {
|
|
2864
|
+
await next();
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
const apiKey = process.env.OPENFORT_API_KEY;
|
|
2868
|
+
if (!apiKey) {
|
|
2869
|
+
throw new Errors4.IncurError({
|
|
2870
|
+
code: "MISSING_API_KEY",
|
|
2871
|
+
message: "OPENFORT_API_KEY environment variable is required.",
|
|
2872
|
+
hint: "Run: openfort login"
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
c.set("openfort", new Openfort(apiKey, {
|
|
2876
|
+
walletSecret: process.env.OPENFORT_WALLET_SECRET,
|
|
2877
|
+
publishableKey: process.env.OPENFORT_PUBLISHABLE_KEY,
|
|
2878
|
+
basePath: API_BASE_URL
|
|
2879
|
+
}));
|
|
2880
|
+
await next();
|
|
2881
|
+
});
|
|
2882
|
+
cli.command(accounts).command(contracts).command(paymasters).command(policies).command(shield).command(sponsorship).command(sessions).command(subscriptions).command(transactions).command(users).command(walletKeys);
|
|
2883
|
+
var cli_default = cli;
|
|
2884
|
+
export {
|
|
2885
|
+
cli_default as default
|
|
2886
|
+
};
|