@verify-network/protocol 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,708 @@
1
+ import { HASH_TO_CURVE_MAX_ITERATIONS, Proof, PublicKey, SENTINEL_PROOF, decodeProof, deriveRandomness, encodeProof, hashToCurveIterations, isFulfillable, isSentinel, proofCommitment, prove, publicKeyPoint, verify } from "./ecvrf.js";
2
+ import { t as RouterDomain } from "./domain-CXJsoNRU.js";
3
+ import { MAX_CALLBACK_DATA_BYTES, Request as Request$1, SERVICE_VRF, STALE_DELAY, isLate, remainingDelay, requestId, staleAt } from "./request.js";
4
+ import { EventLog, decodeRandomnessFulfilled, decodeRandomnessRequested, randomnessFulfilledEvent, randomnessRequestedEvent } from "./event.js";
5
+ import { CALLDATA_GAS_PER_BYTE, DEFAULT_FEE_FLOOR, GasFees, INTRINSIC_GAS, PremiumShare, WHOLE_PREMIUM, ceiling, chargedGas, computeFees, fee, fulfillmentItemGas, lockedGasPrice, premiumShare, settlement, settlementAtShare } from "./fee.js";
6
+ import { fulfillmentDigest, fulfillmentTypedData } from "./fulfillment.js";
7
+ import { Address as Address$1, Hex, LocalAccount, PublicClient } from "viem";
8
+ import { Duration, Effect, Option, Result, Schema, Scope } from "effect";
9
+ import { Socket } from "effect/socket";
10
+ //#region src/attestation.d.ts
11
+ /** A PCR as the Nitro verifier's ABI splits its 48 bytes: 32, then 16 (`Bytes48` in `INitroEnclaveVerifier.sol`). */
12
+ type Bytes48 = {
13
+ readonly first: Hex;
14
+ readonly second: Hex;
15
+ };
16
+ /** Splits a 48-byte PCR the way the Nitro verifier takes it. */
17
+ export declare const bytes48: (pcr: Hex) => Bytes48;
18
+ /**
19
+ * Mirrors `NitroAttestationVerifier._hasExpectedNonce`, the Nitro verifier's check: the nonce an
20
+ * enclave must put in its attestation for this operator to register this key on this router
21
+ * before the deadline (seconds since the epoch), so an attestation registers nowhere else.
22
+ */
23
+ export declare const registrationNonce: ({ chainId, router, operator, publicKey, deadline }: RouterDomain & {
24
+ readonly operator: Address$1;
25
+ readonly publicKey: PublicKey;
26
+ readonly deadline: bigint;
27
+ }) => Hex;
28
+ /**
29
+ * The attestation `registerNode` takes when the Nitro verifier is configured: the SP1 journal
30
+ * and proof of the enclave's attestation document, and the deadline its nonce was bound to, as
31
+ * `NitroAttestationVerifier.EnclaveRegistrationProof`.
32
+ */
33
+ export declare const encodeAttestation: ({ journal, proof, deadline }: {
34
+ readonly journal: Hex;
35
+ readonly proof: Hex;
36
+ readonly deadline: bigint;
37
+ }) => Hex;
38
+ //#endregion
39
+ //#region src/directApi.d.ts
40
+ /**
41
+ * `POST /direct`: the authorization as the signer signed it (`DirectRequest`, whose numbers are
42
+ * decimal strings in JSON, as `GET /` spells the public key) and the signer's signature over it.
43
+ */
44
+ export declare const DirectRequestBody: Schema.Struct<{
45
+ readonly consumer: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
46
+ readonly node: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
47
+ readonly nonce: Schema.BigInt;
48
+ readonly deadline: Schema.BigInt;
49
+ readonly callbackGasLimit: Schema.Number;
50
+ readonly maxGasPrice: Schema.BigInt;
51
+ readonly callbackData: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
52
+ readonly signature: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
53
+ }>;
54
+ export type DirectRequestBody = typeof DirectRequestBody.Type;
55
+ /**
56
+ * What `POST /direct` returns once the node's source has seen the fulfillment land: the id, the
57
+ * randomness the consumer received, the evidence a challenge takes, and the transaction.
58
+ */
59
+ export declare const DirectResponse: Schema.Struct<{
60
+ readonly requestId: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
61
+ readonly randomness: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
62
+ readonly proof: Schema.Tuple<readonly [Schema.BigInt, Schema.BigInt, Schema.BigInt, Schema.BigInt]>;
63
+ readonly enclaveSignature: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
64
+ readonly hash: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
65
+ }>;
66
+ export type DirectResponse = typeof DirectResponse.Type;
67
+ /**
68
+ * `GET /` as a signer reads it: the node the endpoint serves and its public key. The enclave's
69
+ * status carries more (the chain, the runtime's counters); a client needs these two to know the
70
+ * endpoint is the node's the router named, and which key its proofs verify under.
71
+ */
72
+ export declare const NodeIdentity: Schema.Struct<{
73
+ readonly node: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
74
+ readonly publicKey: Schema.Tuple<readonly [Schema.BigInt, Schema.BigInt]>;
75
+ }>;
76
+ export type NodeIdentity = typeof NodeIdentity.Type;
77
+ declare const DirectRequestRefused_base: Schema.Class<DirectRequestRefused, Schema.TaggedStruct<"DirectRequestRefused", {
78
+ readonly reason: Schema.Literals<readonly ["too-long", "wrong-node", "deadline", "max-gas-price", "callback-gas-limit", "bad-signature", "unfulfillable", "insufficient-balance"]>;
79
+ }>, import("effect/Cause").YieldableError>;
80
+ /**
81
+ * A 400: why `POST /direct` refused an authorization, cheapest check first (ADR 0026, 0028):
82
+ * the callback data is over the router's cap; the named node is another; the deadline has
83
+ * passed or is past the horizon; the maximum gas price is under what the sender would bid now;
84
+ * the callback gas limit is over the router's maximum; the signer's signature recovers nobody;
85
+ * the id has no curve point under the enclave key, so the signer picks another nonce; or the
86
+ * signer's balance does not cover the ceiling.
87
+ */
88
+ export declare class DirectRequestRefused extends DirectRequestRefused_base {}
89
+ declare const NonceTaken_base: Schema.Class<NonceTaken, Schema.TaggedStruct<"NonceTaken", {
90
+ readonly signer: Schema.String;
91
+ readonly nonce: Schema.BigInt;
92
+ }>, import("effect/Cause").YieldableError>;
93
+ /** A 409: this node already took up, or saw land, an authorization under `signer` and `nonce`. */
94
+ export declare class NonceTaken extends NonceTaken_base {}
95
+ declare const TooManyRequests_base: Schema.Class<TooManyRequests, Schema.TaggedStruct<"TooManyRequests", {
96
+ readonly reason: Schema.Literals<readonly ["in-flight", "signer", "ip", "edge"]>;
97
+ }>, import("effect/Cause").YieldableError>;
98
+ /**
99
+ * A 429: the node is past a bound (as many direct requests in flight as it takes at once, as
100
+ * many under this signer, or a block on the caller's address for the incorrect authorizations it
101
+ * sent), or the edge in front of it refused the flood with no body of the node's. Nothing was
102
+ * checked or proven; the signer may try another node, or this one again later.
103
+ */
104
+ export declare class TooManyRequests extends TooManyRequests_base {}
105
+ declare const NotServing_base: Schema.Class<NotServing, Schema.TaggedStruct<"NotServing", {
106
+ readonly reason: Schema.Literals<readonly ["not-set-up", "not-active", "disconnected", "chain-unreachable"]>;
107
+ }>, import("effect/Cause").YieldableError>;
108
+ /**
109
+ * A 503: the node serves no direct request right now: it is not set up; it is not in the active
110
+ * set (exiting, ejected, forgotten, or stopped); its request source reports no connection, so it
111
+ * could not see the fulfillment land; or the chain could not be read.
112
+ */
113
+ export declare class NotServing extends NotServing_base {}
114
+ declare const DeadlinePassed_base: Schema.Class<DeadlinePassed, Schema.TaggedStruct<"DeadlinePassed", {
115
+ readonly deadline: Schema.BigInt;
116
+ }>, import("effect/Cause").YieldableError>;
117
+ /**
118
+ * A 504: the authorization's deadline passed before the source saw the fulfillment land: it can
119
+ * no longer land, so the signer may make an on-chain request instead (ADR 0026).
120
+ */
121
+ export declare class DeadlinePassed extends DeadlinePassed_base {}
122
+ /** Every refusal `POST /direct` answers with, as its body spells it. */
123
+ export declare const DirectRefusal: Schema.Union<readonly [typeof DirectRequestRefused, typeof NonceTaken, typeof TooManyRequests, typeof NotServing, typeof DeadlinePassed]>;
124
+ export type DirectRefusal = typeof DirectRefusal.Type;
125
+ //#endregion
126
+ //#region src/directRequest.d.ts
127
+ /**
128
+ * An authorization: what a signer signs to make a direct request (ADR 0026, 0027, 0028). The
129
+ * signer is not a field; the router recovers it from the signature. `node` is the one node that
130
+ * may fulfill it, `deadline` the last second the router takes it, `nonce` unordered and used at
131
+ * most once per signer, `maxGasPrice` the most the charge is priced at.
132
+ */
133
+ export declare const DirectRequest: Schema.Struct<{
134
+ readonly consumer: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
135
+ readonly node: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
136
+ readonly nonce: Schema.BigInt;
137
+ readonly deadline: Schema.BigInt;
138
+ readonly callbackGasLimit: Schema.Number;
139
+ readonly maxGasPrice: Schema.BigInt;
140
+ readonly callbackData: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
141
+ }>;
142
+ export type DirectRequest = typeof DirectRequest.Type;
143
+ /**
144
+ * The typed data a signer signs, as viem's `signTypedData` takes it: the fulfillment's domain
145
+ * (`VerifyNetworkVRF` version 2, the chain, the router) over the `DirectRequest` struct.
146
+ */
147
+ export declare const directRequestTypedData: ({ chainId, router, authorization }: RouterDomain & {
148
+ readonly authorization: DirectRequest;
149
+ }) => {
150
+ readonly domain: {
151
+ readonly name: "VerifyNetworkVRF";
152
+ readonly version: "2";
153
+ readonly chainId: number | bigint;
154
+ readonly verifyingContract: `0x${string}`;
155
+ };
156
+ readonly types: {
157
+ readonly DirectRequest: readonly [{
158
+ readonly name: "consumer";
159
+ readonly type: "address";
160
+ }, {
161
+ readonly name: "node";
162
+ readonly type: "address";
163
+ }, {
164
+ readonly name: "nonce";
165
+ readonly type: "uint256";
166
+ }, {
167
+ readonly name: "deadline";
168
+ readonly type: "uint64";
169
+ }, {
170
+ readonly name: "callbackGasLimit";
171
+ readonly type: "uint32";
172
+ }, {
173
+ readonly name: "maxGasPrice";
174
+ readonly type: "uint256";
175
+ }, {
176
+ readonly name: "callbackData";
177
+ readonly type: "bytes";
178
+ }];
179
+ };
180
+ readonly primaryType: "DirectRequest";
181
+ readonly message: {
182
+ readonly consumer: `0x${string}`;
183
+ readonly node: `0x${string}`;
184
+ readonly nonce: bigint;
185
+ readonly deadline: bigint;
186
+ readonly callbackGasLimit: number;
187
+ readonly maxGasPrice: bigint;
188
+ readonly callbackData: `0x${string}`;
189
+ };
190
+ };
191
+ /**
192
+ * The authorization's EIP-712 digest, which is the direct request's id and the VRF input; the
193
+ * router computes the same (ticket 02) and the contracts parity test holds it to this. The domain binds the chain and the router;
194
+ * the type hash keeps it apart from every on-chain request id.
195
+ */
196
+ export declare const directRequestId: (authorization: Parameters<typeof directRequestTypedData>[0]) => Hex;
197
+ /**
198
+ * Signs an authorization with a viem account that signs locally (a private key or a session
199
+ * key): the strict low-`s` signature the router recovers the signer from over `directRequestId`.
200
+ */
201
+ export declare const signDirectRequest: ({ account, ...input }: Parameters<typeof directRequestTypedData>[0] & {
202
+ readonly account: Pick<LocalAccount, "signTypedData">;
203
+ }) => Promise<Hex>;
204
+ /**
205
+ * `IDirectVrfReceiver.onDirectRandomness`: what a consumer implements to receive a direct
206
+ * request's randomness. A different selector from the on-chain callback, so a consumer that never
207
+ * opted in cannot mistake one for a request it made; `signer` is who paid and who the consumer
208
+ * decides about.
209
+ */
210
+ export declare const onDirectRandomness: {
211
+ readonly name: "onDirectRandomness";
212
+ readonly type: 'function';
213
+ readonly stateMutability: "nonpayable";
214
+ readonly inputs: readonly [{
215
+ readonly type: "bytes32";
216
+ readonly name: "requestId";
217
+ }, {
218
+ readonly type: "address";
219
+ readonly name: "signer";
220
+ }, {
221
+ readonly type: "bytes32";
222
+ readonly name: "randomness";
223
+ }, {
224
+ readonly type: "bytes";
225
+ readonly name: "callbackData";
226
+ }];
227
+ readonly outputs: readonly [];
228
+ };
229
+ /**
230
+ * `VrfFacet.DirectRequestFulfilled`: emitted beside `RandomnessFulfilled` on a direct fulfillment,
231
+ * with the id, the signer and the node indexed. Spelled out here because the protocol package does
232
+ * not depend on the contracts package; the contracts package holds it to the real log once the
233
+ * router emits it (ticket 02 of the direct request).
234
+ */
235
+ export declare const directRequestFulfilledEvent: {
236
+ readonly name: "DirectRequestFulfilled";
237
+ readonly type: 'event';
238
+ readonly inputs: readonly [{
239
+ readonly type: "bytes32";
240
+ readonly name: "requestId";
241
+ readonly indexed: true;
242
+ }, {
243
+ readonly type: "address";
244
+ readonly name: "signer";
245
+ readonly indexed: true;
246
+ }, {
247
+ readonly type: "address";
248
+ readonly name: "node";
249
+ readonly indexed: true;
250
+ }, {
251
+ readonly type: "address";
252
+ readonly name: "consumer";
253
+ }];
254
+ };
255
+ /**
256
+ * `NodesFacet.NodeEndpointSet`: an operator published or changed the endpoint a node serves
257
+ * direct requests at. Empty means the node serves none. Held to the real log as the event above,
258
+ * once the router has the setter (ticket 03).
259
+ */
260
+ export declare const nodeEndpointSetEvent: {
261
+ readonly name: "NodeEndpointSet";
262
+ readonly type: 'event';
263
+ readonly inputs: readonly [{
264
+ readonly type: "address";
265
+ readonly name: "node";
266
+ readonly indexed: true;
267
+ }, {
268
+ readonly type: "address";
269
+ readonly name: "operator";
270
+ readonly indexed: true;
271
+ }, {
272
+ readonly type: "string";
273
+ readonly name: "endpoint";
274
+ }];
275
+ };
276
+ //#endregion
277
+ //#region src/quote.d.ts
278
+ /** `ConfigFacet.pricing()`: the fee parameters the admin set, which every question is priced under. */
279
+ type Pricing = {
280
+ readonly premiumPercent: number;
281
+ readonly fulfillmentOverheadGas: number;
282
+ readonly fulfillmentSettlementGas: number;
283
+ readonly defaultCallbackGasLimit: number;
284
+ readonly maxCallbackGasLimit: number;
285
+ };
286
+ declare const RouterUnreadable_base: Schema.Class<RouterUnreadable, Schema.TaggedStruct<"RouterUnreadable", {
287
+ readonly operation: Schema.String;
288
+ readonly cause: Schema.Defect;
289
+ }>, import("effect/Cause").YieldableError>;
290
+ /** The router could not be read; `operation` names the viem call. */
291
+ export declare class RouterUnreadable extends RouterUnreadable_base {}
292
+ /** The request being priced: its callback data's length, and its callback gas limit when not the router's default. */
293
+ type Priced = {
294
+ readonly callbackDataLength: number;
295
+ /** The router's default when omitted. */
296
+ readonly callbackGasLimit?: number;
297
+ };
298
+ type QuoteOptions = {
299
+ readonly publicClient: PublicClient;
300
+ readonly router: Address$1;
301
+ };
302
+ export type Quote = {
303
+ readonly pricing: Pricing;
304
+ /**
305
+ * The fees the node's sender would bid now: twice the latest base fee plus the tip, never
306
+ * under the floor. What an on-chain request sends with, so the router locks at most this, and
307
+ * what an authorization's maximum gas price must clear, since the node refuses one under its
308
+ * bid (ADR 0028). Read from the chain, at most every `BASE_FEE_MAX_AGE`.
309
+ */
310
+ readonly bid: Effect.Effect<GasFees, RouterUnreadable>;
311
+ /**
312
+ * The reservation an on-chain request locks when sent at `gasPrice`: the gas it reserves at
313
+ * that price, never below the latest base fee (ADR 0019), plus the premium. A ceiling on what
314
+ * the request can cost, not its price; the settlement refunds the rest.
315
+ */
316
+ readonly reservation: (input: Priced & {
317
+ readonly gasPrice: bigint;
318
+ }) => Effect.Effect<bigint, RouterUnreadable>;
319
+ /**
320
+ * The ceiling a direct request's authorization carries at `maxGasPrice`: the reservation
321
+ * formula at that price, which has no base-fee floor since the signer names it (ADR 0028).
322
+ * What the signer's balance must hold for the request to land.
323
+ */
324
+ readonly ceiling: (input: Priced & {
325
+ readonly maxGasPrice: bigint;
326
+ }) => bigint;
327
+ /**
328
+ * The charge a settlement takes of the reservation: `gasUsed` at `lockedGasPrice` plus the
329
+ * premium, capped by `reservation` (ADR 0019); the premium decays in a straight line from
330
+ * `assignedAt` (ADR 0029) to nothing once the request is late (ADR 0025), the same timing the
331
+ * router judges by.
332
+ */
333
+ readonly charge: (input: {
334
+ readonly gasUsed: bigint | number;
335
+ readonly lockedGasPrice: bigint;
336
+ readonly reservation: bigint;
337
+ readonly assignedAt: bigint | number;
338
+ readonly settledAt: bigint | number;
339
+ }) => bigint;
340
+ };
341
+ export declare const Quote: {
342
+ make: (args_0: QuoteOptions) => Effect.Effect<Quote, RouterUnreadable, never>;
343
+ };
344
+ //#endregion
345
+ //#region src/directClient.d.ts
346
+ /** How long an authorization is good for when the caller names no deadline. */
347
+ export declare const DEFAULT_DEADLINE_SECONDS = 5;
348
+ /**
349
+ * Headroom over the bid the node's sender would make now: the maximum gas price an
350
+ * authorization names by default. The charge is at the fulfillment's own gas price under it
351
+ * (ADR 0028), so the headroom bounds the ceiling debited and refunded, not what is paid.
352
+ */
353
+ export declare const MAX_GAS_PRICE_HEADROOM = 2n;
354
+ /** A node in the active set whose endpoint passed validation. */
355
+ type DiscoveredNode = {
356
+ readonly node: Address$1;
357
+ readonly url: URL;
358
+ };
359
+ /** A node that answered `GET /` as itself, and how long the answer took. */
360
+ type MeasuredNode = DiscoveredNode & {
361
+ readonly publicKey: PublicKey;
362
+ readonly latencyMs: number;
363
+ };
364
+ /**
365
+ * What the client posts and measures with: the global `fetch` by default, spelled as the one
366
+ * call it makes so a test can hand a server's handler in and a runtime's own type of `fetch`
367
+ * (Bun's, say) is not required of it.
368
+ */
369
+ type Fetch = (input: string, init?: RequestInit) => Promise<Response>;
370
+ declare const NoNodeServing_base: Schema.Class<NoNodeServing, Schema.TaggedStruct<"NoNodeServing", {
371
+ readonly active: Schema.Int;
372
+ readonly published: Schema.Int;
373
+ }>, import("effect/Cause").YieldableError>;
374
+ /**
375
+ * No node to post to: of `active` nodes, `published` had an endpoint the client trusts the shape
376
+ * of, and none of those answered `GET /` as itself in time.
377
+ */
378
+ export declare class NoNodeServing extends NoNodeServing_base {}
379
+ declare const SigningFailed_base: Schema.Class<SigningFailed, Schema.TaggedStruct<"SigningFailed", {
380
+ readonly cause: Schema.Defect;
381
+ }>, import("effect/Cause").YieldableError>;
382
+ /** The account did not sign the authorization: a wallet refused, or the key could not. */
383
+ export declare class SigningFailed extends SigningFailed_base {}
384
+ declare const UnexpectedResponse_base: Schema.Class<UnexpectedResponse, Schema.TaggedStruct<"UnexpectedResponse", {
385
+ readonly status: Schema.Int;
386
+ readonly body: Schema.String;
387
+ }>, import("effect/Cause").YieldableError>;
388
+ /**
389
+ * The node answered something `POST /direct` does not: neither a landing nor a refusal it
390
+ * spells, under a status that says the authorization was not taken up (a 4xx of the edge's, a
391
+ * landing whose body cannot be read). Not a signal to fall back on: nothing here says whether
392
+ * the fulfillment landed.
393
+ */
394
+ export declare class UnexpectedResponse extends UnexpectedResponse_base {}
395
+ /** What `request` fails with: the node's typed refusals, and what went wrong before or around them. */
396
+ type RequestError = DirectRequestRefused | NonceTaken | TooManyRequests | NotServing | RouterUnreadable | SigningFailed | UnexpectedResponse;
397
+ /** The fulfillment landed: what the node returned once its source saw it, and the authorization behind it. */
398
+ type Landed = {
399
+ readonly _tag: "Landed";
400
+ readonly node: Address$1;
401
+ readonly requestId: Hex;
402
+ readonly authorization: DirectRequest;
403
+ readonly randomness: Hex;
404
+ readonly proof: Proof;
405
+ readonly enclaveSignature: Hex;
406
+ readonly hash: Hex;
407
+ /** From the post leaving to the response read, in milliseconds. */
408
+ readonly elapsedMs: number;
409
+ };
410
+ /**
411
+ * The deadline has passed and no fulfillment was seen to land: the node said so (504); or it
412
+ * could not be reached, did not answer in time, or answered a 5xx it does not spell (the edge in
413
+ * front of it, say), in which case the authorization may have reached it all the same; or it
414
+ * answered a landing for some other request's id, which says nothing about this one's (ADR
415
+ * 0027). Resolved only once the deadline is behind on the chain's clock, the one the router
416
+ * judges it by, so the fallback to an on-chain request cannot race a landing (ADR 0026).
417
+ */
418
+ type NotLanded = {
419
+ readonly _tag: "NotLanded";
420
+ readonly node: Address$1;
421
+ readonly requestId: Hex;
422
+ readonly authorization: DirectRequest;
423
+ readonly reason: "deadline-passed" | "unreachable" | "mismatched-answer";
424
+ readonly elapsedMs: number;
425
+ };
426
+ type DirectRequestInput = {
427
+ readonly consumer: Address$1;
428
+ readonly callbackData: Hex;
429
+ /** The router's default when omitted. */
430
+ readonly callbackGasLimit?: number;
431
+ /** A random one whose id has a curve point when omitted. */
432
+ readonly nonce?: bigint;
433
+ /** The client's `deadlineSeconds` ahead of the chain's clock when omitted. */
434
+ readonly deadline?: bigint;
435
+ /** `MAX_GAS_PRICE_HEADROOM` over the node's bid, read from the chain, when omitted. */
436
+ readonly maxGasPrice?: bigint;
437
+ /**
438
+ * Who signs this one, when not the client's account: a backend serving many session keys
439
+ * keeps one client, and one warm connection, for all of them.
440
+ */
441
+ readonly account?: Pick<LocalAccount, "address" | "signTypedData">;
442
+ };
443
+ type DirectClientOptions = RouterDomain & {
444
+ readonly publicClient: PublicClient;
445
+ /** Who signs: a local key, a session key, or a wallet's account. */
446
+ readonly account: Pick<LocalAccount, "address" | "signTypedData">;
447
+ /**
448
+ * Post here instead of discovering a node on the router. The caller's own choice, so it is not
449
+ * validated: a local node in a test, or an endpoint the caller trusts by other means. The node
450
+ * is whatever `GET /` there reports.
451
+ */
452
+ readonly endpoint?: string;
453
+ /** The `fetch` to use; the global one otherwise. A test hands the enclave's handler in. */
454
+ readonly fetch?: Fetch;
455
+ /**
456
+ * How far ahead of the chain's clock a request's deadline is dated when the caller names none:
457
+ * `DEFAULT_DEADLINE_SECONDS` otherwise.
458
+ */
459
+ readonly deadlineSeconds?: number;
460
+ };
461
+ export type DirectClient = {
462
+ /** The node every request goes to: the fastest measured, kept for the client's lifetime. */
463
+ readonly node: MeasuredNode;
464
+ /** What a request costs: the pricing, and the ceiling an authorization carries (ADR 0028). */
465
+ readonly quote: Quote;
466
+ /**
467
+ * The maximum gas price a request names by default: the quote's bid, the one the node's
468
+ * sender makes and refuses an authorization under, with `MAX_GAS_PRICE_HEADROOM` over it.
469
+ */
470
+ readonly maxGasPrice: Effect.Effect<bigint, RouterUnreadable>;
471
+ /** `GET /` to the node, so the next request finds the connection open. Never fails. */
472
+ readonly warm: Effect.Effect<void>;
473
+ readonly request: (input: DirectRequestInput) => Effect.Effect<Landed | NotLanded, RequestError>;
474
+ };
475
+ /**
476
+ * An endpoint as the client will use it, or nothing when it is not one the client connects to:
477
+ * `https` only, a hostname rather than an IP literal, no credentials, no query. A trailing path
478
+ * is kept, with a slash after it, so the routes resolve under it. A backend that fetched an
479
+ * unvalidated URL from the chain would be an SSRF vector (ADR 0027).
480
+ */
481
+ export declare const validateEndpoint: (endpoint: string) => URL | undefined;
482
+ /**
483
+ * The active set with the endpoints the client will connect to: the router's `activeNodes`,
484
+ * then the endpoints in one multicall, and every endpoint that is not `https` to a hostname
485
+ * dropped (ADR 0027). `active` is the whole set, for telling "no node publishes an endpoint"
486
+ * from "no node at all".
487
+ */
488
+ export declare const discoverNodes: (args_0: {
489
+ readonly publicClient: PublicClient;
490
+ readonly router: Address$1;
491
+ }) => Effect.Effect<{
492
+ active: number;
493
+ nodes: DiscoveredNode[];
494
+ }, RouterUnreadable, never>;
495
+ export declare const DirectClient: {
496
+ connect: (options: DirectClientOptions) => Effect.Effect<DirectClient, NoNodeServing | RouterUnreadable, never>;
497
+ };
498
+ //#endregion
499
+ //#region src/routerWatch.d.ts
500
+ /** A JSON-RPC request as a text frame. */
501
+ export declare const requestFrame: (id: number, method: string, params: ReadonlyArray<unknown>) => string;
502
+ /** The filter of a `pendingLogs` subscription: the emitter, and the selectors of its first topic. */
503
+ type PendingLogsFilter = {
504
+ readonly address: Address$1;
505
+ readonly topics?: ReadonlyArray<Hex | ReadonlyArray<Hex>>;
506
+ };
507
+ /** The `eth_subscribe` of `pendingLogs` under `filter`, as a text frame. */
508
+ export declare const pendingLogsSubscribe: (id: number, filter: PendingLogsFilter) => string;
509
+ /** The reply to a request of ours: the `eth_subscribe`, or anything else sent under an id. */
510
+ export declare const SubscriptionReply: Schema.Struct<{
511
+ readonly id: Schema.Finite;
512
+ readonly result: Schema.optionalKey<Schema.String>;
513
+ readonly error: Schema.optionalKey<Schema.Struct<{
514
+ readonly code: Schema.Finite;
515
+ readonly message: Schema.String;
516
+ }>>;
517
+ }>;
518
+ export type SubscriptionReply = typeof SubscriptionReply.Type;
519
+ /** A notification on a subscription; `result` is whatever the subscription carries. */
520
+ export declare const SubscriptionNotification: Schema.Struct<{
521
+ readonly method: Schema.Literal<"eth_subscription">;
522
+ readonly params: Schema.Struct<{
523
+ readonly subscription: Schema.String;
524
+ readonly result: Schema.Unknown;
525
+ }>;
526
+ }>;
527
+ export type SubscriptionNotification = typeof SubscriptionNotification.Type;
528
+ /** What comes down the socket: one or the other. */
529
+ export declare const SubscriptionFrame: Schema.Union<readonly [Schema.Struct<{
530
+ readonly id: Schema.Finite;
531
+ readonly result: Schema.optionalKey<Schema.String>;
532
+ readonly error: Schema.optionalKey<Schema.Struct<{
533
+ readonly code: Schema.Finite;
534
+ readonly message: Schema.String;
535
+ }>>;
536
+ }>, Schema.Struct<{
537
+ readonly method: Schema.Literal<"eth_subscription">;
538
+ readonly params: Schema.Struct<{
539
+ readonly subscription: Schema.String;
540
+ readonly result: Schema.Unknown;
541
+ }>;
542
+ }>]>;
543
+ export type SubscriptionFrame = typeof SubscriptionFrame.Type;
544
+ export declare const decodeSubscriptionFrame: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Result.Result<{
545
+ readonly id: number;
546
+ readonly result?: string;
547
+ readonly error?: {
548
+ readonly code: number;
549
+ readonly message: string;
550
+ };
551
+ } | {
552
+ readonly method: "eth_subscription";
553
+ readonly params: {
554
+ readonly subscription: string;
555
+ readonly result: unknown;
556
+ };
557
+ }, Schema.SchemaError>;
558
+ /** A log as a `pendingLogs` notification carries it, as far as anything here reads it. */
559
+ export declare const PendingLog: Schema.Struct<{
560
+ readonly address: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
561
+ readonly topics: Schema.$Array<Schema.TemplateLiteral<readonly ["0x", Schema.String]>>;
562
+ readonly data: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
563
+ readonly blockNumber: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
564
+ /** Named by the endpoints that carry it; what a sender matches its own request by. */
565
+ readonly transactionHash: Schema.optionalKey<Schema.TemplateLiteral<readonly ["0x", Schema.String]>>;
566
+ readonly removed: Schema.optionalKey<Schema.Boolean>;
567
+ }>;
568
+ export type PendingLog = typeof PendingLog.Type;
569
+ export declare const decodePendingLog: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Result.Result<{
570
+ readonly address: `0x${string}`;
571
+ readonly topics: readonly `0x${string}`[];
572
+ readonly data: `0x${string}`;
573
+ readonly blockNumber: `0x${string}`;
574
+ readonly transactionHash?: `0x${string}`;
575
+ readonly removed?: boolean;
576
+ }, Schema.SchemaError>;
577
+ /** What every observation carries, whichever event it is. */
578
+ type Observed = {
579
+ readonly requestId: Hex;
580
+ readonly blockNumber: bigint;
581
+ /** The transaction the log came from, when the endpoint named one. */
582
+ readonly transactionHash: Hex | undefined;
583
+ /** `performance.now()` when the frame carrying it reached this process. */
584
+ readonly at: number;
585
+ };
586
+ /** A request the router opened, as its `RandomnessRequested` log carried it. */
587
+ type SeenRequest = Observed & {
588
+ readonly event: "RandomnessRequested";
589
+ readonly request: Request$1;
590
+ };
591
+ /**
592
+ * A fulfillment the router accepted, as its `RandomnessFulfilled` log carried it: `requestId` is
593
+ * the id it closed, with the randomness delivered and the evidence a verifier takes.
594
+ */
595
+ type SeenFulfillment = Observed & {
596
+ readonly event: "RandomnessFulfilled";
597
+ readonly randomness: Hex;
598
+ readonly proof: Proof;
599
+ readonly enclaveSignature: Hex;
600
+ };
601
+ type Seen = SeenRequest | SeenFulfillment;
602
+ /**
603
+ * The observation a pending log carries, if it is one of the router's two the watch is for;
604
+ * `at` is when its frame arrived. A log of another emitter, another event, or one the endpoint
605
+ * withdrew is nothing.
606
+ */
607
+ export declare const seenIn: (router: Address$1, result: unknown, at: number) => Seen | undefined;
608
+ declare const SubscriptionRefused_base: Schema.Class<SubscriptionRefused, Schema.TaggedStruct<"SubscriptionRefused", {
609
+ readonly url: Schema.String;
610
+ readonly reason: Schema.String;
611
+ }>, import("effect/Cause").YieldableError>;
612
+ /** The endpoint refused the router's log subscription, or never confirmed it. */
613
+ export declare class SubscriptionRefused extends SubscriptionRefused_base {
614
+ get message(): string;
615
+ }
616
+ declare const WatchEnded_base: Schema.Class<WatchEnded, Schema.TaggedStruct<"WatchEnded", {
617
+ readonly url: Schema.String;
618
+ }>, import("effect/Cause").YieldableError>;
619
+ /** The socket carrying the router's logs ended while something was still waiting on it. */
620
+ export declare class WatchEnded extends WatchEnded_base {
621
+ get message(): string;
622
+ }
623
+ /** The router's logs from the confirmed subscription on. */
624
+ type RouterWatch = {
625
+ /**
626
+ * The next observation not yet taken, in the order the frames arrived; fails once the socket
627
+ * has ended, so nothing waits on a connection that is gone. Each observation is taken once:
628
+ * two waits on the same watch split the observations between them, so waits that must each see
629
+ * everything take their own `branch`.
630
+ */
631
+ readonly next: Effect.Effect<Seen, WatchEnded>;
632
+ /**
633
+ * A watch of its own, seeing every observation from the moment it is taken, so any number of
634
+ * concurrent waits each see every log. Taken before whatever it must see is fired; scoped.
635
+ */
636
+ readonly branch: Effect.Effect<RouterWatch, never, Scope.Scope>;
637
+ };
638
+ type WatchOptions = {
639
+ /** The provider's WebSocket endpoint. */
640
+ readonly url: string;
641
+ readonly router: Address$1;
642
+ /** How long the endpoint has to confirm the subscription before the watch gives up on it. */
643
+ readonly subscribeTimeout?: Duration.Input;
644
+ /** How long the socket has to open. */
645
+ readonly openTimeout?: Duration.Input;
646
+ };
647
+ /**
648
+ * Opens the socket, subscribes to the router's request and fulfillment logs, and returns once
649
+ * the endpoint has confirmed the subscription, so nothing is fired at the chain before the watch
650
+ * meant to see it is in place. The WebSocket comes from the `Socket.WebSocketConstructor` in
651
+ * context (`Socket.layerWebSocketConstructorGlobal` where there is a global one). Scoped: the
652
+ * socket closes with the scope.
653
+ */
654
+ export declare const watchRouter: (options: WatchOptions) => Effect.Effect<RouterWatch, Socket.SocketError | SubscriptionRefused | WatchEnded, Scope.Scope | Socket.WebSocketConstructor>;
655
+ /**
656
+ * The next observation `match` accepts, or `None` if `timeout` passes first. Observations before
657
+ * it are dropped: they belong to other consumers on the same router.
658
+ */
659
+ export declare const nextSeen: <A extends Seen>(watch: RouterWatch, match: (seen: Seen) => A | undefined, timeout: Duration.Input) => Effect.Effect<Option.Option<A>, WatchEnded, never>;
660
+ /** A WebSocket class, as a browser or Node has one: what the watch is handed where no Effect runs. */
661
+ type WebSocketConstructor = new (url: string, protocols?: string | Array<string>) => globalThis.WebSocket;
662
+ /**
663
+ * The watch as callbacks, for code without Effect, through the package's `run`: opens and
664
+ * subscribes with `webSocket`, succeeds once the subscription is confirmed with the function
665
+ * that closes it, and from then on hands `onSeen` every observation until the socket ends, which
666
+ * `onEnded` learns of. Fails as `watchRouter` does.
667
+ *
668
+ * const close = await run(observeRouter({ url, router, webSocket: WebSocket, onSeen }), signal);
669
+ */
670
+ export declare const observeRouter: (options: WatchOptions & {
671
+ readonly webSocket: WebSocketConstructor;
672
+ readonly onSeen: (seen: Seen) => void;
673
+ readonly onEnded?: (ended: WatchEnded) => void;
674
+ }) => Effect.Effect<() => undefined, Socket.SocketError | SubscriptionRefused | WatchEnded, never>;
675
+ //#endregion
676
+ //#region src/run.d.ts
677
+ /**
678
+ * The package's one binding for code that runs no Effect: any protocol effect, as a promise.
679
+ * It resolves with what the effect succeeds with and rejects with the very error it fails with
680
+ * (the typed classes, so `instanceof` works on them). `signal` aborting interrupts the effect
681
+ * and rejects with the signal's reason. Effect stays beneath the package: a caller needs none.
682
+ *
683
+ * const client = await run(DirectClient.connect(options));
684
+ * const result = await run(client.request(input), signal);
685
+ */
686
+ export declare const run: <A, E>(effect: Effect.Effect<A, E>, signal?: AbortSignal) => Promise<A>;
687
+ //#endregion
688
+ //#region src/schemas.d.ts
689
+ /** A `0x`-prefixed hex string of any length, as viem spells quantities, data, and keys. */
690
+ export declare const HexString: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
691
+ /** Whole bytes in hex: exactly `size` of them, or any number when no size is given. */
692
+ export declare const hexBytes: (size?: number) => Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
693
+ export declare const Address: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
694
+ export declare const Bytes32: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
695
+ /** The schema of a `Request` (request.ts), which `request.test.ts` holds to the same type. */
696
+ export declare const Request: Schema.Struct<{
697
+ readonly consumer: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
698
+ readonly sequence: Schema.BigInt;
699
+ readonly fulfiller: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
700
+ readonly assignedAt: Schema.Number;
701
+ readonly fee: Schema.BigInt;
702
+ readonly gasPrice: Schema.BigInt;
703
+ readonly callbackGasLimit: Schema.Number;
704
+ readonly callbackData: Schema.TemplateLiteral<readonly ["0x", Schema.String]>;
705
+ }>;
706
+ export type Request = typeof Request.Type;
707
+ //#endregion
708
+ export { type Bytes48, CALLDATA_GAS_PER_BYTE, DEFAULT_FEE_FLOOR, type DirectClientOptions, type DirectRequestInput, type DiscoveredNode, type EventLog, type Fetch, type GasFees, HASH_TO_CURVE_MAX_ITERATIONS, INTRINSIC_GAS, type Landed, MAX_CALLBACK_DATA_BYTES, type MeasuredNode, type NotLanded, type PendingLogsFilter, type PremiumShare, type Priced, type Pricing, type Proof, type PublicKey, type QuoteOptions, type RequestError, type RouterDomain, type RouterWatch, SENTINEL_PROOF, SERVICE_VRF, STALE_DELAY, type Seen, type SeenFulfillment, type SeenRequest, WHOLE_PREMIUM, type WatchOptions, type WebSocketConstructor, ceiling, chargedGas, computeFees, decodeProof, decodeRandomnessFulfilled, decodeRandomnessRequested, deriveRandomness, encodeProof, fee, fulfillmentDigest, fulfillmentItemGas, fulfillmentTypedData, hashToCurveIterations, isFulfillable, isLate, isSentinel, lockedGasPrice, premiumShare, proofCommitment, prove, publicKeyPoint, randomnessFulfilledEvent, randomnessRequestedEvent, remainingDelay, requestId, settlement, settlementAtShare, staleAt, verify };