@molpha/sdk 0.2.0-dev-20261001125531 → 0.2.0-dev-20261005112114
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 +31 -14
- package/dist/index.d.ts +82 -41
- package/dist/index.js +129 -80
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/{wallet-HfGXPpOp.d.ts → wallet-LqCFWwV4.d.ts} +13 -11
- package/idl/molpha.json +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,10 +23,10 @@ At a high level:
|
|
|
23
23
|
Consumer
|
|
24
24
|
└─ subscribes (USDC) on Solana
|
|
25
25
|
└─ derives sourceId = keccak256(canonical apiConfig)
|
|
26
|
-
└─ signs a RequestAuth bound to (programId, gateway, sourceId, signaturesRequired,
|
|
26
|
+
└─ signs a RequestAuth bound to (programId, gateway, sourceId, signaturesRequired, authTimestamp)
|
|
27
27
|
|
|
28
28
|
Gateway
|
|
29
|
-
└─
|
|
29
|
+
└─ assigns the round's timestamp (unix ms) from its own clock and coordinates a signing round
|
|
30
30
|
|
|
31
31
|
Verifier nodes
|
|
32
32
|
└─ fetch/recompute the API result independently
|
|
@@ -46,7 +46,7 @@ Every signed attestation commits to the same message across chains:
|
|
|
46
46
|
```text
|
|
47
47
|
message = keccak256(
|
|
48
48
|
keccak256("MOLPHA_MESSAGE_V1") || value || sourceId || u32be(registryVersion) ||
|
|
49
|
-
u8(signaturesRequired) || u64be(
|
|
49
|
+
u8(signaturesRequired) || u64be(timestamp) || signersBitmap
|
|
50
50
|
)
|
|
51
51
|
```
|
|
52
52
|
|
|
@@ -64,7 +64,7 @@ Runtime dependencies include `@solana/kit`, `@anchor-lang/core`, and `@noble/*`.
|
|
|
64
64
|
|
|
65
65
|
| Import | Use |
|
|
66
66
|
|---|---|
|
|
67
|
-
| `@molpha/sdk` | Facade (`MolphaSDK`), `MolphaGateway`, `MolphaSolanaClient`, core hashing (`deriveSourceId`, `attestationMessageHash`, `hashRequestAuth`), EVM/Starknet helpers. Browser-safe; no `fs` in the main entry. |
|
|
67
|
+
| `@molpha/sdk` | Facade (`MolphaSDK`), `MolphaGateway`, `MolphaSolanaClient`, core hashing (`deriveSourceId`, `attestationMessageHash`, `hashRequestAuth`, `timestampSeconds`), EVM/Starknet helpers. Browser-safe; no `fs` in the main entry. |
|
|
68
68
|
| `@molpha/sdk/utils` | `walletFromKeypairFile`, `loadKeypair` — load a Solana CLI keypair as an Anchor `Wallet`. Node.js only. |
|
|
69
69
|
|
|
70
70
|
The package is ESM with `"sideEffects": false`, so gateway-only or read-only apps can tree-shake unused paths.
|
|
@@ -149,11 +149,13 @@ Gateway request authorization binds the gateway's on-chain account, so the clien
|
|
|
149
149
|
|
|
150
150
|
```text
|
|
151
151
|
requestAuthHash = keccak256(
|
|
152
|
-
"MOLPHA_REQAUTH_V1" || programId || gatewayPda || sourceId || u8(signaturesRequired) || u64le(
|
|
152
|
+
"MOLPHA_REQAUTH_V1" || programId || gatewayPda || sourceId || u8(signaturesRequired) || u64le(authTimestamp)
|
|
153
153
|
)
|
|
154
154
|
gatewayPda = PDA(["molpha_gateway", gatewayAuthority], programId)
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
`authTimestamp` is the caller's unix **seconds** at signing: a freshness stamp for the authorization only (the gateway rejects stamps outside its `request_auth.window_seconds`, 60 s by default). It is read from the SDK clock for every attempt, so a retry after a 409 signs a fresh one. It has nothing to do with the round's `timestamp`.
|
|
158
|
+
|
|
157
159
|
Pass `gatewayAuthority` (the gateway's base58 signing pubkey) per endpoint to pin it. When omitted, the SDK calls `GET {url}/v1/info` once per endpoint and reads:
|
|
158
160
|
|
|
159
161
|
```json
|
|
@@ -162,6 +164,20 @@ Pass `gatewayAuthority` (the gateway's base58 signing pubkey) per endpoint to pi
|
|
|
162
164
|
|
|
163
165
|
A `programId` that differs from the client's is rejected. Because the hash differs per gateway, the auth signature is recomputed for every endpoint actually tried during failover — with a browser wallet that means one signing prompt per endpoint tried. `/v1/info` is never contacted when no signer is configured (dev zero-signature path).
|
|
164
166
|
|
|
167
|
+
### Round timestamp
|
|
168
|
+
|
|
169
|
+
The request body carries `authSig` and `authTimestamp` but no round timestamp. The gateway assigns the
|
|
170
|
+
round's `timestamp` from its own clock, in unix **milliseconds**, on a tick grid
|
|
171
|
+
(`floor(now / tickMs) * tickMs`, one second by default), and the result carries it in
|
|
172
|
+
`payload.timestamp`. Committee selection reads only the timestamp's one-second window, so
|
|
173
|
+
nobody can pick a committee by picking a time.
|
|
174
|
+
|
|
175
|
+
- The message the nodes sign is `keccak256(MOLPHA_MESSAGE_V1 || value || sourceId || u32be(registryVersion) || u8(quorum) || u64be(timestamp) || signersBitmap)`.
|
|
176
|
+
- Chain clocks, epochs and `maxAge`/staleness are in **seconds**: compare with
|
|
177
|
+
`timestampSeconds(payload.timestamp)` (floored `ts / 1000`). `timestampAgeSeconds(ts, nowSeconds)` saturates at 0.
|
|
178
|
+
- A round that was already reserved for this consumer, or dispatched to the nodes, cannot run again in the same tick (HTTP 409), so a retry waits for the next one (`tickMs`, default 1000: set it to the gateway's `round.tick_ms`).
|
|
179
|
+
- Private API secrets are encrypted for every node of the registry (the committee is unknown until the gateway stamps the round); the gateway forwards only the selected nodes' envelopes. `verifyNodeKeys` therefore authenticates all of them.
|
|
180
|
+
|
|
165
181
|
## Wallet
|
|
166
182
|
|
|
167
183
|
`wallet` is a single `MolphaWallet` used across both protocol surfaces:
|
|
@@ -169,7 +185,7 @@ A `programId` that differs from the client's is rejected. Because the hash diffe
|
|
|
169
185
|
| Layer | What it signs |
|
|
170
186
|
|---|---|
|
|
171
187
|
| Solana client | Transactions such as `subscribe`, `extendSubscription`, `submitAttestation` |
|
|
172
|
-
| Gateway client | `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired,
|
|
188
|
+
| Gateway client | `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired, authTimestamp })` for authenticated gateway requests |
|
|
173
189
|
|
|
174
190
|
Gateway auth is resolved automatically when you use `MolphaSDK`:
|
|
175
191
|
|
|
@@ -182,7 +198,8 @@ Gateway auth is resolved automatically when you use `MolphaSDK`:
|
|
|
182
198
|
explicit `signer`. Standalone `new MolphaGateway(...)` omits auth unless you pass
|
|
183
199
|
a `defaultSigner` (third constructor arg) or per-call `signer`.
|
|
184
200
|
|
|
185
|
-
The all-zero `authSig` path is for development only. Production jobs should authenticate gateway requests.
|
|
201
|
+
The all-zero `authSig` path is for development only: a gateway rejects it with 401. Production jobs should authenticate gateway requests.
|
|
202
|
+
|
|
186
203
|
|
|
187
204
|
### Node.js utility
|
|
188
205
|
|
|
@@ -276,7 +293,7 @@ const result = await sdk.gateway.requestSignedData({
|
|
|
276
293
|
|
|
277
294
|
The gateway round uses the current on-chain registry version. Selected verifier nodes independently fetch/recompute the result and sign only if the observed value matches the canonical result.
|
|
278
295
|
|
|
279
|
-
The returned `Attestation` matches the cross-VM struct (`payload` + `signature`), plus gateway-only `value` (human-readable) and `fresh`. `payload` carries `sourceId`, the signed 32-byte `value`, `
|
|
296
|
+
The returned `Attestation` matches the cross-VM struct (`payload` + `signature`), plus gateway-only `value` (human-readable) and `fresh`. `payload` carries `sourceId`, the signed 32-byte `value`, `timestamp`, `registryVersion`, and `signaturesRequired`; `signature` carries the aggregate Schnorr material and `signersBitmap`. `signaturesRequired` must be at least the protocol's `min_signers` (currently 3) or the chain rejects the submit.
|
|
280
297
|
|
|
281
298
|
A gateway response is a coordination result, not proof of settlement or of on-chain verification. Consumers still decide freshness, source, quorum and replay policy.
|
|
282
299
|
|
|
@@ -302,7 +319,7 @@ const feedState = await sdk.solana.readFeed(result.payload.sourceId, signaturesR
|
|
|
302
319
|
|
|
303
320
|
`FeedAccount.value` is the 32 signed bytes (`valueKind.value`) or their keccak preimage hash (`valueKind.hash`); `submitter` is the wallet that created the feed.
|
|
304
321
|
|
|
305
|
-
The subscription read
|
|
322
|
+
The subscription read does not expose usage: the program stores no `used_rounds` / `prepaid_usdc` / `price`, and round quota is counted by the gateway's off-chain outbox. `SubscriptionInfo` carries only `owner`, `planType`, `validUntil`, `maxRounds`, `delegateCount`, `maxDelegates`, `maxSigners`.
|
|
306
323
|
|
|
307
324
|
### One-call request + submit
|
|
308
325
|
|
|
@@ -540,7 +557,7 @@ attestation:
|
|
|
540
557
|
sourceId: `0x${string}`, // bytes32
|
|
541
558
|
registryVersion: number, // uint32
|
|
542
559
|
signaturesRequired: number, // uint8
|
|
543
|
-
|
|
560
|
+
timestamp: bigint, // uint64
|
|
544
561
|
},
|
|
545
562
|
signature: {
|
|
546
563
|
signature: `0x${string}`, // bytes32 (Attestation.signature.s)
|
|
@@ -692,7 +709,7 @@ attestation:
|
|
|
692
709
|
source_id: u256,
|
|
693
710
|
registry_version: u32,
|
|
694
711
|
signatures_required: u8,
|
|
695
|
-
|
|
712
|
+
timestamp: u64,
|
|
696
713
|
},
|
|
697
714
|
signature: {
|
|
698
715
|
signature: u256,
|
|
@@ -742,7 +759,7 @@ shared with the EVM verifier contract and exported as `VERIFY_CODES`:
|
|
|
742
759
|
| 0 | `OK` | Verified |
|
|
743
760
|
| 2 | `BAD_REGISTRY_VERSION` | `registryVersion` does not exist on this verifier |
|
|
744
761
|
| 3 | `MALFORMED` | Structurally invalid input, or dated in the future when `maxAge != 0` |
|
|
745
|
-
| 4 | `NOT_YET_ACTIVE` | `
|
|
762
|
+
| 4 | `NOT_YET_ACTIVE` | `timestamp` predates the registry version's activation |
|
|
746
763
|
| 5 | `VERSION_EXPIRED` | Registry version superseded more than the grace window earlier |
|
|
747
764
|
| 7 | `BAD_QUORUM` | Signers are not within the round's derived selection group |
|
|
748
765
|
| 8 | `BAD_AGGREGATE` | The signers' aggregate key is the point at infinity |
|
|
@@ -770,7 +787,7 @@ A Molpha attestation is valid only if the verifier can confirm:
|
|
|
770
787
|
- the update targets the expected `sourceId`;
|
|
771
788
|
- the result was signed against a specific `registryVersion` (an immutable node-set snapshot);
|
|
772
789
|
- the quorum satisfies `signaturesRequired`;
|
|
773
|
-
- the signer bitmap is a subset of the deterministic selection for `(sourceId, registryVersion,
|
|
790
|
+
- the signer bitmap is a subset of the deterministic selection for `(sourceId, registryVersion, timestamp)`;
|
|
774
791
|
- the aggregate Schnorr signature over `attestationMessageHash(...)` is valid;
|
|
775
792
|
- the timestamp is within the accepted freshness bounds;
|
|
776
793
|
- on Solana, the signer `Node` accounts passed as remaining accounts are exactly `registry.nodes[bit]` for every set bit, and the supplied coalition key matches the sum of their keys.
|
|
@@ -834,7 +851,7 @@ Current scope:
|
|
|
834
851
|
|
|
835
852
|
- Solana subscription and extend flow;
|
|
836
853
|
- deterministic source id and attestation message hashing;
|
|
837
|
-
- gateway signed-data requests (failover, retries, per-gateway request auth, context cache);
|
|
854
|
+
- gateway signed-data requests (failover, tick-aware retries, per-gateway request auth, context cache);
|
|
838
855
|
- Solana attestation submission and feed/registry reads;
|
|
839
856
|
- private API encryption helpers (pre-production);
|
|
840
857
|
- caller-funded x402 payments for paywalled API sources (Base USDC, pre-production);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Address } from '@solana/kit';
|
|
2
2
|
import { Wallet, Idl, AnchorProvider } from '@anchor-lang/core';
|
|
3
|
-
import { U as UpstreamQuote, A as APIConfig, a as AssetDomain, b as UpstreamTerms, E as EvmSigner, R as RegistrySelectionConfig, S as Signer, N as NodeKeyVerifier, c as Node, d as NodesInfo, e as SourcePaymentOptions, f as Attestation, g as SolanaAccountMeta, h as SolanaConnection, i as SolanaAddress, j as NodeKeyVerifierArgs, k as AggregationConfig, M as MolphaWallet } from './wallet-
|
|
4
|
-
export { l as AttestationPayload, m as EncKeyBundle, n as NumericConfig, o as RegistryInfo, p as SchnorrSignature, q as gatewaySignerFromWallet, s as signerFromKeypair } from './wallet-
|
|
3
|
+
import { U as UpstreamQuote, A as APIConfig, a as AssetDomain, b as UpstreamTerms, E as EvmSigner, R as RegistrySelectionConfig, S as Signer, N as NodeKeyVerifier, c as Node, d as NodesInfo, e as SourcePaymentOptions, f as Attestation, g as SolanaAccountMeta, h as SolanaConnection, i as SolanaAddress, j as NodeKeyVerifierArgs, k as AggregationConfig, M as MolphaWallet } from './wallet-LqCFWwV4.js';
|
|
4
|
+
export { l as AttestationPayload, m as EncKeyBundle, n as NumericConfig, o as RegistryInfo, p as SchnorrSignature, q as gatewaySignerFromWallet, s as signerFromKeypair } from './wallet-LqCFWwV4.js';
|
|
5
5
|
import BN from 'bn.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -48,8 +48,8 @@ interface RequestAuthFields {
|
|
|
48
48
|
sourceId: Uint8Array | string;
|
|
49
49
|
/** u8 — the per-request quorum. */
|
|
50
50
|
signaturesRequired: number;
|
|
51
|
-
/** u64 unix
|
|
52
|
-
|
|
51
|
+
/** u64 unix SECONDS at signing (the auth freshness stamp, not the round's timestamp). */
|
|
52
|
+
authTimestamp: number | bigint;
|
|
53
53
|
}
|
|
54
54
|
/** Borsh encoding of `RequestAuth` — the hash body, without the domain. */
|
|
55
55
|
declare function encodeRequestAuth(fields: RequestAuthFields): Uint8Array;
|
|
@@ -117,15 +117,16 @@ interface RequestSignedDataOptions {
|
|
|
117
117
|
*/
|
|
118
118
|
subscriptionOwner?: string;
|
|
119
119
|
/**
|
|
120
|
-
* Solana pubkey (base58) of the consumer
|
|
120
|
+
* Solana pubkey (base58) of the consumer: the subscription owner, or a delegate of it.
|
|
121
121
|
* Overrides the gateway's `defaultConsumerAuthority` when set.
|
|
122
122
|
*/
|
|
123
123
|
consumerAuthority?: string;
|
|
124
124
|
/**
|
|
125
|
-
* Signs `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired,
|
|
125
|
+
* Signs `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired, authTimestamp })`.
|
|
126
126
|
* The hash binds the gateway's on-chain account, so it is computed — and the signer
|
|
127
|
-
* invoked — once per endpoint actually tried
|
|
128
|
-
* when set. When both are omitted, sends an all-zero
|
|
127
|
+
* invoked — once per endpoint actually tried, with a fresh `authTimestamp` each time.
|
|
128
|
+
* Overrides the gateway's `defaultSigner` when set. When both are omitted, sends an all-zero
|
|
129
|
+
* authSig (a gateway rejects it with 401; for tests and local tooling only).
|
|
129
130
|
*/
|
|
130
131
|
signer?: Signer;
|
|
131
132
|
encrypt?: {
|
|
@@ -144,8 +145,13 @@ interface RequestSignedDataOptions {
|
|
|
144
145
|
sourcePayment?: SourcePaymentOptions;
|
|
145
146
|
/** Max accepted value age in seconds. Default 60. */
|
|
146
147
|
maxAge?: number;
|
|
147
|
-
/**
|
|
148
|
+
/** Max attempts; each retry waits for a later gateway tick. Default 15. */
|
|
148
149
|
maxRetries?: number;
|
|
150
|
+
/**
|
|
151
|
+
* The gateway's tick grid in milliseconds (its `round.tick_ms`). A retry waits for the start of
|
|
152
|
+
* the next tick so it is a new round, not a duplicate of the last. Default 1000.
|
|
153
|
+
*/
|
|
154
|
+
tickMs?: number;
|
|
149
155
|
/** Per-request timeout in ms. Default 5000. */
|
|
150
156
|
timeoutMs?: number;
|
|
151
157
|
/**
|
|
@@ -177,8 +183,9 @@ interface MolphaGatewayOptions {
|
|
|
177
183
|
/** Solana pubkey (base58) of the consumer authority used when a request omits it. */
|
|
178
184
|
defaultConsumerAuthority?: string;
|
|
179
185
|
/**
|
|
180
|
-
* Molpha program id the request authorization is bound to
|
|
181
|
-
*
|
|
186
|
+
* Molpha program id the request authorization is bound to (and that `fetchGatewayInfo`
|
|
187
|
+
* checks the gateway settles against). Defaults to the vendored `MOLPHA_PROGRAM_ID`;
|
|
188
|
+
* must match the gateway's deployment.
|
|
182
189
|
*/
|
|
183
190
|
programId?: string;
|
|
184
191
|
/**
|
|
@@ -197,9 +204,11 @@ interface MolphaGatewayOptions {
|
|
|
197
204
|
* {@link MolphaGateway.prepareContext} and reuse across many rounds.
|
|
198
205
|
*/
|
|
199
206
|
interface RoundContext extends RegistrySelectionConfig {
|
|
200
|
-
/** Full node set
|
|
207
|
+
/** Full registry node set: private API secrets are encrypted for every node in it. */
|
|
201
208
|
nodes: Node[];
|
|
202
209
|
}
|
|
210
|
+
/** Milliseconds from `nowMs` to the start of the next tick, plus a millisecond of margin. */
|
|
211
|
+
declare function msUntilNextTick(nowMs: number, tickMs: number): number;
|
|
203
212
|
/** Default gateway base URL when `endpoints` is omitted. */
|
|
204
213
|
declare const DEFAULT_GATEWAY_ENDPOINT = "https://dev-gateway.molpha.io/";
|
|
205
214
|
/** Thrown for terminal gateway errors (400/401) — never retried. */
|
|
@@ -222,8 +231,8 @@ declare class MolphaGateway {
|
|
|
222
231
|
private readonly gatewayPdas;
|
|
223
232
|
constructor(endpoints?: GatewayEndpointInput | GatewayEndpointInput[], getRegistrySelectionConfig?: () => Promise<RegistrySelectionConfig>, defaultSigner?: Signer,
|
|
224
233
|
/**
|
|
225
|
-
* Either a default subscription owner (base58) or gateway options. A string
|
|
226
|
-
*
|
|
234
|
+
* Either a default subscription owner (base58) or gateway options. A string is the
|
|
235
|
+
* shorthand for `{ defaultSubscriptionOwner }` used by standalone callers/tests.
|
|
227
236
|
*/
|
|
228
237
|
defaultSubscriptionOwnerOrOptions?: string | MolphaGatewayOptions, defaultConsumerAuthority?: string);
|
|
229
238
|
/** Tries endpoints in order; returns the first node list it can fetch. */
|
|
@@ -233,7 +242,7 @@ declare class MolphaGateway {
|
|
|
233
242
|
* selection policy, which sizes the eligible set a paid source must fund.
|
|
234
243
|
*
|
|
235
244
|
* The `registry` block is advisory: it is whatever the gateway read from the
|
|
236
|
-
* chain, and is absent
|
|
245
|
+
* chain, and is absent when that read failed. Prefer the
|
|
237
246
|
* on-chain read (`MolphaSolanaClient.getRegistrySelectionConfig`) whenever a
|
|
238
247
|
* Solana connection is available — `requestSignedData` already does.
|
|
239
248
|
*/
|
|
@@ -257,12 +266,23 @@ declare class MolphaGateway {
|
|
|
257
266
|
prepareContext(): Promise<RoundContext>;
|
|
258
267
|
/**
|
|
259
268
|
* Request a threshold-signed data update from the gateway, with retry +
|
|
260
|
-
* failover.
|
|
261
|
-
*
|
|
269
|
+
* failover. The body is POSTed to each endpoint in order until one `completed`s.
|
|
270
|
+
*
|
|
271
|
+
* The round's `sourceId` is derived from `apiConfig`. The request carries no round timestamp:
|
|
272
|
+
* the gateway assigns the round's `timestamp` (unix milliseconds) from its own clock
|
|
273
|
+
* on a tick grid, and the committee follows from it. The result carries the assigned
|
|
274
|
+
* timestamp and the signers' bitmap. A retry waits for a later tick, because a round that was
|
|
275
|
+
* already reserved or dispatched cannot run again in the same one (HTTP 409).
|
|
262
276
|
*
|
|
263
|
-
* The
|
|
264
|
-
*
|
|
265
|
-
*
|
|
277
|
+
* The request is authorized by a `RequestAuth` signature (`authSig`) over the program id, the
|
|
278
|
+
* endpoint's Gateway PDA, the source id, the quorum and `authTimestamp` (unix seconds, read
|
|
279
|
+
* from the local clock for every attempt). It only proves the caller may spend the
|
|
280
|
+
* subscription's rounds; it is not part of the round, so the signature is recomputed for every
|
|
281
|
+
* endpoint tried.
|
|
282
|
+
*
|
|
283
|
+
* Because the committee is unknown until the gateway stamps the round, private API
|
|
284
|
+
* secrets are encrypted for **every** node of the registry; the gateway forwards only the
|
|
285
|
+
* selected nodes' envelopes.
|
|
266
286
|
*
|
|
267
287
|
* By default this fetches the registry selection config up front and the node
|
|
268
288
|
* set only when the round needs it (private API encryption, or when the registry
|
|
@@ -392,8 +412,7 @@ interface PlanInfo {
|
|
|
392
412
|
isActive: boolean;
|
|
393
413
|
}
|
|
394
414
|
/**
|
|
395
|
-
* On-chain `Subscription`. The program
|
|
396
|
-
* `prepaid_usdc` and the locked `price` were removed (round quota is counted by the
|
|
415
|
+
* On-chain `Subscription`. The program does not track usage (round quota is counted by the
|
|
397
416
|
* gateway's off-chain outbox), so there is no on-chain "rounds used" figure to read.
|
|
398
417
|
*/
|
|
399
418
|
interface SubscriptionInfo {
|
|
@@ -428,8 +447,8 @@ interface FeedAccount {
|
|
|
428
447
|
hash: Record<string, never>;
|
|
429
448
|
};
|
|
430
449
|
submitter: Address;
|
|
431
|
-
/** u64 unix
|
|
432
|
-
|
|
450
|
+
/** u64 unix MILLISECONDS (the round's gateway-assigned timestamp). */
|
|
451
|
+
timestamp: BN;
|
|
433
452
|
signaturesRequired: number;
|
|
434
453
|
signersBitmap: number[];
|
|
435
454
|
registryVersion: number;
|
|
@@ -443,7 +462,7 @@ interface SubmitAttestationArgs {
|
|
|
443
462
|
sourceId: number[];
|
|
444
463
|
registryVersion: number;
|
|
445
464
|
signaturesRequired: number;
|
|
446
|
-
|
|
465
|
+
timestamp: BN;
|
|
447
466
|
};
|
|
448
467
|
signature: {
|
|
449
468
|
aggSigS: number[];
|
|
@@ -709,8 +728,8 @@ interface AttestationMessageFields {
|
|
|
709
728
|
signersBitmap: string | Uint8Array;
|
|
710
729
|
/** 32-byte packed value (hex or bytes). */
|
|
711
730
|
value: string | Uint8Array;
|
|
712
|
-
/** Unix
|
|
713
|
-
|
|
731
|
+
/** Unix milliseconds (u64), assigned by the gateway. */
|
|
732
|
+
timestamp: number | bigint;
|
|
714
733
|
}
|
|
715
734
|
/** Compute the attestation message hash (32 bytes). */
|
|
716
735
|
declare function attestationMessageHash(fields: AttestationMessageFields): Uint8Array;
|
|
@@ -726,9 +745,17 @@ declare function normalizeSecp256k1PublicKeyHex(publicKeyHex: string, label?: st
|
|
|
726
745
|
declare function secp256k1PublicKeyFromCoordinates(x: Uint8Array, y: Uint8Array, label?: string): string;
|
|
727
746
|
|
|
728
747
|
/**
|
|
729
|
-
*
|
|
748
|
+
* Width in milliseconds of the window selection reads from the timestamp. The timestamp
|
|
749
|
+
* is unix milliseconds; the seed uses `floor(timestamp / SELECTION_WINDOW_MS)`, so
|
|
750
|
+
* sub-second precision never changes the committee. Changing it is a consensus break and must
|
|
751
|
+
* bump the selection prefix.
|
|
730
752
|
*/
|
|
731
|
-
declare
|
|
753
|
+
declare const SELECTION_WINDOW_MS = 1000n;
|
|
754
|
+
/**
|
|
755
|
+
* `seed = keccak256(keccak256("MOLPHA_SELECTION_V1") || sourceId || be32(rv) || be64(ts / 1000))`,
|
|
756
|
+
* where `ts` is the timestamp in unix MILLISECONDS (its 1 s window index is hashed).
|
|
757
|
+
*/
|
|
758
|
+
declare function deriveSelectionSeed(sourceId: Uint8Array, registryVersion: number, timestamp: number | bigint): Uint8Array;
|
|
732
759
|
/** `min(signaturesRequired + redundancyBuffer, nodeCount)`. */
|
|
733
760
|
declare function effectiveSelectionSize(signaturesRequired: number, redundancyBuffer: number, nodeCount: number): number;
|
|
734
761
|
/** Is bit `bit` set in the 32-byte big-endian `bitmap`? */
|
|
@@ -743,10 +770,24 @@ declare function selectedIndices(bitmap: Uint8Array, nodeCount: number): number[
|
|
|
743
770
|
declare function deriveGroupBitmap(seed: Uint8Array, nodeCount: number, groupSize: number): Uint8Array;
|
|
744
771
|
/**
|
|
745
772
|
* Convenience orchestrator: derive the selection bitmap end-to-end.
|
|
746
|
-
* `redundancy` defaults to 0; `ts`
|
|
773
|
+
* `redundancy` defaults to 0; `ts` is the timestamp in unix MILLISECONDS and defaults
|
|
774
|
+
* to now. The gateway assigns the real timestamp of a round, so this is for tests and tools.
|
|
747
775
|
*/
|
|
748
776
|
declare function deriveSelectionBitmap(sourceId: Uint8Array, registryVersion: number, nodeCount: number, signaturesRequired: number, redundancy?: number, ts?: number | bigint): Uint8Array;
|
|
749
777
|
|
|
778
|
+
/**
|
|
779
|
+
* `timestamp` is unix MILLISECONDS, assigned by the gateway. Chain clocks (Solana `Clock`,
|
|
780
|
+
* EVM `block.timestamp`), epoch windows and `maxAge`/staleness are measured in SECONDS, so
|
|
781
|
+
* anything that compares the two must go through {@link timestampSeconds}.
|
|
782
|
+
*/
|
|
783
|
+
/** `timestamp` (unix ms) as whole unix seconds, floored. */
|
|
784
|
+
declare function timestampSeconds(timestamp: number | bigint): number;
|
|
785
|
+
/**
|
|
786
|
+
* Age in whole seconds of a timestamp against `nowSeconds`, saturating at 0 so a
|
|
787
|
+
* timestamp slightly ahead of the local clock never goes negative.
|
|
788
|
+
*/
|
|
789
|
+
declare function timestampAgeSeconds(timestamp: number | bigint, nowSeconds: number): number;
|
|
790
|
+
|
|
750
791
|
/**
|
|
751
792
|
* Result codes returned by Molpha's stateless verifier contracts (`verify` on EVM and
|
|
752
793
|
* Starknet). Shared across VMs: the same attestation yields the same code on every chain.
|
|
@@ -761,11 +802,11 @@ declare const VERIFY_CODES: {
|
|
|
761
802
|
readonly FEED_WITNESS: 1;
|
|
762
803
|
/** The payload's `registryVersion` does not exist on this verifier. */
|
|
763
804
|
readonly BAD_REGISTRY_VERSION: 2;
|
|
764
|
-
/** Structurally invalid input, or a `
|
|
805
|
+
/** Structurally invalid input, or a `timestamp` in the future when `maxAge != 0`. */
|
|
765
806
|
readonly MALFORMED: 3;
|
|
766
|
-
/** `
|
|
807
|
+
/** `timestamp` predates the registry version's activation. */
|
|
767
808
|
readonly NOT_YET_ACTIVE: 4;
|
|
768
|
-
/** The registry version was superseded more than the grace window before `
|
|
809
|
+
/** The registry version was superseded more than the grace window before `timestamp`. */
|
|
769
810
|
readonly VERSION_EXPIRED: 5;
|
|
770
811
|
/** Reserved. Never returned. */
|
|
771
812
|
readonly COMPROMISED_QUORUM: 6;
|
|
@@ -823,7 +864,7 @@ declare const MOLPHA_VERIFIER_ABI: readonly [{
|
|
|
823
864
|
readonly type: "uint8";
|
|
824
865
|
readonly internalType: "uint8";
|
|
825
866
|
}, {
|
|
826
|
-
readonly name: "
|
|
867
|
+
readonly name: "timestamp";
|
|
827
868
|
readonly type: "uint64";
|
|
828
869
|
readonly internalType: "uint64";
|
|
829
870
|
}];
|
|
@@ -1071,8 +1112,8 @@ interface EvmAttestationPayload {
|
|
|
1071
1112
|
registryVersion: number;
|
|
1072
1113
|
/** `uint8`. */
|
|
1073
1114
|
signaturesRequired: number;
|
|
1074
|
-
/** `uint64`, unix seconds. */
|
|
1075
|
-
|
|
1115
|
+
/** `uint64`, unix MILLISECONDS (`timestamp / 1000` is the seconds the verifier's `maxAge` uses). */
|
|
1116
|
+
timestamp: bigint;
|
|
1076
1117
|
}
|
|
1077
1118
|
/** `IVerifier.SchnorrSignature`. */
|
|
1078
1119
|
interface EvmSchnorrSignature {
|
|
@@ -1136,7 +1177,7 @@ declare function buildEvmVerifierArgs(attestation: Attestation, options: BuildEv
|
|
|
1136
1177
|
* ABI calldata for `verify(attestation, maxAge)`: the 4-byte selector followed by nine
|
|
1137
1178
|
* 32-byte words. Both structs are static, so they encode inline with no offsets:
|
|
1138
1179
|
*
|
|
1139
|
-
* `value, sourceId, registryVersion, signaturesRequired,
|
|
1180
|
+
* `value, sourceId, registryVersion, signaturesRequired, timestamp, signature,
|
|
1140
1181
|
* commitment, signersBitmap, maxAge`
|
|
1141
1182
|
*
|
|
1142
1183
|
* For a raw `eth_call` (`{ to: verifier, data }`).
|
|
@@ -1182,8 +1223,8 @@ interface StarknetAttestationPayload {
|
|
|
1182
1223
|
registry_version: number;
|
|
1183
1224
|
/** `u8`. */
|
|
1184
1225
|
signatures_required: number;
|
|
1185
|
-
/** `u64`, unix seconds. */
|
|
1186
|
-
|
|
1226
|
+
/** `u64`, unix MILLISECONDS (`/ 1000` is the seconds the verifier's `max_age` uses). */
|
|
1227
|
+
timestamp: number;
|
|
1187
1228
|
}
|
|
1188
1229
|
/** Starknet calldata shape for `SchnorrSignature`. */
|
|
1189
1230
|
interface StarknetSchnorrSignature {
|
|
@@ -1243,7 +1284,7 @@ declare function buildStarknetVerifierArgs(attestation: Attestation, options: Bu
|
|
|
1243
1284
|
* Flat felt calldata for `verify(attestation, max_age)`, in Cairo `Serde` order — 13 felts:
|
|
1244
1285
|
*
|
|
1245
1286
|
* `value.low, value.high, source_id.low, source_id.high, registry_version,
|
|
1246
|
-
* signatures_required,
|
|
1287
|
+
* signatures_required, timestamp, signature.low, signature.high, commitment,
|
|
1247
1288
|
* signers_bitmap.low, signers_bitmap.high, max_age`
|
|
1248
1289
|
*
|
|
1249
1290
|
* For a raw `starknet_call` with `entry_point_selector = selector("verify")`.
|
|
@@ -1342,4 +1383,4 @@ declare class MolphaSDK {
|
|
|
1342
1383
|
}>;
|
|
1343
1384
|
}
|
|
1344
1385
|
|
|
1345
|
-
export { APIConfig, AggregationConfig, AggregationConfigError, AssetDomain, Attestation, type AttestationMessageFields, type BuildEvmVerifierArgsOptions, type BuildStarknetVerifierArgsOptions, type CoalitionKey, DEFAULT_GATEWAY_ENDPOINT, 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_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, 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 RoundContext, type Secp256k1KeyInput, Signer, SourcePaymentOptions, type StarknetAttestation, type StarknetAttestationPayload, type StarknetFeltLike, type StarknetSchnorrSignature, type StarknetVerifierArgs, type StarknetVerifyResult, type SubmitAttestationArgs, type SubmitAttestationOptions, 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, evmAddressFromPrivateKey, feedPda, formatInt256Decimal, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes, nodePda, normalizeEndpoint, normalizeSecp256k1PublicKeyHex, parseEvmVerifyResult, parseGatewayInfo, parseStarknetVerifyResult, parseUpstreamQuote, planIdFromVariant, planPda, planVariant, probeSource, protocolConfigPda, registryPda, registryStatePda, resolveRemainingAccounts, secp256k1PublicKeyFromCoordinates, selectedIndices, signSourcePayments, signersBitmapToDecimal, signersBitmapToStarknetUint256, signersBitmapToUint256, subscriptionPda, toChecksumAddress, toFixedBytes, toFixedHex, transferWithAuthorizationDigest, transferWithAuthorizationHash, u256beFromBigInt, u32be, u32le, u64be, u64le, u8, utf8, validateSuppliedTerms, verifyCodeName };
|
|
1386
|
+
export { APIConfig, AggregationConfig, AggregationConfigError, AssetDomain, Attestation, type AttestationMessageFields, type BuildEvmVerifierArgsOptions, type BuildStarknetVerifierArgsOptions, type CoalitionKey, DEFAULT_GATEWAY_ENDPOINT, 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_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, 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 RoundContext, SELECTION_WINDOW_MS, type Secp256k1KeyInput, Signer, SourcePaymentOptions, type StarknetAttestation, type StarknetAttestationPayload, type StarknetFeltLike, type StarknetSchnorrSignature, type StarknetVerifierArgs, type StarknetVerifyResult, type SubmitAttestationArgs, type SubmitAttestationOptions, 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, evmAddressFromPrivateKey, feedPda, formatInt256Decimal, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes, msUntilNextTick, nodePda, normalizeEndpoint, normalizeSecp256k1PublicKeyHex, parseEvmVerifyResult, parseGatewayInfo, parseStarknetVerifyResult, parseUpstreamQuote, planIdFromVariant, planPda, planVariant, probeSource, protocolConfigPda, registryPda, registryStatePda, resolveRemainingAccounts, secp256k1PublicKeyFromCoordinates, selectedIndices, signSourcePayments, signersBitmapToDecimal, signersBitmapToStarknetUint256, signersBitmapToUint256, subscriptionPda, timestampAgeSeconds, timestampSeconds, toChecksumAddress, toFixedBytes, toFixedHex, transferWithAuthorizationDigest, transferWithAuthorizationHash, u256beFromBigInt, u32be, u32le, u64be, u64le, u8, utf8, validateSuppliedTerms, verifyCodeName };
|