@molpha/sdk 0.2.0-dev-20261008064918 → 0.2.0-dev-20261010184043
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 +54 -10
- package/dist/index.d.ts +121 -40
- package/dist/index.js +226 -115
- package/dist/index.js.map +1 -1
- package/idl/molpha.json +27 -42
- package/idl/profiles/dev/molpha.json +27 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,30 +193,46 @@ A `programId` that differs from the client's is rejected. Because the hash diffe
|
|
|
193
193
|
|
|
194
194
|
### Round timestamp
|
|
195
195
|
|
|
196
|
-
The request body carries `authSig` and `authTimestamp` but no round timestamp. The gateway
|
|
197
|
-
round
|
|
198
|
-
(`floor(
|
|
199
|
-
|
|
196
|
+
The request body carries `authSig` and `authTimestamp` but no round timestamp. The gateway stamps the
|
|
197
|
+
round with its own clock, in unix **milliseconds**, floored to a fixed 100 ms tick
|
|
198
|
+
(`floor(nowMs / 100) * 100`), and the result carries the stamp in `payload.timestamp`. The tick is a
|
|
199
|
+
protocol constant, exported as `ROUND_TICK_MS`: it is the same on every gateway and node, it is not
|
|
200
|
+
configurable, and `GET /v1/info` does not report it. Stamping does not wait for a tick boundary, so
|
|
201
|
+
it adds no latency. Committee selection reads only the timestamp's one-second window (ten ticks), so
|
|
200
202
|
nobody can pick a committee by picking a time.
|
|
201
203
|
|
|
204
|
+
- One feed (a source, a quorum and a registry version) runs at most 10 rounds per second, whatever
|
|
205
|
+
the request rate.
|
|
206
|
+
- Requests for the same feed inside one tick share one round: the nodes run it once and every caller
|
|
207
|
+
gets the result. Each caller still spends its own unit of round quota, or its own payment.
|
|
208
|
+
- One consumer gets one round per tick per feed, so at most 10 per second. A second request by the
|
|
209
|
+
same consumer for the same source and quorum inside the tick is refused with HTTP 409; the SDK
|
|
210
|
+
retries it after one tick.
|
|
202
211
|
- The message the nodes sign is `keccak256(MOLPHA_MESSAGE_V1 || value || sourceId || u32be(registryVersion) || u8(quorum) || u64be(timestamp) || signersBitmap)`.
|
|
203
212
|
- Chain clocks, epochs and `maxAge`/staleness are in **seconds**: compare with
|
|
204
213
|
`timestampSeconds(payload.timestamp)` (floored `ts / 1000`). `timestampAgeSeconds(ts, nowSeconds)` saturates at 0.
|
|
205
|
-
-
|
|
214
|
+
- The SDK returns `payload.timestamp` exactly as the gateway gave it. Nodes enforce the grid when
|
|
215
|
+
they sign; the on-chain verifiers do not check it.
|
|
206
216
|
|
|
207
217
|
### Retries and timeouts
|
|
208
218
|
|
|
209
|
-
`requestSignedData` makes up to `maxRetries` attempts (default 6) and chooses the wait before each by why the last one failed (`retryDelayMs`). Every wait
|
|
219
|
+
`requestSignedData` makes up to `maxRetries` attempts (default 6) and chooses the wait before each by why the last one failed (`retryDelayMs`). Every wait carries jitter so clients that failed together do not retry together. The backoff step is a capped exponential: 250 ms, 500 ms, up to 5 s.
|
|
210
220
|
|
|
211
221
|
| Last attempt | Wait before the next |
|
|
212
222
|
| --- | --- |
|
|
213
|
-
| 409 (this consumer already has a round for the source in
|
|
214
|
-
| 503 or 429 (gateway at capacity, or nodes
|
|
215
|
-
| timeout, network error, other 5xx |
|
|
223
|
+
| 409 (this consumer already has a round for the source and quorum in the current tick) | one tick (`ROUND_TICK_MS`, 100 ms), plus up to 20 ms |
|
|
224
|
+
| 503 or 429 (gateway at capacity, or too few nodes accepted the round) | the later of the gateway's `Retry-After` and the backoff step, plus up to one more step |
|
|
225
|
+
| timeout, network error, other 5xx | the backoff step, half of it randomized |
|
|
216
226
|
| 400, 401, 402, 403 | none: terminal. 403 means the subscription is inactive or its round quota for the term is spent |
|
|
217
227
|
|
|
218
228
|
A 400 saying the `registryVersion` is not the current one (a cached context, or a registry roll between your read and the request) is the exception: the SDK reads the registry afresh and retries once, without spending an attempt.
|
|
219
229
|
|
|
230
|
+
The wait after a 409 is a full tick rather than the time left to the next boundary: a full tick puts the retry in a later tick whatever the offset between the client's clock and the gateway's, so the SDK never computes a boundary from the local clock. A caller polling one feed gains nothing by asking more often than once per tick: space the requests at least `ROUND_TICK_MS` apart.
|
|
231
|
+
|
|
232
|
+
A retry is a new request, and the gateway stamps it anew, so it is a **new round**: it spends another unit of round quota or needs another payment, and with a paywalled source another set of payment authorizations. Nothing ties a retry to the attempt before it; there is no idempotency key. Set `maxRetries: 1` to make a single attempt and decide about a retry yourself.
|
|
233
|
+
|
|
234
|
+
The gateway limits the total load: at capacity it answers HTTP 503 with a `Retry-After`, and a consumer over its request rate gets HTTP 429. It also answers 503 when too few nodes accept a round. The SDK treats them alike: it backs off and retries, and throws a `GatewayError` with the status when the attempts run out.
|
|
235
|
+
|
|
220
236
|
`timeoutMs` defaults to 35 s, above the gateway's own wait for a round (`roundTimeoutSeconds` in `/v1/info`, 30 s by default). A shorter timeout abandons a round the gateway is still running, and the retry then starts another. A source that cannot be fetched is reported as soon as enough nodes have failed (usually well under a second), not after the wait.
|
|
221
237
|
|
|
222
238
|
## Wallet
|
|
@@ -403,6 +419,34 @@ for (const r of results) {
|
|
|
403
419
|
|
|
404
420
|
It reads the registry inputs once for the whole batch; bounds concurrency, starting from half the gateway's advertised `maxInflightRounds` (at most 64, else 32) and adapting (halving on a busy answer, growing back while requests succeed); runs Solana submits on their own smaller limiter (`submitConcurrency`, default 8); never discards the signed attestation of a round whose submit failed; and returns one result per feed in input order, so a failing feed does not stop the others. Pass `submit: false` to collect attestations only. Throughput is limited by the submit path (one transaction per attestation) long before it is limited by the gateway.
|
|
405
421
|
|
|
422
|
+
### Batching attestations of one feed
|
|
423
|
+
|
|
424
|
+
At a high update rate, submit several attestations of the same feed in one transaction:
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
const { signature, count } = await sdk.solana.submitAttestations([older, newer, newest]);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Each becomes its own `submit_attestation` instruction, sorted by timestamp, and instructions run in
|
|
431
|
+
the order they are listed, so every attestation is applied, oldest first. Separate transactions give
|
|
432
|
+
no such order. Sent a few hundred milliseconds apart they reach a leader in a different order often
|
|
433
|
+
enough (about a third at 250 ms spacing in a devnet run) that the older one is refused with
|
|
434
|
+
`FeedNotNewer`; a batch makes the spacing between transactions several times longer, and one
|
|
435
|
+
transaction costs one fee.
|
|
436
|
+
|
|
437
|
+
- All attestations must be for one feed (the same `sourceId` and `signaturesRequired`), with distinct
|
|
438
|
+
timestamps. They may differ in registry version and signer set.
|
|
439
|
+
- The transaction is atomic. If a newer attestation of the feed has already landed, every
|
|
440
|
+
instruction is stale and none applies, so batch what is due together and send batches of one feed
|
|
441
|
+
in order.
|
|
442
|
+
- A transaction holds 1232 bytes, which is about three attestations with three signers, two with
|
|
443
|
+
four or five. `maxAttestationsPerTransaction(signerCount, { distinctSigners })` estimates it, and a
|
|
444
|
+
batch that does not fit throws `BatchTooLargeError` before sending, with `fits` saying how many
|
|
445
|
+
go: submit those and the rest apart. A priority-fee instruction costs bytes too.
|
|
446
|
+
- `rawValue` is not supported in a batch; use `submitAttestation` for values longer than 32 bytes.
|
|
447
|
+
- An attestation waits for the others in its batch, so a batch of `n` made at an interval of `t`
|
|
448
|
+
delays the oldest by `(n - 1) * t`.
|
|
449
|
+
|
|
406
450
|
### Fast requests with a cached context
|
|
407
451
|
|
|
408
452
|
By default every `requestSignedData` call reads the on-chain registry up front
|
|
@@ -917,7 +961,7 @@ Current scope:
|
|
|
917
961
|
|
|
918
962
|
- Solana subscription and extend flow;
|
|
919
963
|
- deterministic source id and attestation message hashing;
|
|
920
|
-
- gateway signed-data requests (failover,
|
|
964
|
+
- gateway signed-data requests (failover, retries with backoff, per-gateway request auth, context cache);
|
|
921
965
|
- Solana attestation submission and feed/registry reads;
|
|
922
966
|
- private API encryption helpers (pre-production);
|
|
923
967
|
- caller-funded x402 payments for paywalled API sources (Base USDC, pre-production);
|
package/dist/index.d.ts
CHANGED
|
@@ -40,8 +40,6 @@ interface GatewayInfo {
|
|
|
40
40
|
gatewayAuthority: string;
|
|
41
41
|
/** Program id the gateway settles against; must match the client's when present. */
|
|
42
42
|
programId?: string;
|
|
43
|
-
/** The gateway's round timestamp grid in milliseconds (`round.tick_ms`), when advertised. */
|
|
44
|
-
tickMs?: number;
|
|
45
43
|
/** Longest the gateway waits for a round, in seconds (`node.agg_wait_seconds`), when advertised. */
|
|
46
44
|
roundTimeoutSeconds?: number;
|
|
47
45
|
/** Rounds the gateway runs at once (`limits.max_inflight_rounds`); 0 or absent: not advertised. */
|
|
@@ -165,17 +163,12 @@ interface RequestSignedDataOptions {
|
|
|
165
163
|
/** Max accepted value age in seconds. Default 60. */
|
|
166
164
|
maxAge?: number;
|
|
167
165
|
/**
|
|
168
|
-
* Max attempts.
|
|
169
|
-
*
|
|
170
|
-
* see {@link retryDelayMs}.
|
|
166
|
+
* Max attempts. The wait before each retry depends on why the last attempt failed: one round
|
|
167
|
+
* tick after a duplicate (HTTP 409), the gateway's `Retry-After` or a capped exponential backoff
|
|
168
|
+
* after a busy answer, the backoff after anything else; see {@link retryDelayMs}. Every attempt
|
|
169
|
+
* the gateway accepts spends another unit of round quota. Default {@link DEFAULT_MAX_RETRIES}.
|
|
171
170
|
*/
|
|
172
171
|
maxRetries?: number;
|
|
173
|
-
/**
|
|
174
|
-
* The gateway's tick grid in milliseconds (its `round.tick_ms`). A retry waits for the start of
|
|
175
|
-
* the next tick so it is a new round, not a duplicate of the last. Default: the gateway's
|
|
176
|
-
* advertised `tickMs` (read once, on the first retry), else 1000.
|
|
177
|
-
*/
|
|
178
|
-
tickMs?: number;
|
|
179
172
|
/**
|
|
180
173
|
* Per-request timeout in ms. Default {@link DEFAULT_ROUND_TIMEOUT_MS}, above the gateway's own
|
|
181
174
|
* wait for a round: a shorter timeout abandons rounds the gateway is still running and the retry
|
|
@@ -228,6 +221,8 @@ interface MolphaGatewayOptions {
|
|
|
228
221
|
allowUnverifiedNodeKeysForPrivateApi?: boolean;
|
|
229
222
|
/** Source of randomness in [0, 1) for retry jitter; defaults to `Math.random` (tests only). */
|
|
230
223
|
random?: () => number;
|
|
224
|
+
/** Waits `ms` before a retry; defaults to a `setTimeout` timer (tests only). */
|
|
225
|
+
sleep?: (ms: number) => Promise<void>;
|
|
231
226
|
}
|
|
232
227
|
/**
|
|
233
228
|
* The slow-changing inputs a `requestSignedData` round binds to. Fetch once with
|
|
@@ -237,8 +232,6 @@ interface RoundContext extends RegistrySelectionConfig {
|
|
|
237
232
|
/** Full registry node set: private API secrets are encrypted for every node in it. */
|
|
238
233
|
nodes: Node[];
|
|
239
234
|
}
|
|
240
|
-
/** Milliseconds from `nowMs` to the start of the next tick, plus a millisecond of margin. */
|
|
241
|
-
declare function msUntilNextTick(nowMs: number, tickMs: number): number;
|
|
242
235
|
/**
|
|
243
236
|
* Default per-request timeout: above the gateway's own wait for a round (`node.agg_wait_seconds`,
|
|
244
237
|
* 30 s by default), so the client does not abandon a round the gateway is still running and then
|
|
@@ -249,9 +242,10 @@ declare const DEFAULT_ROUND_TIMEOUT_MS = 35000;
|
|
|
249
242
|
declare const DEFAULT_MAX_RETRIES = 6;
|
|
250
243
|
/**
|
|
251
244
|
* Why an attempt failed, as far as it decides how long to wait before the next one:
|
|
252
|
-
* - `conflict`: HTTP 409, this consumer already has a round for the source in
|
|
253
|
-
*
|
|
254
|
-
*
|
|
245
|
+
* - `conflict`: HTTP 409, this consumer already has a round for the source and quorum in the
|
|
246
|
+
* current round tick;
|
|
247
|
+
* - `busy`: HTTP 503 or 429, the gateway is at capacity, or too few nodes accepted the round
|
|
248
|
+
* (unavailable, or busy), optionally with the gateway's `Retry-After`;
|
|
255
249
|
* - `error`: anything else that may be transient (timeout, network, other 5xx).
|
|
256
250
|
*/
|
|
257
251
|
type RetryCause = {
|
|
@@ -263,16 +257,17 @@ type RetryCause = {
|
|
|
263
257
|
kind: "error";
|
|
264
258
|
};
|
|
265
259
|
/**
|
|
266
|
-
* How long to wait before the next attempt, in ms.
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* - error:
|
|
273
|
-
*
|
|
260
|
+
* How long to wait before the next attempt, in ms. Each delay carries jitter, so clients that
|
|
261
|
+
* failed together do not retry together:
|
|
262
|
+
* - conflict: one full round tick ({@link ROUND_TICK_MS}) plus up to 20 ms. The gateway stamps a
|
|
263
|
+
* round with the tick it is in, so a retry a full tick later is in a later tick whatever the
|
|
264
|
+
* offset between the two clocks: no boundary is computed from the local clock;
|
|
265
|
+
* - busy: the later of the gateway's `Retry-After` and the backoff step, plus up to one more step;
|
|
266
|
+
* - error: the backoff step, half of it randomized.
|
|
267
|
+
* The backoff step is a capped exponential (250 ms, 500 ms, ... 5 s). `failures` is the number of
|
|
268
|
+
* attempts that have failed so far (1 after the first).
|
|
274
269
|
*/
|
|
275
|
-
declare function retryDelayMs(cause: RetryCause, failures: number,
|
|
270
|
+
declare function retryDelayMs(cause: RetryCause, failures: number, random?: () => number): number;
|
|
276
271
|
|
|
277
272
|
/** Thrown for terminal gateway errors (400/401) — never retried. */
|
|
278
273
|
declare class GatewayError extends Error {
|
|
@@ -292,9 +287,8 @@ declare class MolphaGateway {
|
|
|
292
287
|
private readonly programIdBytes;
|
|
293
288
|
/** Gateway PDA per endpoint URL; resolved once per client lifetime. */
|
|
294
289
|
private readonly gatewayPdas;
|
|
295
|
-
/** Advertised timing per endpoint URL, read lazily on the first retry. */
|
|
296
|
-
private readonly advertisedInfo;
|
|
297
290
|
private readonly random;
|
|
291
|
+
private readonly sleep;
|
|
298
292
|
constructor(endpoints?: GatewayEndpointInput | GatewayEndpointInput[], getRegistrySelectionConfig?: () => Promise<RegistrySelectionConfig>, defaultSigner?: Signer,
|
|
299
293
|
/**
|
|
300
294
|
* Either a default subscription owner (base58) or gateway options. A string is the
|
|
@@ -337,10 +331,13 @@ declare class MolphaGateway {
|
|
|
337
331
|
* failover. The body is POSTed to each endpoint in order until one `completed`s.
|
|
338
332
|
*
|
|
339
333
|
* The round's `sourceId` is derived from `apiConfig`. The request carries no round timestamp:
|
|
340
|
-
* the gateway
|
|
341
|
-
*
|
|
342
|
-
* timestamp and the signers' bitmap
|
|
343
|
-
*
|
|
334
|
+
* the gateway stamps the round with its own clock floored to the round tick (`timestamp`, unix
|
|
335
|
+
* milliseconds, a multiple of {@link ROUND_TICK_MS}), and the committee follows from it. The
|
|
336
|
+
* result carries the assigned timestamp and the signers' bitmap; the timestamp is taken as the
|
|
337
|
+
* gateway gave it. Requests for the same source, quorum and registry version inside one tick
|
|
338
|
+
* share one round. One consumer gets one round per tick per source and quorum: a second request
|
|
339
|
+
* in the tick is refused (HTTP 409) and retried one tick later. A retry is stamped anew, so it
|
|
340
|
+
* is a new round that spends another unit of round quota.
|
|
344
341
|
*
|
|
345
342
|
* The request is authorized by a `RequestAuth` signature (`authSig`) over the program id, the
|
|
346
343
|
* endpoint's Gateway PDA, the source id, the quorum and `authTimestamp` (unix seconds, read
|
|
@@ -370,12 +367,6 @@ declare class MolphaGateway {
|
|
|
370
367
|
* encryption) or when nothing else can tell us the node count.
|
|
371
368
|
*/
|
|
372
369
|
private resolveContext;
|
|
373
|
-
/**
|
|
374
|
-
* The gateway's advertised tick grid, read once per endpoint and only when a retry needs it. Any
|
|
375
|
-
* failure (an old gateway without `/v1/info`, a timeout) means "not advertised", so the caller
|
|
376
|
-
* falls back to the default; a failure is not cached.
|
|
377
|
-
*/
|
|
378
|
-
private advertisedTickMs;
|
|
379
370
|
/** Gateway PDA bytes for an endpoint, cached per URL. A failed lookup is not cached. */
|
|
380
371
|
private resolveGatewayPda;
|
|
381
372
|
private lookupGatewayPda;
|
|
@@ -479,6 +470,33 @@ declare function planIdFromVariant(variant: Record<string, unknown>): PlanId;
|
|
|
479
470
|
* benchmark's, and a limit that is hit fails the transaction for good.
|
|
480
471
|
*/
|
|
481
472
|
declare function estimateSubmitComputeUnits(signerCount: number): number;
|
|
473
|
+
/**
|
|
474
|
+
* Compute-unit limit for one transaction that carries a `submit_attestation` per entry of
|
|
475
|
+
* `signerCounts`: the same margin as {@link estimateSubmitComputeUnits} on the sum, with the fixed
|
|
476
|
+
* 10k once for the transaction.
|
|
477
|
+
*/
|
|
478
|
+
declare function estimateSubmitBatchComputeUnits(signerCounts: number[]): number;
|
|
479
|
+
/**
|
|
480
|
+
* Bytes of `submit_attestation` instruction data with no raw value: the 8 byte discriminator, the
|
|
481
|
+
* payload (32 + 32 + 4 + 1 + 8), the signature (32 + 20 + 32), the empty `Option` and the coalition
|
|
482
|
+
* key (32 + 32).
|
|
483
|
+
*/
|
|
484
|
+
declare const SUBMIT_INSTRUCTION_DATA_BYTES = 234;
|
|
485
|
+
/**
|
|
486
|
+
* Serialized size of a transaction with `count` attestations of `signerCount` signers each, to plan
|
|
487
|
+
* a batch before there is one. The signer `Node` accounts are shared between attestations, so the
|
|
488
|
+
* size depends on how many distinct ones there are: `distinctSigners` (default `signerCount`, the
|
|
489
|
+
* best case; the registry's node count is the worst).
|
|
490
|
+
*/
|
|
491
|
+
declare function estimateSubmitTransactionSize(count: number, signerCount: number, opts?: {
|
|
492
|
+
distinctSigners?: number;
|
|
493
|
+
priorityFee?: boolean;
|
|
494
|
+
}): number;
|
|
495
|
+
/** The most attestations of `signerCount` signers that fit in one transaction; see {@link estimateSubmitTransactionSize}. */
|
|
496
|
+
declare function maxAttestationsPerTransaction(signerCount: number, opts?: {
|
|
497
|
+
distinctSigners?: number;
|
|
498
|
+
priorityFee?: boolean;
|
|
499
|
+
}): number;
|
|
482
500
|
type Commitment$1 = NonNullable<ConstructorParameters<typeof AnchorProvider>[2]>["commitment"];
|
|
483
501
|
interface SubscribeResult {
|
|
484
502
|
signature: string;
|
|
@@ -516,6 +534,31 @@ interface SubmitResult {
|
|
|
516
534
|
/** Feed PDA written by this submit (`["molpha_feed", sourceId, [signaturesRequired], submitter]`). */
|
|
517
535
|
feed: Address;
|
|
518
536
|
}
|
|
537
|
+
/** What {@link MolphaSolanaClient.submitAttestations} returns. */
|
|
538
|
+
interface SubmitAttestationsResult extends SubmitResult {
|
|
539
|
+
/** Attestations in the transaction. They were applied in timestamp order. */
|
|
540
|
+
count: number;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Thrown by {@link MolphaSolanaClient.submitAttestations} when the attestations do not fit in one
|
|
544
|
+
* transaction. Nothing was sent: submit the first `fits` of them (oldest first) and the rest apart.
|
|
545
|
+
*/
|
|
546
|
+
declare class BatchTooLargeError extends RangeError {
|
|
547
|
+
/** How many of the attestations, oldest first, do fit. */
|
|
548
|
+
readonly fits: number;
|
|
549
|
+
/** The serialized size of the whole batch, in bytes. */
|
|
550
|
+
readonly size: number;
|
|
551
|
+
/** The largest transaction the network accepts, in bytes. */
|
|
552
|
+
readonly limit: number;
|
|
553
|
+
readonly count: number;
|
|
554
|
+
constructor(
|
|
555
|
+
/** How many of the attestations, oldest first, do fit. */
|
|
556
|
+
fits: number,
|
|
557
|
+
/** The serialized size of the whole batch, in bytes. */
|
|
558
|
+
size: number,
|
|
559
|
+
/** The largest transaction the network accepts, in bytes. */
|
|
560
|
+
limit: number, count: number);
|
|
561
|
+
}
|
|
519
562
|
/**
|
|
520
563
|
* On-chain `Feed` (Anchor-decoded). `value` is always the signed
|
|
521
564
|
* `AttestationPayload.value` (32 bytes): the oracle value itself when `valueKind` is
|
|
@@ -586,6 +629,8 @@ interface SubmitAttestationOptions {
|
|
|
586
629
|
*/
|
|
587
630
|
rawValue?: Uint8Array;
|
|
588
631
|
}
|
|
632
|
+
/** Options for {@link MolphaSolanaClient.submitAttestations}. */
|
|
633
|
+
type SubmitAttestationsOptions = Pick<SubmitAttestationOptions, "computeUnitLimit" | "priorityFeeMicroLamports">;
|
|
589
634
|
interface CreateClientOpts {
|
|
590
635
|
connection: SolanaConnection;
|
|
591
636
|
wallet: Wallet;
|
|
@@ -668,6 +713,33 @@ declare class MolphaSolanaClient {
|
|
|
668
713
|
* `keccak256(rawValue)`; {@link buildSubmitAttestationArgs} validates that before send.
|
|
669
714
|
*/
|
|
670
715
|
submitAttestation(attestation: Attestation, opts?: SubmitAttestationOptions): Promise<SubmitResult>;
|
|
716
|
+
/**
|
|
717
|
+
* Submit several attestations of one feed in one transaction.
|
|
718
|
+
*
|
|
719
|
+
* Each becomes its own `submit_attestation` instruction, in timestamp order, and instructions run
|
|
720
|
+
* in the order they are listed: all of them are applied, oldest first, whatever order other
|
|
721
|
+
* transactions reach the leader in. That is what separate submits cannot promise. Transactions sent
|
|
722
|
+
* milliseconds apart for one feed are overtaken by a newer one often enough (about a third at 250 ms
|
|
723
|
+
* spacing in a devnet run) that the older one fails with `FeedNotNewer`; a batch makes the spacing
|
|
724
|
+
* between transactions several times longer and spends one fee and one signature for them all.
|
|
725
|
+
*
|
|
726
|
+
* The transaction is atomic: if one instruction fails (typically because a newer attestation
|
|
727
|
+
* of the feed landed first, so every instruction is stale) none of them applies. Batch only what
|
|
728
|
+
* is due together, and keep batches of one feed in the order they were made.
|
|
729
|
+
*
|
|
730
|
+
* All attestations must be for one feed (the same `sourceId` and `signaturesRequired`) with
|
|
731
|
+
* distinct timestamps. They need not share a registry version or a signer set. Values longer than
|
|
732
|
+
* 32 bytes (`rawValue`) are not supported here: submit those with {@link submitAttestation}.
|
|
733
|
+
*
|
|
734
|
+
* @throws {BatchTooLargeError} when they do not fit in one transaction (about three do with
|
|
735
|
+
* three signers; see {@link maxAttestationsPerTransaction}). Nothing is sent.
|
|
736
|
+
*/
|
|
737
|
+
submitAttestations(attestations: Attestation[], opts?: SubmitAttestationsOptions): Promise<SubmitAttestationsResult>;
|
|
738
|
+
/**
|
|
739
|
+
* Everything one `submit_attestation` instruction needs: the arguments, the named accounts, the
|
|
740
|
+
* signer `Node` accounts (ascending bit order) and the feed address.
|
|
741
|
+
*/
|
|
742
|
+
private prepareSubmit;
|
|
671
743
|
/** The registry for `version`, reused for {@link REGISTRY_CACHE_MS}. */
|
|
672
744
|
private fetchRegistryCached;
|
|
673
745
|
private resolvePriorityFee;
|
|
@@ -877,6 +949,15 @@ declare function deriveSelectionBitmap(sourceId: Uint8Array, registryVersion: nu
|
|
|
877
949
|
* EVM `block.timestamp`), epoch windows and `maxAge`/staleness are measured in SECONDS, so
|
|
878
950
|
* anything that compares the two must go through {@link timestampSeconds}.
|
|
879
951
|
*/
|
|
952
|
+
/**
|
|
953
|
+
* The round tick in milliseconds: the gateway stamps a round with its clock floored to this grid
|
|
954
|
+
* (`floor(nowMs / ROUND_TICK_MS) * ROUND_TICK_MS`) and nodes reject a round whose timestamp is off
|
|
955
|
+
* it. A feed (source, quorum, registry version) therefore runs at most ten rounds per second, and
|
|
956
|
+
* every selection window (`SELECTION_WINDOW_MS`, one second) holds exactly ten ticks. A
|
|
957
|
+
* protocol constant, the same in every gateway and node: not configuration, and not reported by
|
|
958
|
+
* `GET /v1/info`.
|
|
959
|
+
*/
|
|
960
|
+
declare const ROUND_TICK_MS = 100;
|
|
880
961
|
/** `timestamp` (unix ms) as whole unix seconds, floored. */
|
|
881
962
|
declare function timestampSeconds(timestamp: number | bigint): number;
|
|
882
963
|
/**
|
|
@@ -1467,8 +1548,8 @@ interface BulkOptions {
|
|
|
1467
1548
|
*/
|
|
1468
1549
|
concurrency?: number;
|
|
1469
1550
|
/**
|
|
1470
|
-
* Spread request starts over this many ms by a hash of the feed's source id. Feeds that are due
|
|
1471
|
-
* the same
|
|
1551
|
+
* Spread request starts over this many ms by a hash of the feed's source id. Feeds that are due at
|
|
1552
|
+
* the same moment otherwise arrive together and queue at the gateway. Default 0 (no spreading).
|
|
1472
1553
|
*/
|
|
1473
1554
|
spreadMs?: number;
|
|
1474
1555
|
/** Submit each attestation to Solana after its round. Default true. */
|
|
@@ -1592,4 +1673,4 @@ declare class MolphaSDK {
|
|
|
1592
1673
|
}>;
|
|
1593
1674
|
}
|
|
1594
1675
|
|
|
1595
|
-
export { APIConfig, AdaptiveLimiter, AggregationConfig, AggregationConfigError, AssetDomain, Attestation, type AttestationMessageFields, type BuildEvmVerifierArgsOptions, type BuildStarknetVerifierArgsOptions, type BulkFeed, type BulkOptions, type BulkResult, type CoalitionKey, DEFAULT_GATEWAY_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_ROUND_TIMEOUT_MS, EIP712_DOMAIN_TYPEHASH, type Eip712Domain, type EvmAttestation, type EvmAttestationPayload, type EvmSchnorrSignature, EvmSigner, type EvmVerifierArgs, type EvmVerifyResult, type FeedAccount, type GatewayEndpoint, type GatewayEndpointInput, GatewayError, type GatewayInfo, INT256_MAX, INT256_MIN, MESSAGE_PREFIX, MIN_TOLERANCE_SIGNATURES, MOLPHA_DEV_VERIFIERS_PROVISIONAL, MOLPHA_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, MOLPHA_SDK_PROFILE, MOLPHA_VERIFIER_ABI, MOLPHA_VERIFIER_ADDRESS, MOLPHA_VERIFIER_STARKNET_ADDRESSES, MOLPHA_VERIFIER_STARKNET_SEPOLIA, type MolphaEvmNetwork, MolphaGateway, type MolphaGatewayOptions, MolphaSDK, type MolphaSDKOptions, MolphaSolanaClient, type MolphaStarknetNetwork, MolphaWallet, Node, NodeKeyVerifier, NodeKeyVerifierArgs, NodesInfo, type PlanId, type PlanInfo, PlanType, REQUEST_AUTH_DOMAIN, RegistrySelectionConfig, type RegistryStateView, type RegistryView, type RequestAuthFields, type RequestSignedDataOptions, type RetryCause, type RoundContext, SELECTION_WINDOW_MS, type Secp256k1KeyInput, Signer, SourcePaymentOptions, type StarknetAttestation, type StarknetAttestationPayload, type StarknetFeltLike, type StarknetSchnorrSignature, type StarknetVerifierArgs, type StarknetVerifyResult, type SubmitAttestationArgs, type SubmitAttestationOptions, SubmitFailedError, type SubmitResult, type SubscribeResult, type SubscriptionInfo, TRANSFER_WITH_AUTHORIZATION_TYPEHASH, type TransferAuthorization, UpstreamPaymentRequiredError, UpstreamQuote, UpstreamTerms, VERIFY_CODES, type VerifyCode, type VerifyCodeName, addressToBytes, assertAggregationQuorum, attestationMessageHash, attestationMessageHashFromAttestation, base64ToBytes, bigIntFromBytesBe, bitmapBitSet, bitmapToIndices, buildEvmVerifierArgs, buildStarknetVerifierArgs, buildSubmitAttestationArgs, bytesToBase64, bytesToHex, bytesToHex0x, canonicalizeAPIConfig, canonicalizeAggregation, commitmentAddressToStarknetFelt, computeCoalitionKey, concatBytes, createEvmSignerFromPrivateKey, decodeInt256, deriveGatewayPda, deriveGatewayPdaAddress, deriveGroupBitmap, deriveSelectionBitmap, deriveSelectionSeed, deriveSourceId, deriveSourceIdString, domainSeparator, effectiveSelectionSize, eligibleSetSize, encodeEvmVerifyCalldata, encodeInt256, encodeInt256Decimal, encodeRequestAuth, encodeStarknetVerifyCalldata, ensureLength, estimateSubmitComputeUnits, evmAddressFromPrivateKey, feedPda, formatInt256Decimal, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes,
|
|
1676
|
+
export { APIConfig, AdaptiveLimiter, AggregationConfig, AggregationConfigError, AssetDomain, Attestation, type AttestationMessageFields, BatchTooLargeError, type BuildEvmVerifierArgsOptions, type BuildStarknetVerifierArgsOptions, type BulkFeed, type BulkOptions, type BulkResult, type CoalitionKey, DEFAULT_GATEWAY_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_ROUND_TIMEOUT_MS, EIP712_DOMAIN_TYPEHASH, type Eip712Domain, type EvmAttestation, type EvmAttestationPayload, type EvmSchnorrSignature, EvmSigner, type EvmVerifierArgs, type EvmVerifyResult, type FeedAccount, type GatewayEndpoint, type GatewayEndpointInput, GatewayError, type GatewayInfo, INT256_MAX, INT256_MIN, MESSAGE_PREFIX, MIN_TOLERANCE_SIGNATURES, MOLPHA_DEV_VERIFIERS_PROVISIONAL, MOLPHA_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, MOLPHA_SDK_PROFILE, MOLPHA_VERIFIER_ABI, MOLPHA_VERIFIER_ADDRESS, MOLPHA_VERIFIER_STARKNET_ADDRESSES, MOLPHA_VERIFIER_STARKNET_SEPOLIA, type MolphaEvmNetwork, MolphaGateway, type MolphaGatewayOptions, MolphaSDK, type MolphaSDKOptions, MolphaSolanaClient, type MolphaStarknetNetwork, MolphaWallet, Node, NodeKeyVerifier, NodeKeyVerifierArgs, NodesInfo, type PlanId, type PlanInfo, PlanType, REQUEST_AUTH_DOMAIN, ROUND_TICK_MS, RegistrySelectionConfig, type RegistryStateView, type RegistryView, type RequestAuthFields, type RequestSignedDataOptions, type RetryCause, type RoundContext, SELECTION_WINDOW_MS, SUBMIT_INSTRUCTION_DATA_BYTES, type Secp256k1KeyInput, Signer, SourcePaymentOptions, type StarknetAttestation, type StarknetAttestationPayload, type StarknetFeltLike, type StarknetSchnorrSignature, type StarknetVerifierArgs, type StarknetVerifyResult, type SubmitAttestationArgs, type SubmitAttestationOptions, type SubmitAttestationsOptions, type SubmitAttestationsResult, SubmitFailedError, type SubmitResult, type SubscribeResult, type SubscriptionInfo, TRANSFER_WITH_AUTHORIZATION_TYPEHASH, type TransferAuthorization, UpstreamPaymentRequiredError, UpstreamQuote, UpstreamTerms, VERIFY_CODES, type VerifyCode, type VerifyCodeName, addressToBytes, assertAggregationQuorum, attestationMessageHash, attestationMessageHashFromAttestation, base64ToBytes, bigIntFromBytesBe, bitmapBitSet, bitmapToIndices, buildEvmVerifierArgs, buildStarknetVerifierArgs, buildSubmitAttestationArgs, bytesToBase64, bytesToHex, bytesToHex0x, canonicalizeAPIConfig, canonicalizeAggregation, commitmentAddressToStarknetFelt, computeCoalitionKey, concatBytes, createEvmSignerFromPrivateKey, decodeInt256, deriveGatewayPda, deriveGatewayPdaAddress, deriveGroupBitmap, deriveSelectionBitmap, deriveSelectionSeed, deriveSourceId, deriveSourceIdString, domainSeparator, effectiveSelectionSize, eligibleSetSize, encodeEvmVerifyCalldata, encodeInt256, encodeInt256Decimal, encodeRequestAuth, encodeStarknetVerifyCalldata, ensureLength, estimateSubmitBatchComputeUnits, estimateSubmitComputeUnits, estimateSubmitTransactionSize, evmAddressFromPrivateKey, feedPda, formatInt256Decimal, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes, maxAttestationsPerTransaction, nodePda, normalizeEndpoint, normalizeSecp256k1PublicKeyHex, parseEvmVerifyResult, parseGatewayInfo, parseStarknetVerifyResult, parseUpstreamQuote, planIdFromVariant, planPda, planVariant, probeSource, protocolConfigPda, registryPda, registryStatePda, requestMany, resolveRemainingAccounts, retryDelayMs, secp256k1PublicKeyFromCoordinates, selectedIndices, signSourcePayments, signersBitmapToDecimal, signersBitmapToStarknetUint256, signersBitmapToUint256, spreadOffsetMs, subscriptionPda, timestampAgeSeconds, timestampSeconds, toChecksumAddress, toFixedBytes, toFixedHex, transferWithAuthorizationDigest, transferWithAuthorizationHash, u256beFromBigInt, u32be, u32le, u64be, u64le, u8, utf8, validateSuppliedTerms, verifyCodeName };
|