zk-credits 0.2.11 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/circuits/manifest.json +1 -0
- package/dist/activated-credential-setup.d.ts +18 -0
- package/dist/activated-credential-setup.js +64 -0
- package/dist/base-event-sync.js +7 -2
- package/dist/base-sidecar.d.ts +24 -0
- package/dist/base-sidecar.js +74 -6
- package/dist/cli.js +187 -243
- package/dist/codex-launcher.d.ts +2 -1
- package/dist/codex-launcher.js +2 -2
- package/dist/codex-sdk-options.js +3 -0
- package/dist/credential-store.js +11 -6
- package/dist/gateway-root-check.d.ts +3 -0
- package/dist/gateway-root-check.js +53 -21
- package/dist/investigator.mjs +2642 -0
- package/dist/local-x402-agent.d.ts +10 -2
- package/dist/local-x402-agent.js +2166 -1531
- package/dist/responses-bridge.js +10 -1
- package/dist/rpc-config.js +4 -3
- package/dist/rpc-transport.d.ts +2 -0
- package/dist/rpc-transport.js +3 -0
- package/dist/runtime-owner.d.ts +17 -0
- package/dist/runtime-owner.js +72 -0
- package/dist/sidecar-runtime.d.ts +47 -0
- package/dist/sidecar-runtime.js +122 -0
- package/dist/slot-ledger.js +8 -3
- package/dist/task-evidence.d.ts +20 -0
- package/dist/task-evidence.js +41 -0
- package/dist/zk-credits.js +2872 -2293
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ private: anyone with it can spend your credits.
|
|
|
32
32
|
| `zk-credits setup codex` | Import a credential and configure Codex |
|
|
33
33
|
| `zk-credits setup x402` | Prepare an x402 agent |
|
|
34
34
|
| `zk-credits codex [args...]` | Start Codex with the local sidecar |
|
|
35
|
+
| `zk-credits codex --task-evidence` | Run a coding task and show its aggregate payment evidence on exit |
|
|
36
|
+
| `zk-credits investigate --chain base <transaction-hash>` | Investigate a failed Base transaction using prepaid inference |
|
|
35
37
|
| `zk-credits cline [args...]` | Start Cline with the local sidecar |
|
|
36
38
|
| `zk-credits x402-agent` | Run the included x402 agent |
|
|
37
39
|
| `zk-credits serve` | Run the sidecar in the foreground |
|
|
@@ -82,3 +84,47 @@ Your credential stays on your device. Proofs are sent to authorize each spend. T
|
|
|
82
84
|
can observe traffic metadata. This does not hide your IP address.
|
|
83
85
|
|
|
84
86
|
Base Sepolia test credits only. The circuit is not independently audited.
|
|
87
|
+
|
|
88
|
+
### Coding-task evidence (0.2.14 candidate)
|
|
89
|
+
|
|
90
|
+
After setup, `zk-credits codex --task-evidence` launches Codex against a fresh,
|
|
91
|
+
dedicated local sidecar and prints aggregate payment counters when Codex exits.
|
|
92
|
+
The provider and profile are fixed for attribution. The summary contains no
|
|
93
|
+
prompts, bearer credentials, proofs, or payment headers. `exchange_verified`
|
|
94
|
+
confirms a successful agent exit and an observed settled response; inspect the
|
|
95
|
+
code diff and tests separately to judge the coding task. The supported model and
|
|
96
|
+
reasoning defaults are selected automatically, including with older setups:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
zk-credits codex --task-evidence
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Enter your task, review the change and tests, then exit Codex to see the summary.
|
|
103
|
+
Version 0.2.12 includes this command; 0.2.11 lacks it.
|
|
104
|
+
See the [indexer sample](https://github.com/mangekyou-labs/haze-api/tree/main/examples/base-usdc-indexer).
|
|
105
|
+
|
|
106
|
+
### Transaction investigator (0.2.14 candidate)
|
|
107
|
+
|
|
108
|
+
After closing Codex, run `zk-credits investigate --chain base <transaction-hash>`
|
|
109
|
+
with the same configured credential. It fetches public execution evidence and
|
|
110
|
+
uses the custom x402 `zk-prepaid` adapter for model inference. Base mainnet is
|
|
111
|
+
the investigated chain; credit funding remains on Base Sepolia and consumption
|
|
112
|
+
is offchain. It does not purchase external traces. Keep missing-evidence notices
|
|
113
|
+
visible and distinguish observed errors from model hypotheses.
|
|
114
|
+
|
|
115
|
+
Version 0.2.14 fixes the investigator's packaged payment recipient pin and refuses
|
|
116
|
+
builds with missing or placeholder treasury addresses. Payment requirements must
|
|
117
|
+
still match the reviewed deployment before any proof is authorized.
|
|
118
|
+
|
|
119
|
+
Repeating a transaction hash recovers its existing local task without authorizing
|
|
120
|
+
a new paid call. The report shows the original stopping reason and labels prior
|
|
121
|
+
accounting separately from current invocation counters, including when the saved
|
|
122
|
+
run authorized no credits. Upgrading does not resume a stopped investigation.
|
|
123
|
+
Do not delete task journals or reset
|
|
124
|
+
credential accounting to force a fresh exchange. Unknown payment outcomes must
|
|
125
|
+
be reconciled before another paid task. A saved report must be labeled as a prior
|
|
126
|
+
run, with its own payment summary.
|
|
127
|
+
|
|
128
|
+
`challengeObserved` counts challenges presented for authorization, including
|
|
129
|
+
refused terms. A challenge alone does not imply a proof or consumed credit;
|
|
130
|
+
check confirmed, failed, unknown and retired counters separately.
|
package/circuits/manifest.json
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"deployment": {
|
|
34
34
|
"chainId": 84532,
|
|
35
35
|
"bondAddress": "0xcc1909dD30485d6D9a46e3d33cf04C1378b586Ab",
|
|
36
|
+
"treasuryAddress": "0xa8b9b38e748563AF7FbAA276e8a843Da417D7Bc1",
|
|
36
37
|
"deploymentBlock": "47372040",
|
|
37
38
|
"deploymentDomain": "84532",
|
|
38
39
|
"circuitId": "private-credit-spend-bn254-dev",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CredentialStore } from './credential-store.js';
|
|
2
|
+
import { type ResolveSetupInputsOptions, type SetupConfig } from './setup-config.js';
|
|
3
|
+
export interface ActivatedCredentialSetupOptions {
|
|
4
|
+
environment?: NodeJS.ProcessEnv;
|
|
5
|
+
homeDirectory?: string;
|
|
6
|
+
stateDirectory?: string;
|
|
7
|
+
credentialStore?: CredentialStore;
|
|
8
|
+
chooseCandidate?: ResolveSetupInputsOptions['chooseCandidate'];
|
|
9
|
+
/** The caller owns hidden terminal input for explicit legacy import. */
|
|
10
|
+
readLegacyPassword?(): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Imports or loads the credential and prepares validated runtime configuration.
|
|
14
|
+
* Configuration is saved only after all checks pass. Credential import, artifact
|
|
15
|
+
* acquisition and witness synchronization may persist progress on failure so a
|
|
16
|
+
* retry can reuse it. Applies RPC and successful setup paths to the environment.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setupActivatedCredential(options?: ActivatedCredentialSetupOptions): Promise<SetupConfig>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Interactive credential preparation; runtime loading and launch remain separate. */
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { loadCircuitManifest } from './artifact-bundle.js';
|
|
5
|
+
import { validateBaseCreditWitness } from './base-sidecar.js';
|
|
6
|
+
import { importCredentialPath, nativeCredentialStore, readStoredCredential, } from './credential-store.js';
|
|
7
|
+
import { requireGatewayKnownRoot, resolveGatewayOrigin } from './gateway-root-check.js';
|
|
8
|
+
import { createPinnedBaseProofGenerator } from './proof-coordinator.js';
|
|
9
|
+
import { createBaseProofMetrics } from './proof-metrics.js';
|
|
10
|
+
import { applyRpcConfig, checkBaseSepoliaRpc, resolveBaseSepoliaRpc } from './rpc-config.js';
|
|
11
|
+
import { applySetupConfig, readSetupConfig, resolveSetupInputs, writeSetupConfig, } from './setup-config.js';
|
|
12
|
+
import { witnessProviderForSource } from './sidecar-runtime.js';
|
|
13
|
+
/**
|
|
14
|
+
* Imports or loads the credential and prepares validated runtime configuration.
|
|
15
|
+
* Configuration is saved only after all checks pass. Credential import, artifact
|
|
16
|
+
* acquisition and witness synchronization may persist progress on failure so a
|
|
17
|
+
* retry can reuse it. Applies RPC and successful setup paths to the environment.
|
|
18
|
+
*/
|
|
19
|
+
export async function setupActivatedCredential(options = {}) {
|
|
20
|
+
const environment = options.environment ?? process.env;
|
|
21
|
+
const homeDirectory = options.homeDirectory ?? homedir();
|
|
22
|
+
const stateDirectory = options.stateDirectory ?? (environment.ZK_CREDITS_HOME || join(homeDirectory, '.zk-credits'));
|
|
23
|
+
const configPath = join(stateDirectory, 'config.json');
|
|
24
|
+
const credentialStore = options.credentialStore ?? nativeCredentialStore(stateDirectory);
|
|
25
|
+
await applyRpcConfig(environment, stateDirectory);
|
|
26
|
+
const saved = await readSetupConfig(configPath);
|
|
27
|
+
const rpc = resolveBaseSepoliaRpc(environment, saved?.witness.kind === 'base-events' ? saved.witness.rpcUrl : undefined);
|
|
28
|
+
await checkBaseSepoliaRpc(rpc);
|
|
29
|
+
environment.BASE_RPC_URL = rpc;
|
|
30
|
+
const credentialPath = environment.ZK_CREDITS_CREDENTIAL_PATH;
|
|
31
|
+
const legacyPassword = await options.readLegacyPassword?.();
|
|
32
|
+
const credential = credentialPath
|
|
33
|
+
? await importCredentialPath(credentialPath, credentialStore, legacyPassword)
|
|
34
|
+
: await readStoredCredential(credentialStore);
|
|
35
|
+
const manifest = await loadCircuitManifest();
|
|
36
|
+
const config = await resolveSetupInputs({
|
|
37
|
+
environment,
|
|
38
|
+
homeDirectory,
|
|
39
|
+
stateDirectory,
|
|
40
|
+
configPath,
|
|
41
|
+
manifest,
|
|
42
|
+
validateWitness: async (source) => {
|
|
43
|
+
const provider = await witnessProviderForSource(source, join(stateDirectory, 'base-event-sync.json'));
|
|
44
|
+
const witness = validateBaseCreditWitness(await provider.witnessForCredential(credential));
|
|
45
|
+
if (manifest.deployment)
|
|
46
|
+
await requireGatewayKnownRoot(witness.root, resolveGatewayOrigin(environment));
|
|
47
|
+
},
|
|
48
|
+
chooseCandidate: options.chooseCandidate,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
await createPinnedBaseProofGenerator({
|
|
52
|
+
artifactDirectory: config.artifactDirectory,
|
|
53
|
+
metrics: createBaseProofMetrics(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof Error)
|
|
58
|
+
throw new Error(`Pinned proving bundle check failed: ${error.message}`);
|
|
59
|
+
throw new Error('Pinned proving bundle check failed. Reinstall the bundle from your pilot invite.');
|
|
60
|
+
}
|
|
61
|
+
await writeSetupConfig(configPath, config);
|
|
62
|
+
applySetupConfig(environment, config);
|
|
63
|
+
return config;
|
|
64
|
+
}
|
package/dist/base-event-sync.js
CHANGED
|
@@ -13,6 +13,7 @@ import { baseSepolia } from 'viem/chains';
|
|
|
13
13
|
import { createPublicClient, http, parseAbi } from 'viem';
|
|
14
14
|
import { BASE_MEMBERSHIP_TREE_CAPACITY, BN254_FIELD_ORDER, computeCreditLeaf, deriveSparseCreditWitness, } from '@zk-credits/shared/base';
|
|
15
15
|
import { RPC_GUIDANCE } from './rpc-config.js';
|
|
16
|
+
import { rpcFetch } from './rpc-transport.js';
|
|
16
17
|
const BUNDLE_FUNDED_ABI = parseAbi([
|
|
17
18
|
'event BundleFunded(bytes32 indexed commitment, uint8 indexed tierId, uint64 expiry, uint256 leafIndex, uint256 bondAmount, bytes32 root)',
|
|
18
19
|
]);
|
|
@@ -82,12 +83,15 @@ function serializeLeaves(leaves) {
|
|
|
82
83
|
}
|
|
83
84
|
/** Creates a witness provider that syncs finalized BundleFunded events. */
|
|
84
85
|
export function createBaseEventWitnessProvider(options) {
|
|
85
|
-
const client = options.client ?? createPublicClient({ chain: baseSepolia,
|
|
86
|
+
const client = options.client ?? createPublicClient({ chain: baseSepolia,
|
|
87
|
+
transport: http(options.rpcUrl, { fetchFn: rpcFetch, retryCount: 0, timeout: 30_000 }),
|
|
88
|
+
});
|
|
86
89
|
const contract = address(options.contractAddress);
|
|
87
90
|
const confirmations = options.confirmations ?? 3n;
|
|
88
91
|
const maxBlockRange = options.maxBlockRange ?? 2000n;
|
|
89
92
|
let cache;
|
|
90
93
|
let leaves = new Map();
|
|
94
|
+
let pendingSync;
|
|
91
95
|
async function rpcCall(operation) {
|
|
92
96
|
try {
|
|
93
97
|
return await operation;
|
|
@@ -150,7 +154,8 @@ export function createBaseEventWitnessProvider(options) {
|
|
|
150
154
|
}
|
|
151
155
|
return {
|
|
152
156
|
async witnessForCredential(credential) {
|
|
153
|
-
|
|
157
|
+
pendingSync ??= synchronize().finally(() => { pendingSync = undefined; });
|
|
158
|
+
await pendingSync;
|
|
154
159
|
const commitment = field(credential.commitment, 'credential commitment');
|
|
155
160
|
const entry = [...leaves.entries()].find(([, value]) => value.commitment === commitment);
|
|
156
161
|
if (!entry)
|
package/dist/base-sidecar.d.ts
CHANGED
|
@@ -65,6 +65,28 @@ export interface BasePrepaidClientOptions {
|
|
|
65
65
|
* a public signal, or a credential identifier.
|
|
66
66
|
*/
|
|
67
67
|
lifecycle?: ZkPrepaidLifecycleObserver;
|
|
68
|
+
/** Caller-owned durable policy and accounting boundary; failures propagate. */
|
|
69
|
+
authorization?: BaseAuthorizationBridge;
|
|
70
|
+
}
|
|
71
|
+
export interface BaseAuthorizationRequest extends BasePaymentContext {
|
|
72
|
+
attemptId: string;
|
|
73
|
+
body: Uint8Array;
|
|
74
|
+
}
|
|
75
|
+
export type BaseUsageObservation = {
|
|
76
|
+
attemptId: string;
|
|
77
|
+
slot: number;
|
|
78
|
+
} & ({
|
|
79
|
+
type: 'provisional' | 'released' | 'retired';
|
|
80
|
+
} | {
|
|
81
|
+
type: 'settlement';
|
|
82
|
+
outcome: 'confirmed' | 'failed' | 'unknown';
|
|
83
|
+
reservationId?: string;
|
|
84
|
+
});
|
|
85
|
+
export interface BaseAuthorizationBridge {
|
|
86
|
+
/** Persist reservation and validate actual terms before any fresh proof. */
|
|
87
|
+
beforeProof(request: BaseAuthorizationRequest): Promise<void>;
|
|
88
|
+
/** Contains no request content, credential, proof, signature or replay key. */
|
|
89
|
+
observe(event: BaseUsageObservation): Promise<void>;
|
|
68
90
|
}
|
|
69
91
|
export interface BasePrepaidClient {
|
|
70
92
|
client: ZkPrepaidClient;
|
|
@@ -80,6 +102,8 @@ export interface BasePaymentContext {
|
|
|
80
102
|
export interface BasePreparedPayment {
|
|
81
103
|
payment: PaymentPayload;
|
|
82
104
|
responsePrivateKey: string;
|
|
105
|
+
attemptId: string;
|
|
106
|
+
slot: number;
|
|
83
107
|
}
|
|
84
108
|
export declare function validateBaseCreditWitness(witness: BaseCreditWitness): BaseCreditWitness;
|
|
85
109
|
/** Creates the shared local proof factory used by both client transports. */
|
package/dist/base-sidecar.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
9
9
|
*/
|
|
10
|
-
import { createDecipheriv, generateKeyPair as generateKeyPairCallback, privateDecrypt, randomBytes } from 'node:crypto';
|
|
10
|
+
import { createDecipheriv, generateKeyPair as generateKeyPairCallback, privateDecrypt, randomBytes, randomUUID } from 'node:crypto';
|
|
11
11
|
import { promisify } from 'node:util';
|
|
12
12
|
import { BASE_MEMBERSHIP_TREE_CAPACITY, canonicalizeBaseJson, computeCreditLeaf, computeNullifier, computeShare, computeSlotBlinding, deriveRequestSignal, deriveSparseCreditWitness, secretFromBase64Url, secretToField, } from '@zk-credits/shared/base';
|
|
13
13
|
import { buildPaymentPayload, createZkPrepaidClient, decodeHeader, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, } from '@zk-credits/x402-zk-prepaid';
|
|
@@ -77,8 +77,13 @@ export function createBasePaymentFactory(options) {
|
|
|
77
77
|
const slotLedger = options.slotLedger;
|
|
78
78
|
if (!slotLedger)
|
|
79
79
|
throw new Error('A durable slot ledger is required for the Base pilot');
|
|
80
|
+
const attemptId = randomUUID();
|
|
81
|
+
const bytes = new Uint8Array(requestBodyBytes(body));
|
|
82
|
+
await options.authorization?.beforeProof({ attemptId, method, url, body: bytes, requirements: structuredClone(requirements) });
|
|
80
83
|
const selectedSlot = slotLedger.allocateProvisional();
|
|
84
|
+
let retired = false;
|
|
81
85
|
try {
|
|
86
|
+
await options.authorization?.observe({ type: 'provisional', attemptId, slot: selectedSlot });
|
|
82
87
|
const nonce = randomNonce();
|
|
83
88
|
const responseKeys = await responseKey();
|
|
84
89
|
const requestSignal = await deriveRequestSignal({
|
|
@@ -128,6 +133,8 @@ export function createBasePaymentFactory(options) {
|
|
|
128
133
|
throw new Error('Proof public signals do not match the canonical statement');
|
|
129
134
|
}
|
|
130
135
|
await slotLedger.commit(selectedSlot);
|
|
136
|
+
retired = true;
|
|
137
|
+
await options.authorization?.observe({ type: 'retired', attemptId, slot: selectedSlot });
|
|
131
138
|
const payment = buildPaymentPayload({
|
|
132
139
|
requirements,
|
|
133
140
|
proof: proofForPayment(proof.proof),
|
|
@@ -135,10 +142,13 @@ export function createBasePaymentFactory(options) {
|
|
|
135
142
|
nonce,
|
|
136
143
|
responseKey: responseKeys.publicKey,
|
|
137
144
|
});
|
|
138
|
-
return { payment, responsePrivateKey: responseKeys.privateKey };
|
|
145
|
+
return { payment, responsePrivateKey: responseKeys.privateKey, attemptId, slot: selectedSlot };
|
|
139
146
|
}
|
|
140
147
|
catch (error) {
|
|
141
|
-
|
|
148
|
+
if (!retired) {
|
|
149
|
+
slotLedger.release(selectedSlot);
|
|
150
|
+
await options.authorization?.observe({ type: 'released', attemptId, slot: selectedSlot });
|
|
151
|
+
}
|
|
142
152
|
throw error;
|
|
143
153
|
}
|
|
144
154
|
};
|
|
@@ -266,9 +276,49 @@ export function createBasePrepaidClient(options) {
|
|
|
266
276
|
headers: new Headers(response.headers),
|
|
267
277
|
});
|
|
268
278
|
};
|
|
279
|
+
const observeSettlement = async (response, init) => {
|
|
280
|
+
const header = new Headers(init?.headers).get(PAYMENT_SIGNATURE_HEADER);
|
|
281
|
+
if (!header || !options.authorization)
|
|
282
|
+
return;
|
|
283
|
+
let payment;
|
|
284
|
+
try {
|
|
285
|
+
payment = decodeHeader(header);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const key = pendingByNonce.get(payment.payload.nonce);
|
|
291
|
+
const pending = key ? pendingPayments.get(key) : undefined;
|
|
292
|
+
if (!pending)
|
|
293
|
+
return;
|
|
294
|
+
let outcome = 'unknown';
|
|
295
|
+
let reservationId;
|
|
296
|
+
try {
|
|
297
|
+
const encoded = response.headers.get(PAYMENT_RESPONSE_HEADER);
|
|
298
|
+
const result = encoded ? decodeHeader(encoded) : undefined;
|
|
299
|
+
if (result && result.network === pending.payment.accepted.network && result.transaction === ''
|
|
300
|
+
&& (result.reservationId === undefined || (typeof result.reservationId === 'string' && result.reservationId.length > 0 && result.reservationId.length <= 256))
|
|
301
|
+
&& typeof result.success === 'boolean' && !('payer' in result)) {
|
|
302
|
+
// A failed response can describe an ambiguous ready/commit failure.
|
|
303
|
+
outcome = result.success ? 'confirmed' : 'unknown';
|
|
304
|
+
reservationId = result.reservationId;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
catch { /* Missing or malformed settlement leaves consumption unknown. */ }
|
|
308
|
+
await options.authorization.observe({ type: 'settlement', attemptId: pending.attemptId, slot: pending.slot, outcome,
|
|
309
|
+
...(reservationId === undefined ? {} : { reservationId }) });
|
|
310
|
+
};
|
|
269
311
|
const fetchWithReplay = async (input, init) => {
|
|
270
312
|
prunePending();
|
|
271
|
-
|
|
313
|
+
let response;
|
|
314
|
+
try {
|
|
315
|
+
response = await fetcher(input, { ...init, redirect: 'error' });
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
await observeSettlement(new Response(null, { status: 503 }), init);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
await observeSettlement(response, init);
|
|
272
322
|
if (response.status !== 409)
|
|
273
323
|
return trackPaymentResponse(response, init);
|
|
274
324
|
let replayAvailable = false;
|
|
@@ -343,7 +393,7 @@ export function createBasePrepaidClient(options) {
|
|
|
343
393
|
const nonce = payment.payload.nonce;
|
|
344
394
|
const expiresAt = Date.now() + REPLAY_TTL_MS;
|
|
345
395
|
replayKeys.set(nonce, { privateKey: prepared.responsePrivateKey, expiresAt });
|
|
346
|
-
pendingPayments.set(key, { payment, expiresAt });
|
|
396
|
+
pendingPayments.set(key, { payment, expiresAt, attemptId: prepared.attemptId, slot: prepared.slot });
|
|
347
397
|
pendingByNonce.set(nonce, key);
|
|
348
398
|
prunePending();
|
|
349
399
|
return payment;
|
|
@@ -358,7 +408,25 @@ export function createBasePrepaidClient(options) {
|
|
|
358
408
|
}
|
|
359
409
|
},
|
|
360
410
|
});
|
|
361
|
-
return {
|
|
411
|
+
return {
|
|
412
|
+
client: {
|
|
413
|
+
clearRequirements: client.clearRequirements,
|
|
414
|
+
async fetch(input, init) {
|
|
415
|
+
const source = input instanceof Request ? input : undefined;
|
|
416
|
+
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
417
|
+
const body = init?.body ?? (source?.body ? new Uint8Array(await source.clone().arrayBuffer()) : undefined);
|
|
418
|
+
const snapshot = body instanceof ArrayBuffer ? new Uint8Array(body.slice(0))
|
|
419
|
+
: body instanceof Uint8Array ? new Uint8Array(body) : body;
|
|
420
|
+
return client.fetch(url, {
|
|
421
|
+
...(source ? { method: source.method, headers: new Headers(source.headers), signal: source.signal } : {}),
|
|
422
|
+
...init,
|
|
423
|
+
headers: new Headers(init?.headers ?? source?.headers),
|
|
424
|
+
...(snapshot === undefined ? {} : { body: snapshot }),
|
|
425
|
+
});
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
committedSlots: () => options.slotLedger?.committedSlots() ?? [],
|
|
429
|
+
};
|
|
362
430
|
}
|
|
363
431
|
function parsePublicTreeArtifact(value) {
|
|
364
432
|
if (!value || typeof value !== 'object')
|