@orbinum/sdk 2.1.0 → 3.0.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.
- package/README.md +15 -18
- package/dist/adapters/indexeddb/index.d.mts +10 -10
- package/dist/adapters/indexeddb/index.d.ts +10 -10
- package/dist/{chunk-VYKKBXOE.mjs → chunk-54HFH63J.mjs} +493 -256
- package/dist/{index-CLpM1984.d.mts → index-B-dbSIPN.d.mts} +209 -52
- package/dist/{index-CLpM1984.d.ts → index-B-dbSIPN.d.ts} +209 -52
- package/dist/index.d.mts +904 -485
- package/dist/index.d.ts +904 -485
- package/dist/index.js +958 -501
- package/dist/index.mjs +540 -302
- package/dist/{secretStore-CF6Nse__.d.ts → secretStore-CCYo4hna.d.mts} +15 -11
- package/dist/{secretStore-CF6Nse__.d.mts → secretStore-CCYo4hna.d.ts} +15 -11
- package/dist/wallet/worker/index.d.mts +1 -1
- package/dist/wallet/worker/index.d.ts +1 -1
- package/dist/wallet/worker/index.js +428 -111
- package/dist/wallet/worker/index.mjs +3 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Z as ZkNote, D as DecryptedMemo, N as NoteInput, S as ScanCommitment, a as NoteFacts,
|
|
2
|
-
export { C as CURRENT_CIRCUIT_VERSION,
|
|
1
|
+
import { Z as ZkNote, D as DecryptedMemo, N as NoteInput, S as ScanCommitment, a as NoteFacts, b as SentNoteMatch, c as DecryptPool, d as ScanKeys, U as UnmatchedSentHint } from './index-B-dbSIPN.js';
|
|
2
|
+
export { C as CURRENT_CIRCUIT_VERSION, e as DECRYPT_YIELD_EVERY, f as DecryptBatchResult, g as DecryptRequest, E as EMPTY_BATCH_RESULT, K as KnownEphEntry, h as KnownEphWindow, M as MAX_WORKERS, i as MerkleTreeInfo, O as OUTGOING_EPH_WINDOW, P as PAIRWISE_EPH_WINDOW, j as SELF_EPH_WINDOW, k as SentNoteFacts, W as WORKER_CRASHED, l as WorkerFactory, m as WorkerLike, n as WorkerMessage, o as clearKnownEphWindow, p as createDecryptPool, q as createMainThreadPool, r as createWorkerPool, s as decryptHintBatch, t as getKnownEphWindow, u as recoverSentFromSharedSecret, v as recoverSentNote } from './index-B-dbSIPN.js';
|
|
3
3
|
import { ArtifactProvider, ProofResult, CircuitType } from '@orbinum/proof-generator';
|
|
4
4
|
export { ArtifactProvider, CircuitType, ProofResult, WebArtifactProvider, shouldProveSingleThreaded } from '@orbinum/proof-generator';
|
|
5
5
|
import * as polkadot_api from 'polkadot-api';
|
|
@@ -12,8 +12,8 @@ export { base58 } from '@scure/base';
|
|
|
12
12
|
export { getPolkadotSigner as getSubstrateSigner } from 'polkadot-api/signer';
|
|
13
13
|
import { InjectedExtension } from 'polkadot-api/pjs-signer';
|
|
14
14
|
export { SignPayload, SignRaw, getPolkadotSignerFromPjs as getSubstrateSignerFromExtension } from 'polkadot-api/pjs-signer';
|
|
15
|
-
import { V as VaultStorage, a as VaultConfigRecord, E as EncryptedNoteRecord, C as CachedNullifier, N as NullifierSyncMeta, S as SpendDetails, b as EncryptedTxRecord, d as NoteStorage, e as NoteStatusUpdate, T as TxHistoryStore, f as NullifierCache, c as SecretStore } from './secretStore-
|
|
16
|
-
export { D as DeviceKeyStore, g as createDeviceKeyProvider, h as createMemorySecretStore, i as generateDeviceKey, j as importDeviceKey } from './secretStore-
|
|
15
|
+
import { V as VaultStorage, a as VaultConfigRecord, E as EncryptedNoteRecord, C as CachedNullifier, N as NullifierSyncMeta, S as SpendDetails, b as EncryptedTxRecord, d as NoteStorage, e as NoteStatusUpdate, T as TxHistoryStore, f as NullifierCache, c as SecretStore } from './secretStore-CCYo4hna.js';
|
|
16
|
+
export { D as DeviceKeyStore, g as createDeviceKeyProvider, h as createMemorySecretStore, i as generateDeviceKey, j as importDeviceKey } from './secretStore-CCYo4hna.js';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* The two keys a vault runs on, and the AES-GCM envelope they protect.
|
|
@@ -210,7 +210,7 @@ declare const VAULT_SCHEMA_VERSION = 5;
|
|
|
210
210
|
*/
|
|
211
211
|
declare function normalizeChainFingerprint(chainFingerprint?: string | null): string | undefined;
|
|
212
212
|
/** The counters a config write must never drop. */
|
|
213
|
-
type EphemeralCounters = Pick<VaultConfigRecord, 'createdAt' | 'selfEphCounter' | 'pairwiseCounterparties'>;
|
|
213
|
+
type EphemeralCounters = Pick<VaultConfigRecord, 'createdAt' | 'selfEphCounter' | 'outgoingEphCounter' | 'pairwiseCounterparties'>;
|
|
214
214
|
/**
|
|
215
215
|
* Builds a config record ready to persist.
|
|
216
216
|
*
|
|
@@ -250,31 +250,43 @@ declare function buildConfig(existing: EphemeralCounters | null, chainFingerprin
|
|
|
250
250
|
*/
|
|
251
251
|
declare function reserveSelfEphIndex(storage: NoteStorage): Promise<number>;
|
|
252
252
|
/**
|
|
253
|
-
* Reserves the next
|
|
254
|
-
*
|
|
255
|
-
* having: it makes the REVERSE direction cheap too, since their future payments
|
|
256
|
-
* to this wallet become hash lookups instead of one trial ECDH per note.
|
|
253
|
+
* Reserves the next OUTGOING index — the ephemeral published on a note this
|
|
254
|
+
* wallet sends.
|
|
257
255
|
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
256
|
+
* "No history" is unambiguous here, unlike the pairwise counter: a sender can
|
|
257
|
+
* predict every ephPk they published, so a restored wallet recovers the counter
|
|
258
|
+
* by sweeping the chain. That is why this may start at 0 instead of degrading
|
|
259
|
+
* to a random ephemeral.
|
|
261
260
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
261
|
+
* THE COUNTER ONLY MOVES FORWARD. `fromChain` comes from a feed, and a feed
|
|
262
|
+
* that HID the highest published index would report a counter already used —
|
|
263
|
+
* handing it out again republishes that ephPk and links the two notes in
|
|
264
|
+
* public. So it is a floor, never the truth: a stored counter always wins.
|
|
266
265
|
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* — the caller degrades to random, costing the recipient one trial scan, and
|
|
272
|
-
* every later payment to the same counterparty takes the fast path again.
|
|
266
|
+
* The restore itself is the one exposure, having no stored counter to defend
|
|
267
|
+
* with. `RESTORE_SAFETY_GAP` covers it by resuming past a run of unused
|
|
268
|
+
* indexes, so hiding one top index is not enough — a feed would have to hide
|
|
269
|
+
* the whole run. Skipped indexes are free and only widen a window.
|
|
273
270
|
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
271
|
+
* @param fromChain Next index per `reconstructOutgoingIndex`, or undefined on
|
|
272
|
+
* the normal path where the stored counter stands alone.
|
|
276
273
|
*/
|
|
277
|
-
declare function
|
|
274
|
+
declare function reserveOutgoingIndex(storage: NoteStorage, fromChain?: number): Promise<number>;
|
|
275
|
+
/**
|
|
276
|
+
* Records a counterparty this wallet has paid, keyed by their packed viewing
|
|
277
|
+
* public key.
|
|
278
|
+
*
|
|
279
|
+
* Purely an optimisation for the REVERSE direction: once they are known, their
|
|
280
|
+
* future payments to this wallet are found by hash lookup against a precomputed
|
|
281
|
+
* window instead of one trial ECDH per note in the pool. Nothing this wallet
|
|
282
|
+
* publishes depends on it, so a failure here costs scan speed and nothing else.
|
|
283
|
+
*
|
|
284
|
+
* The stored `nextIndex` is legacy — outgoing ephemerals now come from the
|
|
285
|
+
* wallet-wide sequence in `outgoingEphCounter`, which is recoverable where a
|
|
286
|
+
* per-counterparty one was not. It is preserved rather than dropped so that a
|
|
287
|
+
* vault written by an older version still reads back cleanly.
|
|
288
|
+
*/
|
|
289
|
+
declare function registerPairwiseCounterparty(storage: NoteStorage, ivkHex: string): Promise<void>;
|
|
278
290
|
|
|
279
291
|
/**
|
|
280
292
|
* Turning a note into a stored record and back.
|
|
@@ -290,7 +302,7 @@ declare function reservePairwiseIndex(storage: NoteStorage, ivkHex: string): Pro
|
|
|
290
302
|
*/
|
|
291
303
|
declare function applyNoteStatus(note: ZkNote, status?: NoteStatusUpdate): ZkNote;
|
|
292
304
|
/**
|
|
293
|
-
* Encrypts a ZkNote into
|
|
305
|
+
* Encrypts a ZkNote into an `EncryptedNoteRecord`.
|
|
294
306
|
*
|
|
295
307
|
* The full note (values, secrets) is AES-GCM encrypted under `key`; the note
|
|
296
308
|
* identifiers (commitment, nullifier, asset) are stored as BLIND TAGS under
|
|
@@ -664,6 +676,11 @@ declare function fromHex(hex: string): Uint8Array;
|
|
|
664
676
|
declare function ensureHexPrefix(hex: string): string;
|
|
665
677
|
/**
|
|
666
678
|
* Converts a 0x-prefixed hex string (as returned by JSON-RPC) to a number.
|
|
679
|
+
*
|
|
680
|
+
* Throws rather than returning `NaN`. A bare `parseInt` accepts a valid prefix
|
|
681
|
+
* and drops the rest, so `"0x12zz"` used to yield `18` — a plausible block
|
|
682
|
+
* number that is simply wrong. It also has no upper bound: a quantity past
|
|
683
|
+
* 2^53 loses precision silently, and these values come from a server.
|
|
667
684
|
*/
|
|
668
685
|
declare function hexToNumber(hex: string): number;
|
|
669
686
|
/**
|
|
@@ -673,11 +690,10 @@ declare function hexToBigint(hex: string): bigint;
|
|
|
673
690
|
/**
|
|
674
691
|
* A field scalar as canonical 32-byte hex: `0x` + 64 zero-padded chars.
|
|
675
692
|
*
|
|
676
|
-
* Big-endian and fixed-width on purpose. These
|
|
677
|
-
*
|
|
678
|
-
*
|
|
679
|
-
*
|
|
680
|
-
* `0x0…01` two different keys for one value.
|
|
693
|
+
* Big-endian and fixed-width on purpose. These are compared AS STRINGS — a
|
|
694
|
+
* wallet finds its own note by matching an `ownerPk` that way — so one scalar
|
|
695
|
+
* must have exactly one spelling. `toString(16)` at its natural width would
|
|
696
|
+
* make `0x1` and `0x0…01` two different keys for the same value.
|
|
681
697
|
*
|
|
682
698
|
* Not for commitments or nullifiers: those travel LITTLE-endian and go through
|
|
683
699
|
* `toHex(bigintTo32Le(...))`.
|
|
@@ -755,6 +771,78 @@ declare const BABYJUB_SUBORDER = 27360303589799094027808007181571593860768139721
|
|
|
755
771
|
* Returns the point with the canonical (smaller) y, or null if Ax is not on the curve.
|
|
756
772
|
*/
|
|
757
773
|
declare function recoverOwnerPkPoint(ax: bigint): [bigint, bigint] | null;
|
|
774
|
+
/**
|
|
775
|
+
* Unpack a recipient's packed viewing key, refusing keys that would make the
|
|
776
|
+
* ECDH secret guessable.
|
|
777
|
+
*
|
|
778
|
+
* Unpacking alone is not validation. BabyJubJub has a cofactor of 8, so the
|
|
779
|
+
* curve contains a small subgroup, and a point from it has order 1, 2, 4 or 8.
|
|
780
|
+
* `[ephSk]·P` then takes at most 8 values no matter how random `ephSk` is, and
|
|
781
|
+
* an interceptor simply tries them all: a memo sealed toward such a key yields
|
|
782
|
+
* its value, blinding and sourcePk, and a payment slip decrypts, without any
|
|
783
|
+
* secret at all. The all-zero packed value is one of them — an order-4 point.
|
|
784
|
+
*
|
|
785
|
+
* The all-zero byte check that guards privacy addresses does not catch this:
|
|
786
|
+
* the packed value `0` is not the neutral element, it is a legitimate point
|
|
787
|
+
* with y=0 that happens to have order 4. Nor is a low-order key necessarily
|
|
788
|
+
* hostile — it is also what a truncated or half-initialised buffer decodes to.
|
|
789
|
+
* Either way the note is world-readable, so both are refused here.
|
|
790
|
+
*
|
|
791
|
+
* Multiplying by the cofactor is the standard test: `[8]·P` is the identity for
|
|
792
|
+
* every point of the small subgroup and for no other point.
|
|
793
|
+
*
|
|
794
|
+
* @returns the point, or null when it is unusable as a recipient key
|
|
795
|
+
*/
|
|
796
|
+
declare function unpackUsableViewingKey(packed: bigint): [bigint, bigint] | null;
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Guards for SECRET key material.
|
|
800
|
+
*
|
|
801
|
+
* `unpackUsableViewingKey` covers the public side — a point someone else chose,
|
|
802
|
+
* where the risk is a low-order key that collapses the ECDH. This covers the
|
|
803
|
+
* other side: the 32-byte secrets a caller passes in, where the risk is that
|
|
804
|
+
* nothing checks them at all.
|
|
805
|
+
*
|
|
806
|
+
* ## Why a degenerate secret is not merely weak
|
|
807
|
+
*
|
|
808
|
+
* `bytesToBjjScalar` reduces whatever it gets modulo the suborder and clamps a
|
|
809
|
+
* zero result to `1n`. So an all-zero key, or a 16-byte one, does not fail —
|
|
810
|
+
* it becomes a VALID scalar that some other wallet could also arrive at. An
|
|
811
|
+
* empty array is worse: `BigInt('0x')` throws, which surfaces as an exception
|
|
812
|
+
* from whichever primitive happened to touch it first.
|
|
813
|
+
*
|
|
814
|
+
* The same shapes are what a missing field, a truncated buffer, or an
|
|
815
|
+
* uninitialised `new Uint8Array(32)` decode to, so this is the failure a
|
|
816
|
+
* mis-wired caller actually hits.
|
|
817
|
+
*
|
|
818
|
+
* ## Why these THROW
|
|
819
|
+
*
|
|
820
|
+
* A bad secret key is a programming error, not untrusted input. Returning null
|
|
821
|
+
* would fold it into "this note is not mine" / "this slip is not for me", which
|
|
822
|
+
* is indistinguishable from the ordinary case — the wallet would report an
|
|
823
|
+
* empty scan and look perfectly healthy.
|
|
824
|
+
*
|
|
825
|
+
* Data from the network is the opposite and must NOT use this: a malformed
|
|
826
|
+
* backup entry or scan hint is dropped, never thrown, so one bad record cannot
|
|
827
|
+
* take down the batch. `isUsableSecretKey` exists for the paths that have to
|
|
828
|
+
* make that decision without unwinding.
|
|
829
|
+
*/
|
|
830
|
+
/**
|
|
831
|
+
* True when `key` can be used as secret key material.
|
|
832
|
+
*
|
|
833
|
+
* For callers that must not throw — a scan loop, a window builder — where the
|
|
834
|
+
* answer is "turn this capability off", not "abort".
|
|
835
|
+
*/
|
|
836
|
+
declare function isUsableSecretKey(key: Uint8Array | undefined | null): key is Uint8Array;
|
|
837
|
+
/**
|
|
838
|
+
* Throws unless `key` is usable secret key material.
|
|
839
|
+
*
|
|
840
|
+
* @param key the secret to check
|
|
841
|
+
* @param label what it is, named in the error — a caller that wired two keys
|
|
842
|
+
* the wrong way round needs to know WHICH one is wrong, and every
|
|
843
|
+
* secret here is 32 opaque bytes that look alike in a debugger.
|
|
844
|
+
*/
|
|
845
|
+
declare function assertSecretKeyBytes(key: Uint8Array, label: string): void;
|
|
758
846
|
|
|
759
847
|
/** Affine point as zk-kit represents it. */
|
|
760
848
|
type AffinePoint = [bigint, bigint];
|
|
@@ -820,6 +908,19 @@ interface CryptoKey$1 {
|
|
|
820
908
|
readonly usages: string[];
|
|
821
909
|
}
|
|
822
910
|
|
|
911
|
+
/**
|
|
912
|
+
* Rendering on-chain amounts for people.
|
|
913
|
+
*
|
|
914
|
+
* Chain amounts are integers in the smallest unit — 18 decimals for ORB — and
|
|
915
|
+
* every one of these keeps them that way internally: BigInt arithmetic only, no
|
|
916
|
+
* float ever touches a balance. A `number` intermediate would silently lose
|
|
917
|
+
* precision past 2^53, which for 18 decimals starts at about 0.009 ORB.
|
|
918
|
+
*
|
|
919
|
+
* Malformed input yields ZERO rather than a guess. Grouped digits, scientific
|
|
920
|
+
* notation and a leading `+` are all rejected: coercing them would render an
|
|
921
|
+
* amount that is not the one on chain, and a balance nobody can explain is
|
|
922
|
+
* worse than a visible zero.
|
|
923
|
+
*/
|
|
823
924
|
/**
|
|
824
925
|
* Options for {@link formatBalance}.
|
|
825
926
|
*/
|
|
@@ -831,6 +932,7 @@ interface FormatOptions {
|
|
|
831
932
|
/** Whether to append the symbol. Defaults to `true`. */
|
|
832
933
|
showSymbol?: boolean;
|
|
833
934
|
/** Maximum number of decimal digits shown in output. Defaults to `6`. */
|
|
935
|
+
/** MAXIMUM decimal digits shown. Trailing zeros are trimmed, never padded. */
|
|
834
936
|
precision?: number;
|
|
835
937
|
}
|
|
836
938
|
/**
|
|
@@ -851,7 +953,7 @@ interface FormatOptions {
|
|
|
851
953
|
*
|
|
852
954
|
* @example
|
|
853
955
|
* formatBalance('1000000000000000000') // '1 ORB'
|
|
854
|
-
* formatBalance(500000000000000000n, { precision: 2 }) // '0.
|
|
956
|
+
* formatBalance(500000000000000000n, { precision: 2 }) // '0.5 ORB' (max, not pad)
|
|
855
957
|
* formatBalance('0x0de0b6b3a7640000', { showSymbol: false }) // '1'
|
|
856
958
|
* formatBalance(null) // '0 ORB'
|
|
857
959
|
*/
|
|
@@ -931,18 +1033,19 @@ declare function normalizeEvmAddress(addr: string): string;
|
|
|
931
1033
|
* a UI renders, not an exception.
|
|
932
1034
|
*/
|
|
933
1035
|
declare function parseEvmAddress(addr: string): string | null;
|
|
934
|
-
/**
|
|
935
|
-
* Returns true if the string looks like an SS58 encoded address
|
|
936
|
-
* (not a 0x-prefixed hex).
|
|
937
|
-
*/
|
|
938
|
-
declare function isSs58(addr: string): boolean;
|
|
939
1036
|
/**
|
|
940
1037
|
* Returns true if the string looks like a 20-byte EVM address.
|
|
941
1038
|
*/
|
|
942
1039
|
declare function isEvmAddress(addr: string): boolean;
|
|
943
1040
|
/**
|
|
944
|
-
* Pads a 20-byte EVM address to
|
|
945
|
-
*
|
|
1041
|
+
* Pads a 20-byte EVM address to 32 bytes by PREPENDING 12 zero bytes.
|
|
1042
|
+
*
|
|
1043
|
+
* The Ethereum convention, NOT Orbinum's. This chain maps an H160 to an account
|
|
1044
|
+
* by appending — `evmToImplicitSubstrate` is the one that matches the runtime,
|
|
1045
|
+
* and the two produce different accounts for the same address.
|
|
1046
|
+
*
|
|
1047
|
+
* Kept for callers that need the Ethereum-shaped padding (an H256 topic, an ABI
|
|
1048
|
+
* word). Anything that has to name an Orbinum account wants the other one.
|
|
946
1049
|
*/
|
|
947
1050
|
declare function evmAddressToAccountId(evmAddr: string): Uint8Array;
|
|
948
1051
|
/**
|
|
@@ -1035,10 +1138,10 @@ declare function addressToFieldElement(address: string): bigint;
|
|
|
1035
1138
|
* Layout (180 bytes, ECDH):
|
|
1036
1139
|
* nonce(12) || ciphertext+MAC(136) || ephPk_packed(32) = 180
|
|
1037
1140
|
*
|
|
1038
|
-
* View tag
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1141
|
+
* View tag: nonce[0] = deriveViewTag(sharedSecret). Layout and size unchanged.
|
|
1142
|
+
* Memos written before tags carry a RANDOM byte there, so the filter is only
|
|
1143
|
+
* sound at or after the leaf where they were switched on — the scanner passes
|
|
1144
|
+
* that boundary as `ScanKeys.viewTagActivationLeaf`.
|
|
1042
1145
|
*
|
|
1043
1146
|
* Plaintext layout (120 bytes):
|
|
1044
1147
|
* value_lo(8 LE) || value_hi(8 LE) || owner_pk(32) || blinding(32) || asset_id(4 LE) || source_pk(32) || circuit_version(4 LE)
|
|
@@ -1046,7 +1149,9 @@ declare function addressToFieldElement(address: string): bigint;
|
|
|
1046
1149
|
* value is stored as a 128-bit LE unsigned integer (two uint64 words), supporting
|
|
1047
1150
|
* amounts up to ~3.4 × 10^38 planck — well above any realistic token supply.
|
|
1048
1151
|
*
|
|
1049
|
-
*
|
|
1152
|
+
* Key derivation (ECDH). The "v2" in the memo's own wire format names THIS
|
|
1153
|
+
* layout, and is unrelated to the identity version — the v3 identity work
|
|
1154
|
+
* changed which branches derive a wallet's keys, not how a memo is sealed:
|
|
1050
1155
|
* ephSk = random scalar in [1, BABYJUB_SUBORDER)
|
|
1051
1156
|
* ephPk = mulPointEscalar(Base8, ephSk)
|
|
1052
1157
|
* sharedPoint = mulPointEscalar(recipientIvk, ephSk) ← or mulPointEscalar(ephPk, ivsk)
|
|
@@ -1063,7 +1168,7 @@ declare const ENCRYPTED_MEMO_SIZE: number;
|
|
|
1063
1168
|
declare function bytesToBjjScalar(bytes: Uint8Array): bigint;
|
|
1064
1169
|
declare const EncryptedMemo: {
|
|
1065
1170
|
/**
|
|
1066
|
-
* Build and encrypt a memo for a note using ECDH (
|
|
1171
|
+
* Build and encrypt a memo for a note using ECDH (180 bytes).
|
|
1067
1172
|
*
|
|
1068
1173
|
* @param value Note value in planck.
|
|
1069
1174
|
* @param ownerPk 32-byte owner public key (LE).
|
|
@@ -1129,9 +1234,9 @@ declare const EncryptedMemo: {
|
|
|
1129
1234
|
* Cheap view-tag check: does memo nonce[0] match the tag derived from
|
|
1130
1235
|
* `sharedSecret`? One SHA256 + one byte compare — no AEAD work.
|
|
1131
1236
|
*
|
|
1132
|
-
* Only meaningful for memos
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1237
|
+
* Only meaningful for memos that carry a tag — at or after
|
|
1238
|
+
* `ScanKeys.viewTagActivationLeaf`. An older memo has a random byte there
|
|
1239
|
+
* and would false-negative 255/256 of the time.
|
|
1135
1240
|
*/
|
|
1136
1241
|
checkViewTag(memoBytes: Uint8Array, sharedSecret: Uint8Array): boolean;
|
|
1137
1242
|
/**
|
|
@@ -1171,76 +1276,6 @@ declare function serializeMemo(value: bigint, ownerPk: Uint8Array, blinding: Uin
|
|
|
1171
1276
|
*/
|
|
1172
1277
|
declare function deriveViewTag(sharedSecret: Uint8Array): number;
|
|
1173
1278
|
|
|
1174
|
-
/**
|
|
1175
|
-
* OutgoingBlob — the OVK "wrap-the-key" primitive.
|
|
1176
|
-
*
|
|
1177
|
-
* When a wallet sends a private_transfer, the recipient's memo is encrypted ECDH
|
|
1178
|
-
* toward the RECIPIENT's ivk; the sender cannot reopen it, so a cold restore
|
|
1179
|
-
* loses the outgoing history (who/how much). This blob fixes that: it wraps the
|
|
1180
|
-
* memo's 32-byte `sharedSecret` under a key derived from the SENDER's ovk. On
|
|
1181
|
-
* restore the sender unwraps the sharedSecret and feeds it to the SAME memo
|
|
1182
|
-
* decryption path the recipient uses — one decryption routine in the whole
|
|
1183
|
-
* system (OVK plan requirement #7).
|
|
1184
|
-
*
|
|
1185
|
-
* This is Zcash Sapling's `outCiphertext` / Penumbra's `OvkWrappedKey`, adapted
|
|
1186
|
-
* to a shared secret that is a field element (32 bytes), not a group point — so
|
|
1187
|
-
* the blob contains no group element to decode, sidestepping Zcash's canonical-
|
|
1188
|
-
* encoding class of bugs.
|
|
1189
|
-
*
|
|
1190
|
-
* Layout (56 bytes): nonce_suffix(8) || ciphertext(32) || MAC(16).
|
|
1191
|
-
* Cipher: ChaCha20-Poly1305 (IETF), same primitive as EncryptedMemo.
|
|
1192
|
-
*
|
|
1193
|
-
* The outgoing cipher key binds every unique-per-output public value:
|
|
1194
|
-
* ock = HKDF(ikm=ovk, salt=commitment_bytes||ephPk_bytes, info=OCK_DOMAIN)
|
|
1195
|
-
* so each ock encrypts exactly one message. Uniqueness comes from the COMMITMENT
|
|
1196
|
-
* (Poseidon4 with random blinding, consensus rejects duplicates); the ephPk adds
|
|
1197
|
-
* the on-chain binding, not the uniqueness — two self-notes can share an ephPk
|
|
1198
|
-
* but never a commitment, so their ock still differs.
|
|
1199
|
-
*
|
|
1200
|
-
* SALT IS RAW ON-CHAIN BYTES. `commitment_bytes` and `ephPk_bytes` must be the
|
|
1201
|
-
* exact bytes that are/go on chain, never a re-serialization of a decoded point:
|
|
1202
|
-
* two encodings of "the same point" produce different ock and the AEAD fails —
|
|
1203
|
-
* no ambiguity to exploit.
|
|
1204
|
-
*/
|
|
1205
|
-
/** Total on-chain blob size: nonce_suffix(8) || ciphertext(32) || MAC(16). */
|
|
1206
|
-
declare const OVK_BLOB_SIZE: number;
|
|
1207
|
-
/**
|
|
1208
|
-
* Derive the 32-byte outgoing cipher key.
|
|
1209
|
-
* ock = HKDF-SHA256(ikm=ovk, salt=commitmentBytes||ephPkBytes, info=OCK_DOMAIN)
|
|
1210
|
-
*
|
|
1211
|
-
* Both salt parts must be the raw 32-byte on-chain values (see file header).
|
|
1212
|
-
* Throws if either is not exactly 32 bytes — a wrong length here would silently
|
|
1213
|
-
* change the key and make recovery fail far from the cause.
|
|
1214
|
-
*/
|
|
1215
|
-
declare function deriveOutgoingCipherKey(ovk: Uint8Array, commitmentBytes: Uint8Array, ephPkBytes: Uint8Array): Uint8Array;
|
|
1216
|
-
/**
|
|
1217
|
-
* Seal a sharedSecret into a 56-byte outgoing blob under the sender's ovk.
|
|
1218
|
-
*
|
|
1219
|
-
* @param ovk sender's 32-byte outgoing viewing key
|
|
1220
|
-
* @param sharedSecret the memo's 32-byte ECDH shared secret (what we wrap)
|
|
1221
|
-
* @param commitmentBytes raw 32-byte on-chain commitment of the recipient output
|
|
1222
|
-
* @param ephPkBytes raw 32-byte ephemeral public key (from the memo, not recomputed)
|
|
1223
|
-
* @returns 56 bytes: nonce_suffix(8) || ciphertext(32) || MAC(16)
|
|
1224
|
-
*/
|
|
1225
|
-
declare function sealOutgoingBlob(ovk: Uint8Array, sharedSecret: Uint8Array, commitmentBytes: Uint8Array, ephPkBytes: Uint8Array): Uint8Array;
|
|
1226
|
-
/**
|
|
1227
|
-
* Open an outgoing blob, returning the wrapped sharedSecret or null.
|
|
1228
|
-
*
|
|
1229
|
-
* Never throws — this runs in recovery loops over hints that may be foreign,
|
|
1230
|
-
* pre-OVK, or ovk=⊥ random. A wrong ovk, wrong commitment, wrong ephPk, or any
|
|
1231
|
-
* corrupted byte fails the MAC and returns null.
|
|
1232
|
-
*/
|
|
1233
|
-
declare function openOutgoingBlob(ovk: Uint8Array, blob: Uint8Array, commitmentBytes: Uint8Array, ephPkBytes: Uint8Array): Uint8Array | null;
|
|
1234
|
-
/**
|
|
1235
|
-
* A 56-byte random blob for the ovk=⊥ case (sender opts out of recoverability).
|
|
1236
|
-
*
|
|
1237
|
-
* Indistinguishable on-chain from a real blob: a real one is a random 8-byte
|
|
1238
|
-
* suffix plus ChaCha20/Poly1305 output, both uniform without the key. This is
|
|
1239
|
-
* the ONLY path for ⊥ — never zeros (distinguishable), never omission (a length
|
|
1240
|
-
* or SCALE-tag difference is a permanent, retroactive privacy label).
|
|
1241
|
-
*/
|
|
1242
|
-
declare function randomOutgoingBlob(): Uint8Array;
|
|
1243
|
-
|
|
1244
1279
|
/** The fields a payment slip carries — all public on-chain. */
|
|
1245
1280
|
interface PaymentSlipFields {
|
|
1246
1281
|
/** 0x-prefixed 32-byte LE commitment hex of the recipient output. */
|
|
@@ -1292,7 +1327,7 @@ declare function decodePaymentSlip(text: string): Uint8Array | null;
|
|
|
1292
1327
|
* Derive the deterministic 32-byte ephemeral secret for self-note `index`.
|
|
1293
1328
|
* Feed it to EncryptedMemo.encrypt / NoteBuilder.build as `ephSkOverride`.
|
|
1294
1329
|
*/
|
|
1295
|
-
declare function deriveSelfEphSk(
|
|
1330
|
+
declare function deriveSelfEphSk(viewingSecretKey: Uint8Array, index: number): Uint8Array;
|
|
1296
1331
|
/** One precomputed self-note window entry. */
|
|
1297
1332
|
interface SelfEphWindowEntry {
|
|
1298
1333
|
index: number;
|
|
@@ -1307,11 +1342,11 @@ interface SelfEphWindowEntry {
|
|
|
1307
1342
|
* needed to decrypt the memo. One EC pass up front; scanning then matches
|
|
1308
1343
|
* hints by ephPk hex equality with no per-hint EC work.
|
|
1309
1344
|
*
|
|
1310
|
-
* @param
|
|
1345
|
+
* @param viewingSecretKey Wallet incoming viewing key (the seed of the derivation).
|
|
1311
1346
|
* @param ivkPacked The wallet's OWN 32-byte LE packed viewing public key —
|
|
1312
1347
|
* self memos are encrypted to it.
|
|
1313
1348
|
*/
|
|
1314
|
-
declare function selfEphWindow(
|
|
1349
|
+
declare function selfEphWindow(viewingSecretKey: Uint8Array, ivkPacked: Uint8Array, from: number, count: number): SelfEphWindowEntry[];
|
|
1315
1350
|
|
|
1316
1351
|
/**
|
|
1317
1352
|
* The secret shared by a sender/receiver pair: ECDH between one side's viewing
|
|
@@ -1353,6 +1388,83 @@ interface PairwiseEphWindowEntry {
|
|
|
1353
1388
|
*/
|
|
1354
1389
|
declare function pairwiseEphWindow(pairSecret: Uint8Array, receiverIvkPacked: Uint8Array, from: number, count: number): PairwiseEphWindowEntry[];
|
|
1355
1390
|
|
|
1391
|
+
/**
|
|
1392
|
+
* The ephemeral secret for the `index`-th note this wallet sends. Feed it to
|
|
1393
|
+
* `NoteBuilder.build` as `ephSkOverride`.
|
|
1394
|
+
*/
|
|
1395
|
+
declare function deriveOutgoingEphSk(outgoingViewingKey: Uint8Array, index: number): Uint8Array;
|
|
1396
|
+
/** The ephPk this wallet publishes at `index` — the memo's last 32 bytes. */
|
|
1397
|
+
declare function deriveOutgoingEphPk(outgoingViewingKey: Uint8Array, index: number): string;
|
|
1398
|
+
/** One precomputed outgoing window entry. */
|
|
1399
|
+
interface OutgoingEphWindowEntry {
|
|
1400
|
+
index: number;
|
|
1401
|
+
/** 0x-prefixed LE-packed ephPk — byte-identical to the memo's last 32 bytes. */
|
|
1402
|
+
ephPkHex: string;
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Precompute [from, from+count) of the outgoing sequence.
|
|
1406
|
+
*
|
|
1407
|
+
* Only the ephPk, never a shared secret: unlike the self and pairwise windows,
|
|
1408
|
+
* the secret that opens an outgoing memo depends on the RECIPIENT's viewing
|
|
1409
|
+
* key, which is not known until the note is matched. Recovery derives it then,
|
|
1410
|
+
* per candidate, with `deriveOutgoingSharedSecret`.
|
|
1411
|
+
*/
|
|
1412
|
+
declare function outgoingEphWindow(outgoingViewingKey: Uint8Array, from: number, count: number): OutgoingEphWindowEntry[];
|
|
1413
|
+
/**
|
|
1414
|
+
* The secret that opens the memo of the payment this wallet sent at `index`.
|
|
1415
|
+
*
|
|
1416
|
+
* The same value the recipient computes from their viewing secret key and the
|
|
1417
|
+
* published ephPk — reached from the other side, which is what lets the sender
|
|
1418
|
+
* read back a memo sealed toward someone else.
|
|
1419
|
+
*
|
|
1420
|
+
* Throws on a viewing key that is not a curve point; callers sweeping
|
|
1421
|
+
* candidates should treat that as "not this one".
|
|
1422
|
+
*/
|
|
1423
|
+
declare function deriveOutgoingSharedSecret(outgoingViewingKey: Uint8Array, index: number, recipientIvkPacked: Uint8Array): Uint8Array;
|
|
1424
|
+
/**
|
|
1425
|
+
* The next unused outgoing index, read off the chain.
|
|
1426
|
+
*
|
|
1427
|
+
* The sender can predict every ephPk they would publish, so the highest one
|
|
1428
|
+
* that actually appears on chain names the last index used. This is what the
|
|
1429
|
+
* pairwise counter cannot do — its ephemerals depend on a counterparty the
|
|
1430
|
+
* restored wallet no longer knows — and it is why an outgoing sequence may
|
|
1431
|
+
* start at 0 instead of degrading to a random ephemeral.
|
|
1432
|
+
*
|
|
1433
|
+
* ## This result must never be trusted on its own
|
|
1434
|
+
*
|
|
1435
|
+
* Omission is a WRITE attack: a feed that hides the highest index makes this
|
|
1436
|
+
* return a value already published, and using it republishes that ephPk. Two
|
|
1437
|
+
* rules follow, both enforced by the caller in `reserveOutgoingIndex`:
|
|
1438
|
+
*
|
|
1439
|
+
* - never move a counter BACKWARDS — a local counter always wins;
|
|
1440
|
+
* - after a restore, where there is no local counter to compare against,
|
|
1441
|
+
* leave a gap so a feed would have to hide a whole run of consecutive
|
|
1442
|
+
* top indexes rather than a single one.
|
|
1443
|
+
*
|
|
1444
|
+
* @param window How many indexes to consider — must cover the highest ever
|
|
1445
|
+
* used, or a high index stays invisible and gets handed out
|
|
1446
|
+
* again. Grow it with the counter, as `selfEphGap` does.
|
|
1447
|
+
*/
|
|
1448
|
+
declare function reconstructOutgoingIndex(outgoingViewingKey: Uint8Array, publishedEphPks: Iterable<string>, window: number): number;
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* Building a note: its commitment, its nullifier, and the memo that recovers it.
|
|
1452
|
+
*
|
|
1453
|
+
* Everything is local — no chain access — and every note leaves here in one of
|
|
1454
|
+
* two shapes:
|
|
1455
|
+
*
|
|
1456
|
+
* - STEALTH, when the caller supplies both halves of a privacy address. The
|
|
1457
|
+
* commitment covers a one-time owner key, so two payments to one address
|
|
1458
|
+
* cannot be linked, and the memo carries what the recipient needs to
|
|
1459
|
+
* rederive the matching spending key.
|
|
1460
|
+
* - PLAIN, for a wallet's own notes (a shield, a change note), where the
|
|
1461
|
+
* commitment covers the wallet's global owner key because it has to find
|
|
1462
|
+
* the note again with its own keys.
|
|
1463
|
+
*
|
|
1464
|
+
* The blinding is the note's only real secret once an amount is guessed, so an
|
|
1465
|
+
* absent one is drawn from a CSPRNG and never from anything predictable.
|
|
1466
|
+
*/
|
|
1467
|
+
|
|
1356
1468
|
/**
|
|
1357
1469
|
* Builds ZK notes (commitment + nullifier) and encrypted memos locally.
|
|
1358
1470
|
*
|
|
@@ -1380,7 +1492,7 @@ declare class NoteBuilder {
|
|
|
1380
1492
|
* @param input.value Amount in planck (required).
|
|
1381
1493
|
* @param input.assetId Asset ID — default 0n (native ORB-Privacy).
|
|
1382
1494
|
* @param input.ownerPk Sender's or recipient's global BabyJubJub Ax — default 0n.
|
|
1383
|
-
* @param input.blinding Random scalar — defaults to
|
|
1495
|
+
* @param input.blinding Random scalar — defaults to a CSPRNG draw.
|
|
1384
1496
|
* @param input.spendingKey Secret key for nullifier — default 0n.
|
|
1385
1497
|
* @param input.viewingPublicKey Recipient's 32-byte LE packed BJJ ivk. Triggers memo encryption.
|
|
1386
1498
|
* @param input.recipientOwnerPk Recipient's global ownerPk. Required with viewingPublicKey
|
|
@@ -1397,7 +1509,7 @@ declare class NoteBuilder {
|
|
|
1397
1509
|
* @param note The ZkNote whose fields populate the plaintext.
|
|
1398
1510
|
* @param recipientIvkPacked 32-byte LE packed BJJ viewing public key of the recipient.
|
|
1399
1511
|
* Pass `new Uint8Array(32)` (default) for a public/dummy memo.
|
|
1400
|
-
* @param sourcePk
|
|
1512
|
+
* @param sourcePk 32-byte counterparty BabyJubJub Ax.
|
|
1401
1513
|
* Pass `new Uint8Array(32)` (default) for no counterparty.
|
|
1402
1514
|
*/
|
|
1403
1515
|
static buildMemo(note: ZkNote, recipientIvkPacked?: Uint8Array, sourcePk?: Uint8Array): Uint8Array;
|
|
@@ -1453,8 +1565,9 @@ interface TryDecryptOptions {
|
|
|
1453
1565
|
* 1-byte tag in memo nonce[0], and skip the AEAD decrypt on mismatch
|
|
1454
1566
|
* (255/256 of foreign notes; `reason: 'view_tag_mismatch'`).
|
|
1455
1567
|
*
|
|
1456
|
-
*
|
|
1457
|
-
*
|
|
1568
|
+
* Enable only for commitments at or after the leaf where tags were switched
|
|
1569
|
+
* on — the scanner tracks it as `ScanKeys.viewTagActivationLeaf`. Older
|
|
1570
|
+
* memos carry a random byte there and would be dropped in silence.
|
|
1458
1571
|
*/
|
|
1459
1572
|
viewTag?: boolean;
|
|
1460
1573
|
/**
|
|
@@ -1489,41 +1602,6 @@ declare function tryDecryptNoteVerbose(commitment: ScanCommitment, viewingSecret
|
|
|
1489
1602
|
note: ZkNote | null;
|
|
1490
1603
|
reason?: string;
|
|
1491
1604
|
};
|
|
1492
|
-
/** A scan hint plus the per-transaction OVK blob the indexer serves alongside it. */
|
|
1493
|
-
type OutgoingHint = ScanCommitment & {
|
|
1494
|
-
ovkBlob?: string | null;
|
|
1495
|
-
};
|
|
1496
|
-
/**
|
|
1497
|
-
* Recover a note the caller SENT, using their outgoing viewing key (ovk).
|
|
1498
|
-
*
|
|
1499
|
-
* The sender's memo was encrypted toward the RECIPIENT, so they cannot reopen it
|
|
1500
|
-
* directly. Instead the ovk blob wraps the memo's shared secret; unwrapping it
|
|
1501
|
-
* gives the same secret the recipient gets via ECDH, and feeding it to the shared
|
|
1502
|
-
* decrypt-and-verify step rebuilds the sent note's public facts.
|
|
1503
|
-
*
|
|
1504
|
-
* Returns an OutgoingNoteRecord (value, recipient stealth pk, counterparty,
|
|
1505
|
-
* circuit version) — NEVER a spendable note: no spendingKey, no nullifier. The
|
|
1506
|
-
* sender does not own this note. Never throws (runs in recovery loops).
|
|
1507
|
-
*
|
|
1508
|
-
* Security (OVK plan §3.4), in three non-algebraic but sound layers:
|
|
1509
|
-
* 1. The blob MAC (openOutgoingBlob) proves whoever wrote it knew the ovk, and
|
|
1510
|
-
* the ock binds it to THIS (commitment, ephPk) — blobs are not transplantable.
|
|
1511
|
-
* 2. The memo MAC (inside decryptAndVerifyPlaintext) proves this shared secret
|
|
1512
|
-
* is the one that encrypted this memo — the same secret the recipient derives.
|
|
1513
|
-
* 3. The commitment check ties the recovered fields to the note in the tree.
|
|
1514
|
-
* Not verifiable by the sender: that `sharedSecret` corresponds to `ephPk` — that
|
|
1515
|
-
* needs the recipient's ivsk. Residual: a leaked ovk lets an attacker fabricate a
|
|
1516
|
-
* self-consistent (commitment, memo, blob) and plant false outgoing history. It
|
|
1517
|
-
* moves no funds; Zcash accepts the same residual. Mitigated in the app by only
|
|
1518
|
-
* running this over commitments from extrinsics that spent our own nullifiers.
|
|
1519
|
-
*
|
|
1520
|
-
* @param hint scan hint with commitmentHex, encryptedMemo, and ovkBlob.
|
|
1521
|
-
* @param ovk the sender's 32-byte outgoing viewing key.
|
|
1522
|
-
* @param opts viewTagActivationLeaf gates the view-tag check for legacy memos.
|
|
1523
|
-
*/
|
|
1524
|
-
declare function tryRecoverOutgoing(hint: OutgoingHint, ovk: Uint8Array, opts?: {
|
|
1525
|
-
viewTagActivationLeaf?: number;
|
|
1526
|
-
}): OutgoingNoteRecord | null;
|
|
1527
1605
|
/**
|
|
1528
1606
|
* Collect what a sender can still say about a note they sent.
|
|
1529
1607
|
*
|
|
@@ -1543,6 +1621,43 @@ declare function tryRecoverOutgoing(hint: OutgoingHint, ovk: Uint8Array, opts?:
|
|
|
1543
1621
|
*/
|
|
1544
1622
|
declare function collectOutgoingFacts(hint: ScanCommitment): NoteFacts | null;
|
|
1545
1623
|
|
|
1624
|
+
/**
|
|
1625
|
+
* Seal (or open — XOR is its own inverse) a recipient's packed viewing key for
|
|
1626
|
+
* carriage in a change note's `sourcePk`.
|
|
1627
|
+
*
|
|
1628
|
+
* Returns the input unchanged when it is not 32 bytes: a caller with a
|
|
1629
|
+
* malformed key must not silently ship a truncated one, and every consumer
|
|
1630
|
+
* here already treats an unusable book entry as "no recipient known".
|
|
1631
|
+
*
|
|
1632
|
+
* @param ivkPacked 32-byte packed viewing key, sealed or plain
|
|
1633
|
+
* @param outgoingViewingKey this wallet's OUTGOING viewing key (ovk) — the
|
|
1634
|
+
* capability "see what I sent", delegable on its own
|
|
1635
|
+
* @param paymentCommitmentHex the PAYMENT's commitment — NOT the change note's.
|
|
1636
|
+
* It is the one value both sides hold: the sender
|
|
1637
|
+
* has it while building, and a restored wallet has
|
|
1638
|
+
* it the moment the outgoing window matches that
|
|
1639
|
+
* payment, which is the only time the entry is
|
|
1640
|
+
* needed.
|
|
1641
|
+
*/
|
|
1642
|
+
declare function sealRecipientBookEntry(ivkPacked: Uint8Array, outgoingViewingKey: Uint8Array, paymentCommitmentHex: string): Uint8Array;
|
|
1643
|
+
/**
|
|
1644
|
+
* Recover a recipient's packed viewing key from a change note's `sourcePk`.
|
|
1645
|
+
*
|
|
1646
|
+
* The value is transported as a raw 32-byte little-endian integer with no field
|
|
1647
|
+
* reduction, so a ciphertext above the BN254 modulus survives intact — which
|
|
1648
|
+
* matters, because most of them are.
|
|
1649
|
+
*
|
|
1650
|
+
* The result is unverified by construction: whether it is really a viewing key
|
|
1651
|
+
* is settled by trying to open the payment memo with it.
|
|
1652
|
+
*
|
|
1653
|
+
* Returns 32 zero bytes for anything that cannot be a `sourcePk` — negative, or
|
|
1654
|
+
* wider than the 32 bytes the field is carved from. A memo can never yield one
|
|
1655
|
+
* (the slice is 32 bytes), but this is public API taking a bigint, and every
|
|
1656
|
+
* neighbour here answers an impossible input with a value no memo will open
|
|
1657
|
+
* rather than an exception a caller has to catch mid-scan.
|
|
1658
|
+
*/
|
|
1659
|
+
declare function openRecipientBookEntry(sealedSourcePk: bigint, outgoingViewingKey: Uint8Array, paymentCommitmentHex: string): Uint8Array;
|
|
1660
|
+
|
|
1546
1661
|
/**
|
|
1547
1662
|
* Proving what ONE note holds, without granting any power to spend it.
|
|
1548
1663
|
*
|
|
@@ -1631,12 +1746,24 @@ interface ProofOptions {
|
|
|
1631
1746
|
* `Data cannot be cloned, out of memory`.
|
|
1632
1747
|
*
|
|
1633
1748
|
* Pass it only when the host knows better than the heuristic — a desktop
|
|
1634
|
-
* app certain of its environment, or a benchmark pinning one mode.
|
|
1635
|
-
* proof
|
|
1749
|
+
* app certain of its environment, or a benchmark pinning one mode. Either
|
|
1750
|
+
* mode yields a proof the chain verifies; only the wall-clock changes.
|
|
1636
1751
|
*/
|
|
1637
1752
|
singleThread?: boolean;
|
|
1638
1753
|
}
|
|
1639
1754
|
|
|
1755
|
+
/**
|
|
1756
|
+
* Witness assembly for the 2-in/2-out private-transfer circuit.
|
|
1757
|
+
*
|
|
1758
|
+
* Pure marshalling: bigints and hex in, decimal strings the prover accepts out.
|
|
1759
|
+
* Nothing here VALIDATES the witness — the circuit is what enforces every
|
|
1760
|
+
* constraint, and a caller that assembles an inconsistent one gets a proof
|
|
1761
|
+
* failure rather than a wrong proof.
|
|
1762
|
+
*
|
|
1763
|
+
* Always two inputs and two outputs. A single-note spend pads slot B with a
|
|
1764
|
+
* dummy (see `buildDummyTransferInput`), because the circuit's shape is fixed.
|
|
1765
|
+
*/
|
|
1766
|
+
|
|
1640
1767
|
/** A single input note for a private transfer. */
|
|
1641
1768
|
interface TransferInputNote {
|
|
1642
1769
|
nullifier: bigint;
|
|
@@ -1668,20 +1795,49 @@ interface PrivateTransferProofInputs {
|
|
|
1668
1795
|
merkleRoot: string;
|
|
1669
1796
|
inputs: [TransferInputNote, TransferInputNote];
|
|
1670
1797
|
outputs: [TransferOutputNote, TransferOutputNote];
|
|
1671
|
-
/**
|
|
1798
|
+
/**
|
|
1799
|
+
* Gasless fee in planck (default 0n).
|
|
1800
|
+
*
|
|
1801
|
+
* The circuit constrains `input_sum == output_sum + fee`. Nothing here
|
|
1802
|
+
* checks it — the caller balances the amounts (`transferNotes` does, before
|
|
1803
|
+
* proving) and an unbalanced witness fails at proof time.
|
|
1804
|
+
*/
|
|
1672
1805
|
fee?: bigint;
|
|
1673
1806
|
}
|
|
1674
1807
|
/**
|
|
1675
1808
|
* Generate a Groth16 proof for a PrivateTransfer operation.
|
|
1809
|
+
*
|
|
1810
|
+
* The merkle root arrives LITTLE-ENDIAN hex and is converted here; passing it
|
|
1811
|
+
* big-endian yields a root the circuit cannot match against the paths.
|
|
1676
1812
|
*/
|
|
1677
1813
|
declare function generateTransferProof(params: PrivateTransferProofInputs, options?: ProofOptions): Promise<ProofResult>;
|
|
1678
1814
|
|
|
1679
1815
|
/**
|
|
1680
|
-
*
|
|
1681
|
-
*
|
|
1682
|
-
*
|
|
1816
|
+
* Which notes pay an amount, and what the forest allows.
|
|
1817
|
+
*
|
|
1818
|
+
* The circuit is 2-in/2-out, so a spend draws on at most TWO notes and the
|
|
1819
|
+
* selection is a search over pairs rather than a greedy sum. A pair must agree
|
|
1820
|
+
* on two things beyond covering the amount: the same CIRCUIT VERSION, since one
|
|
1821
|
+
* proof is verified against one VK, and the same FOREST TREE, since both paths
|
|
1822
|
+
* resolve under one root and a cross-tree pair can never converge.
|
|
1823
|
+
*
|
|
1824
|
+
* Pure arithmetic over notes: nothing here reserves anything or touches the
|
|
1825
|
+
* chain, and every guard it applies is one the circuit would apply anyway,
|
|
1826
|
+
* seconds later and without naming the note.
|
|
1827
|
+
*/
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* Leaves one forest tree holds — the value this SDK assumes for the chain's
|
|
1831
|
+
* `MaxLeavesPerTree`.
|
|
1832
|
+
*
|
|
1833
|
+
* The pallet's `integrity_test` requires that constant to be a power of two no
|
|
1834
|
+
* greater than `2^MAX_TREE_DEPTH`, and forbids changing it on a live chain,
|
|
1835
|
+
* precisely because clients derive `tree_id` from a global leaf index with it.
|
|
1836
|
+
* It does NOT pin it to 2^20: a chain configured lower still passes, and this
|
|
1837
|
+
* constant would then place notes in the wrong tree.
|
|
1683
1838
|
*
|
|
1684
|
-
* Exported so a host can reason about tree boundaries
|
|
1839
|
+
* Exported so a host can reason about tree boundaries — and so a deployment on
|
|
1840
|
+
* a differently-configured chain has one place to look.
|
|
1685
1841
|
*/
|
|
1686
1842
|
declare const LEAVES_PER_TREE: number;
|
|
1687
1843
|
/**
|
|
@@ -1922,6 +2078,18 @@ declare function deriveSpendingKeyMessageV2(chainId: number, address: string): s
|
|
|
1922
2078
|
*/
|
|
1923
2079
|
declare function canonicalAccountId(address: string): string;
|
|
1924
2080
|
|
|
2081
|
+
/**
|
|
2082
|
+
* The derivation scheme an identity was built under.
|
|
2083
|
+
*
|
|
2084
|
+
* Only `v3` exists. It lives here, beside the derivations themselves, rather
|
|
2085
|
+
* than in the wallet: the vault name and the address scheme both hang off it,
|
|
2086
|
+
* and having `protocol` reach up into `wallet` for the type would invert the
|
|
2087
|
+
* layering for a single string union.
|
|
2088
|
+
*
|
|
2089
|
+
* Kept as a named union rather than dropped: the next scheme gets added here,
|
|
2090
|
+
* and a bare string would let a typo pick a vault nobody ever wrote to.
|
|
2091
|
+
*/
|
|
2092
|
+
type IdentityVersion = 'v3';
|
|
1925
2093
|
/**
|
|
1926
2094
|
* Reduces master key bytes to the circuit's spending-key scalar.
|
|
1927
2095
|
*
|
|
@@ -1934,17 +2102,46 @@ declare function canonicalAccountId(address: string): string;
|
|
|
1934
2102
|
*/
|
|
1935
2103
|
declare function deriveSpendingKeyFromMaster(masterBytes: Uint8Array): bigint;
|
|
1936
2104
|
/**
|
|
1937
|
-
*
|
|
2105
|
+
* The v2 viewing secret key, chained off the SPENDING key.
|
|
1938
2106
|
* ivsk = HKDF-SHA256(ikm=bigintTo32Le(spendingKey), info="orbinum-ivk-v1")
|
|
1939
2107
|
*
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1942
|
-
*
|
|
2108
|
+
* NOT what a v3 wallet uses. `deriveViewingSecretKeyV3(masterBytes)` is the
|
|
2109
|
+
* live branch, and the two produce DIFFERENT keys from one signature: deriving
|
|
2110
|
+
* this one beside a v3 identity yields a second wallet whose notes the first
|
|
2111
|
+
* cannot see. `PrivacyKeyManager` only ever calls the v3 branch.
|
|
2112
|
+
*
|
|
2113
|
+
* Chaining off the spending key is exactly what v3 removed — it made a viewing
|
|
2114
|
+
* key impossible to delegate, since anything that revealed it revealed the key
|
|
2115
|
+
* that spends. Kept for reading material derived under the older scheme.
|
|
1943
2116
|
*
|
|
1944
|
-
* SECURITY:
|
|
1945
|
-
*
|
|
2117
|
+
* SECURITY: a symmetric secret — never embed it in a shareable address. Use
|
|
2118
|
+
* `deriveViewingPublicKey()` for the public half.
|
|
1946
2119
|
*/
|
|
1947
2120
|
declare function deriveViewingSecretKey(spendingKey: bigint): Uint8Array;
|
|
2121
|
+
/**
|
|
2122
|
+
* The v3 spending scalar — the authority to move funds, and nothing else.
|
|
2123
|
+
*
|
|
2124
|
+
* Reduced into the curve's scalar field like its v2 counterpart, so the circuit
|
|
2125
|
+
* accepts it unchanged. Unlike v2 it is a LEAF: no other key hangs off it.
|
|
2126
|
+
*/
|
|
2127
|
+
declare function deriveSpendingKeyV3(rootSecret: Uint8Array): bigint;
|
|
2128
|
+
/**
|
|
2129
|
+
* The v3 incoming viewing key — read what arrives, spend nothing.
|
|
2130
|
+
*
|
|
2131
|
+
* This is the branch that makes a watch-only wallet possible: it is a sibling of
|
|
2132
|
+
* the spending key, so holding it proves nothing about the spending key and
|
|
2133
|
+
* gives no path to it.
|
|
2134
|
+
*/
|
|
2135
|
+
declare function deriveViewingSecretKeyV3(rootSecret: Uint8Array): Uint8Array;
|
|
2136
|
+
/**
|
|
2137
|
+
* The v3 outgoing viewing key — read what this wallet SENT.
|
|
2138
|
+
*
|
|
2139
|
+
* Seeds the outgoing ephemerals and the recipient book, so a holder can
|
|
2140
|
+
* enumerate every payment the wallet made and name who received it. That is the
|
|
2141
|
+
* capability, not a leak — but it makes this strictly more sensitive than the
|
|
2142
|
+
* incoming viewing key, which only reveals what arrived.
|
|
2143
|
+
*/
|
|
2144
|
+
declare function deriveOutgoingViewingKeyV3(rootSecret: Uint8Array): Uint8Array;
|
|
1948
2145
|
/**
|
|
1949
2146
|
* Derive the packed BabyJubJub viewing public key (ivk) from ivsk bytes.
|
|
1950
2147
|
*
|
|
@@ -1955,7 +2152,7 @@ declare function deriveViewingSecretKey(spendingKey: bigint): Uint8Array;
|
|
|
1955
2152
|
* The packed bigint is stored in little-endian so it is consistent with the
|
|
1956
2153
|
* rest of the SDK's 32-byte scalar encoding (bigintTo32Le / bytesToBigintLE).
|
|
1957
2154
|
*
|
|
1958
|
-
* @param ivsk 32-byte
|
|
2155
|
+
* @param ivsk 32-byte viewing secret key — `deriveViewingSecretKeyV3` on v3.
|
|
1959
2156
|
* @returns 32-byte LE-encoded packed BJJ point (goes in the privacy address).
|
|
1960
2157
|
*/
|
|
1961
2158
|
declare function deriveViewingPublicKey(ivsk: Uint8Array): Uint8Array;
|
|
@@ -1966,20 +2163,6 @@ declare function deriveViewingPublicKey(ivsk: Uint8Array): Uint8Array;
|
|
|
1966
2163
|
* Returns 0n if BabyJubJub computation fails (e.g. invalid scalar).
|
|
1967
2164
|
*/
|
|
1968
2165
|
declare function deriveOwnerPk(spendingKey: bigint): bigint;
|
|
1969
|
-
/**
|
|
1970
|
-
* Derive the 32-byte outgoing viewing key (ovk) from master bytes.
|
|
1971
|
-
* ovk = HKDF-SHA256(ikm=masterBytes, info="orbinum-ovk-v1")
|
|
1972
|
-
*
|
|
1973
|
-
* Mirror of the vault-key derivation: rooted at masterBytes, not the spendingKey
|
|
1974
|
-
* scalar (see the derivation chain above for why). The ovk lets the SENDER of a
|
|
1975
|
-
* private transfer recover what they sent — it wraps the memo's shared secret so
|
|
1976
|
-
* a cold restore rebuilds the outgoing history. Sibling of the ivsk, delegable
|
|
1977
|
-
* independently.
|
|
1978
|
-
*
|
|
1979
|
-
* SECRET. Never embed it in a shareable address — it stays out of
|
|
1980
|
-
* encodePrivacyAddress by construction (there is no public component to derive).
|
|
1981
|
-
*/
|
|
1982
|
-
declare function deriveOutgoingViewingKey(masterBytes: Uint8Array): Uint8Array;
|
|
1983
2166
|
|
|
1984
2167
|
/**
|
|
1985
2168
|
* PrivacyKeyManager
|
|
@@ -1994,17 +2177,31 @@ declare function deriveOutgoingViewingKey(masterBytes: Uint8Array): Uint8Array;
|
|
|
1994
2177
|
* The caller (application layer) is responsible for key persistence and session
|
|
1995
2178
|
* caching. Each instance holds independent state — safe for multi-wallet use.
|
|
1996
2179
|
*
|
|
1997
|
-
* Derivation scheme (from wallet signature):
|
|
2180
|
+
* Derivation scheme (from wallet signature) — every branch hangs off the root:
|
|
1998
2181
|
* sig → HKDF → masterBytes (32 bytes, stable root for all derived keys)
|
|
1999
|
-
* ├── spendingKey =
|
|
2000
|
-
* ├── viewingSecretKey = HKDF(
|
|
2001
|
-
* ├──
|
|
2182
|
+
* ├── spendingKey = HKDF(masterBytes, info="orbinum-spend-v3") (circuit scalar)
|
|
2183
|
+
* ├── viewingSecretKey = HKDF(masterBytes, info="orbinum-ivk-v3") ← delegable
|
|
2184
|
+
* ├── outgoingViewingKey= HKDF(masterBytes, info="orbinum-ovk-v3") ← own-payment recovery
|
|
2185
|
+
* ├── viewingPublicKey = packPoint(BJJ_mul(Base8, ivsk_scalar)) ← in the privacy address
|
|
2002
2186
|
* ├── ownerPk = BabyJubJub Ax from (spendingKey × Base8)
|
|
2003
2187
|
* └── vaultKey = HKDF(masterBytes, info="orbinum-vault-key-v1") ← stable
|
|
2004
2188
|
*
|
|
2189
|
+
* The branches are DISJOINT: knowing one reveals nothing about the others, so a
|
|
2190
|
+
* viewing key can be handed out without handing out the ability to spend.
|
|
2191
|
+
*
|
|
2005
2192
|
* Cache format: "mk:0x{masterBytes_hex}" — storing masterBytes (not the sk scalar)
|
|
2006
2193
|
* ensures the vault key remains stable if the circuit modulus ever changes.
|
|
2007
2194
|
*/
|
|
2195
|
+
|
|
2196
|
+
/**
|
|
2197
|
+
* Every address scheme this decoder still READS.
|
|
2198
|
+
*
|
|
2199
|
+
* Reading an old address is not the same as supporting the old identity: an
|
|
2200
|
+
* address is just an owner key plus a viewing key, and paying one works no
|
|
2201
|
+
* matter which scheme derived it. Only `orbpriv3` is ever EMITTED — see
|
|
2202
|
+
* `encodePrivacyAddress`.
|
|
2203
|
+
*/
|
|
2204
|
+
type PrivacyAddressScheme = 'orbpriv1' | 'orbpriv2' | 'orbpriv3';
|
|
2008
2205
|
declare class PrivacyKeyManager {
|
|
2009
2206
|
private _state;
|
|
2010
2207
|
/**
|
|
@@ -2012,11 +2209,12 @@ declare class PrivacyKeyManager {
|
|
|
2012
2209
|
* Derives viewingSecretKey, viewingPublicKeyPacked, and ownerPk immediately.
|
|
2013
2210
|
* Replaces any previously loaded key.
|
|
2014
2211
|
*
|
|
2015
|
-
* @param
|
|
2016
|
-
*
|
|
2017
|
-
*
|
|
2212
|
+
* @param _legacySpendingKey IGNORED. Kept so v2-era callers still compile;
|
|
2213
|
+
* the scalar is re-derived from `masterBytes`.
|
|
2214
|
+
* @param masterBytes Raw 32-byte HKDF output. The root every v3 branch and
|
|
2215
|
+
* the stable vault key hang off.
|
|
2018
2216
|
*/
|
|
2019
|
-
load(
|
|
2217
|
+
load(_legacySpendingKey: bigint, masterBytes: Uint8Array): Promise<void>;
|
|
2020
2218
|
/** Clear all key material from memory. Call on vault lock / sign-out. */
|
|
2021
2219
|
clear(): void;
|
|
2022
2220
|
/** Returns true if a spending key has been loaded. */
|
|
@@ -2037,13 +2235,24 @@ declare class PrivacyKeyManager {
|
|
|
2037
2235
|
* Throws if not loaded.
|
|
2038
2236
|
*/
|
|
2039
2237
|
getViewingPublicKeyPacked(): Uint8Array;
|
|
2040
|
-
/** Returns the BabyJubJub owner public key (x-coordinate). Throws if not loaded. */
|
|
2041
|
-
getOwnerPk(): bigint;
|
|
2042
2238
|
/**
|
|
2043
|
-
*
|
|
2044
|
-
*
|
|
2239
|
+
* The OUTGOING viewing key (ovk) — reads what this wallet SENT.
|
|
2240
|
+
*
|
|
2241
|
+
* Seeds the outgoing ephemeral sequence and opens the recipient book, so a
|
|
2242
|
+
* holder can enumerate every payment the wallet made and name who received
|
|
2243
|
+
* it. That makes it strictly more sensitive than the incoming viewing key,
|
|
2244
|
+
* which yields amounts and no counterparties: hand it out only where the
|
|
2245
|
+
* payment graph is meant to travel with it.
|
|
2246
|
+
*
|
|
2247
|
+
* A scan without it still finds every note the wallet OWNS and simply
|
|
2248
|
+
* reconstructs no sent history — the watch-only case.
|
|
2249
|
+
*
|
|
2250
|
+
* SECURITY: never expose this in an address or a network request.
|
|
2251
|
+
* Throws if not loaded.
|
|
2045
2252
|
*/
|
|
2046
2253
|
getOutgoingViewingKey(): Uint8Array;
|
|
2254
|
+
/** Returns the BabyJubJub owner public key (x-coordinate). Throws if not loaded. */
|
|
2255
|
+
getOwnerPk(): bigint;
|
|
2047
2256
|
/** Returns the spending key as a 32-byte little-endian Uint8Array. Throws if not loaded. */
|
|
2048
2257
|
getSpendingKeyBytes(): Uint8Array;
|
|
2049
2258
|
/**
|
|
@@ -2062,7 +2271,7 @@ declare class PrivacyKeyManager {
|
|
|
2062
2271
|
* Exports a shareable privacy address encoding the owner public key and
|
|
2063
2272
|
* viewing PUBLIC key of the currently loaded identity.
|
|
2064
2273
|
*
|
|
2065
|
-
* Format: `
|
|
2274
|
+
* Format: `orbpriv3:{ownerPk_hex}:{viewingPublicKey_hex}:{checksum}`
|
|
2066
2275
|
*
|
|
2067
2276
|
* The recipient uses this address so the sender can:
|
|
2068
2277
|
* 1. Embed `ownerPk` in the note commitment (Poseidon4 input).
|
|
@@ -2077,24 +2286,35 @@ declare class PrivacyKeyManager {
|
|
|
2077
2286
|
*
|
|
2078
2287
|
* Throws if no key is loaded.
|
|
2079
2288
|
*/
|
|
2080
|
-
encodePrivacyAddress(): string;
|
|
2289
|
+
encodePrivacyAddress(version?: IdentityVersion): string;
|
|
2081
2290
|
/**
|
|
2082
2291
|
* Decode a privacy address into `{ ownerPkHex, viewingPublicKeyHex }`, or
|
|
2083
2292
|
* `null` if it does not parse.
|
|
2084
2293
|
*
|
|
2085
|
-
*
|
|
2086
|
-
*
|
|
2087
|
-
*
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2294
|
+
* Reads every scheme ever emitted; only `orbpriv3` is written.
|
|
2295
|
+
*
|
|
2296
|
+
* - `orbpriv3` / `orbpriv2` — checksum verified; a mismatch (corrupted
|
|
2297
|
+
* paste, or a relabelled prefix) returns null.
|
|
2298
|
+
* - `orbpriv1` — legacy, predates the checksum entirely. The FIELDS are
|
|
2299
|
+
* validated exactly as above, since this branch has no integrity check
|
|
2300
|
+
* of its own.
|
|
2301
|
+
*
|
|
2302
|
+
* Reading an old address is not the same as supporting an old identity. An
|
|
2303
|
+
* address is an owner key and a viewing key; paying one works whatever
|
|
2304
|
+
* scheme derived it, and whoever shares it may not have upgraded yet.
|
|
2305
|
+
* Refusing them here would break incoming payments for no gain.
|
|
2090
2306
|
*/
|
|
2091
2307
|
static decodePrivacyAddress(address: string): {
|
|
2092
2308
|
ownerPkHex: string;
|
|
2093
2309
|
viewingPublicKeyHex: string;
|
|
2310
|
+
scheme: PrivacyAddressScheme;
|
|
2094
2311
|
} | null;
|
|
2095
2312
|
/**
|
|
2096
2313
|
* Load keys from a cached "mk:0x{masterBytes_hex}" string produced by exportHex().
|
|
2097
|
-
*
|
|
2314
|
+
*
|
|
2315
|
+
* Throws on a bad prefix, on non-hex content, and on a master that is not
|
|
2316
|
+
* 32 usable bytes — an all-zero one included, since every wallet would
|
|
2317
|
+
* derive the same identity from it.
|
|
2098
2318
|
*/
|
|
2099
2319
|
importFromHex(hex: string): Promise<void>;
|
|
2100
2320
|
}
|
|
@@ -2110,14 +2330,19 @@ declare const MIN_SIGNATURE_BYTES = 32;
|
|
|
2110
2330
|
*
|
|
2111
2331
|
* masterBytes = HKDF-SHA256(ikm=sigBytes, salt=empty, info="orbinum-sk-v2:{chainId}:{address}")
|
|
2112
2332
|
*
|
|
2113
|
-
* These bytes are the stable root for ALL derived keys
|
|
2114
|
-
*
|
|
2115
|
-
* -
|
|
2333
|
+
* These bytes are the stable root for ALL derived keys, each its own HKDF
|
|
2334
|
+
* branch of the SAME root — none derived from another:
|
|
2335
|
+
* - spendingKey (circuit scalar) = HKDF(masterBytes, info="orbinum-spend-v3")
|
|
2336
|
+
* - viewingSecretKey = HKDF(masterBytes, info="orbinum-ivk-v3")
|
|
2337
|
+
* - outgoingViewingKey = HKDF(masterBytes, info="orbinum-ovk-v3")
|
|
2116
2338
|
* - vaultKey = HKDF(masterBytes, info="orbinum-vault-key-v1")
|
|
2117
2339
|
*
|
|
2118
|
-
*
|
|
2119
|
-
*
|
|
2120
|
-
*
|
|
2340
|
+
* Disjoint branches are what make a viewing key delegable: handing one out
|
|
2341
|
+
* grants sight and never the ability to spend.
|
|
2342
|
+
*
|
|
2343
|
+
* Separating masterBytes from the circuit scalar also keeps the viewing and
|
|
2344
|
+
* vault keys STABLE across any future change to the modulus — they never depend
|
|
2345
|
+
* on which prime field the circuit uses.
|
|
2121
2346
|
*
|
|
2122
2347
|
* @throws If the signature is not valid hex, or carries less entropy than the
|
|
2123
2348
|
* shortest real signing scheme (see {@link MIN_SIGNATURE_BYTES}).
|
|
@@ -2126,12 +2351,13 @@ declare function deriveMasterKeyBytes(signatureHex: string, chainId: number, add
|
|
|
2126
2351
|
/**
|
|
2127
2352
|
* Derives an Orbinum spending key from a wallet signature.
|
|
2128
2353
|
*
|
|
2129
|
-
*
|
|
2130
|
-
*
|
|
2354
|
+
* Reduces the master bytes modulo BABYJUB_SUBORDER directly. NOT the v3
|
|
2355
|
+
* branch — a v3 wallet derives its spending key with
|
|
2356
|
+
* `deriveSpendingKeyV3(masterBytes)`, through HKDF under `orbinum-spend-v3`,
|
|
2357
|
+
* and the two produce different scalars from the same signature.
|
|
2131
2358
|
*
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2134
|
-
* keys remain stable if the circuit's modulus ever changes again.
|
|
2359
|
+
* Kept for reading material derived under the older scheme. Every other key
|
|
2360
|
+
* comes from `masterBytes` and never from this scalar, so it is not a root.
|
|
2135
2361
|
*
|
|
2136
2362
|
* @param signatureHex 0x-prefixed or bare hex of the wallet signature.
|
|
2137
2363
|
* @param chainId Chain ID used when building the signing message.
|
|
@@ -2142,6 +2368,21 @@ declare function deriveMasterKeyBytes(signatureHex: string, chainId: number, add
|
|
|
2142
2368
|
*/
|
|
2143
2369
|
declare function deriveSpendingKeyFromSignature(signatureHex: string, chainId: number, address: string): Promise<bigint>;
|
|
2144
2370
|
|
|
2371
|
+
/**
|
|
2372
|
+
* Witness assembly for the unshield circuit — one note in, a public payout and
|
|
2373
|
+
* an optional change note out.
|
|
2374
|
+
*
|
|
2375
|
+
* The only entry point here that BUILDS anything rather than marshalling it:
|
|
2376
|
+
* a partial unshield needs a change note, and its blinding and commitment are
|
|
2377
|
+
* computed here when the caller does not supply them. The blinding comes from
|
|
2378
|
+
* a CSPRNG — it is the only unknown in `Poseidon4(value, assetId, ownerPk,
|
|
2379
|
+
* blinding)` once an observer guesses the amount, so a predictable one makes
|
|
2380
|
+
* the commitment brute-forceable.
|
|
2381
|
+
*
|
|
2382
|
+
* A total unshield has no change, and the circuit constrains its commitment to
|
|
2383
|
+
* be exactly zero — not a commitment to a zero-value note.
|
|
2384
|
+
*/
|
|
2385
|
+
|
|
2145
2386
|
/**
|
|
2146
2387
|
* Inputs required to generate an Unshield proof.
|
|
2147
2388
|
*
|
|
@@ -2698,7 +2939,10 @@ declare class EvmClient {
|
|
|
2698
2939
|
request<T>(method: string, params?: unknown[]): Promise<T>;
|
|
2699
2940
|
/**
|
|
2700
2941
|
* Performs multiple JSON-RPC calls in a single HTTP request (batch).
|
|
2701
|
-
*
|
|
2942
|
+
*
|
|
2943
|
+
* Results come back in the order of `calls`, as a typed tuple. A call the
|
|
2944
|
+
* server answered with an error, or did not answer at all, lands as `null`
|
|
2945
|
+
* in its own slot — never shifting the ones after it.
|
|
2702
2946
|
*/
|
|
2703
2947
|
batchRequest<T extends unknown[]>(calls: Array<{
|
|
2704
2948
|
method: string;
|
|
@@ -2726,7 +2970,10 @@ declare class EvmClient {
|
|
|
2726
2970
|
sendRawTransaction(signedHex: string): Promise<string>;
|
|
2727
2971
|
/** Executes a read-only call without creating a transaction. Returns the raw ABI-encoded response. */
|
|
2728
2972
|
call(to: string, data: string, from?: string): Promise<string>;
|
|
2729
|
-
/**
|
|
2973
|
+
/**
|
|
2974
|
+
* Estimates a transaction's gas, in GAS UNITS — not wei. Multiply by
|
|
2975
|
+
* `getGasPrice()` for a cost.
|
|
2976
|
+
*/
|
|
2730
2977
|
estimateGas(params: {
|
|
2731
2978
|
from?: string;
|
|
2732
2979
|
to: string;
|
|
@@ -2787,7 +3034,11 @@ interface EvmTransaction {
|
|
|
2787
3034
|
nonce: number;
|
|
2788
3035
|
/** ABI-encoded call data (0x-prefixed hex). `'0x'` for plain transfers. */
|
|
2789
3036
|
input: string;
|
|
2790
|
-
/**
|
|
3037
|
+
/**
|
|
3038
|
+
* `1` for success, `0` for revert — and `0` ALSO when no receipt could be
|
|
3039
|
+
* read, which is what a pending transaction or a failed receipt call looks
|
|
3040
|
+
* like. Not proof of a revert on its own.
|
|
3041
|
+
*/
|
|
2791
3042
|
status: number;
|
|
2792
3043
|
/** Deployed contract address for contract-creation transactions; `null` otherwise. */
|
|
2793
3044
|
contractAddress: string | null;
|
|
@@ -2823,7 +3074,12 @@ interface EvmAddressInfo {
|
|
|
2823
3074
|
codeSize: number;
|
|
2824
3075
|
/** Deployed bytecode (truncated to 100 bytes + ellipsis for display). `'0x'` for EOAs. */
|
|
2825
3076
|
code: string;
|
|
2826
|
-
/**
|
|
3077
|
+
/**
|
|
3078
|
+
* Up to 50 recent logs EMITTED BY this address — `eth_getLogs` filters on
|
|
3079
|
+
* the emitting contract, so nothing where the address merely appears as an
|
|
3080
|
+
* indexed topic is here. A plain EOA emits nothing and gets an empty list;
|
|
3081
|
+
* `getTokenTransfers` is the call that finds received activity.
|
|
3082
|
+
*/
|
|
2827
3083
|
recentLogs: EvmLog[];
|
|
2828
3084
|
}
|
|
2829
3085
|
/** EVM block header with transaction hashes (not full tx objects). */
|
|
@@ -2865,7 +3121,12 @@ interface EvmTxSummary {
|
|
|
2865
3121
|
gasUsed: number;
|
|
2866
3122
|
/** Gas price in wei, as a 0x-prefixed hex string. */
|
|
2867
3123
|
gasPrice: string;
|
|
2868
|
-
/**
|
|
3124
|
+
/**
|
|
3125
|
+
* `true` on receipt status `0x1` — and ALSO when no receipt could be read,
|
|
3126
|
+
* since a transaction still in the pool has not failed. Optimistic by
|
|
3127
|
+
* design, and the opposite default from `EvmTransaction.status`: read it as
|
|
3128
|
+
* "not known to have failed", never as confirmed success.
|
|
3129
|
+
*/
|
|
2869
3130
|
status: boolean;
|
|
2870
3131
|
/** `true` when the transaction created a new contract (`to` is `null`). */
|
|
2871
3132
|
isContractCreation: boolean;
|
|
@@ -2926,7 +3187,7 @@ declare class EvmExplorer {
|
|
|
2926
3187
|
getTransactionsByAddress(address: string, maxBlocks?: number): Promise<EvmTxSummary[]>;
|
|
2927
3188
|
/**
|
|
2928
3189
|
* Returns aggregated on-chain data for an EVM address: balance, nonce,
|
|
2929
|
-
* bytecode (truncated), and up to 50
|
|
3190
|
+
* bytecode (truncated), and up to 50 logs it EMITTED in the last 1 001 blocks.
|
|
2930
3191
|
*/
|
|
2931
3192
|
getAddressInfo(address: string): Promise<EvmAddressInfo>;
|
|
2932
3193
|
/** Returns the native token balance of `address`, formatted as a decimal string (no symbol). */
|
|
@@ -2941,7 +3202,7 @@ declare class EvmExplorer {
|
|
|
2941
3202
|
*/
|
|
2942
3203
|
getTokenInfo(address: string): Promise<TokenInfo | null>;
|
|
2943
3204
|
/**
|
|
2944
|
-
* Returns ERC-20 `Transfer` events for `address` from the last 1
|
|
3205
|
+
* Returns ERC-20 `Transfer` events for `address` from the last 1 001 blocks.
|
|
2945
3206
|
* When `holderAddress` is provided, restricts results to transfers sent or received by that address.
|
|
2946
3207
|
*/
|
|
2947
3208
|
getTokenTransfers(address: string, holderAddress?: string): Promise<TokenTransfer[]>;
|
|
@@ -3316,8 +3577,14 @@ declare class PrivacyModule {
|
|
|
3316
3577
|
constructor(substrate: SubstrateClient);
|
|
3317
3578
|
/** Returns the current Merkle tree root. */
|
|
3318
3579
|
getMerkleRoot(): Promise<string>;
|
|
3319
|
-
/**
|
|
3320
|
-
|
|
3580
|
+
/**
|
|
3581
|
+
* Returns the Merkle proof for a LEAF INDEX.
|
|
3582
|
+
*
|
|
3583
|
+
* The node declares this parameter `u32`, so a commitment hex is rejected
|
|
3584
|
+
* by deserialisation before any lookup runs — `getMerkleProofByCommitment`
|
|
3585
|
+
* is the one that takes a string.
|
|
3586
|
+
*/
|
|
3587
|
+
getMerkleProof(leafIndex: number): Promise<RpcV2MerkleProof>;
|
|
3321
3588
|
/**
|
|
3322
3589
|
* Returns the Merkle inclusion proof for a given commitment hex,
|
|
3323
3590
|
* bundled with the Merkle root.
|
|
@@ -3572,9 +3839,17 @@ declare class CryptoPrecompiles {
|
|
|
3572
3839
|
* const stats = await client.privacy.getPoolStats();
|
|
3573
3840
|
* console.log('root:', stats.merkleRoot, 'leaves:', stats.commitmentCount);
|
|
3574
3841
|
*
|
|
3575
|
-
* // Shield tokens (with a SubstrateSigner)
|
|
3842
|
+
* // Shield tokens (with a SubstrateSigner). `NoteBuilder.build` produces the
|
|
3843
|
+
* // commitment and the 180-byte memo together — both are required, and a note
|
|
3844
|
+
* // shielded without a valid memo is unrecoverable.
|
|
3845
|
+
* const note = await NoteBuilder.build({ value: 1000n, assetId: 1n, ownerPk });
|
|
3576
3846
|
* const result = await client.shieldedPool.shield(
|
|
3577
|
-
* {
|
|
3847
|
+
* {
|
|
3848
|
+
* assetId: 1,
|
|
3849
|
+
* amount: note.value,
|
|
3850
|
+
* commitment: note.commitmentHex,
|
|
3851
|
+
* encryptedMemo: Uint8Array.from(note.memo),
|
|
3852
|
+
* },
|
|
3578
3853
|
* signer,
|
|
3579
3854
|
* );
|
|
3580
3855
|
* console.log('tx ok:', result.ok, 'block:', result.blockHash);
|
|
@@ -3797,9 +4072,13 @@ declare class OrbinumClientProvider {
|
|
|
3797
4072
|
private stopStableTimer;
|
|
3798
4073
|
/**
|
|
3799
4074
|
* Schedules the next connection attempt using exponential backoff
|
|
3800
|
-
* (capped at `reconnectMaxMs`) with
|
|
3801
|
-
* `'reconnecting'`.
|
|
3802
|
-
*
|
|
4075
|
+
* (capped at `reconnectMaxMs`) with EQUAL jitter, then transitions to
|
|
4076
|
+
* `'reconnecting'`.
|
|
4077
|
+
*
|
|
4078
|
+
* The delay lands in `[capped/2, capped]` — half fixed, half random. That
|
|
4079
|
+
* spreads a shared outage's reconnects over a `capped/2` window instead of
|
|
4080
|
+
* having every client retry in lockstep, while keeping a floor so the first
|
|
4081
|
+
* attempts do not all pile up near zero the way full jitter allows.
|
|
3803
4082
|
*/
|
|
3804
4083
|
private scheduleReconnect;
|
|
3805
4084
|
private cancelReconnect;
|
|
@@ -3832,11 +4111,19 @@ declare class OrbinumClientProvider {
|
|
|
3832
4111
|
}
|
|
3833
4112
|
|
|
3834
4113
|
/**
|
|
3835
|
-
*
|
|
4114
|
+
* Naming the positional fields of a decoded extrinsic or event.
|
|
4115
|
+
*
|
|
4116
|
+
* A Substrate/PAPI node returns `arg0`, `arg1`, … when metadata-based decoding
|
|
4117
|
+
* is unavailable. These two tables map those positions onto the field names the
|
|
4118
|
+
* pallets declare, so a caller reads `nullifier` instead of `arg2`.
|
|
4119
|
+
*
|
|
4120
|
+
* BEST EFFORT, BY METHOD NAME ONLY. Neither helper is given the pallet section,
|
|
4121
|
+
* so two pallets that declare the same method name are indistinguishable here —
|
|
4122
|
+
* see the `Executed` note below. A consumer that needs certainty decodes
|
|
4123
|
+
* against metadata instead.
|
|
3836
4124
|
*
|
|
3837
|
-
*
|
|
3838
|
-
*
|
|
3839
|
-
* to human-readable semantic names for all Orbinum pallets.
|
|
4125
|
+
* `events.ts` is the canonical model of the shielded-pool events; this file is
|
|
4126
|
+
* a display convenience and does not replace it.
|
|
3840
4127
|
*/
|
|
3841
4128
|
/**
|
|
3842
4129
|
* Maps raw extrinsic args (which may use positional keys like `arg0`, `arg1`)
|
|
@@ -3872,16 +4159,14 @@ declare class RpcV2Module {
|
|
|
3872
4159
|
/**
|
|
3873
4160
|
* Classification of shielded-pool failures out of raw chain errors.
|
|
3874
4161
|
*
|
|
3875
|
-
*
|
|
3876
|
-
*
|
|
3877
|
-
*
|
|
3878
|
-
*
|
|
4162
|
+
* Pallet vocabulary, not app policy. The strings are the runtime's error
|
|
4163
|
+
* variants, and what each MEANS for a wallet — resync, purge a note, retry — is
|
|
4164
|
+
* protocol knowledge: without it a ghost note reads as a generic failure and
|
|
4165
|
+
* the unspendable note stays in the vault.
|
|
3879
4166
|
*
|
|
3880
|
-
*
|
|
3881
|
-
*
|
|
3882
|
-
*
|
|
3883
|
-
* that `UnknownMerkleRoot` means "rescan and retry" while phrasing it however
|
|
3884
|
-
* they like.
|
|
4167
|
+
* This module answers "what kind of failure, and what should a wallet DO"; the
|
|
4168
|
+
* words a person reads belong to the host. Two wallets should agree that
|
|
4169
|
+
* `UnknownMerkleRoot` means "rescan and retry" while phrasing it differently.
|
|
3885
4170
|
*/
|
|
3886
4171
|
/**
|
|
3887
4172
|
* The pallet error name inside a raw chain error, or null.
|
|
@@ -4022,7 +4307,7 @@ type ShieldedEvent = {
|
|
|
4022
4307
|
amount: bigint;
|
|
4023
4308
|
/** 0x-prefixed 32-byte Poseidon commitment (LE). */
|
|
4024
4309
|
commitment: string;
|
|
4025
|
-
/** 0x-prefixed encrypted memo bytes
|
|
4310
|
+
/** 0x-prefixed encrypted memo (180 bytes — see `ENCRYPTED_MEMO_SIZE`). */
|
|
4026
4311
|
encryptedMemo: string;
|
|
4027
4312
|
/** Leaf index assigned in the Merkle tree. */
|
|
4028
4313
|
leafIndex: number;
|
|
@@ -4051,7 +4336,11 @@ type CommitmentsInsertedEvent = {
|
|
|
4051
4336
|
};
|
|
4052
4337
|
/**
|
|
4053
4338
|
* Emitted by `unshield()` when a note is withdrawn to the public chain.
|
|
4054
|
-
*
|
|
4339
|
+
*
|
|
4340
|
+
* Rust variant: `Unshielded { nullifier, amount, recipient, change_commitment,
|
|
4341
|
+
* change_encrypted_memo, change_leaf_index }`. The last two are NOT modelled
|
|
4342
|
+
* here — a consumer that needs the change note's memo or its leaf position
|
|
4343
|
+
* reads the raw event, or finds the note by scanning.
|
|
4055
4344
|
*/
|
|
4056
4345
|
type UnshieldedEvent = {
|
|
4057
4346
|
/** 0x-prefixed 32-byte Poseidon nullifier (LE). */
|
|
@@ -4074,7 +4363,11 @@ type MerkleRootUpdatedEvent = {
|
|
|
4074
4363
|
oldRoot: string;
|
|
4075
4364
|
/** 0x-prefixed new Merkle root (32 bytes, LE). */
|
|
4076
4365
|
newRoot: string;
|
|
4077
|
-
/**
|
|
4366
|
+
/**
|
|
4367
|
+
* Total leaves ever inserted, GLOBAL across the whole forest — never the
|
|
4368
|
+
* current tree's size. Dense and monotonic, which is what indexer chunking
|
|
4369
|
+
* and scan cursors rely on; per-tree size is `treeSize % LEAVES_PER_TREE`.
|
|
4370
|
+
*/
|
|
4078
4371
|
treeSize: number;
|
|
4079
4372
|
};
|
|
4080
4373
|
/**
|
|
@@ -4098,7 +4391,13 @@ type AssetVerifiedEvent = {
|
|
|
4098
4391
|
type AssetUnverifiedEvent = {
|
|
4099
4392
|
assetId: number;
|
|
4100
4393
|
};
|
|
4101
|
-
/**
|
|
4394
|
+
/**
|
|
4395
|
+
* The pallet events this SDK models, as a discriminated union.
|
|
4396
|
+
*
|
|
4397
|
+
* NOT every variant: `TreeSealed` (forest rotation) and `ValidatorFeesClaimed`
|
|
4398
|
+
* are emitted by the pallet and absent here. A consumer that acts on a tree
|
|
4399
|
+
* rotation has to read the raw event.
|
|
4400
|
+
*/
|
|
4102
4401
|
type ShieldedPoolEvent = {
|
|
4103
4402
|
type: 'Shielded';
|
|
4104
4403
|
data: ShieldedEvent;
|
|
@@ -4557,6 +4856,20 @@ interface TransferFactsSource {
|
|
|
4557
4856
|
byCommitments(commitments: string[]): Promise<TransferFactsRow[]>;
|
|
4558
4857
|
}
|
|
4559
4858
|
|
|
4859
|
+
/**
|
|
4860
|
+
* What a scan reports: progress while it runs, and its outcome when it ends.
|
|
4861
|
+
*
|
|
4862
|
+
* A host renders both, so these are the scanner's public vocabulary. The
|
|
4863
|
+
* counters are DIAGNOSTICS, not results — the notes themselves land in the
|
|
4864
|
+
* vault, and every field here exists so a host can tell a scan that found
|
|
4865
|
+
* nothing from a scan that failed to look.
|
|
4866
|
+
*
|
|
4867
|
+
* That distinction is the reason the discovery counters are surfaced at all:
|
|
4868
|
+
* the fast paths fail silently by design (a window that never matches costs
|
|
4869
|
+
* only speed), so without them "the fast path is off" and "the fast path ran
|
|
4870
|
+
* and matched nothing" are indistinguishable.
|
|
4871
|
+
*/
|
|
4872
|
+
|
|
4560
4873
|
/** Live progress, reported after each scanned page or chunk. */
|
|
4561
4874
|
interface ScanProgress {
|
|
4562
4875
|
scanned: number;
|
|
@@ -4573,12 +4886,48 @@ interface ScanResult {
|
|
|
4573
4886
|
purged: number;
|
|
4574
4887
|
/** Whether this was a full scan (from leafIndex 0) or an incremental one. */
|
|
4575
4888
|
incremental: boolean;
|
|
4889
|
+
/**
|
|
4890
|
+
* Notes this wallet SENT, recovered during the same sweep.
|
|
4891
|
+
*
|
|
4892
|
+
* Free of extra requests — the outgoing ephPk window recognises our own
|
|
4893
|
+
* payments, and the change notes in the same feed carry the recipient keys
|
|
4894
|
+
* that open them. Feed them to `reconstructOutgoingTxRecords` to turn a
|
|
4895
|
+
* derived history row into the exact amount, plus a re-issued payment slip.
|
|
4896
|
+
*/
|
|
4897
|
+
sentNotes: SentNoteMatch[];
|
|
4898
|
+
/**
|
|
4899
|
+
* How the scan found what it found — diagnostics, not results.
|
|
4900
|
+
*
|
|
4901
|
+
* The two fast routes recognise a note by hash lookup against a precomputed
|
|
4902
|
+
* window instead of a trial ECDH per hint, and they are the difference
|
|
4903
|
+
* between a scan that takes seconds and one that takes minutes. Both fail
|
|
4904
|
+
* SILENTLY: a window that never matches costs only speed, so the notes
|
|
4905
|
+
* quietly take the expensive path and nothing reports it.
|
|
4906
|
+
*
|
|
4907
|
+
* Surfaced here so a host can tell "the fast path is off" from "the fast
|
|
4908
|
+
* path ran". The counters existed before this and were accumulated where
|
|
4909
|
+
* nothing could read them.
|
|
4910
|
+
*/
|
|
4911
|
+
discovery: {
|
|
4912
|
+
/** Own notes matched via the self-eph window (shields, change). */
|
|
4913
|
+
self: number;
|
|
4914
|
+
/** Notes from registered counterparties matched via their pairwise window. */
|
|
4915
|
+
pairwise: number;
|
|
4916
|
+
/** Hints rejected by the 1-byte view-tag filter, before any AEAD work. */
|
|
4917
|
+
tagFiltered: number;
|
|
4918
|
+
};
|
|
4576
4919
|
}
|
|
4577
4920
|
|
|
4578
4921
|
interface WalletScanKeys {
|
|
4579
4922
|
viewingKey: Uint8Array;
|
|
4580
4923
|
spendingKey: bigint;
|
|
4581
4924
|
ownerPk: bigint;
|
|
4925
|
+
/**
|
|
4926
|
+
* Outgoing viewing key (ovk). Omit to scan WITHOUT payment history: every
|
|
4927
|
+
* note the wallet owns is still found, and the sender-side record of what
|
|
4928
|
+
* it paid simply is not reconstructed. That is the watch-only case.
|
|
4929
|
+
*/
|
|
4930
|
+
outgoingViewingKey?: Uint8Array;
|
|
4582
4931
|
}
|
|
4583
4932
|
interface RunScanParams {
|
|
4584
4933
|
vault: VaultStore;
|
|
@@ -4620,7 +4969,6 @@ declare function gapMargin(windowSize: number): number;
|
|
|
4620
4969
|
declare function resolveSelfEphCeiling(params: {
|
|
4621
4970
|
/** The wallet's notes AFTER persist — self notes carry their ephPk in the memo. */
|
|
4622
4971
|
notes: ZkNote[];
|
|
4623
|
-
spendingKey: bigint;
|
|
4624
4972
|
viewingKey: Uint8Array;
|
|
4625
4973
|
/** Highest window-matched index reported by the scan. */
|
|
4626
4974
|
scanMaxIndex: number | null;
|
|
@@ -4632,10 +4980,11 @@ declare function resolveSelfEphCeiling(params: {
|
|
|
4632
4980
|
* the gap margin) falls inside the fast path, and never past `MAX_EPH_WINDOW`.
|
|
4633
4981
|
*
|
|
4634
4982
|
* The counter is read from a config that survives restores and hand-editing, so
|
|
4635
|
-
* a non-finite value is treated as "no history" rather than propagated
|
|
4636
|
-
*
|
|
4637
|
-
*
|
|
4638
|
-
* that
|
|
4983
|
+
* a non-finite value is treated as "no history" rather than propagated. The
|
|
4984
|
+
* window builders reject a non-integer `count` outright, so passing one through
|
|
4985
|
+
* would abort the scan with a throw — turning a corrupt stored counter into a
|
|
4986
|
+
* wallet that cannot scan at all, where falling back to the default size costs
|
|
4987
|
+
* only the fast path for indexes past it.
|
|
4639
4988
|
*/
|
|
4640
4989
|
declare function windowSizeForCounter(counter: number): number;
|
|
4641
4990
|
|
|
@@ -4719,8 +5068,41 @@ interface ScanOutcome {
|
|
|
4719
5068
|
* path fired rather than the notes quietly taking the expensive route.
|
|
4720
5069
|
*/
|
|
4721
5070
|
pairwiseDiscovered: number;
|
|
5071
|
+
/**
|
|
5072
|
+
* Notes this wallet SENT, recovered in the same sweep.
|
|
5073
|
+
*
|
|
5074
|
+
* Free of extra requests: the outgoing ephPk window recognises our own
|
|
5075
|
+
* payments, and the change notes in the same feed carry the recipient keys
|
|
5076
|
+
* that open them. Kept out of `scanEntries` — the sender does not own them.
|
|
5077
|
+
*/
|
|
5078
|
+
sentNotes: SentNoteMatch[];
|
|
5079
|
+
/**
|
|
5080
|
+
* Recipient viewing keys learned while opening payments, as lowercase hex.
|
|
5081
|
+
*
|
|
5082
|
+
* Accumulated across the whole scan and fed forward, so a second payment to
|
|
5083
|
+
* the same person opens from the first one's key.
|
|
5084
|
+
*/
|
|
5085
|
+
learnedRecipients: Set<string>;
|
|
5086
|
+
/**
|
|
5087
|
+
* Payments recognised as ours that no batch managed to open.
|
|
5088
|
+
*
|
|
5089
|
+
* Their book entry sits in a change note that landed in a different page.
|
|
5090
|
+
* Kept so the caller can retry them once the whole feed has been read —
|
|
5091
|
+
* dropping one costs a history row and a re-issuable slip for good.
|
|
5092
|
+
*/
|
|
5093
|
+
unmatchedSent: UnmatchedSentHint[];
|
|
5094
|
+
/**
|
|
5095
|
+
* Every sealed book entry the scan saw, as decimal `sourcePk` strings.
|
|
5096
|
+
*
|
|
5097
|
+
* A payment and its change can land in different pages, and then neither
|
|
5098
|
+
* half is usable alone. Accumulating both across the whole scan is what lets
|
|
5099
|
+
* the final retry pair them up.
|
|
5100
|
+
*/
|
|
5101
|
+
sealedBookEntries: Set<string>;
|
|
4722
5102
|
/** Highest self-eph index seen — the caller bumps the vault counter past it. */
|
|
4723
5103
|
maxSelfEphIndex: number | null;
|
|
5104
|
+
/** Highest outgoing index seen — same repair, for the payment sequence. */
|
|
5105
|
+
maxOutgoingEphIndex: number | null;
|
|
4724
5106
|
}
|
|
4725
5107
|
interface CollectScanEntriesParams {
|
|
4726
5108
|
source: ScanHintSource;
|
|
@@ -4760,7 +5142,7 @@ interface CollectScanEntriesParams {
|
|
|
4760
5142
|
* discoveries into the set; harmless, since the ghost purge filters them.
|
|
4761
5143
|
*/
|
|
4762
5144
|
vaultHexes?: Set<string> | undefined;
|
|
4763
|
-
/** Sink for the
|
|
5145
|
+
/** Sink for the one non-fatal warning this phase emits: the chunk fallback. */
|
|
4764
5146
|
onWarning?: ((message: string, cause?: unknown) => void) | undefined;
|
|
4765
5147
|
}
|
|
4766
5148
|
/**
|
|
@@ -4804,31 +5186,21 @@ declare function resolveSpentStatus(params: {
|
|
|
4804
5186
|
}): Promise<Map<string, SpendDetails>>;
|
|
4805
5187
|
|
|
4806
5188
|
/**
|
|
4807
|
-
* Spent-status resolution —
|
|
4808
|
-
*
|
|
5189
|
+
* Spent-status resolution — which of the wallet's own nullifiers are spent,
|
|
5190
|
+
* WITHOUT ever asking the server about a specific one.
|
|
4809
5191
|
*
|
|
4810
|
-
*
|
|
4811
|
-
* implementation
|
|
4812
|
-
* exactly which notes the caller owns
|
|
4813
|
-
*
|
|
4814
|
-
*
|
|
5192
|
+
* The most important privacy property in the scanner, and the one a
|
|
5193
|
+
* re-implementation gets wrong by default: asking "is nullifier X spent?" tells
|
|
5194
|
+
* the server exactly which notes the caller owns. Instead the whole set is
|
|
5195
|
+
* downloaded and intersected locally, so every request looks identical for
|
|
5196
|
+
* every caller.
|
|
4815
5197
|
*
|
|
4816
|
-
* Sealed chunks make that affordable
|
|
4817
|
-
*
|
|
4818
|
-
*
|
|
5198
|
+
* Sealed chunks make that affordable — universal manifest, only missing chunks
|
|
5199
|
+
* fetched, the set persisted in the injected cache — so a scan transfers about
|
|
5200
|
+
* one chunk plus the tail rather than the entire set.
|
|
4819
5201
|
*
|
|
4820
5202
|
* On any hard failure the caller degrades: notes stay unspent and are
|
|
4821
|
-
* re-verified
|
|
4822
|
-
*
|
|
4823
|
-
* ## Hex casing
|
|
4824
|
-
*
|
|
4825
|
-
* The intersection is an exact string match, so both sides must agree on
|
|
4826
|
-
* casing. The wallet lowercases its own nullifiers before asking; the feed's
|
|
4827
|
-
* are lowercased HERE, on the way in. Skipping that makes an uppercase-serving
|
|
4828
|
-
* indexer report every spent note as unspent — the wallet then offers notes it
|
|
4829
|
-
* cannot spend, and each attempt dies on a duplicate nullifier. Normalising at
|
|
4830
|
-
* ingestion means the cache only ever holds one form, so a feed that changes
|
|
4831
|
-
* casing between runs cannot split one nullifier into two entries.
|
|
5203
|
+
* re-verified next pass.
|
|
4832
5204
|
*/
|
|
4833
5205
|
|
|
4834
5206
|
interface OpenSpentSetParams {
|
|
@@ -4881,26 +5253,19 @@ interface PersistParams {
|
|
|
4881
5253
|
}
|
|
4882
5254
|
/**
|
|
4883
5255
|
* The notes to purge as ghosts: unspent, absent from the on-chain set, and
|
|
4884
|
-
* already in the vault when the scan
|
|
5256
|
+
* already in the vault when the scan BEGAN.
|
|
4885
5257
|
*
|
|
4886
|
-
* That last condition
|
|
4887
|
-
*
|
|
4888
|
-
*
|
|
4889
|
-
*
|
|
4890
|
-
* absence alone deleted that note from memory AND storage seconds after the user
|
|
4891
|
-
* saw it, and only a later rescan brought it back.
|
|
5258
|
+
* That last condition protects a note the user just created. `onChainHexes` is
|
|
5259
|
+
* frozen as the scan pages the feed, so a shield or transfer landing mid-scan is
|
|
5260
|
+
* legitimately missing from it — purging on absence alone deleted such a note
|
|
5261
|
+
* from memory and storage seconds after the user saw it.
|
|
4892
5262
|
*
|
|
4893
|
-
* A note born mid-scan is
|
|
4894
|
-
* against a feed that has caught up, reconciles it.
|
|
5263
|
+
* A note born mid-scan is not this scan's business; the next pass reconciles it.
|
|
4895
5264
|
*/
|
|
4896
5265
|
declare function selectGhosts(notes: ZkNote[], onChainHexes: Set<string>, preScanHexes?: Set<string>): string[];
|
|
4897
5266
|
/**
|
|
4898
|
-
* Phase 3:
|
|
4899
|
-
*
|
|
4900
|
-
*
|
|
4901
|
-
* Both the scanned notes and the memo-failed reconciliation feed a SINGLE
|
|
4902
|
-
* saveMany → one storage transaction and one cache write, so subscribers
|
|
4903
|
-
* re-render once per call instead of once per note.
|
|
5267
|
+
* Phase 3: build the batched save-entry list, write it in one transaction, then
|
|
5268
|
+
* purge ghost notes (full scan only). Returns how many ghosts were purged.
|
|
4904
5269
|
*/
|
|
4905
5270
|
declare function persistScanResults(params: PersistParams): Promise<number>;
|
|
4906
5271
|
/**
|
|
@@ -4928,6 +5293,12 @@ interface ReconstructedTxRecord {
|
|
|
4928
5293
|
/** Set when the fee was unreadable — the amount overstates by exactly it. */
|
|
4929
5294
|
amountApproximate?: true;
|
|
4930
5295
|
timestampMs: number;
|
|
5296
|
+
/**
|
|
5297
|
+
* A freshly sealed `orbslip1:` slip, when this row was recovered from the
|
|
5298
|
+
* memo. RE-ISSUED, not remembered: a slip is sealed toward the recipient,
|
|
5299
|
+
* so the sender never held a readable copy. It carries only public facts.
|
|
5300
|
+
*/
|
|
5301
|
+
paymentSlip?: string;
|
|
4931
5302
|
}
|
|
4932
5303
|
interface ReconstructDeps {
|
|
4933
5304
|
vault: Pick<VaultStore, 'getAll' | 'getTxRecords' | 'saveTxRecord'>;
|
|
@@ -4935,6 +5306,13 @@ interface ReconstructDeps {
|
|
|
4935
5306
|
txFacts: TxFactsSource;
|
|
4936
5307
|
/** Injectable clock — reconstruction stamps rows whose block time is unknown. */
|
|
4937
5308
|
now?: () => number;
|
|
5309
|
+
/**
|
|
5310
|
+
* Notes this wallet sent, as the scan recovered them.
|
|
5311
|
+
*
|
|
5312
|
+
* Comes from `ScanOutcome.sentNotes` — the sweep already recognises them by
|
|
5313
|
+
* their outgoing ephPk. Omit to keep the arithmetic-only behaviour.
|
|
5314
|
+
*/
|
|
5315
|
+
sentNotes?: SentNoteMatch[];
|
|
4938
5316
|
}
|
|
4939
5317
|
declare function reconstructOutgoingTxRecords(deps: ReconstructDeps): Promise<void>;
|
|
4940
5318
|
|
|
@@ -4981,6 +5359,12 @@ interface NoteBuildKeys {
|
|
|
4981
5359
|
viewingPublicKey: Uint8Array;
|
|
4982
5360
|
/** Needed only for pairwise derivation; omit to disable that path. */
|
|
4983
5361
|
viewingSecretKey?: Uint8Array | undefined;
|
|
5362
|
+
/**
|
|
5363
|
+
* Outgoing viewing key (ovk). Omit and a payment falls back to a random
|
|
5364
|
+
* ephemeral: still spendable by the recipient, but the sender loses the
|
|
5365
|
+
* ability to read it back later.
|
|
5366
|
+
*/
|
|
5367
|
+
outgoingViewingKey?: Uint8Array | undefined;
|
|
4984
5368
|
}
|
|
4985
5369
|
interface BuildNoteParams {
|
|
4986
5370
|
/** Note value in the asset's indivisible units. Must be greater than zero. */
|
|
@@ -4997,6 +5381,11 @@ interface BuildNoteParams {
|
|
|
4997
5381
|
sourcePk?: bigint | undefined;
|
|
4998
5382
|
/** Recipient's global ownerPk. With `viewingPublicKey`, enables stealth. */
|
|
4999
5383
|
recipientOwnerPk?: bigint | undefined;
|
|
5384
|
+
/**
|
|
5385
|
+
* Next outgoing index as reconstructed from chain data, for the first
|
|
5386
|
+
* payment after a restore. Taken as a floor only — see `reserveOutgoingIndex`.
|
|
5387
|
+
*/
|
|
5388
|
+
outgoingIndexFromChain?: number | undefined;
|
|
5000
5389
|
/**
|
|
5001
5390
|
* Circuit version to stamp. A fresh note carries no proof, so this only
|
|
5002
5391
|
* matters when it is later spent — pass the version the chain reports as
|
|
@@ -5012,6 +5401,21 @@ interface BuildNoteDeps {
|
|
|
5012
5401
|
*/
|
|
5013
5402
|
storage?: NoteStorage | undefined;
|
|
5014
5403
|
}
|
|
5404
|
+
/** A built note, plus the outgoing index it published when it is a payment. */
|
|
5405
|
+
interface BuiltNote {
|
|
5406
|
+
note: ZkNote;
|
|
5407
|
+
/**
|
|
5408
|
+
* Which index of the outgoing sequence this note used, when it is a payment
|
|
5409
|
+
* to a privacy address. Absent for self notes and for a payment that fell
|
|
5410
|
+
* back to a random ephemeral.
|
|
5411
|
+
*
|
|
5412
|
+
* The transfer reads it as a flag: an index present means this payment can
|
|
5413
|
+
* be recovered later, so its change note is worth giving a recipient book
|
|
5414
|
+
* entry. The entry is keyed on the payment's commitment, not on this index.
|
|
5415
|
+
*/
|
|
5416
|
+
outgoingIndex?: number;
|
|
5417
|
+
}
|
|
5418
|
+
declare function buildZkNoteWithIndex(params: BuildNoteParams, deps: BuildNoteDeps): Promise<BuiltNote>;
|
|
5015
5419
|
declare function buildZkNote(params: BuildNoteParams, deps: BuildNoteDeps): Promise<ZkNote>;
|
|
5016
5420
|
|
|
5017
5421
|
interface SelfStealthKeys {
|
|
@@ -5032,104 +5436,29 @@ interface SelfStealthKeys {
|
|
|
5032
5436
|
*/
|
|
5033
5437
|
declare function recoverSelfStealthNote(note: ZkNote, keys: SelfStealthKeys): ZkNote | null;
|
|
5034
5438
|
|
|
5035
|
-
/** URI namespace. The version is in the path, so a v2 scanner can refuse a v1. */
|
|
5036
|
-
declare const NOTE_TRANSFER_URI_SCHEME = "orbinum://notes/v1/";
|
|
5037
|
-
/**
|
|
5038
|
-
* Max characters per page. Chosen for QR error-correction level M, which stays
|
|
5039
|
-
* scannable from a phone at arm's length.
|
|
5040
|
-
*/
|
|
5041
|
-
declare const QR_PAGE_MAX_CHARS = 1800;
|
|
5042
|
-
/**
|
|
5043
|
-
* One note on the wire. Field names are abbreviated because every byte costs
|
|
5044
|
-
* QR density — and they are FROZEN: renaming one breaks every deployed scanner.
|
|
5045
|
-
*/
|
|
5046
|
-
interface NoteTransferEntry {
|
|
5047
|
-
/** commitmentHex */
|
|
5048
|
-
c: string;
|
|
5049
|
-
/** nullifierHex */
|
|
5050
|
-
n: string;
|
|
5051
|
-
/** value, decimal string */
|
|
5052
|
-
val: string;
|
|
5053
|
-
/** assetId, decimal string */
|
|
5054
|
-
aid: string;
|
|
5055
|
-
/** ownerPk, 0x-prefixed 64-char hex */
|
|
5056
|
-
opk: string;
|
|
5057
|
-
/** blinding, 0x-prefixed 64-char hex */
|
|
5058
|
-
bld: string;
|
|
5059
|
-
/** spendingKey, 0x-prefixed 64-char hex */
|
|
5060
|
-
sk: string;
|
|
5061
|
-
}
|
|
5062
|
-
interface NoteTransferPayload {
|
|
5063
|
-
v: 1;
|
|
5064
|
-
/** Encode time (ms). Informational — a scanner may warn on a stale batch. */
|
|
5065
|
-
ts: number;
|
|
5066
|
-
/** Page index, 0-based. */
|
|
5067
|
-
p: number;
|
|
5068
|
-
/** Total pages in this batch. */
|
|
5069
|
-
pt: number;
|
|
5070
|
-
notes: NoteTransferEntry[];
|
|
5071
|
-
}
|
|
5072
|
-
declare function noteToTransferEntry(note: ZkNote): NoteTransferEntry;
|
|
5073
5439
|
/**
|
|
5074
|
-
*
|
|
5440
|
+
* CLOSED JSON backup: notes moved between a user's devices as a plain file,
|
|
5441
|
+
* WITHOUT exposing any spending key.
|
|
5075
5442
|
*
|
|
5076
|
-
*
|
|
5077
|
-
*
|
|
5078
|
-
*/
|
|
5079
|
-
declare function encodeNoteTransferPages(notes: ZkNote[], options?: {
|
|
5080
|
-
now?: () => number;
|
|
5081
|
-
maxChars?: number;
|
|
5082
|
-
}): string[];
|
|
5083
|
-
/**
|
|
5084
|
-
* Decodes one scanned page, or throws with a reason a scanner can show.
|
|
5085
|
-
*
|
|
5086
|
-
* Strict on purpose: a partially-understood payload would import notes with
|
|
5087
|
-
* missing fields, and an unspendable note in a vault is worse than a failed
|
|
5088
|
-
* scan the user can retry.
|
|
5089
|
-
*/
|
|
5090
|
-
declare function decodeNoteTransferPage(uri: string): NoteTransferPayload;
|
|
5091
|
-
/**
|
|
5092
|
-
* Reassembles a scanned batch into notes.
|
|
5093
|
-
*
|
|
5094
|
-
* Rejects an incomplete or mixed batch rather than importing what it has: a
|
|
5095
|
-
* partial import looks like a successful one, and the user would never learn
|
|
5096
|
-
* which notes never made it.
|
|
5097
|
-
*/
|
|
5098
|
-
declare function assembleNoteTransfer(pages: NoteTransferPayload[]): NoteTransferEntry[];
|
|
5099
|
-
|
|
5100
|
-
/**
|
|
5101
|
-
* CLOSED JSON backup of notes — the same notes moved between a user's devices as
|
|
5102
|
-
* a plain file, WITHOUT exposing any spending key.
|
|
5103
|
-
*
|
|
5104
|
-
* ## The idea
|
|
5105
|
-
*
|
|
5106
|
-
* A backup entry carries only what is already PUBLIC on chain: the commitment and
|
|
5107
|
-
* the encrypted memo. It contains no spending key, so the file is safe to hold
|
|
5108
|
-
* and even share — it grants nothing on its own.
|
|
5443
|
+
* An entry carries only what is already PUBLIC on chain — the commitment and
|
|
5444
|
+
* the encrypted memo — so the file grants nothing on its own.
|
|
5109
5445
|
*
|
|
5110
|
-
*
|
|
5111
|
-
*
|
|
5112
|
-
*
|
|
5113
|
-
*
|
|
5114
|
-
* - the memo does not decrypt → the note is someone else's → it is dropped.
|
|
5446
|
+
* DECRYPTION IS THE PROOF OF OWNERSHIP. On import each memo is opened with the
|
|
5447
|
+
* importer's viewing key: one that opens rebuilds a full spendable `ZkNote`
|
|
5448
|
+
* (spending and stealth keys derived from their identity); one that does not is
|
|
5449
|
+
* someone else's note and is dropped.
|
|
5115
5450
|
*
|
|
5116
|
-
*
|
|
5117
|
-
*
|
|
5118
|
-
* is not yours simply fails to import.
|
|
5451
|
+
* Not a chain scan — only the N memos in the file are tried, which is what lets
|
|
5452
|
+
* a device restore without re-scanning the pool.
|
|
5119
5453
|
*
|
|
5120
|
-
*
|
|
5121
|
-
*
|
|
5122
|
-
*
|
|
5123
|
-
* Does NOT travel: value, ownerPk, blinding, spendingKey — all recovered by
|
|
5124
|
-
* decrypting the memo. The Merkle proof is re-fetched at spend time.
|
|
5454
|
+
* Travels: `commitmentHex`, `encryptedMemo`, `leafIndex` (informational).
|
|
5455
|
+
* Recovered from the memo: value, ownerPk, blinding, spendingKey. The Merkle
|
|
5456
|
+
* proof is re-fetched at spend time.
|
|
5125
5457
|
*/
|
|
5126
5458
|
|
|
5127
5459
|
/** Current backup format version. Bumped only if the entry shape changes. */
|
|
5128
5460
|
declare const NOTE_BACKUP_VERSION: 1;
|
|
5129
|
-
/**
|
|
5130
|
-
* One note in a closed backup — public data only. Field names are short but not
|
|
5131
|
-
* cryptic; readability matters more than density in a file (unlike the QR path).
|
|
5132
|
-
*/
|
|
5461
|
+
/** One note in a closed backup — public data only. */
|
|
5133
5462
|
interface NoteBackupEntry {
|
|
5134
5463
|
/** 0x-prefixed 32-byte LE commitment hex. */
|
|
5135
5464
|
commitmentHex: string;
|
|
@@ -5189,15 +5518,12 @@ declare function decodeNoteBackup(json: string | object): NoteBackupEntry[];
|
|
|
5189
5518
|
declare function importNotesFromBackup(entries: NoteBackupEntry[], keys: BackupImportKeys): ZkNote[];
|
|
5190
5519
|
|
|
5191
5520
|
/**
|
|
5192
|
-
* Reconstruct a note from a payment slip.
|
|
5521
|
+
* Reconstruct a note from a payment slip, without scanning the pool.
|
|
5193
5522
|
*
|
|
5194
|
-
*
|
|
5195
|
-
*
|
|
5196
|
-
*
|
|
5197
|
-
*
|
|
5198
|
-
* recipient's viewing key, derives the stealth spending key, and verifies the
|
|
5199
|
-
* commitment. The result is a fully spendable `ZkNote`, obtained without scanning
|
|
5200
|
-
* the pool.
|
|
5523
|
+
* An `orbslip1:` string carries the note's public locators — commitment,
|
|
5524
|
+
* encrypted memo, leaf index. Those feed the SAME path a scan uses
|
|
5525
|
+
* (`tryDecryptNote`), which opens the memo, derives the stealth spending key
|
|
5526
|
+
* and verifies the commitment. Out comes a fully spendable `ZkNote`.
|
|
5201
5527
|
*/
|
|
5202
5528
|
|
|
5203
5529
|
/** Keys the recipient needs to open a slip and reconstruct the note. */
|
|
@@ -5306,16 +5632,28 @@ interface TransferSubmitRequest {
|
|
|
5306
5632
|
interface TransferDeps {
|
|
5307
5633
|
privacy: SpendPrivacyReads;
|
|
5308
5634
|
resolver: Pick<CircuitVersionResolver, 'resolve'>;
|
|
5309
|
-
/**
|
|
5635
|
+
/**
|
|
5636
|
+
* Builds the two output notes. Owns keys and the ephemeral reservations.
|
|
5637
|
+
*
|
|
5638
|
+
* Returns the outgoing index alongside the note, used only as a signal that
|
|
5639
|
+
* this payment published a DERIVED ephemeral and is therefore recoverable —
|
|
5640
|
+
* which is what decides whether the change note carries a book entry at all.
|
|
5641
|
+
* The entry itself is keyed on the payment's commitment, never on this
|
|
5642
|
+
* index; see `recipientBook`.
|
|
5643
|
+
*/
|
|
5310
5644
|
buildNote: (params: {
|
|
5311
5645
|
value: bigint;
|
|
5312
5646
|
assetId: bigint;
|
|
5313
|
-
|
|
5647
|
+
/** Omit for a note owned by the wallet itself — the builder fills its own. */
|
|
5648
|
+
ownerPk?: bigint;
|
|
5314
5649
|
spendingKey?: bigint;
|
|
5315
5650
|
sourcePk: bigint;
|
|
5316
5651
|
viewingPublicKey?: Uint8Array;
|
|
5317
5652
|
recipientOwnerPk?: bigint;
|
|
5318
|
-
}) => Promise<
|
|
5653
|
+
}) => Promise<{
|
|
5654
|
+
note: ZkNote;
|
|
5655
|
+
outgoingIndex?: number;
|
|
5656
|
+
}>;
|
|
5319
5657
|
vault: SpendVault;
|
|
5320
5658
|
/** Spendable form of a self-addressed stealth note, or null (see selfStealthNote). */
|
|
5321
5659
|
recoverStealth: (note: ZkNote) => ZkNote | null;
|
|
@@ -5327,6 +5665,14 @@ interface TransferDeps {
|
|
|
5327
5665
|
* immediately instead of waiting for a rescan.
|
|
5328
5666
|
*/
|
|
5329
5667
|
selfOwnerPk: bigint | null;
|
|
5668
|
+
/**
|
|
5669
|
+
* The wallet's outgoing viewing key (ovk), when it has one.
|
|
5670
|
+
*
|
|
5671
|
+
* Seals the recipient book into the change note. Absent — a watch-only or
|
|
5672
|
+
* legacy identity — the change keeps the older meaning and the transfer is
|
|
5673
|
+
* simply not recoverable from the seed later.
|
|
5674
|
+
*/
|
|
5675
|
+
outgoingViewingKey?: Uint8Array;
|
|
5330
5676
|
/** Route stamped on persisted notes (explorer link kind). */
|
|
5331
5677
|
txKind?: TxKind;
|
|
5332
5678
|
}
|
|
@@ -5336,6 +5682,19 @@ interface TransferParams {
|
|
|
5336
5682
|
recipientPk: bigint;
|
|
5337
5683
|
/** Packed viewing key from the recipient's privacy address. Omitted → dummy memo, they must scan. */
|
|
5338
5684
|
recipientViewingPublicKey?: Uint8Array | undefined;
|
|
5685
|
+
/**
|
|
5686
|
+
* What the recipient sees as `sourcePk` — who paid them.
|
|
5687
|
+
*
|
|
5688
|
+
* PASS IT EXPLICITLY. The default is the spent note's owner, so what gets
|
|
5689
|
+
* disclosed depends on coin selection: spending a received note discloses a
|
|
5690
|
+
* one-time key that names nobody, spending a shield or change note
|
|
5691
|
+
* discloses the wallet's GLOBAL identity, linkable across every payment
|
|
5692
|
+
* made from one. Naming the counterparty is the field's purpose, so neither
|
|
5693
|
+
* is a leak — but the choice should not be made by the coin selector.
|
|
5694
|
+
*
|
|
5695
|
+
* A stable pseudonym for a merchant tracking repeat payments, a
|
|
5696
|
+
* per-recipient value to stay unlinkable, or `0n` to say nothing.
|
|
5697
|
+
*/
|
|
5339
5698
|
senderPk?: bigint | undefined;
|
|
5340
5699
|
fee?: bigint | undefined;
|
|
5341
5700
|
}
|
|
@@ -5367,7 +5726,18 @@ interface UnshieldSubmitRequest {
|
|
|
5367
5726
|
interface UnshieldDeps {
|
|
5368
5727
|
privacy: SpendPrivacyReads;
|
|
5369
5728
|
resolver: Pick<CircuitVersionResolver, 'resolve'>;
|
|
5370
|
-
/**
|
|
5729
|
+
/**
|
|
5730
|
+
* Builds the stealth change note. Owns the keys it is built under.
|
|
5731
|
+
*
|
|
5732
|
+
* No ephemeral is reserved: passing `recipientOwnerPk` without a
|
|
5733
|
+
* `viewingPublicKey` takes neither the self nor the outgoing branch in
|
|
5734
|
+
* `buildZkNoteWithIndex`, so the note publishes a RANDOM ephemeral and a rescan
|
|
5735
|
+
* finds it by trial decryption rather than by index lookup.
|
|
5736
|
+
*
|
|
5737
|
+
* Shares its shape with the transfer's builder so one bound function serves
|
|
5738
|
+
* both; the outgoing index it may return is unused here, since an unshield
|
|
5739
|
+
* has no recipient to record.
|
|
5740
|
+
*/
|
|
5371
5741
|
buildNote: (params: {
|
|
5372
5742
|
value: bigint;
|
|
5373
5743
|
assetId: bigint;
|
|
@@ -5375,7 +5745,9 @@ interface UnshieldDeps {
|
|
|
5375
5745
|
blinding: bigint;
|
|
5376
5746
|
spendingKey: bigint;
|
|
5377
5747
|
recipientOwnerPk: bigint;
|
|
5378
|
-
}) => Promise<
|
|
5748
|
+
}) => Promise<{
|
|
5749
|
+
note: ZkNote;
|
|
5750
|
+
}>;
|
|
5379
5751
|
vault: SpendVault;
|
|
5380
5752
|
/**
|
|
5381
5753
|
* The spendable form of a stealth note this wallet authored, or null. Null
|
|
@@ -5441,12 +5813,12 @@ declare function claimFees(deps: FeeClaimDeps, { assetId, amount, signer }: FeeC
|
|
|
5441
5813
|
/**
|
|
5442
5814
|
* Whether a note still matches the commitment stored on chain.
|
|
5443
5815
|
*
|
|
5444
|
-
* The circuit ignores the ownerPk it is
|
|
5445
|
-
* commitment from BabyPbk(spending_key).Ax
|
|
5446
|
-
*
|
|
5447
|
-
*
|
|
5448
|
-
*
|
|
5449
|
-
*
|
|
5816
|
+
* The circuit ignores the `ownerPk` it is handed and rebuilds each input
|
|
5817
|
+
* commitment from `BabyPbk(spending_key).Ax`, so a drifted spendingKey, value,
|
|
5818
|
+
* assetId or blinding kills witness generation on the Merkle constraint.
|
|
5819
|
+
*
|
|
5820
|
+
* ~0.13 ms here — one EC mul plus a Poseidon hash — against seconds of proving
|
|
5821
|
+
* that fails anyway, and this one names the note.
|
|
5450
5822
|
*/
|
|
5451
5823
|
declare function noteMatchesCommitment(note: ZkNote): boolean;
|
|
5452
5824
|
/**
|
|
@@ -5547,12 +5919,11 @@ declare function chainActiveCircuitVersion(zkVerifier: Pick<ZkVerifierModule, 'g
|
|
|
5547
5919
|
* A WebSocket drop between submit and finalization surfaces as an error for a
|
|
5548
5920
|
* tx that may have landed anyway. Reporting that as "failed" is the dangerous
|
|
5549
5921
|
* outcome: the user retries, and the retry double-spends (shield) or dies on a
|
|
5550
|
-
* duplicate nullifier (transfer/unshield).
|
|
5551
|
-
* explicitly does not.
|
|
5922
|
+
* duplicate nullifier (transfer/unshield).
|
|
5552
5923
|
*
|
|
5553
|
-
*
|
|
5554
|
-
*
|
|
5555
|
-
*
|
|
5924
|
+
* So "the chain rejected it" and "we lost the line" are told apart, and only
|
|
5925
|
+
* the second is polled — against an on-chain predicate the caller supplies: a
|
|
5926
|
+
* nullifier turned spent, a commitment now in the tree.
|
|
5556
5927
|
*/
|
|
5557
5928
|
|
|
5558
5929
|
/** Whether an error leaves the submit outcome unknown rather than rejected. */
|
|
@@ -5582,20 +5953,26 @@ declare function txLandedAfterError(err: unknown, landed: () => Promise<boolean>
|
|
|
5582
5953
|
declare const RECOVERED_TX_RESULT: TxResult;
|
|
5583
5954
|
|
|
5584
5955
|
/**
|
|
5585
|
-
* Storage
|
|
5956
|
+
* Storage name for one account's vault on one chain.
|
|
5586
5957
|
*
|
|
5587
|
-
*
|
|
5588
|
-
*
|
|
5589
|
-
*
|
|
5590
|
-
*
|
|
5591
|
-
|
|
5958
|
+
* `chainFingerprint` is the genesis hash, optional because a host may not know
|
|
5959
|
+
* it during connect: the name then scopes by account alone and is promoted once
|
|
5960
|
+
* it arrives. Opening under the short name and later the long one is safe —
|
|
5961
|
+
* `unlock` detects the change and resets rather than mixing two chains' notes.
|
|
5962
|
+
*/
|
|
5963
|
+
declare function vaultStorageName(address: string, chainFingerprint?: string, version?: IdentityVersion): string;
|
|
5964
|
+
|
|
5965
|
+
/**
|
|
5966
|
+
* Storage key for one cached identity — same three parts as the vault name, for
|
|
5967
|
+
* the same reason (see `vaultName`).
|
|
5592
5968
|
*
|
|
5593
|
-
* The
|
|
5594
|
-
*
|
|
5595
|
-
*
|
|
5596
|
-
*
|
|
5969
|
+
* The chain is PART of the identity: the derivation's `info` carries the chain
|
|
5970
|
+
* id, so one wallet yields a different key per network. The account goes through
|
|
5971
|
+
* `canonicalAccountId` so this matches what the derivation keys by — an address
|
|
5972
|
+
* re-listed under another SS58 prefix would otherwise file one identity under
|
|
5973
|
+
* two names.
|
|
5597
5974
|
*/
|
|
5598
|
-
declare function sessionCacheKey(address: string, chainId: number): string;
|
|
5975
|
+
declare function sessionCacheKey(address: string, chainId: number, version?: IdentityVersion): string;
|
|
5599
5976
|
interface SessionCacheDeps {
|
|
5600
5977
|
store: SecretStore;
|
|
5601
5978
|
/**
|
|
@@ -5635,61 +6012,87 @@ declare function restoreSession(deps: SessionCacheDeps, address: string, chainId
|
|
|
5635
6012
|
*/
|
|
5636
6013
|
declare function clearSession(store: SecretStore, address: string, chainId?: number): Promise<void>;
|
|
5637
6014
|
|
|
6015
|
+
interface WalletIdentity {
|
|
6016
|
+
version: IdentityVersion;
|
|
6017
|
+
spendingKey: bigint;
|
|
6018
|
+
ownerPk: bigint;
|
|
6019
|
+
viewingSecretKey: Uint8Array;
|
|
6020
|
+
viewingPublicKey: Uint8Array;
|
|
6021
|
+
/** Absent on a watch-only identity, which is handed everything except this. */
|
|
6022
|
+
outgoingViewingKey?: Uint8Array;
|
|
6023
|
+
}
|
|
5638
6024
|
/**
|
|
5639
|
-
*
|
|
6025
|
+
* Assemble the identity. v3 is the only scheme.
|
|
6026
|
+
*
|
|
6027
|
+
* Throws on a root that is not 32 bytes or is all zeros. Neither is an error the
|
|
6028
|
+
* derivation itself would raise: the branches are pure HKDF, so they answer for
|
|
6029
|
+
* ANY input — an empty one included — with a complete, deterministic and
|
|
6030
|
+
* publicly derivable identity. This is the only place that catches a caller who
|
|
6031
|
+
* wired the root from something that was not there.
|
|
5640
6032
|
*
|
|
5641
|
-
*
|
|
5642
|
-
*
|
|
5643
|
-
*
|
|
5644
|
-
*
|
|
5645
|
-
*
|
|
6033
|
+
* Nothing migrates from an older scheme: a note is committed on chain under the
|
|
6034
|
+
* `ownerPk` inside the Merkle tree, so re-deriving an identity does not move it,
|
|
6035
|
+
* it orphans it. Holders unshield first.
|
|
6036
|
+
*
|
|
6037
|
+
* @param rootSecret 32 bytes — the master key material. Not retained.
|
|
5646
6038
|
*/
|
|
5647
|
-
declare function
|
|
5648
|
-
|
|
6039
|
+
declare function deriveIdentity(rootSecret: Uint8Array, version: IdentityVersion): WalletIdentity;
|
|
5649
6040
|
/**
|
|
5650
|
-
*
|
|
6041
|
+
* What a watch-only holder is given: read access, no spend authority.
|
|
5651
6042
|
*
|
|
5652
|
-
*
|
|
5653
|
-
*
|
|
5654
|
-
*
|
|
6043
|
+
* The spending key is absent by TYPE, not by a runtime check — a credential
|
|
6044
|
+
* cannot be passed where a spend needs one.
|
|
6045
|
+
*
|
|
6046
|
+
* `includeOutgoing` is opt-in and stays that way: the incoming key reveals what
|
|
6047
|
+
* arrived, the outgoing one reveals who was PAID. Bundling them by default would
|
|
6048
|
+
* hand the payment graph to anyone granted a look at the balance.
|
|
6049
|
+
*/
|
|
6050
|
+
interface ViewingCredential {
|
|
6051
|
+
version: IdentityVersion;
|
|
6052
|
+
ownerPk: bigint;
|
|
6053
|
+
viewingSecretKey: Uint8Array;
|
|
6054
|
+
viewingPublicKey: Uint8Array;
|
|
6055
|
+
outgoingViewingKey?: Uint8Array;
|
|
6056
|
+
}
|
|
6057
|
+
declare function exportViewingCredential(identity: WalletIdentity, options?: {
|
|
6058
|
+
includeOutgoing?: boolean;
|
|
6059
|
+
}): ViewingCredential;
|
|
6060
|
+
|
|
6061
|
+
/**
|
|
6062
|
+
* Whether browser wallet extensions can be discovered at all. A host that gets
|
|
6063
|
+
* false must sign some other way — there is no fallback to arrange here.
|
|
5655
6064
|
*/
|
|
5656
6065
|
declare function hasInjectedExtensions(): boolean;
|
|
5657
6066
|
/**
|
|
5658
6067
|
* Installed extension ids, or an empty list where none can exist.
|
|
5659
6068
|
*
|
|
5660
|
-
*
|
|
5661
|
-
* honest answer
|
|
5662
|
-
* render a picker wants a list, not an exception.
|
|
6069
|
+
* Empty rather than a throw: off-page, "which extensions are present" has an
|
|
6070
|
+
* honest answer, and it is "none". A caller rendering a picker wants a list.
|
|
5663
6071
|
*/
|
|
5664
6072
|
declare function getInjectedExtensions(): string[];
|
|
5665
6073
|
/**
|
|
5666
|
-
* Connects to one extension by id.
|
|
5667
|
-
*
|
|
5668
|
-
*
|
|
5669
|
-
* extension, so an empty result would misreport "not installed" for what is
|
|
5670
|
-
* really "this host cannot reach extensions at all".
|
|
6074
|
+
* Connects to one extension by id. Throws off-page, unlike the enumerator: the
|
|
6075
|
+
* caller named an extension, so silence would misreport "not installed" for
|
|
6076
|
+
* "this host cannot reach extensions at all".
|
|
5671
6077
|
*/
|
|
5672
6078
|
declare function connectInjectedExtension(name: string, origin?: string): Promise<InjectedExtension>;
|
|
5673
6079
|
|
|
5674
6080
|
/**
|
|
5675
|
-
* NoteProvenance —
|
|
5676
|
-
*
|
|
6081
|
+
* NoteProvenance — one vocabulary for "where did this note come from, and where
|
|
6082
|
+
* did it go".
|
|
5677
6083
|
*
|
|
5678
|
-
*
|
|
5679
|
-
*
|
|
6084
|
+
* Two mechanisms answer that, and they are PROVIDERS of the same fact rather
|
|
6085
|
+
* than competing designs; `ProvenanceSource` records which one spoke:
|
|
5680
6086
|
*
|
|
5681
|
-
* - the memo's `sourcePk
|
|
5682
|
-
*
|
|
5683
|
-
* - a lookup by commitment,
|
|
5684
|
-
*
|
|
6087
|
+
* - the memo's `sourcePk`, readable by whoever can decrypt the note — the
|
|
6088
|
+
* recipient always, the sender only for the change note they kept;
|
|
6089
|
+
* - a lookup by commitment, returning only what is already public: no amount,
|
|
6090
|
+
* no recipient, but enough to re-issue a payment slip.
|
|
5685
6091
|
*
|
|
5686
|
-
*
|
|
5687
|
-
*
|
|
5688
|
-
*
|
|
5689
|
-
*
|
|
5690
|
-
* A sender cannot reopen a memo sealed toward someone else, so the amount and
|
|
5691
|
-
* recipient of an outgoing transfer are NOT recoverable from a seed alone. What
|
|
5692
|
-
* survives is the ability to hand the recipient a working slip again.
|
|
6092
|
+
* Nothing here derives a key — this layer only holds what was already
|
|
6093
|
+
* recovered. And a sender cannot reopen a memo sealed toward someone else, so
|
|
6094
|
+
* the amount and recipient of an outgoing transfer are NOT recoverable from a
|
|
6095
|
+
* seed. What survives is the ability to hand over a working slip again.
|
|
5693
6096
|
*/
|
|
5694
6097
|
|
|
5695
6098
|
/**
|
|
@@ -5819,16 +6222,12 @@ declare function selectDescribingNoteByCommitment<T extends Pick<ZkNote, 'source
|
|
|
5819
6222
|
/**
|
|
5820
6223
|
* Merging what a rescan learned into what the wallet already knew.
|
|
5821
6224
|
*
|
|
5822
|
-
*
|
|
5823
|
-
*
|
|
5824
|
-
*
|
|
5825
|
-
*
|
|
5826
|
-
*
|
|
5827
|
-
* The payment slip itself is not at risk — it can be re-issued from public
|
|
5828
|
-
* fields — but a thin `chain` record must never replace a rich local one.
|
|
6225
|
+
* Reconstruction runs after every scan, over records the wallet may have
|
|
6226
|
+
* written ITSELF at submit time — and those hold what no recovery path can
|
|
6227
|
+
* reach: the amount and the recipient, which live inside a memo sealed toward
|
|
6228
|
+
* someone else. A thin `chain` record must never replace a rich local one.
|
|
5829
6229
|
*
|
|
5830
|
-
*
|
|
5831
|
-
* reconstruction loop. The rule is now explicit and testable on its own.
|
|
6230
|
+
* The slip is the exception: it can always be re-issued from public fields.
|
|
5832
6231
|
*/
|
|
5833
6232
|
|
|
5834
6233
|
declare function outranks(a: ProvenanceSource, b: ProvenanceSource): boolean;
|
|
@@ -5861,25 +6260,20 @@ declare function mergeProvenance(existing: NoteProvenanceRecord, incoming: NoteP
|
|
|
5861
6260
|
/**
|
|
5862
6261
|
* Seal a fresh `orbslip1:` slip for a transfer recovered from history.
|
|
5863
6262
|
*
|
|
5864
|
-
*
|
|
5865
|
-
*
|
|
5866
|
-
*
|
|
5867
|
-
*
|
|
5868
|
-
*
|
|
5869
|
-
*
|
|
5870
|
-
* renders those fields with the authority of a decrypted slip, on a device
|
|
5871
|
-
* where nothing explains which server supplied them.
|
|
5872
|
-
*
|
|
5873
|
-
* So the check belongs on THIS side of the wire: a value that slipped through
|
|
5874
|
-
* would fail on the recipient's device, or worse, not fail at all.
|
|
6263
|
+
* VALIDATES ON THIS SIDE OF THE WIRE. The facts crossed a trust boundary (they
|
|
6264
|
+
* were looked up by commitment) and sealing them produces an AUTHENTICATED
|
|
6265
|
+
* envelope: a valid MAC proves the sender knew the recipient's viewing key, not
|
|
6266
|
+
* that the server which answered was honest. The recipient's wallet then renders
|
|
6267
|
+
* those fields with the authority of a decrypted slip, on a device that cannot
|
|
6268
|
+
* tell where they came from.
|
|
5875
6269
|
*
|
|
5876
|
-
* Throws on a malformed commitment, memo or leaf index —
|
|
5877
|
-
* identity, and a slip carrying a wrong one is not
|
|
5878
|
-
*
|
|
6270
|
+
* Throws on a malformed commitment, memo or leaf index — they are the note's
|
|
6271
|
+
* identity, and a slip carrying a wrong one is broken, not degraded. `txHash` is
|
|
6272
|
+
* informational, so it is DROPPED instead.
|
|
5879
6273
|
*
|
|
5880
6274
|
* @param facts public facts of the sent note, looked up by commitment
|
|
5881
6275
|
* @param recipientIvkPacked 32-byte packed viewing key from the recipient's privacy address
|
|
5882
|
-
* @param txHash the transfer's hash, when known — informational
|
|
6276
|
+
* @param txHash the transfer's hash, when known — informational
|
|
5883
6277
|
*/
|
|
5884
6278
|
declare function regeneratePaymentSlip(facts: NoteFacts, recipientIvkPacked: Uint8Array, txHash?: string): string;
|
|
5885
6279
|
|
|
@@ -5931,6 +6325,16 @@ interface OrbinumWalletConfig {
|
|
|
5931
6325
|
* that already resolved it — a wrong value yields unspendable notes.
|
|
5932
6326
|
*/
|
|
5933
6327
|
circuitVersion?: number | undefined;
|
|
6328
|
+
/**
|
|
6329
|
+
* Which derivation scheme this wallet's keys come from.
|
|
6330
|
+
*
|
|
6331
|
+
* Only `v3` exists, so this is here for the NEXT scheme rather than for a
|
|
6332
|
+
* choice available today — passing it changes nothing. v2 was removed, not
|
|
6333
|
+
* deprecated: it chained the viewing key off the spending key, which made a
|
|
6334
|
+
* watch-only wallet impossible and left no branch to hang the outgoing
|
|
6335
|
+
* viewing key on.
|
|
6336
|
+
*/
|
|
6337
|
+
identityVersion?: IdentityVersion | undefined;
|
|
5934
6338
|
}
|
|
5935
6339
|
interface ScanOptions {
|
|
5936
6340
|
/**
|
|
@@ -5947,8 +6351,16 @@ declare class OrbinumWallet {
|
|
|
5947
6351
|
private readonly session;
|
|
5948
6352
|
private readonly notes;
|
|
5949
6353
|
private readonly vaultStore;
|
|
5950
|
-
/**
|
|
5951
|
-
|
|
6354
|
+
/**
|
|
6355
|
+
* The identity this wallet is unlocked as, or null.
|
|
6356
|
+
*
|
|
6357
|
+
* Held as a bundle rather than a single scalar because v3 keys are SIBLINGS:
|
|
6358
|
+
* the spending key no longer produces the viewing key, so there is nothing
|
|
6359
|
+
* left to derive the others from once unlock returns. Keeping the root out
|
|
6360
|
+
* of this object is deliberate — the branches are what the wallet needs, and
|
|
6361
|
+
* the root is the thing worth not retaining.
|
|
6362
|
+
*/
|
|
6363
|
+
private identity;
|
|
5952
6364
|
constructor(config: OrbinumWalletConfig);
|
|
5953
6365
|
/** The underlying store, for operations the facade does not cover. */
|
|
5954
6366
|
get vault(): VaultStore;
|
|
@@ -5958,11 +6370,14 @@ declare class OrbinumWallet {
|
|
|
5958
6370
|
* signature produces — the same value `PrivacyKeyManager.getMasterBytes()`
|
|
5959
6371
|
* returns.
|
|
5960
6372
|
*
|
|
5961
|
-
* Master bytes rather than the spending-key scalar, deliberately: the
|
|
5962
|
-
* is the
|
|
5963
|
-
*
|
|
5964
|
-
*
|
|
5965
|
-
*
|
|
6373
|
+
* Master bytes rather than the spending-key scalar, deliberately: the master
|
|
6374
|
+
* is the root EVERY branch hangs off — spending key, viewing key, outgoing
|
|
6375
|
+
* viewing key and vault key are each their own HKDF of it, none derived
|
|
6376
|
+
* from another. Only `ownerPk` comes from the spending scalar, because the
|
|
6377
|
+
* circuit defines it that way.
|
|
6378
|
+
*
|
|
6379
|
+
* It is also what keeps a stored vault readable across a modulus change:
|
|
6380
|
+
* the vault key is derived pre-reduction.
|
|
5966
6381
|
*
|
|
5967
6382
|
* Reports whether the stored vault was RESET: a different chain, a different
|
|
5968
6383
|
* key, or notes the chain no longer recognises. When it was, the wallet
|
|
@@ -6027,6 +6442,7 @@ declare class OrbinumWallet {
|
|
|
6027
6442
|
spendingKey: bigint;
|
|
6028
6443
|
viewingSecretKey: Uint8Array;
|
|
6029
6444
|
ownerPk: bigint;
|
|
6445
|
+
outgoingViewingKey?: Uint8Array;
|
|
6030
6446
|
};
|
|
6031
6447
|
/**
|
|
6032
6448
|
* `recoverStealth` for the spend ops, bound to this wallet's keys.
|
|
@@ -6043,10 +6459,13 @@ declare class OrbinumWallet {
|
|
|
6043
6459
|
* guessed version produces a note the chain refuses to spend after a
|
|
6044
6460
|
* verifying-key rotation, and the failure surfaces much later.
|
|
6045
6461
|
*/
|
|
6046
|
-
buildOutputNote: (params: Omit<BuildNoteParams, "circuitVersion">) => Promise<
|
|
6462
|
+
buildOutputNote: (params: Omit<BuildNoteParams, "circuitVersion">) => Promise<{
|
|
6463
|
+
note: ZkNote;
|
|
6464
|
+
outgoingIndex?: number;
|
|
6465
|
+
}>;
|
|
6047
6466
|
/** The circuit version a new note should carry. */
|
|
6048
6467
|
circuitVersion(): Promise<number>;
|
|
6049
|
-
private
|
|
6468
|
+
private requireIdentity;
|
|
6050
6469
|
}
|
|
6051
6470
|
|
|
6052
|
-
export { type AssetRegisteredEvent, type AssetUnverifiedEvent, type AssetVerifiedEvent, BABYJUB_SUBORDER, BN254_R, type BackupImportKeys, type BlockInfo, type BuildNoteDeps, type BuildNoteParams, type Bytes32, CachedNullifier, type ChainInfo, ChainModule, type ChunkInfo, CircuitId, CircuitVersionResolver, type ClaimShieldedFeesParams, type ClientProviderConfig, type CoinSelection, type CollectScanEntriesParams, type CommitmentsInsertedEvent, type ConnectionStatus, type CryptoKey$1 as CryptoKey, CryptoPrecompiles, type DecodedPrecompile, DecryptPool, DecryptedMemo, type DynamicBuilder, ENCRYPTED_MEMO_SIZE, EncryptedMemo, EncryptedNoteRecord, EncryptedTxRecord, type EventData, type EventPhase, type EventRecord, type EvmAddressInfo, type EvmBlock, EvmClient, EvmExplorer, type EvmLog, type EvmSigner, type EvmTransaction, type EvmTxRequest, type EvmTxSummary, type ExtrinsicDecoder, type ExtrinsicFacts, type ExtrinsicRecord, type FeeClaimDeps, type FeeClaimParams, type FeeClaimProofInputs, type FeeClaimProofOutput, type FeeClaimStep, type FormatOptions, KNOWN_PALLET_ERRORS, KNOWN_PRECOMPILES, type KnownPrecompileInfo, LEAVES_PER_TREE, MIN_GASLESS_FEE, MIN_SIGNATURE_BYTES, MemoryVaultStorage, type MerkleRootUpdatedEvent, type MutableWalletSession, NATIVE_ASSET_ID, NOTE_BACKUP_VERSION, NOTE_BIGINT_FIELDS,
|
|
6471
|
+
export { type AssetRegisteredEvent, type AssetUnverifiedEvent, type AssetVerifiedEvent, BABYJUB_SUBORDER, BN254_R, type BackupImportKeys, type BlockInfo, type BuildNoteDeps, type BuildNoteParams, type Bytes32, CachedNullifier, type ChainInfo, ChainModule, type ChunkInfo, CircuitId, CircuitVersionResolver, type ClaimShieldedFeesParams, type ClientProviderConfig, type CoinSelection, type CollectScanEntriesParams, type CommitmentsInsertedEvent, type ConnectionStatus, type CryptoKey$1 as CryptoKey, CryptoPrecompiles, type DecodedPrecompile, DecryptPool, DecryptedMemo, type DynamicBuilder, ENCRYPTED_MEMO_SIZE, EncryptedMemo, EncryptedNoteRecord, EncryptedTxRecord, type EventData, type EventPhase, type EventRecord, type EvmAddressInfo, type EvmBlock, EvmClient, EvmExplorer, type EvmLog, type EvmSigner, type EvmTransaction, type EvmTxRequest, type EvmTxSummary, type ExtrinsicDecoder, type ExtrinsicFacts, type ExtrinsicRecord, type FeeClaimDeps, type FeeClaimParams, type FeeClaimProofInputs, type FeeClaimProofOutput, type FeeClaimStep, type FormatOptions, type IdentityVersion, KNOWN_PALLET_ERRORS, KNOWN_PRECOMPILES, type KnownPrecompileInfo, LEAVES_PER_TREE, MIN_GASLESS_FEE, MIN_SIGNATURE_BYTES, MemoryVaultStorage, type MerkleRootUpdatedEvent, type MutableWalletSession, NATIVE_ASSET_ID, NOTE_BACKUP_VERSION, NOTE_BIGINT_FIELDS, type NoteBackup, type NoteBackupEntry, type NoteBuildKeys, NoteBuilder, type NoteDisclosure, NoteFacts, NoteInput, type NoteOrigin, type NoteProvenanceRecord, NoteStatusUpdate, NoteStorage, type NoteWithMeta, type NotesCache, NullifierCache, type NullifierChunkBody, type NullifierManifest, type NullifierSource, NullifierSyncMeta, type NullifierTail, type NullifiersSpentEvent, type ObservableNotesCache, OrbinumClient, type OrbinumClientConfig, OrbinumClientProvider, OrbinumWallet, type OrbinumWalletConfig, type OutgoingEphWindowEntry, PAGE_SIZE, PAYMENT_SLIP_SCHEME, PRECOMPILE_ADDR, type PairwiseEphWindowEntry, type PalletErrorKind, type PaymentSlipFields, type PersistParams, type PkScope, type PrecompileMethod, PrivacyKeyManager, type PrivacyMerkleProof, PrivacyModule, type PrivateTransferArgs, type PrivateTransferInput, type PrivateTransferOutput, type PrivateTransferParams, type PrivateTransferProofInputs, type ProofOptions, type ProvenanceAmount, type ProvenancePeer, type ProvenanceSource, type ProviderFactory, RECOVERED_TX_RESULT, type RawBlock, type RawBlockHeader, type RawTransferInput, type RawTransferOutput, type ReconstructDeps, type ReconstructedTxRecord, type RegisterAssetArgs, type RelayerInfo, RelayerStatusModule, type ResolveSpentSetParams, type ResolvedProverVersion, type ResolvedSpendVersion, type RpcV2MerkleProof, RpcV2Module, type RpcV2NullifierStatus, type RpcV2PoolAssetBalance, type RpcV2PoolStats, type RunScanParams, SPENDING_KEY_CANONICAL_ORIGIN, SPENDING_KEY_VERIFYING_CONTRACT, SPENDING_KEY_WARNING, type ScanChunkManifest, ScanCommitment, type ScanHint, type ScanHintPage, type ScanHintSource, ScanKeys, type ScanOptions, type ScanOutcome, type ScanProgress, type ScanResult, SecretStore, type SelfEphWindowEntry, type SelfStealthKeys, SentNoteMatch, type SessionCacheDeps, type ShieldArgs, type ShieldBatchArgs, type ShieldBatchItem, type ShieldBatchParams, type ShieldOperation, type ShieldParams, type ShieldedEvent, type ShieldedPoolCall, type ShieldedPoolEvent, ShieldedPoolModule, ShieldedPoolPrecompile, type SlipImportKeys, SpendDetails, type SpendPlanProblem, type SpendPrivacyReads, type SpendVault, type SpendableInputsCheck, type SpendingKeyTypedData, type StatusChangeEvent, type StatusListener, SubstrateClient, type SystemHealth, TRANSFER_INPUTS, TRANSFER_OUTPUTS, type TokenInfo, type TokenTransfer, type TransferDeps, type TransferFactsRow, type TransferFactsSource, type TransferInputNote, type TransferOutputNote, type TransferParams, type TransferPlan, type TransferResult, type TransferStep, type TransferSubmitRequest, type TxFactsSource, TxHistoryStore, type TxKind, type TxLandingPollOptions, type TxResult, UnmatchedSentHint, type UnsafeTxOptions, type UnshieldArgs, type UnshieldDeps, type UnshieldNoteParams, type UnshieldParams, type UnshieldPlan, type UnshieldProofInputs, type UnshieldProofResult, type UnshieldStep, type UnshieldSubmitRequest, type UnshieldedEvent, type UnverifyAssetArgs, VAULT_SCHEMA_VERSION, VaultConfigRecord, VaultLockedError, VaultStorage, VaultStore, type VaultStoreDeps, type VaultUnlockOptions, type VerifyAssetArgs, type VersionedArtifactProvider, type ViewingCredential, type WalletIdentity, type WalletScanKeys, type WalletSession, ZkNote, type ZkVerifierCircuitVersionInfo, type ZkVerifierHistoricalVersion, ZkVerifierModule, type ZkVerifierVersionStats, type ZkVerifierVkHash, accountIdHexToSs58, addressToAccountIdHex, addressToFieldElement, applyBatch, applyNoteStatus, assertSecretKeyBytes, base64UrlDecode, base64UrlEncode, bigintTo32Be, bigintTo32Le, bigintTo32LeArr, blindTag, buildConfig, buildDummyTransferInput, buildShieldBatchOperations, buildShieldParams, buildZkNote, buildZkNoteWithIndex, bytesToBigintLE, bytesToBjjScalar, cacheSession, canPairWith, canonicalAccountId, chainActiveCircuitVersion, checkSpendableInputs, claimFees, classifyChainError, clearSession, collectNullifiersToQuery, collectOutgoingFacts, collectScanEntries, commitmentHexOf, computeNoteCommitment, computeNullifier, computePathIndices, connectInjectedExtension, createNoteDisclosureKey, createNotesCache, createWalletSession, decodeNoteBackup, decodeNoteDisclosureKey, decodePaymentSlip, decodePrecompileCalldata, decryptJson, decryptNoteRecord, deriveIdentity, deriveMasterKeyBytes, deriveOutgoingEphPk, deriveOutgoingEphSk, deriveOutgoingSharedSecret, deriveOutgoingViewingKeyV3, deriveOwnerPk, derivePairwiseEphSk, derivePairwiseSharedSecret, deriveSelfEphSk, deriveSpendingKeyFromMaster, deriveSpendingKeyFromSignature, deriveSpendingKeyMessageV2, deriveSpendingKeyTypedData, deriveSpendingKeyV3, deriveStealthOwnerPk, deriveStealthSk, deriveVaultBlindKey, deriveVaultKey, deriveViewTag, deriveViewingPublicKey, deriveViewingSecretKey, deriveViewingSecretKeyV3, detectCommitmentMismatch, encodeNoteBackup, encodePaymentSlip, encryptJson, encryptNote, ensureCreatedAt, ensureHexPrefix, evmAddressToAccountId, evmToImplicitSubstrate, evmToMappedAccountHex, evmToSubstrate, exportViewingCredential, extractPalletError, failed, fastMulBase, fastMulPoint, fetchExtrinsicFacts, formatAmountPlain, formatBalance, formatORB, fromBase64, fromHex, gapMargin, generateFeeClaimProof, generateTransferProof, generateUnshieldProof, getInjectedExtensions, getPrecompileLabel, hasCachedSession, hasInjectedExtensions, hasSourcePk, hexToBigint, hexToNumber, implicitSubstrateToEvm, importNotesFromBackup, importPaymentSlip, isAbortError, isAlreadySpentError, isConnectionLossError, isEvmAddress, isGhostNoteError, isHexOfLength, isImplicitEvmAccount, isNativeAsset, isNoteSelfConsistent, isSpendable, isSubstrateAddress, isUnifiedAddress, isUsableSecretKey, isValidLeafIndex, leHexToBigint, mapExtrinsicArgs, mapZkEventData, markInputsSpent, mergeProvenance, normalizeChainFingerprint, normalizeEvmAddress, normalizeNote, normalizeNotes, noteBlindTag, noteCreatedAt, noteCreatedTxHash, noteMatchesCommitment, noteOrigin, noteSpentTxHash, noteTxKind, openPaymentSlip, openRecipientBookEntry, outgoingEphWindow, outranks, pairwiseEphWindow, palletErrorKind, parseAmount, parseEvmAddress, persistCursor, persistScanResults, planTransfer, planUnshield, randomBlinding, reconstructOutgoingIndex, reconstructOutgoingTxRecords, recoverOwnerPkPoint, recoverSelfStealthNote, refuseIfAlreadySpent, regeneratePaymentSlip, registerPairwiseCounterparty, removeByCommitment, requireSessionKeys, reserveOutgoingIndex, reserveSelfEphIndex, resolveSelfEphCeiling, resolveSpentSet, resolveSpentStatus, restoreSession, runScan, scalarToHex, scanAbortError, sealPaymentSlip, sealRecipientBookEntry, selectDescribingNote, selectDescribingNoteByCommitment, selectGhosts, selectNotes, selfEphWindow, serializeMemo, sessionCacheKey, shortHash, signAndSubmitTx, spendableBalance, stampCreatedAt, stampCreatedTxHash, stampSpentTxHash, substrateSs58ToAccountIdHex, substrateToEvm, toBase64, toHex, toTxResult, transferNotes, treeIdOf, treeOf, truncateMiddle, tryDecryptNote, tryDecryptNoteVerbose, txLandedAfterError, unpackUsableViewingKey, unshieldNote, upsertNote, vaultReplacer, vaultReviver, vaultStorageName, windowSizeForCounter };
|