@ninsei-labs/sdk 0.53.0 → 0.55.0

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.
@@ -99,6 +99,43 @@ export function toWei(human, decimals = 18) {
99
99
  return BigInt(intPart || "0") * 10n ** BigInt(decimals) + BigInt(frac || "0");
100
100
  }
101
101
 
102
+ // THE ONE NATIVE AMOUNT OF A TOKEN-FUNDED ORDER.
103
+ //
104
+ // The escrow holds the network's NATIVE coin; a quote paid in USDC/USDT carries a different number in the token.
105
+ // The native figure is the quote's own `payNative`, in the network's native decimals. A quote without that figure
106
+ // is a NAMED refusal, never a fallback to the payment amount: rescaling the payment amount is a known wrong answer
107
+ // (10^12 on a 6-decimal token), not a smaller error. This is the rule both the intent target and the escrow order
108
+ // read, so the two cannot diverge.
109
+ export function escrowNativeWei({ quote = null, nativeDecimals = 18 } = {}) {
110
+ const raw = quote ? quote.payNative : null;
111
+ if (raw === null || raw === undefined || raw === "") {
112
+ return { ok: false, code: "native-amount-unread", reason: "the quote carries no native amount" };
113
+ }
114
+ const n = Number(raw);
115
+ if (!Number.isFinite(n) || n <= 0) {
116
+ return { ok: false, code: "native-amount-unread", reason: "the quote's native amount is not a positive number" };
117
+ }
118
+ const dec = Number(nativeDecimals);
119
+ if (!Number.isInteger(dec) || dec < 0) {
120
+ return { ok: false, code: "native-amount-unread", reason: "the native decimals are not a whole number" };
121
+ }
122
+ // THE QUOTE'S OWN DIGITS, NOT A RE-ROUNDED COPY. An exponent form falls back to toFixed(18), as the rest of the
123
+ // page does; everything else keeps exactly the digits it was typed with.
124
+ const text = /e/i.test(String(raw)) ? n.toFixed(18) : String(raw);
125
+ // DECIMAL DIGITS ONLY. BigInt accepts "0x10", and a native amount read as a hex literal would silently become
126
+ // sixteen times the token amount; a quote carries decimal text.
127
+ if (!/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(text)) {
128
+ return { ok: false, code: "native-amount-unread", reason: "the native amount is not a decimal number" };
129
+ }
130
+ let wei;
131
+ try { wei = toWei(text, dec); }
132
+ catch { return { ok: false, code: "native-amount-unread", reason: "the native amount is not a decimal number" }; }
133
+ if (wei <= 0n) {
134
+ return { ok: false, code: "native-amount-unread", reason: "the native amount rounds to zero wei" };
135
+ }
136
+ return { ok: true, wei: wei.toString(), source: "native" };
137
+ }
138
+
102
139
  // WE SET THE GAS OURSELVES, WITH A MARGIN - A CURE FOR A REAL BUG, NOT CAUTION.
103
140
  // createOrderAndFund goes as ONE transaction, but the wallet estimates it at an address where the escrow does NOT
104
141
  // exist yet: instead of cloning and recording the deposit it counts a plain transfer (21000 plus data). The wallet
