@zerc20/wallet-sdk 0.3.0 → 0.4.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/dist/context.d.ts +6 -4
- package/dist/context.js +2 -1
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/sync.d.ts +1 -1
- package/dist/sync.js +5 -2
- package/dist/sync.js.map +1 -1
- package/dist/viewKey.d.ts +14 -0
- package/dist/viewKey.js +45 -0
- package/dist/viewKey.js.map +1 -0
- package/dist/wallet.d.ts +17 -2
- package/dist/wallet.js +103 -32
- package/dist/wallet.js.map +1 -1
- package/package.json +3 -2
- package/src/context.ts +8 -5
- package/src/errors.ts +2 -0
- package/src/index.ts +3 -0
- package/src/sync.ts +4 -2
- package/src/viewKey.ts +49 -0
- package/src/wallet.ts +142 -35
- package/wasm/zerc20_wallet_core.d.ts +7 -0
- package/wasm/zerc20_wallet_core.js +30 -0
- package/wasm/zerc20_wallet_core_bg.wasm +0 -0
- package/wasm/zerc20_wallet_core_bg.wasm.d.ts +1 -0
package/src/wallet.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
encodeCode,
|
|
11
11
|
lookupRecipient,
|
|
12
12
|
nextPosLane,
|
|
13
|
+
notifyKey,
|
|
13
14
|
planDeposit,
|
|
14
15
|
planPosLane,
|
|
15
16
|
posKey,
|
|
@@ -23,13 +24,25 @@ import {
|
|
|
23
24
|
type WalletClient,
|
|
24
25
|
bytesToHex,
|
|
25
26
|
formatUnits,
|
|
27
|
+
getAddress,
|
|
26
28
|
hexToBytes,
|
|
27
29
|
isAddress,
|
|
28
30
|
numberToHex,
|
|
29
31
|
zeroAddress,
|
|
30
32
|
} from 'viem';
|
|
33
|
+
import { toAccount } from 'viem/accounts';
|
|
31
34
|
import { Chain, MAX_REFERRAL_BPS, NATIVE, type Referrer, type Token, erc20Abi, tokenAbi } from './chain.js';
|
|
32
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
type ChainCtx,
|
|
37
|
+
type Ctx,
|
|
38
|
+
type SpendKey,
|
|
39
|
+
chainCtx,
|
|
40
|
+
chainState,
|
|
41
|
+
owner,
|
|
42
|
+
switched,
|
|
43
|
+
walletOn,
|
|
44
|
+
walletSees,
|
|
45
|
+
} from './context.js';
|
|
33
46
|
import { burnAddressFor, core, initCore } from './core.js';
|
|
34
47
|
import { type ErrorCode, WalletError, fail, guard } from './errors.js';
|
|
35
48
|
import { type Network, checkNetwork } from './network.js';
|
|
@@ -79,6 +92,7 @@ import {
|
|
|
79
92
|
topUpBurns,
|
|
80
93
|
unusedBurn,
|
|
81
94
|
} from './sync.js';
|
|
95
|
+
import { decodeViewKey, encodeViewKey } from './viewKey.js';
|
|
82
96
|
|
|
83
97
|
/** The ledger's bound outside an emergency. */
|
|
84
98
|
const NO_BOUND = 2n ** 64n - 1n;
|
|
@@ -106,6 +120,11 @@ export interface OpenOptions {
|
|
|
106
120
|
referrer?: Referrer;
|
|
107
121
|
}
|
|
108
122
|
|
|
123
|
+
export interface WatchOptions extends Pick<OpenOptions, 'network' | 'persist' | 'birthday'> {
|
|
124
|
+
/** The account's view key, from its wallet's `viewKey()`. */
|
|
125
|
+
viewKey: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
109
128
|
/** What a deposit, or a deposit address, waits on: for an app to show while it does. */
|
|
110
129
|
export type DepositStep =
|
|
111
130
|
/** Behind another call of this wallet: a sync, or another operation. */
|
|
@@ -253,6 +272,7 @@ export class Wallet {
|
|
|
253
272
|
#release = () => {};
|
|
254
273
|
#referrer: Referrer | undefined;
|
|
255
274
|
readonly #unlock: (() => Promise<Uint8Array>) | undefined;
|
|
275
|
+
#readOnly = false;
|
|
256
276
|
#closed = new AbortController();
|
|
257
277
|
|
|
258
278
|
private constructor(ctx: Ctx, unlock?: () => Promise<Uint8Array>) {
|
|
@@ -272,6 +292,18 @@ export class Wallet {
|
|
|
272
292
|
return this.#ctx.address;
|
|
273
293
|
}
|
|
274
294
|
|
|
295
|
+
/** The account's view key, for `watch` to follow it with on another device: whoever holds it sees what this wallet
|
|
296
|
+
* shows, except the private payments to receive codes, and can spend none of it. Checksummed text (bech32m,
|
|
297
|
+
* `zerc20view1…`). */
|
|
298
|
+
viewKey(): string {
|
|
299
|
+
return encodeViewKey(this.#ctx.view, owner(this.#ctx)!);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Whether this wallet only watches its account (`watch`): it shows what the account holds and spends nothing. */
|
|
303
|
+
get readOnly(): boolean {
|
|
304
|
+
return this.#readOnly;
|
|
305
|
+
}
|
|
306
|
+
|
|
275
307
|
/** Opens the wallet. The first time on this address, registers it for payments: one signature. */
|
|
276
308
|
static async open(opts: OpenOptions): Promise<Wallet> {
|
|
277
309
|
checkNetwork(opts.network);
|
|
@@ -301,12 +333,7 @@ export class Wallet {
|
|
|
301
333
|
|
|
302
334
|
static async #open(opts: OpenOptions, seed: Uint8Array, account: Account, release: () => void): Promise<Wallet> {
|
|
303
335
|
const address = account.address;
|
|
304
|
-
const chains = opts.network
|
|
305
|
-
config,
|
|
306
|
-
chain: new Chain(config),
|
|
307
|
-
indexer: new Indexer(config.indexer),
|
|
308
|
-
asp: new Asp(config.asp),
|
|
309
|
-
}));
|
|
336
|
+
const chains = chainsOf(opts.network);
|
|
310
337
|
const code = await chains[0]?.chain.client.getCode({ address });
|
|
311
338
|
// an EIP-7702 delegated account is still an EOA that signs
|
|
312
339
|
if (code && code !== '0x' && !code.startsWith('0xef0100'))
|
|
@@ -327,39 +354,99 @@ export class Wallet {
|
|
|
327
354
|
const restoring =
|
|
328
355
|
!saved?.length && opts.birthday === undefined && !!(await storage.registration(hexToBytes(address)));
|
|
329
356
|
const view = await registeredViewKey(storage, seed, signer, hexToBytes(address), publicKey);
|
|
330
|
-
const
|
|
357
|
+
const wallet = await Wallet.#begin(
|
|
358
|
+
{
|
|
359
|
+
network: opts.network,
|
|
360
|
+
seed,
|
|
361
|
+
owners: new Map(),
|
|
362
|
+
address,
|
|
363
|
+
account,
|
|
364
|
+
walletClient: opts.walletClient ?? null,
|
|
365
|
+
storage,
|
|
366
|
+
view,
|
|
367
|
+
chains,
|
|
368
|
+
},
|
|
369
|
+
{ persist: opts.persist, saved, key: stateKey(seed), from: restoring ? 0n : opts.birthday },
|
|
370
|
+
typeof opts.seed === 'function' ? opts.seed : undefined,
|
|
371
|
+
);
|
|
372
|
+
wallet.#release = release;
|
|
373
|
+
wallet.#referrer = opts.referrer;
|
|
374
|
+
return wallet;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Opens an account to follow by its view key (`viewKey()`): its balances, coins and history as its own wallet shows
|
|
378
|
+
* them, less the private payments to its receive codes, whose keys only the seed derives. It spends and writes
|
|
379
|
+
* nothing: a call that would fails with `read-only`. The key must be the account's current one on this network. */
|
|
380
|
+
static async watch(opts: WatchOptions): Promise<Wallet> {
|
|
381
|
+
checkNetwork(opts.network);
|
|
382
|
+
await initCore();
|
|
383
|
+
const { view, owner } = decodeViewKey(opts.viewKey) ?? fail('invalid', 'not a view key');
|
|
384
|
+
const address = getAddress(bytesToHex(view.address));
|
|
385
|
+
const release = await lockWallet(address, 'view');
|
|
386
|
+
try {
|
|
387
|
+
const storage = await CanisterClient.connect(opts.network.storage.host, opts.network.storage.canisterId);
|
|
388
|
+
// what the account signed: a nullifying key that is not the account's would show spent coins as unspent
|
|
389
|
+
const r = await lookupRecipient(storage, view.address);
|
|
390
|
+
if (!r || bytesToHex(r.publicKey) !== owner.publicKey || bytesToHex(r.notifyKey) !== bytesToHex(notifyKey(view)))
|
|
391
|
+
fail('invalid', `not ${address}'s view key on ${opts.network.name}, or one it has replaced`);
|
|
392
|
+
const wallet = await Wallet.#begin(
|
|
393
|
+
{
|
|
394
|
+
network: opts.network,
|
|
395
|
+
seed: null,
|
|
396
|
+
owners: new Map([['', owner]]),
|
|
397
|
+
address,
|
|
398
|
+
// signs nothing: every call that would send is refused first
|
|
399
|
+
account: toAccount(address),
|
|
400
|
+
walletClient: null,
|
|
401
|
+
storage,
|
|
402
|
+
view,
|
|
403
|
+
chains: chainsOf(opts.network),
|
|
404
|
+
},
|
|
405
|
+
// registered, so its past is looked for
|
|
406
|
+
{
|
|
407
|
+
persist: opts.persist,
|
|
408
|
+
saved: await opts.persist.load(),
|
|
409
|
+
key: stateKey(view.seed),
|
|
410
|
+
from: opts.birthday ?? 0n,
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
wallet.#release = release;
|
|
414
|
+
wallet.#readOnly = true;
|
|
415
|
+
return wallet;
|
|
416
|
+
} catch (e) {
|
|
417
|
+
release();
|
|
418
|
+
throw e;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** The wallet over `base`, its state opened from what `persist` saved, with `key`, or started `from` a block or date. */
|
|
423
|
+
static async #begin(
|
|
424
|
+
base: Omit<Ctx, 'state' | 'save' | 'lastFullRefreshMs'>,
|
|
425
|
+
{
|
|
426
|
+
persist,
|
|
427
|
+
saved,
|
|
428
|
+
key,
|
|
429
|
+
from,
|
|
430
|
+
}: { persist: OpenOptions['persist']; saved: Uint8Array | null | undefined; key: Uint8Array; from?: bigint | Date },
|
|
431
|
+
unlock?: () => Promise<Uint8Array>,
|
|
432
|
+
): Promise<Wallet> {
|
|
331
433
|
const loaded = saved?.length ? openState(key, saved) : null;
|
|
332
434
|
// never started over in place: the first save would overwrite what it held, operations in flight included
|
|
333
435
|
if (saved?.length && !loaded) {
|
|
334
436
|
fail(
|
|
335
437
|
'invalid',
|
|
336
|
-
'the saved state does not open with this
|
|
438
|
+
'the saved state does not open with this key (another seed or view key, a newer version, or damaged): clear it to start over, which finds what it held again',
|
|
337
439
|
);
|
|
338
440
|
}
|
|
339
|
-
if (loaded && loaded.address.toLowerCase() !== address.toLowerCase())
|
|
441
|
+
if (loaded && loaded.address.toLowerCase() !== base.address.toLowerCase())
|
|
340
442
|
fail('invalid', `the saved state is ${loaded.address}'s: keep one per address`);
|
|
341
|
-
const state: WalletState = loaded ?? emptyWalletState(address);
|
|
342
|
-
const ctx: Ctx = {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
owners: new Map(),
|
|
346
|
-
address,
|
|
347
|
-
account,
|
|
348
|
-
walletClient: opts.walletClient ?? null,
|
|
349
|
-
storage,
|
|
350
|
-
view,
|
|
351
|
-
chains,
|
|
352
|
-
state,
|
|
353
|
-
save: () => opts.persist.save(sealState(key, state)),
|
|
354
|
-
lastFullRefreshMs: 0,
|
|
355
|
-
};
|
|
356
|
-
if (!loaded) await start(ctx, restoring ? 0n : opts.birthday);
|
|
357
|
-
const wallet = new Wallet(ctx, typeof opts.seed === 'function' ? opts.seed : undefined);
|
|
358
|
-
wallet.#release = release;
|
|
359
|
-
wallet.#referrer = opts.referrer;
|
|
443
|
+
const state: WalletState = loaded ?? emptyWalletState(base.address);
|
|
444
|
+
const ctx: Ctx = { ...base, state, save: () => persist.save(sealState(key, state)), lastFullRefreshMs: 0 };
|
|
445
|
+
if (!loaded) await start(ctx, from);
|
|
446
|
+
const wallet = new Wallet(ctx, unlock);
|
|
360
447
|
// a saved state names its tokens by id, and its coins stand by the chains' roots: read both now, so balances, coins
|
|
361
448
|
// and history work before the first sync
|
|
362
|
-
const [tokens] = await Promise.all([Promise.all(chains.map((c) => c.chain.tokens())), wallet.#readRoots()]);
|
|
449
|
+
const [tokens] = await Promise.all([Promise.all(ctx.chains.map((c) => c.chain.tokens())), wallet.#readRoots()]);
|
|
363
450
|
wallet.#tokens = tokens.flat();
|
|
364
451
|
keyAll(ctx, wallet.#tokens);
|
|
365
452
|
return wallet;
|
|
@@ -391,10 +478,16 @@ export class Wallet {
|
|
|
391
478
|
* anything else (a browser shows a passkey prompt only in the click that asked), and queued in the step that took it,
|
|
392
479
|
* so that a sync ending meanwhile does not let it go. */
|
|
393
480
|
async #seeded<T>(f: () => Promise<T>, needs = true): Promise<T> {
|
|
481
|
+
this.#writable();
|
|
394
482
|
if (needs && !this.#ctx.seed) this.#hold(await this.#unlock!());
|
|
395
483
|
return this.#exclusive(f);
|
|
396
484
|
}
|
|
397
485
|
|
|
486
|
+
/** Refuses a call that spends or writes to storage, in a wallet that watches. */
|
|
487
|
+
#writable(): void {
|
|
488
|
+
if (this.#readOnly) fail('read-only', 'this wallet watches its account by its view key: open it with its seed');
|
|
489
|
+
}
|
|
490
|
+
|
|
398
491
|
/** Runs `f` after everything queued before it: one state, changed by one task at a time. */
|
|
399
492
|
#exclusive<T>(f: () => Promise<T>): Promise<T> {
|
|
400
493
|
this.#busy++;
|
|
@@ -435,8 +528,9 @@ export class Wallet {
|
|
|
435
528
|
return new Promise((resolve, reject) => {
|
|
436
529
|
this.#exclusive(async () => {
|
|
437
530
|
await this.#catchUp().then(resolve, reject);
|
|
438
|
-
// still this task's: a deposit queued meanwhile finds the one recorded ahead, rather than writing at handout
|
|
439
|
-
|
|
531
|
+
// still this task's: a deposit queued meanwhile finds the one recorded ahead, rather than writing at handout;
|
|
532
|
+
// tried again after the next sync. A wallet that watches records none, as it writes nothing.
|
|
533
|
+
if (!this.#readOnly) await topUpBurns(this.#ctx, this.#closed.signal).catch(() => {});
|
|
440
534
|
this.#dropSeed();
|
|
441
535
|
}).catch(reject); // closed before it ran
|
|
442
536
|
});
|
|
@@ -818,6 +912,7 @@ export class Wallet {
|
|
|
818
912
|
* addresses. */
|
|
819
913
|
posKey(): Promise<Hex> {
|
|
820
914
|
return this.#exclusive(async () => {
|
|
915
|
+
this.#writable();
|
|
821
916
|
const ctx = this.#ctx;
|
|
822
917
|
const tokens = await tokenIds(ctx);
|
|
823
918
|
let n = 0;
|
|
@@ -951,6 +1046,7 @@ export class Wallet {
|
|
|
951
1046
|
from?: WalletClient;
|
|
952
1047
|
onStep?: (step: DepositStep) => void;
|
|
953
1048
|
}): Promise<Operation> {
|
|
1049
|
+
this.#writable();
|
|
954
1050
|
if (opts.amount <= 0n) fail('invalid', 'the amount must be positive');
|
|
955
1051
|
const payer = opts.from ? (opts.from.account ?? fail('invalid', 'the wallet client has no account')) : null;
|
|
956
1052
|
const step = opts.onStep ?? (() => {});
|
|
@@ -1091,6 +1187,7 @@ export class Wallet {
|
|
|
1091
1187
|
const step = opts.onStep ?? (() => {});
|
|
1092
1188
|
if (this.#busy > 0) step('queued');
|
|
1093
1189
|
return this.#exclusive(async () => {
|
|
1190
|
+
this.#writable();
|
|
1094
1191
|
const c = chainCtx(this.#ctx, token.chainId);
|
|
1095
1192
|
const record = await this.#burnAddress(token, null, () => step('burn-address'));
|
|
1096
1193
|
const { depositAddress, fee } = await registerDeposit(
|
|
@@ -1315,15 +1412,25 @@ export class Wallet {
|
|
|
1315
1412
|
}
|
|
1316
1413
|
}
|
|
1317
1414
|
|
|
1415
|
+
/** Each chain of `network`, with its servers. */
|
|
1416
|
+
const chainsOf = (network: Network): ChainCtx[] =>
|
|
1417
|
+
network.chains.map((config) => ({
|
|
1418
|
+
config,
|
|
1419
|
+
chain: new Chain(config),
|
|
1420
|
+
indexer: new Indexer(config.indexer),
|
|
1421
|
+
asp: new Asp(config.asp),
|
|
1422
|
+
}));
|
|
1423
|
+
|
|
1318
1424
|
/** Holds `address`'s wallet until the returned function is called: two tabs on one wallet would each overwrite the
|
|
1319
|
-
* other's state and spend the same notes.
|
|
1320
|
-
|
|
1425
|
+
* other's state and spend the same notes. A wallet that watches it (`view`) is held apart, as its state is its own.
|
|
1426
|
+
* Nothing where there are no Web Locks. */
|
|
1427
|
+
export async function lockWallet(address: Address, kind: 'wallet' | 'view' = 'wallet'): Promise<() => void> {
|
|
1321
1428
|
const locks = (globalThis as { navigator?: Navigator }).navigator?.locks;
|
|
1322
1429
|
if (!locks) return () => {};
|
|
1323
1430
|
let release = () => {};
|
|
1324
1431
|
const held = new Promise<void>((r) => (release = r));
|
|
1325
1432
|
const got = await new Promise<boolean>((resolve) => {
|
|
1326
|
-
void locks.request(`zerc20
|
|
1433
|
+
void locks.request(`zerc20-${kind}:${address.toLowerCase()}`, { ifAvailable: true }, (lock) => {
|
|
1327
1434
|
resolve(lock !== null);
|
|
1328
1435
|
return lock ? held : undefined;
|
|
1329
1436
|
});
|
|
@@ -73,6 +73,12 @@ export function path(i: bigint, n: bigint, chunk_leaves: Uint8Array, page_chunks
|
|
|
73
73
|
*/
|
|
74
74
|
export function pathRoot(leaf: string, i: bigint, siblings: string[]): string;
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The public key a signing key's hash and a nullifying key make: how a view key's holder checks that the nullifying
|
|
78
|
+
* key it was given is the one the account's notes commit to.
|
|
79
|
+
*/
|
|
80
|
+
export function publicKey(auth_key_hash: string, nullifying_key: string): string;
|
|
81
|
+
|
|
76
82
|
/**
|
|
77
83
|
* Seals a merge witness (JSON) to the merge prover's key, padded with spaces to `pad_to` bytes. Take the key from
|
|
78
84
|
* `verifyAttestation`, as for the attester's.
|
|
@@ -138,6 +144,7 @@ export interface InitOutput {
|
|
|
138
144
|
readonly nullifier: (a: bigint, b: bigint, c: number, d: number) => [number, number, number, number];
|
|
139
145
|
readonly path: (a: bigint, b: bigint, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => [number, number, number, number];
|
|
140
146
|
readonly pathRoot: (a: number, b: number, c: bigint, d: number, e: number) => [number, number, number, number];
|
|
147
|
+
readonly publicKey: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
141
148
|
readonly sealMergeWitness: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
142
149
|
readonly sealWitness: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
143
150
|
readonly signMerge: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
@@ -324,6 +324,36 @@ export function pathRoot(leaf, i, siblings) {
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/**
|
|
328
|
+
* The public key a signing key's hash and a nullifying key make: how a view key's holder checks that the nullifying
|
|
329
|
+
* key it was given is the one the account's notes commit to.
|
|
330
|
+
* @param {string} auth_key_hash
|
|
331
|
+
* @param {string} nullifying_key
|
|
332
|
+
* @returns {string}
|
|
333
|
+
*/
|
|
334
|
+
export function publicKey(auth_key_hash, nullifying_key) {
|
|
335
|
+
let deferred4_0;
|
|
336
|
+
let deferred4_1;
|
|
337
|
+
try {
|
|
338
|
+
const ptr0 = passStringToWasm0(auth_key_hash, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
339
|
+
const len0 = WASM_VECTOR_LEN;
|
|
340
|
+
const ptr1 = passStringToWasm0(nullifying_key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
341
|
+
const len1 = WASM_VECTOR_LEN;
|
|
342
|
+
const ret = wasm.publicKey(ptr0, len0, ptr1, len1);
|
|
343
|
+
var ptr3 = ret[0];
|
|
344
|
+
var len3 = ret[1];
|
|
345
|
+
if (ret[3]) {
|
|
346
|
+
ptr3 = 0; len3 = 0;
|
|
347
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
348
|
+
}
|
|
349
|
+
deferred4_0 = ptr3;
|
|
350
|
+
deferred4_1 = len3;
|
|
351
|
+
return getStringFromWasm0(ptr3, len3);
|
|
352
|
+
} finally {
|
|
353
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
327
357
|
/**
|
|
328
358
|
* Seals a merge witness (JSON) to the merge prover's key, padded with spaces to `pad_to` bytes. Take the key from
|
|
329
359
|
* `verifyAttestation`, as for the attester's.
|
|
Binary file
|
|
@@ -14,6 +14,7 @@ export const noteTag: (a: number, b: number, c: number) => [number, number, numb
|
|
|
14
14
|
export const nullifier: (a: bigint, b: bigint, c: number, d: number) => [number, number, number, number];
|
|
15
15
|
export const path: (a: bigint, b: bigint, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => [number, number, number, number];
|
|
16
16
|
export const pathRoot: (a: number, b: number, c: bigint, d: number, e: number) => [number, number, number, number];
|
|
17
|
+
export const publicKey: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
17
18
|
export const sealMergeWitness: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
18
19
|
export const sealWitness: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
19
20
|
export const signMerge: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|