@tangle-network/sandbox 0.60.16-develop.20261006055839.0a30657 → 0.60.16
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/index.d.ts +10 -10
- package/dist/intelligence/index.d.ts +1 -75
- package/dist/intelligence/index.js +20 -71
- package/package.json +2 -2
- package/dist/gpu-lease/index.d.ts +0 -503
- package/dist/gpu-lease/index.js +0 -410
package/dist/index.d.ts
CHANGED
|
@@ -870,8 +870,8 @@ declare const manageSandboxesInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
870
870
|
off: "off";
|
|
871
871
|
}>>;
|
|
872
872
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
873
|
-
on: "on";
|
|
874
873
|
off: "off";
|
|
874
|
+
on: "on";
|
|
875
875
|
}>>;
|
|
876
876
|
}, z.core.$strict>>;
|
|
877
877
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -1199,8 +1199,8 @@ declare const manageSandboxesInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1199
1199
|
off: "off";
|
|
1200
1200
|
}>>;
|
|
1201
1201
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
1202
|
-
on: "on";
|
|
1203
1202
|
off: "off";
|
|
1203
|
+
on: "on";
|
|
1204
1204
|
}>>;
|
|
1205
1205
|
}, z.core.$strict>>;
|
|
1206
1206
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -1538,8 +1538,8 @@ declare const manageSandboxesInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1538
1538
|
off: "off";
|
|
1539
1539
|
}>>;
|
|
1540
1540
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
1541
|
-
on: "on";
|
|
1542
1541
|
off: "off";
|
|
1542
|
+
on: "on";
|
|
1543
1543
|
}>>;
|
|
1544
1544
|
}, z.core.$strict>>;
|
|
1545
1545
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -1862,8 +1862,8 @@ declare const manageSandboxesInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1862
1862
|
off: "off";
|
|
1863
1863
|
}>>;
|
|
1864
1864
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
1865
|
-
on: "on";
|
|
1866
1865
|
off: "off";
|
|
1866
|
+
on: "on";
|
|
1867
1867
|
}>>;
|
|
1868
1868
|
}, z.core.$strict>>;
|
|
1869
1869
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -2191,8 +2191,8 @@ declare const manageSandboxesInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2191
2191
|
off: "off";
|
|
2192
2192
|
}>>;
|
|
2193
2193
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
2194
|
-
on: "on";
|
|
2195
2194
|
off: "off";
|
|
2195
|
+
on: "on";
|
|
2196
2196
|
}>>;
|
|
2197
2197
|
}, z.core.$strict>>;
|
|
2198
2198
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -2625,8 +2625,8 @@ declare const MANAGE_SANDBOXES_PARAMETERS: z.core.ZodStandardJSONSchemaPayload<z
|
|
|
2625
2625
|
off: "off";
|
|
2626
2626
|
}>>;
|
|
2627
2627
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
2628
|
-
on: "on";
|
|
2629
2628
|
off: "off";
|
|
2629
|
+
on: "on";
|
|
2630
2630
|
}>>;
|
|
2631
2631
|
}, z.core.$strict>>;
|
|
2632
2632
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -2954,8 +2954,8 @@ declare const MANAGE_SANDBOXES_PARAMETERS: z.core.ZodStandardJSONSchemaPayload<z
|
|
|
2954
2954
|
off: "off";
|
|
2955
2955
|
}>>;
|
|
2956
2956
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
2957
|
-
on: "on";
|
|
2958
2957
|
off: "off";
|
|
2958
|
+
on: "on";
|
|
2959
2959
|
}>>;
|
|
2960
2960
|
}, z.core.$strict>>;
|
|
2961
2961
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -3293,8 +3293,8 @@ declare const MANAGE_SANDBOXES_PARAMETERS: z.core.ZodStandardJSONSchemaPayload<z
|
|
|
3293
3293
|
off: "off";
|
|
3294
3294
|
}>>;
|
|
3295
3295
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
3296
|
-
on: "on";
|
|
3297
3296
|
off: "off";
|
|
3297
|
+
on: "on";
|
|
3298
3298
|
}>>;
|
|
3299
3299
|
}, z.core.$strict>>;
|
|
3300
3300
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -3617,8 +3617,8 @@ declare const MANAGE_SANDBOXES_PARAMETERS: z.core.ZodStandardJSONSchemaPayload<z
|
|
|
3617
3617
|
off: "off";
|
|
3618
3618
|
}>>;
|
|
3619
3619
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
3620
|
-
on: "on";
|
|
3621
3620
|
off: "off";
|
|
3621
|
+
on: "on";
|
|
3622
3622
|
}>>;
|
|
3623
3623
|
}, z.core.$strict>>;
|
|
3624
3624
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -3946,8 +3946,8 @@ declare const MANAGE_SANDBOXES_PARAMETERS: z.core.ZodStandardJSONSchemaPayload<z
|
|
|
3946
3946
|
off: "off";
|
|
3947
3947
|
}>>;
|
|
3948
3948
|
logs: z.ZodOptional<z.ZodEnum<{
|
|
3949
|
-
on: "on";
|
|
3950
3949
|
off: "off";
|
|
3950
|
+
on: "on";
|
|
3951
3951
|
}>>;
|
|
3952
3952
|
}, z.core.$strict>>;
|
|
3953
3953
|
idempotencyKey: z.ZodOptional<z.ZodString>;
|
|
@@ -181,66 +181,6 @@ interface SessionSummaryList {
|
|
|
181
181
|
items: SessionSummary[];
|
|
182
182
|
nextCursor: string | null;
|
|
183
183
|
}
|
|
184
|
-
/**
|
|
185
|
-
* One agent session file the platform captured from a cloud sandbox of a run
|
|
186
|
-
* (`GET /v1/run-sessions/{runId}`). Files outlive the sandbox; the stored
|
|
187
|
-
* bytes are redacted, and `sourceSha256` names the bytes as captured.
|
|
188
|
-
*/
|
|
189
|
-
interface RunSessionFile {
|
|
190
|
-
runId: string;
|
|
191
|
-
sandboxId: string;
|
|
192
|
-
/** The sidecar session the file was captured from. */
|
|
193
|
-
sessionId: string;
|
|
194
|
-
/** `native/<executionId>/<attempt>/<storePath>`, `events/<executionId>.ndjson` or `capture.json`. */
|
|
195
|
-
path: string;
|
|
196
|
-
harness: string | null;
|
|
197
|
-
format: string | null;
|
|
198
|
-
contentType: string;
|
|
199
|
-
/** `withheld`: captured but not stored (`unscannable_binary` or `too_large`). */
|
|
200
|
-
state: "stored" | "withheld";
|
|
201
|
-
withheldReason: string | null;
|
|
202
|
-
sourceSha256: string;
|
|
203
|
-
sourceBytes: number;
|
|
204
|
-
storedSha256: string | null;
|
|
205
|
-
storedBytes: number | null;
|
|
206
|
-
redactionVersion: string | null;
|
|
207
|
-
redactionCount: number | null;
|
|
208
|
-
updatedAt: string;
|
|
209
|
-
}
|
|
210
|
-
/** The final capture of one sandbox, sealed before the sandbox was deleted. */
|
|
211
|
-
interface RunSessionSeal {
|
|
212
|
-
runId: string;
|
|
213
|
-
sandboxId: string;
|
|
214
|
-
/** Whether the sandbox was running when its final capture was taken. */
|
|
215
|
-
runtime: "running" | "not_running";
|
|
216
|
-
/** True when the final capture named no gap. */
|
|
217
|
-
complete: boolean;
|
|
218
|
-
missing: string[];
|
|
219
|
-
storedFiles: number;
|
|
220
|
-
withheldFiles: number;
|
|
221
|
-
storedBytes: number;
|
|
222
|
-
workspaceSnapshot: string | null;
|
|
223
|
-
sealedAt: string;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* One page of a run's captured files (`GET /v1/run-sessions/{runId}`), in
|
|
227
|
-
* sandbox, session and path order. Every sandbox's seal comes with the first
|
|
228
|
-
* page; later pages carry an empty `seals`.
|
|
229
|
-
*/
|
|
230
|
-
interface RunSessionList {
|
|
231
|
-
runId: string;
|
|
232
|
-
files: RunSessionFile[];
|
|
233
|
-
seals: RunSessionSeal[];
|
|
234
|
-
/** Pass as `cursor` for the next page; null on the last page. */
|
|
235
|
-
nextCursor: string | null;
|
|
236
|
-
}
|
|
237
|
-
/** Query params for {@link IntelligenceClient.listRunSessionFiles}. */
|
|
238
|
-
interface ListRunSessionFilesParams {
|
|
239
|
-
/** Files per page, clamped server-side to `[1, 5000]` (default 1000). */
|
|
240
|
-
limit?: number;
|
|
241
|
-
/** Opaque cursor from the prior page's `nextCursor`. */
|
|
242
|
-
cursor?: string;
|
|
243
|
-
}
|
|
244
184
|
/** Query params for {@link IntelligenceClient.listTraces}. */
|
|
245
185
|
interface ListTracesParams {
|
|
246
186
|
/** Page size, clamped server-side to `[1, 200]` (default 50). */
|
|
@@ -320,20 +260,6 @@ interface IntelligenceClient {
|
|
|
320
260
|
getRun(runId: string): Promise<Run>;
|
|
321
261
|
/** List the spans pivoted to this run (by `run_id`), bounded window. */
|
|
322
262
|
getRunTraces(runId: string): Promise<RunSpanWindow>;
|
|
323
|
-
/**
|
|
324
|
-
* List one page of the agent session files the platform captured from this
|
|
325
|
-
* run's cloud sandboxes; the first page also carries each sandbox's final
|
|
326
|
-
* seal. A run is the sandbox's create `metadata.run`, or the sandbox id when
|
|
327
|
-
* the sandbox named no run.
|
|
328
|
-
*/
|
|
329
|
-
listRunSessionFiles(runId: string, params?: ListRunSessionFilesParams): Promise<RunSessionList>;
|
|
330
|
-
/**
|
|
331
|
-
* Async iterator over every captured file of a run, following `nextCursor`
|
|
332
|
-
* page by page. Seals are on the first page of {@link listRunSessionFiles}.
|
|
333
|
-
*/
|
|
334
|
-
iterateRunSessionFiles(runId: string, params?: ListRunSessionFilesParams): AsyncGenerator<RunSessionFile, void, unknown>;
|
|
335
|
-
/** Download one captured file's stored (redacted) bytes. */
|
|
336
|
-
downloadRunSessionFile(runId: string, file: Pick<RunSessionFile, "sandboxId" | "sessionId" | "path">): Promise<Uint8Array>;
|
|
337
263
|
/** List tenant-wide session summaries (one row per session), newest first. */
|
|
338
264
|
listSessions(params?: ListSessionsParams): Promise<SessionSummaryList>;
|
|
339
265
|
/** List one session's traces as the trace-summary shape, keyset-paginated. */
|
|
@@ -363,4 +289,4 @@ interface IntelligenceClient {
|
|
|
363
289
|
*/
|
|
364
290
|
declare function createIntelligenceClient(config: IntelligenceClientConfig): IntelligenceClient;
|
|
365
291
|
//#endregion
|
|
366
|
-
export { DEFAULT_INTELLIGENCE_BASE_URL, GetSessionTracesParams, GetTraceSpansParams, IntelligenceClient, IntelligenceClientConfig,
|
|
292
|
+
export { DEFAULT_INTELLIGENCE_BASE_URL, GetSessionTracesParams, GetTraceSpansParams, IntelligenceClient, IntelligenceClientConfig, ListRunsParams, ListSessionsParams, ListTracesParams, NanoString, Run, RunList, RunSpanWindow, SerializedSpan, SessionSummary, SessionSummaryList, SpanPage, TraceStatus, TraceSummary, TraceSummaryList, createIntelligenceClient };
|
|
@@ -67,51 +67,37 @@ function createIntelligenceClient(config) {
|
|
|
67
67
|
* an `AbortController` timeout that surfaces as `TimeoutError`, and a
|
|
68
68
|
* transport failure wrapped as `NetworkError`. Never reuses the sandbox
|
|
69
69
|
* `baseUrl` — this is the intelligence host.
|
|
70
|
-
*
|
|
71
|
-
* The timeout covers `read` as well, so a server that sends its headers
|
|
72
|
-
* and then stalls the body still times out. A caller that hands the body
|
|
73
|
-
* stream on (the NDJSON export) returns the response from `read` and owns
|
|
74
|
-
* the stream's pace from there.
|
|
75
70
|
*/
|
|
76
|
-
async function request(path
|
|
71
|
+
async function request(path) {
|
|
77
72
|
const url = `${baseUrl}${path}`;
|
|
78
73
|
const controller = new AbortController();
|
|
79
74
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
80
75
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
signal: controller.signal
|
|
89
|
-
});
|
|
90
|
-
} catch (err) {
|
|
91
|
-
if (controller.signal.aborted || err instanceof Error && err.name === "AbortError") throw new TimeoutError(timeoutMs);
|
|
92
|
-
throw new NetworkError(`Failed to connect to Intelligence API: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
|
|
93
|
-
endpoint: path,
|
|
94
|
-
origin: "sandbox-api"
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return await read(response);
|
|
76
|
+
return await globalThis.fetch(url, {
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${apiKey}`,
|
|
79
|
+
Accept: "application/json"
|
|
80
|
+
},
|
|
81
|
+
signal: controller.signal
|
|
82
|
+
});
|
|
98
83
|
} catch (err) {
|
|
99
|
-
if (
|
|
100
|
-
throw err
|
|
84
|
+
if (err instanceof Error && err.name === "AbortError") throw new TimeoutError(timeoutMs);
|
|
85
|
+
throw new NetworkError(`Failed to connect to Intelligence API: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
|
|
86
|
+
endpoint: path,
|
|
87
|
+
origin: "sandbox-api"
|
|
88
|
+
});
|
|
101
89
|
} finally {
|
|
102
90
|
clearTimeout(timeoutId);
|
|
103
91
|
}
|
|
104
92
|
}
|
|
105
93
|
/** GET a JSON route, raising the SDK's typed error on a non-2xx response. */
|
|
106
94
|
async function getJson(path) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return text;
|
|
114
|
-
});
|
|
95
|
+
const response = await request(path);
|
|
96
|
+
const body = await response.text();
|
|
97
|
+
if (!response.ok) throw parseErrorResponse(response.status, body, {
|
|
98
|
+
method: "GET",
|
|
99
|
+
path
|
|
100
|
+
}, response.headers);
|
|
115
101
|
return JSON.parse(body);
|
|
116
102
|
}
|
|
117
103
|
async function listTraces(params = {}) {
|
|
@@ -135,7 +121,7 @@ function createIntelligenceClient(config) {
|
|
|
135
121
|
}
|
|
136
122
|
async function exportTraceSpansNdjson(traceId) {
|
|
137
123
|
const path = `/v1/traces/${encodeURIComponent(traceId)}/spans.ndjson`;
|
|
138
|
-
const response = await request(path
|
|
124
|
+
const response = await request(path);
|
|
139
125
|
if (!response.ok) {
|
|
140
126
|
const body = await response.text();
|
|
141
127
|
throw parseErrorResponse(response.status, body, {
|
|
@@ -168,40 +154,6 @@ function createIntelligenceClient(config) {
|
|
|
168
154
|
async function getRunTraces(runId) {
|
|
169
155
|
return getJson(`/v1/runs/${encodeURIComponent(runId)}/traces`);
|
|
170
156
|
}
|
|
171
|
-
async function listRunSessionFiles(runId, params = {}) {
|
|
172
|
-
const search = new URLSearchParams();
|
|
173
|
-
appendParam(search, "limit", params.limit);
|
|
174
|
-
appendParam(search, "cursor", params.cursor);
|
|
175
|
-
const suffix = search.size > 0 ? `?${search}` : "";
|
|
176
|
-
return getJson(`/v1/run-sessions/${encodeURIComponent(runId)}${suffix}`);
|
|
177
|
-
}
|
|
178
|
-
async function* iterateRunSessionFiles(runId, params = {}) {
|
|
179
|
-
let cursor = params.cursor;
|
|
180
|
-
for (;;) {
|
|
181
|
-
const page = await listRunSessionFiles(runId, {
|
|
182
|
-
...params,
|
|
183
|
-
cursor
|
|
184
|
-
});
|
|
185
|
-
for (const file of page.files) yield file;
|
|
186
|
-
if (!page.nextCursor) return;
|
|
187
|
-
cursor = page.nextCursor;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
async function downloadRunSessionFile(runId, file) {
|
|
191
|
-
const search = new URLSearchParams({
|
|
192
|
-
sandboxId: file.sandboxId,
|
|
193
|
-
sessionId: file.sessionId,
|
|
194
|
-
path: file.path
|
|
195
|
-
});
|
|
196
|
-
const path = `/v1/run-sessions/${encodeURIComponent(runId)}/content?${search}`;
|
|
197
|
-
return request(path, async (response) => {
|
|
198
|
-
if (!response.ok) throw parseErrorResponse(response.status, await response.text(), {
|
|
199
|
-
method: "GET",
|
|
200
|
-
path
|
|
201
|
-
}, response.headers);
|
|
202
|
-
return new Uint8Array(await response.arrayBuffer());
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
157
|
async function listSessions(params = {}) {
|
|
206
158
|
const search = new URLSearchParams();
|
|
207
159
|
appendParam(search, "limit", params.limit);
|
|
@@ -262,9 +214,6 @@ function createIntelligenceClient(config) {
|
|
|
262
214
|
listRuns,
|
|
263
215
|
getRun,
|
|
264
216
|
getRunTraces,
|
|
265
|
-
listRunSessionFiles,
|
|
266
|
-
iterateRunSessionFiles,
|
|
267
|
-
downloadRunSessionFile,
|
|
268
217
|
listSessions,
|
|
269
218
|
getSessionTraces,
|
|
270
219
|
iterateTraceSpans,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/sandbox",
|
|
3
|
-
"version": "0.60.16
|
|
3
|
+
"version": "0.60.16",
|
|
4
4
|
"description": "Client SDK for the Tangle Sandbox platform - build AI agent applications with dev containers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -151,9 +151,9 @@
|
|
|
151
151
|
"ws": "^8.20.0",
|
|
152
152
|
"yjs": "13.6.30",
|
|
153
153
|
"@products/sandbox-test-utils": "0.0.0",
|
|
154
|
-
"@repo/shared": "0.0.0",
|
|
155
154
|
"@tangle-network/agent-profile-materialize": "0.20.9",
|
|
156
155
|
"@tangle-network/cli-agent-registry": "0.5.0",
|
|
156
|
+
"@repo/shared": "0.0.0",
|
|
157
157
|
"@tangle-network/runtime-contracts": "0.14.0",
|
|
158
158
|
"@tangle-network/sdk": "3.3.41",
|
|
159
159
|
"@tangle-network/sse-core": "0.0.0"
|
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
//#region src/gpu-lease/intent.d.ts
|
|
2
|
-
declare const INTENT_VERSION = 1;
|
|
3
|
-
/** keccak256 of the canonical intent string. */
|
|
4
|
-
declare function gpuLeaseIntentHash(input: {
|
|
5
|
-
intentVersion: number;
|
|
6
|
-
gpuClass: string;
|
|
7
|
-
durationSeconds: bigint | number;
|
|
8
|
-
confidentiality: number;
|
|
9
|
-
region: string;
|
|
10
|
-
}): `0x${string}`;
|
|
11
|
-
/** ABI shape of GpuLeaseRequest — mirrors the blueprint's sol! type. */
|
|
12
|
-
declare const GPU_LEASE_REQUEST_ABI: never;
|
|
13
|
-
interface GpuLeaseRequestParams {
|
|
14
|
-
intentVersion: number;
|
|
15
|
-
intentHash: `0x${string}`;
|
|
16
|
-
pricePerSecondWei: bigint;
|
|
17
|
-
durationSeconds: bigint;
|
|
18
|
-
confidentiality: number;
|
|
19
|
-
gpuClass: string;
|
|
20
|
-
region: string;
|
|
21
|
-
lessee: `0x${string}`;
|
|
22
|
-
leaseId: `0x${string}`;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* ABI-encoded GpuLeaseRequest — the LEASE job calldata payload.
|
|
26
|
-
* Positional (ABI order) — order is pinned by the blueprint's generated
|
|
27
|
-
* encodeType in metadata/blueprint.json.
|
|
28
|
-
*/
|
|
29
|
-
declare function encodeGpuLeaseRequest(params: GpuLeaseRequestParams): `0x${string}`;
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/gpu-lease/types.d.ts
|
|
32
|
-
/**
|
|
33
|
-
* GPU lease client types — mirrors the gpu-lease-blueprint operator API
|
|
34
|
-
* (gpu-lease-blueprint/gpu-lease-blueprint-lib/src/api.rs) and the on-chain
|
|
35
|
-
* ABI (contracts/src/GpuLeaseBlueprint.sol sol! mirror).
|
|
36
|
-
*
|
|
37
|
-
* Every on-chain and off-chain surface is schemaVersioned; unknown versions
|
|
38
|
-
* fail closed (SPEC §3 of the blueprint).
|
|
39
|
-
*/
|
|
40
|
-
/** The only schema this client understands. */
|
|
41
|
-
declare const GPU_LEASE_SCHEMA_VERSION: 1;
|
|
42
|
-
interface ClassCapability {
|
|
43
|
-
id: string;
|
|
44
|
-
tee: boolean;
|
|
45
|
-
unit: string;
|
|
46
|
-
/** Indicative policy price (wei/second) — the binding price is the quote. */
|
|
47
|
-
pricePerSecond: string;
|
|
48
|
-
idleCount: number;
|
|
49
|
-
}
|
|
50
|
-
interface Capabilities {
|
|
51
|
-
schemaVersion: number;
|
|
52
|
-
compute: {
|
|
53
|
-
kind: string;
|
|
54
|
-
classes: ClassCapability[];
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
interface OperatorQuote {
|
|
58
|
-
schemaVersion: number;
|
|
59
|
-
gpuClass: string;
|
|
60
|
-
/** The operator's EVM address — who the escrow names (I5 binding).
|
|
61
|
-
* When the quote is signed this MUST equal the recovered signer (verified
|
|
62
|
-
* in quotes.ts); config-supplied values are interim-trust only. */
|
|
63
|
-
operatorAddress: `0x${string}`;
|
|
64
|
-
/** EIP-191 personal_sign over the canonical quote payload (0x RSV). */
|
|
65
|
-
signature?: `0x${string}`;
|
|
66
|
-
/** wei/second, from the operator's signed policy at request time. */
|
|
67
|
-
pricePerSecond: string;
|
|
68
|
-
durationSeconds: number;
|
|
69
|
-
confidentiality: number;
|
|
70
|
-
/** wei — pricePerSecond × durationSeconds exactly. */
|
|
71
|
-
escrowTotal: string;
|
|
72
|
-
/** Utilization the price was struck at (bps of 10_000) — the surge "why". */
|
|
73
|
-
utilizationBps: number;
|
|
74
|
-
/** keccak256(canonical intent) — binds the RFQ and the vault lease (I5). */
|
|
75
|
-
intentHash: `0x${string}`;
|
|
76
|
-
/** Unix seconds after which the quote is stale. */
|
|
77
|
-
validUntil: number;
|
|
78
|
-
}
|
|
79
|
-
interface LeaseStatus {
|
|
80
|
-
schemaVersion: number;
|
|
81
|
-
leaseId: `0x${string}`;
|
|
82
|
-
deviceId: string;
|
|
83
|
-
lessee: string;
|
|
84
|
-
/** Unix seconds — the chain-of-truth session end (parking meter). */
|
|
85
|
-
expiresAt: number;
|
|
86
|
-
endpoint: string;
|
|
87
|
-
}
|
|
88
|
-
interface SessionChallenge {
|
|
89
|
-
nonce: `0x${string}`;
|
|
90
|
-
/** The exact string the lessee must EIP-191 personal_sign. */
|
|
91
|
-
message: string;
|
|
92
|
-
expiresAt: number;
|
|
93
|
-
}
|
|
94
|
-
interface SessionCredential {
|
|
95
|
-
token: string;
|
|
96
|
-
leaseId: `0x${string}`;
|
|
97
|
-
scopes: string[];
|
|
98
|
-
expiresAt: number;
|
|
99
|
-
}
|
|
100
|
-
/** A validated, ready-to-escrow quote. */
|
|
101
|
-
interface ValidatedQuote {
|
|
102
|
-
quote: OperatorQuote;
|
|
103
|
-
pricePerSecondWei: bigint;
|
|
104
|
-
escrowTotalWei: bigint;
|
|
105
|
-
}
|
|
106
|
-
/** A resolved lease handed to the caller by `gpuLease()`. */
|
|
107
|
-
interface GpuLease {
|
|
108
|
-
leaseId: `0x${string}`;
|
|
109
|
-
/** Public endpoint descriptor (versioned union; v1 = local-attach). */
|
|
110
|
-
endpoint: string;
|
|
111
|
-
schemaVersion: number;
|
|
112
|
-
quote: ValidatedQuote;
|
|
113
|
-
}
|
|
114
|
-
interface RefundReceipt {
|
|
115
|
-
leaseId: `0x${string}`;
|
|
116
|
-
/** Exact wei refunded: pricePerSecond × remainingSeconds at settle time. */
|
|
117
|
-
refundWei: bigint;
|
|
118
|
-
operatorTakeWei: bigint;
|
|
119
|
-
}
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/gpu-lease/operators.d.ts
|
|
122
|
-
interface QuoteParams {
|
|
123
|
-
gpuClass: string;
|
|
124
|
-
durationSeconds: number;
|
|
125
|
-
confidentiality?: number;
|
|
126
|
-
region?: string;
|
|
127
|
-
}
|
|
128
|
-
interface OperatorEndpoint {
|
|
129
|
-
/** Operator base URL, e.g. https://gpu.example.com */
|
|
130
|
-
baseUrl: string;
|
|
131
|
-
/** The operator's EVM address (escrow + job binding). */
|
|
132
|
-
address: `0x${string}`;
|
|
133
|
-
fetch?: typeof fetch;
|
|
134
|
-
}
|
|
135
|
-
/** JSON request body — named at the I/O boundary (anti-slop: no `unknown`). */
|
|
136
|
-
type JsonRequestBody = Record<string, unknown>;
|
|
137
|
-
declare class GpuLeaseOperatorClient {
|
|
138
|
-
private readonly endpoint;
|
|
139
|
-
constructor(endpoint: OperatorEndpoint);
|
|
140
|
-
capabilities(): Promise<Capabilities>;
|
|
141
|
-
quote(params: QuoteParams): Promise<OperatorQuote>;
|
|
142
|
-
leaseStatus(leaseId: `0x${string}`): Promise<LeaseStatus>;
|
|
143
|
-
sessionChallenge(leaseId: `0x${string}`, lessee: string): Promise<SessionChallenge>;
|
|
144
|
-
sessionVerify(nonce: `0x${string}`, signature: `0x${string}`): Promise<SessionCredential>;
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region src/gpu-lease/output.d.ts
|
|
148
|
-
interface GpuLeaseOutputDecoded {
|
|
149
|
-
leaseId: `0x${string}`;
|
|
150
|
-
endpoint: string;
|
|
151
|
-
schemaVersion: number;
|
|
152
|
-
}
|
|
153
|
-
/** Decode + fail closed on unknown schemaVersion (blueprint SPEC §3). */
|
|
154
|
-
declare function decodeGpuLeaseOutput(encoded: `0x${string}`): GpuLeaseOutputDecoded;
|
|
155
|
-
//#endregion
|
|
156
|
-
//#region src/gpu-lease/quotes.d.ts
|
|
157
|
-
/** The exact string the operator signs — mirrors the blueprint's
|
|
158
|
-
* `canonical_quote_payload` byte-for-byte. Every priced field is bound. */
|
|
159
|
-
declare function canonicalQuotePayload(quote: {
|
|
160
|
-
gpuClass: string;
|
|
161
|
-
pricePerSecond: string;
|
|
162
|
-
durationSeconds: number;
|
|
163
|
-
confidentiality: number;
|
|
164
|
-
escrowTotal: string;
|
|
165
|
-
intentHash: string;
|
|
166
|
-
validUntil: number;
|
|
167
|
-
}): string;
|
|
168
|
-
/** Offline EIP-191 recovery over the canonical payload. */
|
|
169
|
-
declare function verifyOperatorQuote(quote: OperatorQuote): Promise<`0x${string}`>;
|
|
170
|
-
type QuoteRejection = {
|
|
171
|
-
kind: "stale";
|
|
172
|
-
validUntil: number;
|
|
173
|
-
now: number;
|
|
174
|
-
} | {
|
|
175
|
-
kind: "class-mismatch";
|
|
176
|
-
requested: string;
|
|
177
|
-
quoted: string;
|
|
178
|
-
} | {
|
|
179
|
-
kind: "escrow-inconsistent";
|
|
180
|
-
expected: bigint;
|
|
181
|
-
actual: bigint;
|
|
182
|
-
} | {
|
|
183
|
-
kind: "confidentiality-mismatch";
|
|
184
|
-
requested: number;
|
|
185
|
-
quoted: number;
|
|
186
|
-
} | {
|
|
187
|
-
kind: "signature-mismatch";
|
|
188
|
-
claimed: string;
|
|
189
|
-
recovered: string;
|
|
190
|
-
} | {
|
|
191
|
-
kind: "unsigned";
|
|
192
|
-
operator: string;
|
|
193
|
-
};
|
|
194
|
-
interface QuoteFilterInput {
|
|
195
|
-
requestedClass: string;
|
|
196
|
-
requestedDurationSeconds: number;
|
|
197
|
-
requestedConfidentiality: number;
|
|
198
|
-
now?: () => number;
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Validate one quote. Fail-closed on every field the RFQ binds:
|
|
202
|
-
* class, duration-derived escrow, confidentiality, and expiry.
|
|
203
|
-
*/
|
|
204
|
-
declare function validateQuote(quote: OperatorQuote, input: QuoteFilterInput): ValidatedQuote | QuoteRejection;
|
|
205
|
-
/**
|
|
206
|
-
* Collect validated quotes from N operators and rank cheapest-first.
|
|
207
|
-
* Operators that fail validation (or whose fetch rejects) are reported,
|
|
208
|
-
* never silently dropped — the buyer sees why an operator lost.
|
|
209
|
-
*/
|
|
210
|
-
declare function selectQuotes(quotes: {
|
|
211
|
-
operator: string;
|
|
212
|
-
quote: OperatorQuote;
|
|
213
|
-
}[], input: QuoteFilterInput): {
|
|
214
|
-
ranked: {
|
|
215
|
-
operator: string;
|
|
216
|
-
validated: ValidatedQuote;
|
|
217
|
-
}[];
|
|
218
|
-
rejected: {
|
|
219
|
-
operator: string;
|
|
220
|
-
reason: QuoteRejection;
|
|
221
|
-
}[];
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* Enforce the signed RFQ envelope when present:
|
|
225
|
-
* - signature present => it MUST recover to the claimed operator address;
|
|
226
|
-
* invalid signature => reject (config-trust is dead on this path).
|
|
227
|
-
* - no signature => the endpoint-config address is used (interim fallback);
|
|
228
|
-
* strict mode rejects unsigned quotes outright.
|
|
229
|
-
*/
|
|
230
|
-
declare function validateQuoteIdentity(quote: OperatorQuote, opts?: {
|
|
231
|
-
strict?: boolean;
|
|
232
|
-
}): Promise<ValidatedQuote | QuoteRejection>;
|
|
233
|
-
//#endregion
|
|
234
|
-
//#region src/gpu-lease/vault.d.ts
|
|
235
|
-
declare const GPU_LEASE_VAULT_ABI: readonly [{
|
|
236
|
-
readonly name: "create";
|
|
237
|
-
readonly type: "function";
|
|
238
|
-
readonly stateMutability: "payable";
|
|
239
|
-
readonly inputs: readonly [{
|
|
240
|
-
readonly type: "address";
|
|
241
|
-
readonly name: "operator";
|
|
242
|
-
}, {
|
|
243
|
-
readonly type: "uint128";
|
|
244
|
-
readonly name: "pricePerSecond";
|
|
245
|
-
}, {
|
|
246
|
-
readonly type: "uint64";
|
|
247
|
-
readonly name: "durationSeconds";
|
|
248
|
-
}, {
|
|
249
|
-
readonly type: "bytes32";
|
|
250
|
-
readonly name: "intentHash";
|
|
251
|
-
}, {
|
|
252
|
-
readonly type: "uint8";
|
|
253
|
-
readonly name: "confidentiality";
|
|
254
|
-
}, {
|
|
255
|
-
readonly type: "bytes";
|
|
256
|
-
readonly name: "endpointInfo";
|
|
257
|
-
}];
|
|
258
|
-
readonly outputs: readonly [{
|
|
259
|
-
readonly type: "bytes32";
|
|
260
|
-
readonly name: "leaseId";
|
|
261
|
-
}];
|
|
262
|
-
}, {
|
|
263
|
-
readonly name: "extend";
|
|
264
|
-
readonly type: "function";
|
|
265
|
-
readonly stateMutability: "payable";
|
|
266
|
-
readonly inputs: readonly [{
|
|
267
|
-
readonly type: "bytes32";
|
|
268
|
-
readonly name: "leaseId";
|
|
269
|
-
}, {
|
|
270
|
-
readonly type: "uint64";
|
|
271
|
-
readonly name: "addSeconds";
|
|
272
|
-
}];
|
|
273
|
-
readonly outputs: readonly [];
|
|
274
|
-
}, {
|
|
275
|
-
readonly name: "release";
|
|
276
|
-
readonly type: "function";
|
|
277
|
-
readonly stateMutability: "nonpayable";
|
|
278
|
-
readonly inputs: readonly [{
|
|
279
|
-
readonly type: "bytes32";
|
|
280
|
-
readonly name: "leaseId";
|
|
281
|
-
}];
|
|
282
|
-
readonly outputs: readonly [];
|
|
283
|
-
}, {
|
|
284
|
-
readonly name: "reap";
|
|
285
|
-
readonly type: "function";
|
|
286
|
-
readonly stateMutability: "nonpayable";
|
|
287
|
-
readonly inputs: readonly [{
|
|
288
|
-
readonly type: "bytes32";
|
|
289
|
-
readonly name: "leaseId";
|
|
290
|
-
}];
|
|
291
|
-
readonly outputs: readonly [];
|
|
292
|
-
}, {
|
|
293
|
-
readonly name: "withdrawEarnings";
|
|
294
|
-
readonly type: "function";
|
|
295
|
-
readonly stateMutability: "nonpayable";
|
|
296
|
-
readonly inputs: readonly [];
|
|
297
|
-
readonly outputs: readonly [];
|
|
298
|
-
}, {
|
|
299
|
-
readonly name: "totalEscrowed";
|
|
300
|
-
readonly type: "function";
|
|
301
|
-
readonly stateMutability: "view";
|
|
302
|
-
readonly inputs: readonly [];
|
|
303
|
-
readonly outputs: readonly [{
|
|
304
|
-
readonly type: "uint256";
|
|
305
|
-
}];
|
|
306
|
-
}, {
|
|
307
|
-
readonly name: "operatorEarnings";
|
|
308
|
-
readonly type: "function";
|
|
309
|
-
readonly stateMutability: "view";
|
|
310
|
-
readonly inputs: readonly [];
|
|
311
|
-
readonly outputs: readonly [{
|
|
312
|
-
readonly type: "uint256";
|
|
313
|
-
}];
|
|
314
|
-
}, {
|
|
315
|
-
readonly name: "leases";
|
|
316
|
-
readonly type: "function";
|
|
317
|
-
readonly stateMutability: "view";
|
|
318
|
-
readonly inputs: readonly [{
|
|
319
|
-
readonly type: "bytes32";
|
|
320
|
-
}];
|
|
321
|
-
readonly outputs: readonly [{
|
|
322
|
-
readonly type: "address";
|
|
323
|
-
readonly name: "operator";
|
|
324
|
-
}, {
|
|
325
|
-
readonly type: "address";
|
|
326
|
-
readonly name: "lessee";
|
|
327
|
-
}, {
|
|
328
|
-
readonly type: "uint128";
|
|
329
|
-
readonly name: "escrow";
|
|
330
|
-
}, {
|
|
331
|
-
readonly type: "uint128";
|
|
332
|
-
readonly name: "pricePerSecond";
|
|
333
|
-
}, {
|
|
334
|
-
readonly type: "uint64";
|
|
335
|
-
readonly name: "expiry";
|
|
336
|
-
}, {
|
|
337
|
-
readonly type: "bytes32";
|
|
338
|
-
readonly name: "intentHash";
|
|
339
|
-
}, {
|
|
340
|
-
readonly type: "uint8";
|
|
341
|
-
readonly name: "confidentiality";
|
|
342
|
-
}, {
|
|
343
|
-
readonly type: "uint8";
|
|
344
|
-
readonly name: "state";
|
|
345
|
-
}];
|
|
346
|
-
}, {
|
|
347
|
-
readonly name: "LeaseCreated";
|
|
348
|
-
readonly type: "event";
|
|
349
|
-
readonly inputs: readonly [{
|
|
350
|
-
readonly type: "bytes32";
|
|
351
|
-
readonly name: "leaseId";
|
|
352
|
-
readonly indexed: true;
|
|
353
|
-
}, {
|
|
354
|
-
readonly type: "address";
|
|
355
|
-
readonly name: "operator";
|
|
356
|
-
readonly indexed: true;
|
|
357
|
-
}, {
|
|
358
|
-
readonly type: "address";
|
|
359
|
-
readonly name: "lessee";
|
|
360
|
-
readonly indexed: true;
|
|
361
|
-
}, {
|
|
362
|
-
readonly type: "uint128";
|
|
363
|
-
readonly name: "escrow";
|
|
364
|
-
}, {
|
|
365
|
-
readonly type: "uint128";
|
|
366
|
-
readonly name: "pricePerSecond";
|
|
367
|
-
}, {
|
|
368
|
-
readonly type: "uint64";
|
|
369
|
-
readonly name: "expiry";
|
|
370
|
-
}, {
|
|
371
|
-
readonly type: "bytes32";
|
|
372
|
-
readonly name: "intentHash";
|
|
373
|
-
}, {
|
|
374
|
-
readonly type: "uint8";
|
|
375
|
-
readonly name: "confidentiality";
|
|
376
|
-
}, {
|
|
377
|
-
readonly type: "bytes";
|
|
378
|
-
readonly name: "endpointInfo";
|
|
379
|
-
}, {
|
|
380
|
-
readonly type: "uint16";
|
|
381
|
-
readonly name: "schemaVersion";
|
|
382
|
-
}];
|
|
383
|
-
}, {
|
|
384
|
-
readonly name: "LeaseReleased";
|
|
385
|
-
readonly type: "event";
|
|
386
|
-
readonly inputs: readonly [{
|
|
387
|
-
readonly type: "bytes32";
|
|
388
|
-
readonly name: "leaseId";
|
|
389
|
-
readonly indexed: true;
|
|
390
|
-
}, {
|
|
391
|
-
readonly type: "uint128";
|
|
392
|
-
readonly name: "refund";
|
|
393
|
-
}, {
|
|
394
|
-
readonly type: "uint128";
|
|
395
|
-
readonly name: "operatorTake";
|
|
396
|
-
}];
|
|
397
|
-
}, {
|
|
398
|
-
readonly name: "LeaseReaped";
|
|
399
|
-
readonly type: "event";
|
|
400
|
-
readonly inputs: readonly [{
|
|
401
|
-
readonly type: "bytes32";
|
|
402
|
-
readonly name: "leaseId";
|
|
403
|
-
readonly indexed: true;
|
|
404
|
-
}, {
|
|
405
|
-
readonly type: "uint128";
|
|
406
|
-
readonly name: "operatorTake";
|
|
407
|
-
}, {
|
|
408
|
-
readonly type: "address";
|
|
409
|
-
readonly name: "caller";
|
|
410
|
-
}];
|
|
411
|
-
}];
|
|
412
|
-
/** Vault lease states (mirrors the contract). */
|
|
413
|
-
declare const LEASE_STATE: {
|
|
414
|
-
readonly LIVE: 0;
|
|
415
|
-
readonly RELEASED: 1;
|
|
416
|
-
readonly REAPED: 2;
|
|
417
|
-
};
|
|
418
|
-
interface VaultLeaseView {
|
|
419
|
-
operator: `0x${string}`;
|
|
420
|
-
lessee: `0x${string}`;
|
|
421
|
-
escrowWei: bigint;
|
|
422
|
-
pricePerSecondWei: bigint;
|
|
423
|
-
/** Unix seconds — the chain clock is the parking meter's truth. */
|
|
424
|
-
expiry: bigint;
|
|
425
|
-
intentHash: `0x${string}`;
|
|
426
|
-
confidentiality: number;
|
|
427
|
-
state: number;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Exact refund projection (I3): pricePerSecond × max(expiry − now, 0).
|
|
431
|
-
* Exact by construction because escrow === price × paidSeconds in the vault.
|
|
432
|
-
*/
|
|
433
|
-
declare function projectRefundWei(lease: VaultLeaseView, nowSeconds: bigint): {
|
|
434
|
-
refundWei: bigint;
|
|
435
|
-
operatorTakeWei: bigint;
|
|
436
|
-
};
|
|
437
|
-
/** I2 from the client side: unpayable time can never be requested. */
|
|
438
|
-
declare function maxAffordableSeconds(escrowWei: bigint, pricePerSecondWei: bigint): bigint;
|
|
439
|
-
//#endregion
|
|
440
|
-
//#region src/gpu-lease/resolver.d.ts
|
|
441
|
-
/** Job ids — MUST match the blueprint router (sequential, no gaps). */
|
|
442
|
-
declare const GPU_LEASE_JOBS: {
|
|
443
|
-
readonly LEASE: 0;
|
|
444
|
-
readonly RELEASE: 1;
|
|
445
|
-
readonly EXTEND: 2;
|
|
446
|
-
readonly REAP: 3;
|
|
447
|
-
};
|
|
448
|
-
interface GpuLeaseChain {
|
|
449
|
-
/** The buyer's address (the RFQ binds the requester — I5). */
|
|
450
|
-
readonly account: `0x${string}`;
|
|
451
|
-
/** Create the escrowed lease on the vault; returns the vault leaseId. */
|
|
452
|
-
createVaultLease(input: {
|
|
453
|
-
operator: `0x${string}`;
|
|
454
|
-
pricePerSecondWei: bigint;
|
|
455
|
-
durationSeconds: bigint;
|
|
456
|
-
intentHash: `0x${string}`;
|
|
457
|
-
confidentiality: number;
|
|
458
|
-
endpointInfo: string;
|
|
459
|
-
escrowWei: bigint;
|
|
460
|
-
}): Promise<`0x${string}`>;
|
|
461
|
-
/** Submit a job through tnt-core; resolves with the result payload. */
|
|
462
|
-
submitJob(jobId: number, encodedInput: `0x${string}`): Promise<`0x${string}`>;
|
|
463
|
-
/** Read a vault lease (chain clock truth for projections). */
|
|
464
|
-
readLease(leaseId: `0x${string}`): Promise<VaultLeaseView>;
|
|
465
|
-
/** The chain's current timestamp (unix seconds) — meter truth, not Date.now(). */
|
|
466
|
-
chainNow?(): Promise<bigint>;
|
|
467
|
-
/** Voluntary release on the vault; returns {refund, take} wei. */
|
|
468
|
-
releaseLease(leaseId: `0x${string}`): Promise<{
|
|
469
|
-
refundWei: bigint;
|
|
470
|
-
operatorTakeWei: bigint;
|
|
471
|
-
}>;
|
|
472
|
-
}
|
|
473
|
-
interface GpuLeaseOptions {
|
|
474
|
-
gpuClass: string;
|
|
475
|
-
durationSeconds: number;
|
|
476
|
-
confidentiality?: number;
|
|
477
|
-
region?: string;
|
|
478
|
-
/** Operators to request quotes from (multi-quote = the decentralized scheduler). */
|
|
479
|
-
operators: OperatorEndpoint[];
|
|
480
|
-
chain: GpuLeaseChain;
|
|
481
|
-
now?: () => number;
|
|
482
|
-
}
|
|
483
|
-
interface GpuLeaseOutcome {
|
|
484
|
-
lease: GpuLease;
|
|
485
|
-
/** Operators ranked cheapest-first. */
|
|
486
|
-
rankedOperators: string[];
|
|
487
|
-
}
|
|
488
|
-
/** Resolve a GPU lease end-to-end. Throws with the full picture on failure. */
|
|
489
|
-
declare function gpuLease(options: GpuLeaseOptions): Promise<GpuLeaseOutcome>;
|
|
490
|
-
/** Teardown: voluntary release with an exact-refund receipt (I3/I4). */
|
|
491
|
-
declare function releaseGpuLease(leaseId: `0x${string}`, chain: GpuLeaseChain): Promise<RefundReceipt>;
|
|
492
|
-
/**
|
|
493
|
-
* Refund projection for UI meters. Uses the chain clock when the injected
|
|
494
|
-
* chain provides `chainNow()`; otherwise requires an explicit timestamp.
|
|
495
|
-
* Never Date.now() — the drift lesson from the blueprint's own E2E.
|
|
496
|
-
*/
|
|
497
|
-
declare function projectGpuLeaseRefund(leaseId: `0x${string}`, chain: GpuLeaseChain, explicitNowSeconds?: bigint): Promise<{
|
|
498
|
-
refundWei: bigint;
|
|
499
|
-
operatorTakeWei: bigint;
|
|
500
|
-
nowSeconds: bigint;
|
|
501
|
-
}>;
|
|
502
|
-
//#endregion
|
|
503
|
-
export { Capabilities, ClassCapability, GPU_LEASE_JOBS, GPU_LEASE_REQUEST_ABI, GPU_LEASE_SCHEMA_VERSION, GPU_LEASE_VAULT_ABI, GpuLease, GpuLeaseChain, GpuLeaseOperatorClient, GpuLeaseOptions, GpuLeaseOutcome, GpuLeaseOutputDecoded, GpuLeaseRequestParams, INTENT_VERSION, JsonRequestBody, LEASE_STATE, LeaseStatus, OperatorEndpoint, OperatorQuote, QuoteFilterInput, QuoteParams, QuoteRejection, RefundReceipt, SessionChallenge, SessionCredential, ValidatedQuote, VaultLeaseView, canonicalQuotePayload, decodeGpuLeaseOutput, encodeGpuLeaseRequest, gpuLease, gpuLeaseIntentHash, maxAffordableSeconds, projectGpuLeaseRefund, projectRefundWei, releaseGpuLease, selectQuotes, validateQuote, validateQuoteIdentity, verifyOperatorQuote };
|
package/dist/gpu-lease/index.js
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
import { decodeAbiParameters, encodeAbiParameters, keccak256, parseAbi, parseAbiParameters, recoverMessageAddress, stringToHex } from "viem";
|
|
2
|
-
//#region src/gpu-lease/intent.ts
|
|
3
|
-
/**
|
|
4
|
-
* Canonical GPU-lease intent + job ABI encoding — MUST match:
|
|
5
|
-
* gpu-lease-blueprint/gpu-lease-blueprint-lib/src/jobs/mod.rs (intent_hash)
|
|
6
|
-
* gpu-lease-blueprint/contracts/src/GpuLeaseBlueprint.sol (GpuLeaseRequest)
|
|
7
|
-
* gpu-lease-blueprint/metadata/blueprint.json (encodeType, generated).
|
|
8
|
-
*/
|
|
9
|
-
const INTENT_VERSION = 1;
|
|
10
|
-
/** keccak256 of the canonical intent string. */
|
|
11
|
-
function gpuLeaseIntentHash(input) {
|
|
12
|
-
return keccak256(stringToHex(`gpu-lease-intent|v${input.intentVersion}|${input.gpuClass}|${input.durationSeconds}|${input.confidentiality}|${input.region}`));
|
|
13
|
-
}
|
|
14
|
-
/** ABI shape of GpuLeaseRequest — mirrors the blueprint's sol! type. */
|
|
15
|
-
const GPU_LEASE_REQUEST_ABI = parseAbiParameters("(uint8 intentVersion, bytes32 intentHash, uint128 pricePerSecond, uint64 durationSeconds, uint8 confidentiality, string gpuClass, string region, address lessee, bytes32 leaseId)");
|
|
16
|
-
/**
|
|
17
|
-
* ABI-encoded GpuLeaseRequest — the LEASE job calldata payload.
|
|
18
|
-
* Positional (ABI order) — order is pinned by the blueprint's generated
|
|
19
|
-
* encodeType in metadata/blueprint.json.
|
|
20
|
-
*/
|
|
21
|
-
function encodeGpuLeaseRequest(params) {
|
|
22
|
-
return encodeAbiParameters(GPU_LEASE_REQUEST_ABI, [[
|
|
23
|
-
params.intentVersion,
|
|
24
|
-
params.intentHash,
|
|
25
|
-
params.pricePerSecondWei,
|
|
26
|
-
params.durationSeconds,
|
|
27
|
-
params.confidentiality,
|
|
28
|
-
params.gpuClass,
|
|
29
|
-
params.region,
|
|
30
|
-
params.lessee,
|
|
31
|
-
params.leaseId
|
|
32
|
-
]]);
|
|
33
|
-
}
|
|
34
|
-
//#endregion
|
|
35
|
-
//#region src/gpu-lease/types.ts
|
|
36
|
-
/**
|
|
37
|
-
* GPU lease client types — mirrors the gpu-lease-blueprint operator API
|
|
38
|
-
* (gpu-lease-blueprint/gpu-lease-blueprint-lib/src/api.rs) and the on-chain
|
|
39
|
-
* ABI (contracts/src/GpuLeaseBlueprint.sol sol! mirror).
|
|
40
|
-
*
|
|
41
|
-
* Every on-chain and off-chain surface is schemaVersioned; unknown versions
|
|
42
|
-
* fail closed (SPEC §3 of the blueprint).
|
|
43
|
-
*/
|
|
44
|
-
/** The only schema this client understands. */
|
|
45
|
-
const GPU_LEASE_SCHEMA_VERSION = 1;
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/gpu-lease/operators.ts
|
|
48
|
-
function assertKnownSchema(actual, where) {
|
|
49
|
-
if (actual !== 1) throw new Error(`${where}: unknown schemaVersion ${actual} (client understands ${GPU_LEASE_VERSION_TEXT}) — failing closed`);
|
|
50
|
-
}
|
|
51
|
-
const GPU_LEASE_VERSION_TEXT = String(1);
|
|
52
|
-
async function getJson(endpoint, path) {
|
|
53
|
-
const res = await (endpoint.fetch ?? fetch)(new URL(path, endpoint.baseUrl).toString(), { headers: { accept: "application/json" } });
|
|
54
|
-
if (!res.ok) throw new Error(`GET ${path}: operator returned ${res.status}`);
|
|
55
|
-
const body = await res.json();
|
|
56
|
-
assertKnownSchema(body.schemaVersion, `GET ${path}`);
|
|
57
|
-
return body;
|
|
58
|
-
}
|
|
59
|
-
async function postJson(endpoint, path, payload, requireSchema = false) {
|
|
60
|
-
const res = await (endpoint.fetch ?? fetch)(new URL(path, endpoint.baseUrl).toString(), {
|
|
61
|
-
method: "POST",
|
|
62
|
-
headers: {
|
|
63
|
-
"content-type": "application/json",
|
|
64
|
-
accept: "application/json"
|
|
65
|
-
},
|
|
66
|
-
body: JSON.stringify(payload)
|
|
67
|
-
});
|
|
68
|
-
if (!res.ok) {
|
|
69
|
-
const detail = await res.text().catch(() => "");
|
|
70
|
-
throw new Error(`POST ${path}: operator returned ${res.status} ${detail.slice(0, 200)}`);
|
|
71
|
-
}
|
|
72
|
-
const body = await res.json();
|
|
73
|
-
if (requireSchema) assertKnownSchema(body.schemaVersion, `POST ${path}`);
|
|
74
|
-
return body;
|
|
75
|
-
}
|
|
76
|
-
var GpuLeaseOperatorClient = class {
|
|
77
|
-
constructor(endpoint) {
|
|
78
|
-
this.endpoint = endpoint;
|
|
79
|
-
}
|
|
80
|
-
capabilities() {
|
|
81
|
-
return getJson(this.endpoint, "/api/capabilities");
|
|
82
|
-
}
|
|
83
|
-
async quote(params) {
|
|
84
|
-
const quote = await postJson(this.endpoint, "/api/quote", {
|
|
85
|
-
gpuClass: params.gpuClass,
|
|
86
|
-
durationSeconds: params.durationSeconds,
|
|
87
|
-
confidentiality: params.confidentiality ?? 0,
|
|
88
|
-
...params.region !== void 0 ? { region: params.region } : {}
|
|
89
|
-
}, true);
|
|
90
|
-
return {
|
|
91
|
-
...quote,
|
|
92
|
-
operatorAddress: quote.operatorAddress ?? this.endpoint.address
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
leaseStatus(leaseId) {
|
|
96
|
-
return getJson(this.endpoint, `/api/leases/${leaseId.replace(/^0x/, "")}`);
|
|
97
|
-
}
|
|
98
|
-
sessionChallenge(leaseId, lessee) {
|
|
99
|
-
return postJson(this.endpoint, "/api/session/challenge", {
|
|
100
|
-
leaseId,
|
|
101
|
-
lessee
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
sessionVerify(nonce, signature) {
|
|
105
|
-
return postJson(this.endpoint, "/api/session/verify", {
|
|
106
|
-
nonce,
|
|
107
|
-
signature
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
//#endregion
|
|
112
|
-
//#region src/gpu-lease/output.ts
|
|
113
|
-
/**
|
|
114
|
-
* GpuLeaseOutput decoding — the LEASE job result payload. The operator API
|
|
115
|
-
* does NOT carry this (it is a job RESULT); it arrives from the chain via
|
|
116
|
-
* the injected job client.
|
|
117
|
-
*/
|
|
118
|
-
const GPU_LEASE_OUTPUT_ABI = parseAbiParameters("(bytes32 leaseId, string endpoint, uint16 schemaVersion)");
|
|
119
|
-
/** Decode + fail closed on unknown schemaVersion (blueprint SPEC §3). */
|
|
120
|
-
function decodeGpuLeaseOutput(encoded) {
|
|
121
|
-
const [decoded] = decodeAbiParameters(GPU_LEASE_OUTPUT_ABI, encoded);
|
|
122
|
-
if (decoded.schemaVersion !== 1) throw new Error(`GpuLeaseOutput: unknown schemaVersion ${decoded.schemaVersion} — failing closed`);
|
|
123
|
-
return decoded;
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/gpu-lease/quotes.ts
|
|
127
|
-
/**
|
|
128
|
-
* Multi-operator RFQ: collect quotes, validate each against fail-closed
|
|
129
|
-
* rules, rank by price. Pure — no I/O. Mirrors the validated-quote flow
|
|
130
|
-
* proven in blueprint #1568 and the operator policy's ceiling semantics.
|
|
131
|
-
*/
|
|
132
|
-
/** The exact string the operator signs — mirrors the blueprint's
|
|
133
|
-
* `canonical_quote_payload` byte-for-byte. Every priced field is bound. */
|
|
134
|
-
function canonicalQuotePayload(quote) {
|
|
135
|
-
return `gpu-lease-quote|v1|${quote.gpuClass}|${quote.pricePerSecond}|${quote.durationSeconds}|${quote.confidentiality}|${quote.escrowTotal}|${quote.intentHash}|${quote.validUntil}`;
|
|
136
|
-
}
|
|
137
|
-
/** Offline EIP-191 recovery over the canonical payload. */
|
|
138
|
-
async function verifyOperatorQuote(quote) {
|
|
139
|
-
return (await recoverMessageAddress({
|
|
140
|
-
message: canonicalQuotePayload(quote),
|
|
141
|
-
signature: quote.signature
|
|
142
|
-
})).toLowerCase();
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Validate one quote. Fail-closed on every field the RFQ binds:
|
|
146
|
-
* class, duration-derived escrow, confidentiality, and expiry.
|
|
147
|
-
*/
|
|
148
|
-
function validateQuote(quote, input) {
|
|
149
|
-
const now = (input.now ?? Date.now)() / 1e3;
|
|
150
|
-
if (quote.gpuClass !== input.requestedClass) return {
|
|
151
|
-
kind: "class-mismatch",
|
|
152
|
-
requested: input.requestedClass,
|
|
153
|
-
quoted: quote.gpuClass
|
|
154
|
-
};
|
|
155
|
-
if (quote.confidentiality !== input.requestedConfidentiality) return {
|
|
156
|
-
kind: "confidentiality-mismatch",
|
|
157
|
-
requested: input.requestedConfidentiality,
|
|
158
|
-
quoted: quote.confidentiality
|
|
159
|
-
};
|
|
160
|
-
const price = BigInt(quote.pricePerSecond);
|
|
161
|
-
const expectedEscrow = price * BigInt(quote.durationSeconds);
|
|
162
|
-
const actualEscrow = BigInt(quote.escrowTotal);
|
|
163
|
-
if (expectedEscrow !== actualEscrow) return {
|
|
164
|
-
kind: "escrow-inconsistent",
|
|
165
|
-
expected: expectedEscrow,
|
|
166
|
-
actual: actualEscrow
|
|
167
|
-
};
|
|
168
|
-
if (quote.validUntil <= now) return {
|
|
169
|
-
kind: "stale",
|
|
170
|
-
validUntil: quote.validUntil,
|
|
171
|
-
now
|
|
172
|
-
};
|
|
173
|
-
return {
|
|
174
|
-
quote,
|
|
175
|
-
pricePerSecondWei: price,
|
|
176
|
-
escrowTotalWei: actualEscrow
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Collect validated quotes from N operators and rank cheapest-first.
|
|
181
|
-
* Operators that fail validation (or whose fetch rejects) are reported,
|
|
182
|
-
* never silently dropped — the buyer sees why an operator lost.
|
|
183
|
-
*/
|
|
184
|
-
function selectQuotes(quotes, input) {
|
|
185
|
-
const ranked = [];
|
|
186
|
-
const rejected = [];
|
|
187
|
-
for (const { operator, quote } of quotes) {
|
|
188
|
-
const result = validateQuote(quote, input);
|
|
189
|
-
if ("kind" in result) rejected.push({
|
|
190
|
-
operator,
|
|
191
|
-
reason: result
|
|
192
|
-
});
|
|
193
|
-
else ranked.push({
|
|
194
|
-
operator,
|
|
195
|
-
validated: result
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
ranked.sort((a, b) => {
|
|
199
|
-
if (a.validated.pricePerSecondWei !== b.validated.pricePerSecondWei) return a.validated.pricePerSecondWei < b.validated.pricePerSecondWei ? -1 : 1;
|
|
200
|
-
return a.validated.escrowTotalWei < b.validated.escrowTotalWei ? -1 : 1;
|
|
201
|
-
});
|
|
202
|
-
return {
|
|
203
|
-
ranked,
|
|
204
|
-
rejected
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Enforce the signed RFQ envelope when present:
|
|
209
|
-
* - signature present => it MUST recover to the claimed operator address;
|
|
210
|
-
* invalid signature => reject (config-trust is dead on this path).
|
|
211
|
-
* - no signature => the endpoint-config address is used (interim fallback);
|
|
212
|
-
* strict mode rejects unsigned quotes outright.
|
|
213
|
-
*/
|
|
214
|
-
async function validateQuoteIdentity(quote, opts = {}) {
|
|
215
|
-
const base = {
|
|
216
|
-
quote,
|
|
217
|
-
pricePerSecondWei: BigInt(quote.pricePerSecond),
|
|
218
|
-
escrowTotalWei: BigInt(quote.escrowTotal)
|
|
219
|
-
};
|
|
220
|
-
if (quote.signature) {
|
|
221
|
-
const recovered = await verifyOperatorQuote(quote).catch(() => null);
|
|
222
|
-
const claimed = quote.operatorAddress.toLowerCase();
|
|
223
|
-
if (recovered === null || recovered !== claimed) return {
|
|
224
|
-
kind: "signature-mismatch",
|
|
225
|
-
claimed,
|
|
226
|
-
recovered: recovered ?? "unrecoverable"
|
|
227
|
-
};
|
|
228
|
-
return base;
|
|
229
|
-
}
|
|
230
|
-
if (opts.strict) return {
|
|
231
|
-
kind: "unsigned",
|
|
232
|
-
operator: quote.operatorAddress
|
|
233
|
-
};
|
|
234
|
-
return base;
|
|
235
|
-
}
|
|
236
|
-
//#endregion
|
|
237
|
-
//#region src/gpu-lease/vault.ts
|
|
238
|
-
/**
|
|
239
|
-
* Vault money semantics — the client mirror of GpuLeaseVault.sol
|
|
240
|
-
* (gpu-lease-blueprint/contracts/src/GpuLeaseVault.sol), invariants I1–I5.
|
|
241
|
-
* Exact integers everywhere; wei only, never floats.
|
|
242
|
-
*/
|
|
243
|
-
const GPU_LEASE_VAULT_ABI = parseAbi([
|
|
244
|
-
"function create(address operator, uint128 pricePerSecond, uint64 durationSeconds, bytes32 intentHash, uint8 confidentiality, bytes endpointInfo) external payable returns (bytes32 leaseId)",
|
|
245
|
-
"function extend(bytes32 leaseId, uint64 addSeconds) external payable",
|
|
246
|
-
"function release(bytes32 leaseId) external",
|
|
247
|
-
"function reap(bytes32 leaseId) external",
|
|
248
|
-
"function withdrawEarnings() external",
|
|
249
|
-
"function totalEscrowed() external view returns (uint256)",
|
|
250
|
-
"function operatorEarnings() external view returns (uint256)",
|
|
251
|
-
"function leases(bytes32) external view returns (address operator, address lessee, uint128 escrow, uint128 pricePerSecond, uint64 expiry, bytes32 intentHash, uint8 confidentiality, uint8 state)",
|
|
252
|
-
"event LeaseCreated(bytes32 indexed leaseId, address indexed operator, address indexed lessee, uint128 escrow, uint128 pricePerSecond, uint64 expiry, bytes32 intentHash, uint8 confidentiality, bytes endpointInfo, uint16 schemaVersion)",
|
|
253
|
-
"event LeaseReleased(bytes32 indexed leaseId, uint128 refund, uint128 operatorTake)",
|
|
254
|
-
"event LeaseReaped(bytes32 indexed leaseId, uint128 operatorTake, address caller)"
|
|
255
|
-
]);
|
|
256
|
-
/** Vault lease states (mirrors the contract). */
|
|
257
|
-
const LEASE_STATE = {
|
|
258
|
-
LIVE: 0,
|
|
259
|
-
RELEASED: 1,
|
|
260
|
-
REAPED: 2
|
|
261
|
-
};
|
|
262
|
-
/**
|
|
263
|
-
* Exact refund projection (I3): pricePerSecond × max(expiry − now, 0).
|
|
264
|
-
* Exact by construction because escrow === price × paidSeconds in the vault.
|
|
265
|
-
*/
|
|
266
|
-
function projectRefundWei(lease, nowSeconds) {
|
|
267
|
-
const remaining = lease.expiry > nowSeconds ? lease.expiry - nowSeconds : 0n;
|
|
268
|
-
const refundWei = lease.pricePerSecondWei * remaining;
|
|
269
|
-
return {
|
|
270
|
-
refundWei,
|
|
271
|
-
operatorTakeWei: lease.escrowWei - refundWei
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
/** I2 from the client side: unpayable time can never be requested. */
|
|
275
|
-
function maxAffordableSeconds(escrowWei, pricePerSecondWei) {
|
|
276
|
-
if (pricePerSecondWei <= 0n) throw new Error("pricePerSecond must be positive");
|
|
277
|
-
return escrowWei / pricePerSecondWei;
|
|
278
|
-
}
|
|
279
|
-
//#endregion
|
|
280
|
-
//#region src/gpu-lease/resolver.ts
|
|
281
|
-
/**
|
|
282
|
-
* `gpuLease()` — the SPEC §5 resolver: collect + validate quotes → escrow on
|
|
283
|
-
* the vault → LEASE job through tnt-core → teardown with an exact refund
|
|
284
|
-
* receipt. Chain and job submission are INJECTED (transport-agnostic: works
|
|
285
|
-
* with viem wallets, the TangleDriver, or test doubles).
|
|
286
|
-
*/
|
|
287
|
-
/** Job ids — MUST match the blueprint router (sequential, no gaps). */
|
|
288
|
-
const GPU_LEASE_JOBS = {
|
|
289
|
-
LEASE: 0,
|
|
290
|
-
RELEASE: 1,
|
|
291
|
-
EXTEND: 2,
|
|
292
|
-
REAP: 3
|
|
293
|
-
};
|
|
294
|
-
/** Resolve a GPU lease end-to-end. Throws with the full picture on failure. */
|
|
295
|
-
async function gpuLease(options) {
|
|
296
|
-
const { gpuClass, durationSeconds, region = "any" } = options;
|
|
297
|
-
const confidentiality = options.confidentiality ?? 0;
|
|
298
|
-
const collected = (await Promise.allSettled(options.operators.map(async (endpoint) => {
|
|
299
|
-
const quote = await new GpuLeaseOperatorClient(endpoint).quote({
|
|
300
|
-
gpuClass,
|
|
301
|
-
durationSeconds,
|
|
302
|
-
confidentiality,
|
|
303
|
-
region
|
|
304
|
-
});
|
|
305
|
-
return {
|
|
306
|
-
operator: endpoint.baseUrl,
|
|
307
|
-
quote
|
|
308
|
-
};
|
|
309
|
-
}))).flatMap((s) => s.status === "fulfilled" ? [s.value] : []);
|
|
310
|
-
if (collected.length === 0) throw new Error("gpuLease: no operator returned a quote");
|
|
311
|
-
const { ranked, rejected } = selectQuotes(collected, {
|
|
312
|
-
requestedClass: gpuClass,
|
|
313
|
-
requestedDurationSeconds: durationSeconds,
|
|
314
|
-
requestedConfidentiality: confidentiality,
|
|
315
|
-
now: options.now
|
|
316
|
-
});
|
|
317
|
-
if (ranked.length === 0) {
|
|
318
|
-
const reasons = rejected.map((r) => `${r.operator}: ${r.reason.kind}`).join(", ");
|
|
319
|
-
throw new Error(`gpuLease: every quote failed validation (${reasons})`);
|
|
320
|
-
}
|
|
321
|
-
let best;
|
|
322
|
-
for (const candidate of ranked) {
|
|
323
|
-
const identity = await validateQuoteIdentity(candidate.validated.quote);
|
|
324
|
-
if ("kind" in identity) {
|
|
325
|
-
rejected.push({
|
|
326
|
-
operator: candidate.operator,
|
|
327
|
-
reason: identity
|
|
328
|
-
});
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
best = {
|
|
332
|
-
...candidate,
|
|
333
|
-
validated: identity
|
|
334
|
-
};
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
if (!best) {
|
|
338
|
-
const reasons = rejected.map((r) => `${r.operator}: ${r.reason.kind}`).join(", ");
|
|
339
|
-
throw new Error(`gpuLease: no quote passed identity verification (${reasons})`);
|
|
340
|
-
}
|
|
341
|
-
const operatorAddress = best.validated.quote.operatorAddress;
|
|
342
|
-
const intentHash = gpuLeaseIntentHash({
|
|
343
|
-
intentVersion: 1,
|
|
344
|
-
gpuClass,
|
|
345
|
-
durationSeconds,
|
|
346
|
-
confidentiality,
|
|
347
|
-
region
|
|
348
|
-
});
|
|
349
|
-
const leaseId = await options.chain.createVaultLease({
|
|
350
|
-
operator: operatorAddress,
|
|
351
|
-
pricePerSecondWei: best.validated.pricePerSecondWei,
|
|
352
|
-
durationSeconds: BigInt(durationSeconds),
|
|
353
|
-
intentHash,
|
|
354
|
-
confidentiality,
|
|
355
|
-
endpointInfo: "{}",
|
|
356
|
-
escrowWei: best.validated.escrowTotalWei
|
|
357
|
-
});
|
|
358
|
-
const encoded = encodeGpuLeaseRequest({
|
|
359
|
-
intentVersion: 1,
|
|
360
|
-
intentHash,
|
|
361
|
-
pricePerSecondWei: best.validated.pricePerSecondWei,
|
|
362
|
-
durationSeconds: BigInt(durationSeconds),
|
|
363
|
-
confidentiality,
|
|
364
|
-
gpuClass,
|
|
365
|
-
region,
|
|
366
|
-
lessee: options.chain.account,
|
|
367
|
-
leaseId
|
|
368
|
-
});
|
|
369
|
-
const output = decodeGpuLeaseOutput(await options.chain.submitJob(GPU_LEASE_JOBS.LEASE, encoded));
|
|
370
|
-
if (output.leaseId !== leaseId) throw new Error(`gpuLease: job returned leaseId ${output.leaseId}, expected the vault leaseId ${leaseId} (one identity across money and routing)`);
|
|
371
|
-
return {
|
|
372
|
-
lease: {
|
|
373
|
-
leaseId,
|
|
374
|
-
endpoint: output.endpoint,
|
|
375
|
-
schemaVersion: output.schemaVersion,
|
|
376
|
-
quote: best.validated
|
|
377
|
-
},
|
|
378
|
-
rankedOperators: ranked.map((r) => r.operator)
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
/** Teardown: voluntary release with an exact-refund receipt (I3/I4). */
|
|
382
|
-
async function releaseGpuLease(leaseId, chain) {
|
|
383
|
-
const { refundWei, operatorTakeWei } = await chain.releaseLease(leaseId);
|
|
384
|
-
return {
|
|
385
|
-
leaseId,
|
|
386
|
-
refundWei,
|
|
387
|
-
operatorTakeWei
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Refund projection for UI meters. Uses the chain clock when the injected
|
|
392
|
-
* chain provides `chainNow()`; otherwise requires an explicit timestamp.
|
|
393
|
-
* Never Date.now() — the drift lesson from the blueprint's own E2E.
|
|
394
|
-
*/
|
|
395
|
-
async function projectGpuLeaseRefund(leaseId, chain, explicitNowSeconds) {
|
|
396
|
-
const lease = await chain.readLease(leaseId);
|
|
397
|
-
let nowSeconds = explicitNowSeconds;
|
|
398
|
-
if (nowSeconds === void 0) {
|
|
399
|
-
if (!chain.chainNow) throw new Error("projectGpuLeaseRefund: chain has no chainNow() — pass explicitNowSeconds");
|
|
400
|
-
nowSeconds = await chain.chainNow();
|
|
401
|
-
}
|
|
402
|
-
const { refundWei, operatorTakeWei } = projectRefundWei(lease, nowSeconds);
|
|
403
|
-
return {
|
|
404
|
-
refundWei,
|
|
405
|
-
operatorTakeWei,
|
|
406
|
-
nowSeconds
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
//#endregion
|
|
410
|
-
export { GPU_LEASE_JOBS, GPU_LEASE_REQUEST_ABI, GPU_LEASE_SCHEMA_VERSION, GPU_LEASE_VAULT_ABI, GpuLeaseOperatorClient, INTENT_VERSION, LEASE_STATE, canonicalQuotePayload, decodeGpuLeaseOutput, encodeGpuLeaseRequest, gpuLease, gpuLeaseIntentHash, maxAffordableSeconds, projectGpuLeaseRefund, projectRefundWei, releaseGpuLease, selectQuotes, validateQuote, validateQuoteIdentity, verifyOperatorQuote };
|