package/index.d.ts CHANGED
@@ -454,6 +454,11 @@ export interface QuotesApi {
454
454
  snapshot(): QuoteSnapshot | null;
455
455
  /** A binding quote with a TTL. A refusal comes as a code, not text. */
456
456
  firm(offer: FirmOffer): Promise<Quote>;
457
+ /**
458
+ * A firm quote through a relay, built from one recovery key. The relay answer is verified against the
459
+ * requested terms and the on-chain registry/factory binding before it is returned.
460
+ */
461
+ firmRelay(request: FirmRelayOffer): Promise<FirmRelayAnswer>;
457
462
  /**
458
463
  * A reverse-mode ticket: the maker sells XMR. The request is the node's `request` object; the answer carries the
459
464
  * signed order quote and its claim tip, which is checked against the gas price before it is returned.
@@ -660,11 +665,60 @@ export interface QuoteReference {
660
665
  }
661
666
 
662
667
  export interface FirmOffer {
663
- readonly direction: "buy" | "sell";
664
- readonly token: string;
665
- readonly amount: number;
666
- readonly receiveTo: string;
667
- readonly providerId?: string;
668
+ /** Who gives the quote. Without it there is no one to ask. */
669
+ readonly providerId: string;
670
+ /** The order terms the signature is bound to. */
671
+ readonly order: Readonly<Record<string, unknown>>;
672
+ /** The taker's maker view half when the order was built from a recovery key. */
673
+ readonly viewHalfClaimer?: string;
674
+ }
675
+
676
+ export interface FirmRelayOffer {
677
+ /** Relay origin, without the `/v1/quote` path. */
678
+ readonly relayUrl: string;
679
+ /** The signed public features the relay forwarded; they are verified before anything is sent. */
680
+ readonly features: Readonly<Record<string, unknown>>;
681
+ readonly order: Readonly<Record<string, unknown>>;
682
+ readonly side: "ask" | "bid";
683
+ /** The twelve-word recovery key or an object carrying it. */
684
+ readonly recoveryKey: string | { readonly mnemonic: string };
685
+ /** A fresh salt the client owns; it must equal `order.salt`. Defaults to `order.salt`. */
686
+ readonly recoverySalt?: string;
687
+ /** The v1 index; it is mutually exclusive with `recoverySalt`. */
688
+ readonly recoveryIndex?: number;
689
+ /** The market's chain and asset, for example `421614:ETH`. Derived when exactly one window matches. */
690
+ readonly market?: string;
691
+ readonly xmrNetwork?: string;
692
+ readonly xmrAmount: string | number;
693
+ readonly claimTip?: string | number;
694
+ readonly partner?: string;
695
+ readonly fetchImpl?: typeof fetch;
696
+ readonly timeoutMs?: number;
697
+ }
698
+
699
+ export interface FirmRelayAnswer {
700
+ readonly quote: Readonly<Record<string, unknown>>;
701
+ readonly orderQuote: Readonly<Record<string, unknown>>;
702
+ /** The exact order terms the quote is bound to. */
703
+ readonly order: Readonly<Record<string, unknown>>;
704
+ readonly nodeHalf: Readonly<Record<string, unknown>>;
705
+ /** Ready to pass as `swaps.start({ counterparty })`: proof, claimer commitment and maker view half. */
706
+ readonly counterparty: Readonly<Record<string, unknown>>;
707
+ readonly edViewPointLocker: string;
708
+ readonly edViewPointClaimer: string;
709
+ readonly context: string;
710
+ readonly viewHalfClaimer: string;
711
+ readonly viewHalfPoint: string;
712
+ /** The one-time Monero address assembled from the recovery key and the answer's points. */
713
+ readonly jointAddress: string;
714
+ /** The escrow address predicted from the signed quote and the depositor's half. */
715
+ readonly escrow: string;
716
+ readonly recovery: { readonly kind: "salt-v2"; readonly salt: string }
717
+ | { readonly kind: "index-v1"; readonly index: number };
718
+ readonly relay: string | null;
719
+ readonly offered: number | null;
720
+ readonly forwarded: Readonly<Record<string, unknown>> | null;
721
+ readonly answer: Readonly<Record<string, unknown>>;
668
722
  }
669
723
 
670
724
  /**
@@ -758,6 +812,13 @@ export interface SwapsApi {
758
812
  * the swap with if the browser is lost.
759
813
  */
760
814
  start(request: StartRequest): Promise<SwapStart>;
815
+ /**
816
+ * START A SELL from a verified relay offer. It records the one-time address, the escrow, our half and the
817
+ * order expectations; it sends nothing. The same offer retried yields the same record (`resumed: true`).
818
+ */
819
+ startSell(request: SellStartRequest): Promise<SellStart>;
820
+ /** CLAIM THE ETH on a sell from the record: the half and the expectations are the ones stored by `startSell`. */
821
+ sellClaim(request: SellClaimRequest, wallet: WalletAdapter): Promise<unknown>;
761
822
  /**
762
823
  * WAIT FOR THE XMR TO ARRIVE at the order's joint address. The polling uses the same request as the page's
763
824
  * (GET /swaps/{id}), the rate and the timeout - from `config.limits` and overridable here.
@@ -774,6 +835,12 @@ export interface SwapsApi {
774
835
  * signed, and the decline is written into the record, so every later read of the swap reports the same state.
775
836
  */
776
837
  watch(request: SwapWatchRequest): Promise<SwapWatch | SwapDeclinedWatch>;
838
+ /**
839
+ * WAIT FOR THE NODE'S SIDE ON A SELL. The escrow is the one predicted by `quotes.firmRelay`; the client sends
840
+ * XMR to the joint address, and this reads the escrow itself until the locker marks it ready, claims it or
841
+ * refunds it. No backend watcher is involved. A wait that expires is `sell-timeout`.
842
+ */
843
+ sellWatch(request: SellWatchRequest): Promise<SellWatchResult>;
777
844
  /**
778
845
  * THE XMR ARRIVAL CHECK WITHOUT THE WATCH LOOP (issue #85). The client reads the chain itself with its own view
779
846
  * key and `ready` opens only when at least two nodes of DIFFERENT operators see the transaction IN THE SAME BLOCK
@@ -1021,6 +1088,53 @@ export interface SwapStart {
1021
1088
  readonly next: "watch";
1022
1089
  }
1023
1090
 
1091
+ export interface SellStartRequest {
1092
+ /** The verified `quotes.firmRelay` answer for the bid side. */
1093
+ readonly offer: FirmRelayAnswer;
1094
+ /** The twelve-word key; required only when no key is stored yet. */
1095
+ readonly recoveryKey?: string | { readonly mnemonic: string };
1096
+ }
1097
+
1098
+ export interface SellStart {
1099
+ readonly id: string;
1100
+ readonly side: "sell";
1101
+ readonly escrow: string;
1102
+ /** The one-time Monero address the client sends XMR to. */
1103
+ readonly address: string;
1104
+ readonly xmrAmount: string;
1105
+ readonly claimTip: string | null;
1106
+ readonly orderQuote: Readonly<Record<string, unknown>> | null;
1107
+ readonly resumed: boolean;
1108
+ readonly next: "send-xmr";
1109
+ }
1110
+
1111
+ export interface SellClaimRequest {
1112
+ readonly id: string;
1113
+ readonly escrow?: string;
1114
+ readonly halfClaimer?: string;
1115
+ readonly expect?: Readonly<Record<string, unknown>>;
1116
+ readonly onStep?: (step: unknown) => void;
1117
+ }
1118
+
1119
+ export interface SellWatchRequest {
1120
+ /** The escrow predicted by the relay adapter. */
1121
+ readonly escrow: string;
1122
+ readonly timeoutMs?: number;
1123
+ readonly pollMs?: number;
1124
+ }
1125
+
1126
+ export interface SellWatchResult {
1127
+ readonly escrow: string;
1128
+ readonly state: "ready" | "claimed" | "refunded";
1129
+ readonly funded: boolean;
1130
+ readonly claimed: boolean;
1131
+ readonly refunded: boolean;
1132
+ /** `null` for a terminal claim/refund: the ready mark is not part of that answer. */
1133
+ readonly ready: boolean | null;
1134
+ readonly balanceWei: string;
1135
+ readonly waitedMs: number;
1136
+ }
1137
+
1024
1138
  export interface SwapWatchRequest {
1025
1139
  /** The watch record's identifier at the service (from SwapStart.watch.id). */
1026
1140
  readonly id: string;
@@ -1585,7 +1699,11 @@ export interface SweepRunResult {
1585
1699
 
1586
1700
  // --- Recovery// --- Recovery ------------------------------------------------------------------------------
1587
1701
 
1588
- /** Order checks. Both are BEFORE the signature: after it there is nothing to fix. */
1702
+ /** Order checks and pure order helpers. Checks are BEFORE the signature: after it there is nothing to fix. */
1703
+ export type EscrowNativeAmount =
1704
+ | { readonly ok: true; readonly wei: string; readonly source: "native" }
1705
+ | { readonly ok: false; readonly code: "native-amount-unread"; readonly reason: string };
1706
+
1589
1707
  export interface OrderApi {
1590
1708
  /** The order context string the proof and the quote signature are bound to. */
1591
1709
  context(terms: Readonly<Record<string, unknown>>): string;
@@ -1593,6 +1711,13 @@ export interface OrderApi {
1593
1711
  verifyCounterparty(request: { readonly side: unknown; readonly order: Readonly<Record<string, unknown>>; readonly sealed?: unknown; readonly ownEncPriv?: unknown }): unknown;
1594
1712
  /** The joint Monero address from your own spend half and the other's point. */
1595
1713
  jointAddress(request: { readonly ownSpendHalf: string; readonly ownViewHalf: string; readonly otherSpendPoint: string; readonly otherViewPoint: string; readonly network?: string }): unknown;
1714
+ /**
1715
+ * The ONE native amount of a token-funded order: the quote's `payNative` in the network's native decimals.
1716
+ * The escrow holds native coin, so the token amount is never used as the escrow amount (a 6-decimal token
1717
+ * would be off by 10^12). A quote without a native figure answers `{ ok: false, code: "native-amount-unread" }`;
1718
+ * it is never replaced by the payment amount.
1719
+ */
1720
+ escrowNativeWei(request?: { readonly quote?: Readonly<Record<string, unknown>> | null; readonly nativeDecimals?: number }): EscrowNativeAmount;
1596
1721
  /**
1597
1722
  * The order state, READ FROM THE CHAIN (escrow status()): which of the four states the order is in. The state is
1598
1723
  * read by a call, not guessed from logs. It is read by the same chain-read seam as the actions (`evmCall`), so
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ninsei-labs/sdk",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -41,11 +41,23 @@
41
41
  "check:sale-auth": "node tools/check-sale-auth.mjs",
42
42
  "check:backup-confirmation": "node tools/check-backup-confirmation.mjs",
43
43
  "check:key-view": "node tools/check-key-view.mjs",
44
+ "check:relay-view": "node tools/check-relay-view.mjs",
45
+ "check:relay-terms": "node tools/check-relay-terms.mjs",
46
+ "check:relay-features": "node tools/check-relay-features.mjs",
47
+ "check:relay-request": "node tools/check-relay-request.mjs",
48
+ "check:relay-answer": "node tools/check-relay-answer.mjs",
49
+ "check:relay-http": "node tools/check-relay-http.mjs",
50
+ "check:relay-adapter": "node tools/check-relay-adapter.mjs",
51
+ "check:sell-watch": "node tools/check-sell-watch.mjs",
52
+ "check:sell-start": "node tools/check-sell-start.mjs",
44
53
  "check:arrival-consensus": "node tools/check-arrival-consensus.mjs",
45
54
  "check:arrival-real": "node tools/check-arrival-real.mjs",
46
55
  "check:order-proof": "node tools/check-order-proof.mjs",
47
56
  "check:daemon-address": "node tools/check-daemon-address.mjs",
48
57
  "check:ci-scripts": "node tools/check-ci-scripts.mjs",
58
+ "check:licenses": "node tools/check-licenses.mjs",
59
+ "notices": "node tools/third-party-notices.mjs",
60
+ "check:notices": "node tools/third-party-notices.mjs --check",
49
61
  "check:factory-selectors": "node tools/check-factory-selectors.mjs",
50
62
  "check:fee-estimate": "node tools/check-fee-estimate.mjs",
51
63
  "check:deadline-scale": "node tools/check-deadline-scale.mjs",
@@ -61,7 +73,8 @@
61
73
  "check:packed-consumer": "node tools/check-packed-consumer.mjs",
62
74
  "check:quote-binding": "node tools/check-quote-binding.mjs",
63
75
  "check:types-consumer": "node node_modules/typescript/bin/tsc -p tools/ts-consumer/tsconfig.json",
64
- "check:monero-live": "node tools/check-monero-live.mjs"
76
+ "check:monero-live": "node tools/check-monero-live.mjs",
77
+ "check:native-amount": "node tools/check-native-amount.mjs"
65
78
  },
66
79
  "types": "./index.d.ts",
67
80
  "exports": {
@@ -100,6 +113,10 @@
100
113
  "./provider": {
101
114
  "types": "./src/public/provider.d.ts",
102
115
  "default": "./src/public/provider.mjs"
116
+ },
117
+ "./relay": {
118
+ "types": "./src/public/relay.d.ts",
119
+ "default": "./src/public/relay.mjs"
103
120
  }
104
121
  },
105
122
  "files": [
@@ -109,7 +126,9 @@
109
126
  "index.d.ts",
110
127
  "README.md",
111
128
  "CHANGELOG.md",
112
- "LICENSE"
129
+ "LICENSE",
130
+ "LICENSE-POLICY.md",
131
+ "THIRD_PARTY_NOTICES.md"
113
132
  ],
114
133
  "engines": {
115
134
  "node": ">=24.22.1"
@@ -138,6 +157,9 @@
138
157
  "url": "https://github.com/Ninsei-Labs/sdk/issues"
139
158
  },
140
159
  "dependencies": {
160
+ "@hpke/chacha20poly1305": "1.8.0",
161
+ "@hpke/core": "1.9.0",
162
+ "@hpke/dhkem-x25519": "1.8.0",
141
163
  "@noble/curves": "^2.4.0",
142
164
  "@noble/hashes": "^2.4.0",
143
165
  "@scure/bip39": "2.4.0",
package/src/index.mjs CHANGED
@@ -249,6 +249,10 @@ export function createNinsei(options) {
249
249
  context: (terms) => contextOf(terms),
250
250
  verifyCounterparty: (request) => verifyCounterparty(request),
251
251
  jointAddress: (request) => jointAddress(request),
252
+ // THE ONE NATIVE AMOUNT OF A TOKEN-FUNDED ORDER. The escrow holds native coin, while a stablecoin quote
253
+ // carries a different number in the token; this reads the quote's native figure. A quote without it is a
254
+ // named refusal (`native-amount-unread`), never a rescale of the payment amount.
255
+ escrowNativeWei: (request) => engine.evm.escrowNativeWei(request),
252
256
  // ORDER STATE FROM THE CHAIN (escrow slot 3): which of the four states the order is in. Read, not guessed
253
257
  // from logs - the very call the engine used to make from www/js/core/swap-flow.js.
254
258
  status: (escrow) => orderFlow.orderStatus(escrow, orderDeps),
@@ -270,6 +274,8 @@ export function createNinsei(options) {
270
274
  // A firm quote is stage 2: it is signed with a key and lives in the order protocol, not in a market snapshot.
271
275
  // A FIRM QUOTE: accepted only with a confirmed provider signature.
272
276
  firm: (request) => quotes.firm(request),
277
+ // THE RELAY PATH: one recovery key in, signed orderQuote and its maker view half out.
278
+ firmRelay: (request) => quotes.firmRelay(request),
273
279
  // A REVERSE TICKET: the node signs it; its claim tip is checked here before the caller sees it.
274
280
  sale: (request) => quotes.sale(request),
275
281
  },
@@ -269,6 +269,8 @@ export declare function recoveryFileName(swapId?: string | null): string;
269
269
  export declare const RECOVERY_KEY_VERSION: number;
270
270
  /** Twelve words, by the BIP39 rules. */
271
271
  export declare const RECOVERY_KEY_WORDS: number;
272
+ /** The default number of v1 indices one `findSwaps` call scans. */
273
+ export declare const RECOVERY_SCAN_DEFAULT: number;
272
274
  /** The store key a browser adapter keeps the key under. */
273
275
  export declare const RECOVERY_KEY_STORE: string;
274
276
  /** The first line of a plain backup file. */
@@ -431,8 +433,15 @@ export declare function findSwaps(request: {
431
433
  toBlock?: number | string;
432
434
  /** Deprecated and ignored: discovery no longer stops after a run of empty numbers. */
433
435
  gap?: number;
434
- /** The last index to try. Defaults to the allocator's ceiling; a smaller value returns `complete: false`. */
436
+ /** The first index to try. Defaults to 0; a continuation passes the previous `nextIndex`. */
437
+ fromIndex?: number;
438
+ /** How many indices this call may try. Defaults to `RECOVERY_SCAN_DEFAULT` (1000), not the allocator ceiling. */
435
439
  maxIndex?: number;
440
+ /** Stop the scan between chunks. An aborted scan returns `complete: false`, `incompleteReason: "aborted"` and
441
+ * the `nextIndex` to resume from. */
442
+ signal?: { readonly aborted: boolean } | null;
443
+ /** Called after every chunk and after the last index, with the count and the index just scanned. */
444
+ onProgress?: ((value: { readonly scanned: number; readonly index: number }) => void) | null;
436
445
  /** Reads the settlement block timestamp, in seconds: (blockNumber) -> seconds. */
437
446
  evmBlockTime?: (blockNumber: number) => Promise<number>;
438
447
  /** Reads contract code: (address) -> 0x-hex. Used to read the XMR amount from an order clone. */
@@ -453,8 +462,10 @@ export declare function findSwaps(request: {
453
462
  scanned: number;
454
463
  /** The last index tried, or null when no index was scanned. */
455
464
  searchedUpTo: number | null;
456
- /** True only when the whole allocator range was searched. */
465
+ /** True when every order in the logs was matched, or when the allocator range was searched to its end. */
457
466
  complete: boolean;
458
- /** `max-index` when a smaller caller-supplied bound stopped the search. */
467
+ /** `max-index` or `aborted` when a bound or the caller stopped the search before every order was matched. */
459
468
  incompleteReason?: string;
469
+ /** The next index to pass as `fromIndex`; absent when the search is complete. */
470
+ nextIndex?: number;
460
471
  }>;
@@ -33,6 +33,7 @@ export {
33
33
  RECOVERY_KEY_VERSION,
34
34
  MAKER_VIEW_HALF_DOMAIN,
35
35
  RECOVERY_KEY_WORDS,
36
+ RECOVERY_SCAN_DEFAULT,
36
37
  commitRecoveryIndex,
37
38
  createRecoveryKey,
38
39
  createRecoveryKeyFile,
@@ -0,0 +1,77 @@
1
+ export declare const RELAY_FEATURES_TYPE_NAME: "NodeFeatures";
2
+ export declare const RELAY_DOMAIN_NAME: "Ninsei Relay";
3
+ export declare const RELAY_DOMAIN_VERSION: "1";
4
+ export declare const FIRM_WINDOW_TYPE: string;
5
+ export declare const NODE_FEATURES_TYPE: string;
6
+ export declare const FIRM_WINDOW_FIELDS: ReadonlyArray<readonly [string, string]>;
7
+ export declare const NODE_FEATURES_FIELDS: ReadonlyArray<readonly [string, string]>;
8
+
9
+ export interface RelayFirmWindow {
10
+ market: string;
11
+ side: "ask" | "bid";
12
+ xmrNetwork: string;
13
+ readyMinSeconds: number;
14
+ readyMaxSeconds: number;
15
+ settlementMinSeconds: number;
16
+ settlementMaxSeconds: number;
17
+ quoteTtlSeconds: number;
18
+ }
19
+
20
+ export interface RelayNodeFeatures {
21
+ type: "node_features";
22
+ version: 1;
23
+ relayId: string;
24
+ provider: string;
25
+ quoteKey: string;
26
+ registry: string;
27
+ capabilities: string[];
28
+ hpkeKey: string;
29
+ firmWindows: RelayFirmWindow[];
30
+ time: number;
31
+ nonce: string;
32
+ signature: string;
33
+ }
34
+
35
+ export interface RelayVerifyTerms {
36
+ market: string;
37
+ side: "ask" | "bid";
38
+ maker: string;
39
+ registry: string;
40
+ xmrNetwork: string;
41
+ }
42
+
43
+ export declare function nodeFeaturesStructHash(features: RelayNodeFeatures): Uint8Array;
44
+ export declare function nodeFeaturesDomainSeparator(): Uint8Array;
45
+ export declare function nodeFeaturesDigest(features: RelayNodeFeatures): Uint8Array;
46
+ export declare function verifyNodeFeatures(input: { features: RelayNodeFeatures; terms?: RelayVerifyTerms | null }): {
47
+ featuresHash: string;
48
+ hpkeKey: string;
49
+ window: RelayFirmWindow | null;
50
+ };
51
+ export declare function nodeFeaturesMissingFields(features: Partial<RelayNodeFeatures>): string[];
52
+
53
+ export declare function firmTermsDigest(input: { crypto: { keccak256(bytes: Uint8Array): Uint8Array }; terms: Record<string, unknown> }): Uint8Array;
54
+ export declare function firmTermsMissingFields(terms: Record<string, unknown>): string[];
55
+
56
+ export declare const RELAY_VIEW_INFO_PREFIX: string;
57
+ export declare function relayViewInfo(input: {
58
+ termsDigest: string;
59
+ commitHalf: string;
60
+ edPoint: string;
61
+ edViewPointClient: string;
62
+ edViewPointNode: string;
63
+ }): Uint8Array;
64
+ export declare function sealViewEnvelope(input: { hpkeKey: string; info: Uint8Array; plaintext: Uint8Array }): Promise<{ enc: string; ciphertext: string }>;
65
+ export declare function openViewEnvelope(input: { privateKey: string; enc: string; ciphertext: string; info: Uint8Array }): Promise<Uint8Array>;
66
+
67
+ export declare const RELAY_QUOTE_TYPE: string;
68
+ export declare function relayQuoteStructHash(answer: Record<string, unknown>): Uint8Array;
69
+ export declare function relayQuoteDomainSeparator(): Uint8Array;
70
+ export declare function relayQuoteDigest(answer: Record<string, unknown>): Uint8Array;
71
+ export declare function verifyRelayQuoteFrame(answer: Record<string, unknown>, quoteKey: string): Record<string, unknown>;
72
+ export declare function verifyFirmAnswer(input: {
73
+ answer: Record<string, unknown>;
74
+ features: RelayNodeFeatures;
75
+ request: { terms: Record<string, unknown>; edViewPointClient: string; edViewPointNode: string };
76
+ now?: number | null;
77
+ }): Record<string, unknown>;
@@ -0,0 +1,37 @@
1
+ // THE RELAY EXCHANGE FOR A NODE THAT EMBEDS THE SDK.
2
+ //
3
+ // A maker needs the other half of the same rules a client uses: the public features digest it signs, the terms
4
+ // digest, the HPKE view envelope it opens, and the answer verifier. Names only; no second implementation.
5
+
6
+ export {
7
+ RELAY_FEATURES_TYPE_NAME,
8
+ RELAY_DOMAIN_NAME,
9
+ RELAY_DOMAIN_VERSION,
10
+ FIRM_WINDOW_TYPE,
11
+ NODE_FEATURES_TYPE,
12
+ FIRM_WINDOW_FIELDS,
13
+ NODE_FEATURES_FIELDS,
14
+ nodeFeaturesStructHash,
15
+ nodeFeaturesDomainSeparator,
16
+ nodeFeaturesDigest,
17
+ verifyNodeFeatures,
18
+ nodeFeaturesMissingFields,
19
+ } from "../relayFeatures.mjs";
20
+
21
+ export { firmTermsDigest, firmTermsMissingFields } from "../relayTerms.mjs";
22
+
23
+ export {
24
+ RELAY_VIEW_INFO_PREFIX,
25
+ relayViewInfo,
26
+ sealViewEnvelope,
27
+ openViewEnvelope,
28
+ } from "../relayView.mjs";
29
+
30
+ export {
31
+ RELAY_QUOTE_TYPE,
32
+ relayQuoteStructHash,
33
+ relayQuoteDomainSeparator,
34
+ relayQuoteDigest,
35
+ verifyRelayQuoteFrame,
36
+ verifyFirmAnswer,
37
+ } from "../relayQuote.mjs";