@unlink-xyz/core 0.1.3-canary.0877bfe → 0.1.3-canary.0bfbcf1
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 +9 -0
- package/dist/account/account.d.ts +31 -2
- package/dist/account/account.d.ts.map +1 -1
- package/dist/account/account.js +26 -5
- package/dist/account/accounts.d.ts +42 -0
- package/dist/account/accounts.d.ts.map +1 -0
- package/dist/account/accounts.js +119 -0
- package/dist/account/seed.d.ts +45 -0
- package/dist/account/seed.d.ts.map +1 -0
- package/dist/account/seed.js +91 -0
- package/dist/account/serialization.d.ts +6 -0
- package/dist/account/serialization.d.ts.map +1 -0
- package/dist/account/serialization.js +53 -0
- package/dist/browser/index.js +33339 -86194
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/wallet/index.js +55120 -0
- package/dist/browser/wallet/index.js.map +1 -0
- package/dist/clients/broadcaster.d.ts +1 -0
- package/dist/clients/broadcaster.d.ts.map +1 -1
- package/dist/clients/broadcaster.js +31 -8
- package/dist/clients/indexer.d.ts +1 -0
- package/dist/clients/indexer.d.ts.map +1 -1
- package/dist/clients/indexer.js +1 -2
- package/dist/config.d.ts +7 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +40 -7
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +0 -2
- package/dist/crypto/adapters/index.d.ts +17 -0
- package/dist/crypto/adapters/index.d.ts.map +1 -0
- package/dist/crypto/adapters/index.js +53 -0
- package/dist/crypto/adapters/polyfills.d.ts +5 -0
- package/dist/crypto/adapters/polyfills.d.ts.map +1 -0
- package/dist/crypto/adapters/polyfills.js +8 -0
- package/dist/crypto/encrypt.d.ts +33 -0
- package/dist/crypto/encrypt.d.ts.map +1 -0
- package/dist/crypto/encrypt.js +84 -0
- package/dist/crypto/secure-memory.d.ts.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/keys/derive.d.ts +2 -2
- package/dist/keys/derive.d.ts.map +1 -1
- package/dist/keys/derive.js +6 -9
- package/dist/keys/hex.d.ts +1 -4
- package/dist/keys/hex.d.ts.map +1 -1
- package/dist/keys/hex.js +0 -19
- package/dist/keys/mnemonic.d.ts +0 -2
- package/dist/keys/mnemonic.d.ts.map +1 -1
- package/dist/keys/mnemonic.js +1 -8
- package/dist/keys.d.ts +1 -0
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +1 -0
- package/dist/prover/config.d.ts +54 -9
- package/dist/prover/config.d.ts.map +1 -1
- package/dist/prover/config.js +65 -12
- package/dist/prover/integrity.d.ts +20 -0
- package/dist/prover/integrity.d.ts.map +1 -0
- package/dist/prover/integrity.js +93 -0
- package/dist/prover/prover.d.ts +16 -31
- package/dist/prover/prover.d.ts.map +1 -1
- package/dist/prover/prover.js +195 -87
- package/dist/state/merkle/hydrator.d.ts +21 -19
- package/dist/state/merkle/hydrator.d.ts.map +1 -1
- package/dist/state/merkle/hydrator.js +19 -27
- package/dist/state/merkle/index.d.ts +1 -1
- package/dist/state/merkle/index.d.ts.map +1 -1
- package/dist/state/merkle/merkle-tree.js +1 -1
- package/dist/state/store/ciphertext-store.d.ts +7 -0
- package/dist/state/store/ciphertext-store.d.ts.map +1 -1
- package/dist/state/store/ciphertext-store.js +14 -0
- package/dist/state/store/jobs.d.ts +5 -12
- package/dist/state/store/jobs.d.ts.map +1 -1
- package/dist/state/store/leaf-store.d.ts +4 -0
- package/dist/state/store/leaf-store.d.ts.map +1 -1
- package/dist/state/store/leaf-store.js +11 -1
- package/dist/state/store/nullifier-store.d.ts.map +1 -1
- package/dist/state/store/nullifier-store.js +1 -3
- package/dist/state/store/store.d.ts +18 -0
- package/dist/state/store/store.d.ts.map +1 -1
- package/dist/state/store/store.js +69 -0
- package/dist/storage/indexeddb.d.ts.map +1 -1
- package/dist/storage/indexeddb.js +69 -31
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +10 -0
- package/dist/transactions/deposit.d.ts +1 -1
- package/dist/transactions/deposit.d.ts.map +1 -1
- package/dist/transactions/deposit.js +9 -6
- package/dist/transactions/note-sync.d.ts.map +1 -1
- package/dist/transactions/note-sync.js +71 -44
- package/dist/transactions/reconcile.d.ts +1 -1
- package/dist/transactions/reconcile.d.ts.map +1 -1
- package/dist/transactions/reconcile.js +8 -2
- package/dist/transactions/transact.d.ts +1 -1
- package/dist/transactions/transact.d.ts.map +1 -1
- package/dist/transactions/transact.js +33 -21
- package/dist/transactions/transaction-planner.d.ts +1 -1
- package/dist/transactions/transaction-planner.d.ts.map +1 -1
- package/dist/transactions/transaction-planner.js +7 -5
- package/dist/transactions/transfer-planner.d.ts +2 -1
- package/dist/transactions/transfer-planner.d.ts.map +1 -1
- package/dist/transactions/transfer-planner.js +8 -2
- package/dist/transactions/types/domain.d.ts +3 -0
- package/dist/transactions/types/domain.d.ts.map +1 -1
- package/dist/transactions/types/options.d.ts +8 -5
- package/dist/transactions/types/options.d.ts.map +1 -1
- package/dist/transactions/types/planning.d.ts +2 -0
- package/dist/transactions/types/planning.d.ts.map +1 -1
- package/dist/transactions/types/state-stores.d.ts +45 -5
- package/dist/transactions/types/state-stores.d.ts.map +1 -1
- package/dist/transactions/types/transact.d.ts +5 -3
- package/dist/transactions/types/transact.d.ts.map +1 -1
- package/dist/transactions/withdrawal-planner.d.ts +1 -1
- package/dist/transactions/withdrawal-planner.d.ts.map +1 -1
- package/dist/transactions/withdrawal-planner.js +4 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsup.browser.config.js +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/amounts.d.ts +0 -13
- package/dist/utils/amounts.d.ts.map +1 -1
- package/dist/utils/amounts.js +0 -33
- package/dist/utils/bigint.d.ts +0 -2
- package/dist/utils/bigint.d.ts.map +1 -1
- package/dist/utils/bigint.js +0 -12
- package/dist/utils/signature.js +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js +0 -3
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +0 -6
- package/dist/wallet/burner/service.d.ts +32 -0
- package/dist/wallet/burner/service.d.ts.map +1 -0
- package/dist/wallet/burner/service.js +121 -0
- package/dist/wallet/burner/types.d.ts +47 -0
- package/dist/wallet/burner/types.d.ts.map +1 -0
- package/dist/wallet/burner/types.js +1 -0
- package/dist/wallet/index.d.ts +19 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +11 -0
- package/dist/wallet/sdk.d.ts +40 -0
- package/dist/wallet/sdk.d.ts.map +1 -0
- package/dist/wallet/sdk.js +690 -0
- package/dist/wallet/types.d.ts +278 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +2 -0
- package/package.json +13 -3
- package/dist/crypto-adapters/auto-init.d.ts +0 -2
- package/dist/crypto-adapters/auto-init.d.ts.map +0 -1
- package/dist/crypto-adapters/auto-init.js +0 -7
- package/dist/crypto-adapters/index.d.ts +0 -22
- package/dist/crypto-adapters/index.d.ts.map +0 -1
- package/dist/crypto-adapters/index.js +0 -47
- package/dist/crypto-adapters/polyfills.d.ts +0 -5
- package/dist/crypto-adapters/polyfills.d.ts.map +0 -1
- package/dist/crypto-adapters/polyfills.js +0 -8
- package/dist/utils/crypto.d.ts +0 -18
- package/dist/utils/crypto.d.ts.map +0 -1
- package/dist/utils/crypto.js +0 -45
- package/dist/utils/secure-memory.d.ts.map +0 -1
- /package/dist/{utils → crypto}/secure-memory.d.ts +0 -0
- /package/dist/{utils → crypto}/secure-memory.js +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @unlink-xyz/core
|
|
2
|
+
|
|
3
|
+
Low-level TypeScript SDK for the Unlink privacy protocol.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Core library providing key derivation, proof generation, transaction construction, state management, and high-level wallet API for UTXO-based private transactions on EVM blockchains. Used as a foundation by `@unlink-xyz/react` and consumed directly for server-side applications.
|
|
8
|
+
|
|
9
|
+
> **Documentation:** [SDK overview](../../docs/sdk/index.mdx) | [Architecture](../../docs/concepts/4-architecture/sdk.mdx)
|
|
@@ -22,8 +22,37 @@ export type Account = {
|
|
|
22
22
|
/** Bech32m address (0zk1...) for this account */
|
|
23
23
|
address: string;
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Read-only account identity — the fields needed by the transaction layer
|
|
27
|
+
* without any signing capability. Both Account and MultisigAccount satisfy this.
|
|
28
|
+
*/
|
|
29
|
+
export type AccountView = {
|
|
30
|
+
nullifyingKey: bigint;
|
|
31
|
+
masterPublicKey: bigint;
|
|
32
|
+
viewingKeyPair: ViewingKeyPair;
|
|
33
|
+
address: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Signing capability decoupled from account identity.
|
|
37
|
+
* Async to support multi-round protocols (FROST), hardware wallets, etc.
|
|
38
|
+
*/
|
|
39
|
+
export type Signer = {
|
|
40
|
+
publicKey: [bigint, bigint];
|
|
41
|
+
sign(message: bigint): Promise<{
|
|
42
|
+
R8: [bigint, bigint];
|
|
43
|
+
S: bigint;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Extract an AccountView from a full Account.
|
|
48
|
+
*/
|
|
49
|
+
export declare function toAccountView(account: Account): AccountView;
|
|
50
|
+
/**
|
|
51
|
+
* Create a Signer from a single spending key pair.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createSingleKeySigner(privateKey: Uint8Array, pubkey: [bigint, bigint]): Signer;
|
|
54
|
+
export declare function deriveAccount(masterSeed: Uint8Array, accountIndex?: number): Account;
|
|
55
|
+
export declare function deriveAccountFromMnemonic(mnemonic: string, accountIndex?: number, password?: string): Account;
|
|
27
56
|
export declare function generateMasterSeed({ storage, rng, crypto, overwrite, mnemonicPassphrase, }: GenerateMasterSeedOptions): Promise<Uint8Array>;
|
|
28
57
|
export declare function loadMasterSeed(storage: Storage, crypto?: MasterSeedCrypto): Promise<Uint8Array | null>;
|
|
29
58
|
export declare function storeMasterSeed(storage: Storage, seed: Uint8Array, crypto?: MasterSeedCrypto): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../account/account.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../account/account.ts"],"names":[],"mappings":"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"}
|
package/dist/account/account.js
CHANGED
|
@@ -1,21 +1,42 @@
|
|
|
1
|
+
import { zeroize } from "../crypto/secure-memory.js";
|
|
1
2
|
import { ValidationError } from "../errors.js";
|
|
2
3
|
import { encodeAddress } from "../keys/address.js";
|
|
3
4
|
import { deriveAccountKeys, } from "../keys/derive.js";
|
|
4
5
|
import { Hex } from "../keys/hex.js";
|
|
5
6
|
import { Mnemonic } from "../keys/mnemonic.js";
|
|
6
|
-
import {
|
|
7
|
+
import { signTransactMessage } from "../utils/signature.js";
|
|
7
8
|
export const MASTER_SEED_LENGTH = 64;
|
|
8
9
|
export const MASTER_SEED_KEY = "cfg:wallet:master_seed/v1";
|
|
9
10
|
export const MASTER_MNEMONIC_KEY = "cfg:wallet:master_mnemonic/v1";
|
|
10
11
|
const MNEMONIC_ENTROPY_BYTES = 32;
|
|
11
12
|
const textEncoder = new TextEncoder();
|
|
12
13
|
const textDecoder = new TextDecoder();
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Extract an AccountView from a full Account.
|
|
16
|
+
*/
|
|
17
|
+
export function toAccountView(account) {
|
|
18
|
+
return {
|
|
19
|
+
nullifyingKey: account.nullifyingKey,
|
|
20
|
+
masterPublicKey: account.masterPublicKey,
|
|
21
|
+
viewingKeyPair: account.viewingKeyPair,
|
|
22
|
+
address: account.address,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a Signer from a single spending key pair.
|
|
27
|
+
*/
|
|
28
|
+
export function createSingleKeySigner(privateKey, pubkey) {
|
|
29
|
+
return {
|
|
30
|
+
publicKey: pubkey,
|
|
31
|
+
sign: async (message) => signTransactMessage(privateKey, message),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function deriveAccount(masterSeed, accountIndex = 0) {
|
|
14
35
|
const seed = normalizeMasterSeed(masterSeed);
|
|
15
36
|
if (!Number.isInteger(accountIndex) || accountIndex < 0) {
|
|
16
37
|
throw new ValidationError("accountIndex must be a non-negative integer");
|
|
17
38
|
}
|
|
18
|
-
const keys =
|
|
39
|
+
const keys = deriveAccountKeys(seed, accountIndex);
|
|
19
40
|
const address = encodeAddress({
|
|
20
41
|
masterPublicKey: keys.masterPublicKey,
|
|
21
42
|
viewingPublicKey: keys.viewing.pubkey,
|
|
@@ -28,11 +49,11 @@ export async function deriveAccount(masterSeed, accountIndex = 0) {
|
|
|
28
49
|
address,
|
|
29
50
|
};
|
|
30
51
|
}
|
|
31
|
-
export
|
|
52
|
+
export function deriveAccountFromMnemonic(mnemonic, accountIndex = 0, password = "") {
|
|
32
53
|
const normalized = normalizeMnemonic(mnemonic);
|
|
33
54
|
const seed = mnemonicToSeed(normalized, password);
|
|
34
55
|
try {
|
|
35
|
-
return
|
|
56
|
+
return deriveAccount(seed, accountIndex);
|
|
36
57
|
}
|
|
37
58
|
finally {
|
|
38
59
|
zeroize(seed);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Storage } from "../types.js";
|
|
2
|
+
import type { AccountInfo } from "../wallet/types.js";
|
|
3
|
+
import { deriveAccount as deriveAccountFn, type Account } from "./account.js";
|
|
4
|
+
export declare const DERIVED_ACCOUNTS_KEY = "cfg:wallet:derived_accounts";
|
|
5
|
+
export declare const ACTIVE_ACCOUNT_INDEX_KEY = "cfg:wallet:active_account_index";
|
|
6
|
+
export declare const ACCOUNT_KEY_PREFIX = "cfg:wallet:account:";
|
|
7
|
+
export type AccountsServiceDeps = {
|
|
8
|
+
storage: Storage;
|
|
9
|
+
deriveAccount: typeof deriveAccountFn;
|
|
10
|
+
getMasterSeed: () => Promise<Uint8Array>;
|
|
11
|
+
};
|
|
12
|
+
export type AccountsService = {
|
|
13
|
+
/**
|
|
14
|
+
* List all derived accounts (index + mpk only, safe to display).
|
|
15
|
+
*/
|
|
16
|
+
list(): Promise<AccountInfo[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Get full Account by index (null if not derived yet).
|
|
19
|
+
*/
|
|
20
|
+
get(index: number): Promise<Account | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Derive and persist a new account at the specified index.
|
|
23
|
+
* If index is not specified, uses the next available index.
|
|
24
|
+
* @throws If the index is already used
|
|
25
|
+
*/
|
|
26
|
+
create(index?: number): Promise<Account>;
|
|
27
|
+
/**
|
|
28
|
+
* Get the currently active account (null if none).
|
|
29
|
+
*/
|
|
30
|
+
getActive(): Promise<Account | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Get the currently active account index (null if none).
|
|
33
|
+
*/
|
|
34
|
+
getActiveIndex(): Promise<number | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Switch to a different account by index.
|
|
37
|
+
* @throws If the account at the given index doesn't exist
|
|
38
|
+
*/
|
|
39
|
+
setActive(index: number): Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
export declare function createAccountsService(deps: AccountsServiceDeps): AccountsService;
|
|
42
|
+
//# sourceMappingURL=accounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../account/accounts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,IAAI,eAAe,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAM9E,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAClE,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,kBAAkB,wBAAwB,CAAC;AAExD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,eAAe,CAAC;IACtC,aAAa,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE/B;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAE5C;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzC;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAErC;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEzC;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC,CAAC;AAyBF,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,mBAAmB,GACxB,eAAe,CAkHjB"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
import { deserializeAccountRecord, serializeAccountRecord, } from "./serialization.js";
|
|
3
|
+
export const DERIVED_ACCOUNTS_KEY = "cfg:wallet:derived_accounts";
|
|
4
|
+
export const ACTIVE_ACCOUNT_INDEX_KEY = "cfg:wallet:active_account_index";
|
|
5
|
+
export const ACCOUNT_KEY_PREFIX = "cfg:wallet:account:";
|
|
6
|
+
const encoder = new TextEncoder();
|
|
7
|
+
const decoder = new TextDecoder();
|
|
8
|
+
function accountKey(index) {
|
|
9
|
+
return `${ACCOUNT_KEY_PREFIX}${index}`;
|
|
10
|
+
}
|
|
11
|
+
function encodeIndices(indices) {
|
|
12
|
+
return encoder.encode(JSON.stringify(indices));
|
|
13
|
+
}
|
|
14
|
+
function decodeIndices(data) {
|
|
15
|
+
return JSON.parse(decoder.decode(data));
|
|
16
|
+
}
|
|
17
|
+
function encodeIndex(index) {
|
|
18
|
+
return encoder.encode(JSON.stringify(index));
|
|
19
|
+
}
|
|
20
|
+
function decodeIndex(data) {
|
|
21
|
+
return JSON.parse(decoder.decode(data));
|
|
22
|
+
}
|
|
23
|
+
export function createAccountsService(deps) {
|
|
24
|
+
const { storage, deriveAccount, getMasterSeed } = deps;
|
|
25
|
+
async function getDerivedIndices() {
|
|
26
|
+
const stored = await storage.get(DERIVED_ACCOUNTS_KEY);
|
|
27
|
+
if (!stored)
|
|
28
|
+
return [];
|
|
29
|
+
return decodeIndices(stored);
|
|
30
|
+
}
|
|
31
|
+
async function setDerivedIndices(indices) {
|
|
32
|
+
await storage.put(DERIVED_ACCOUNTS_KEY, encodeIndices(indices));
|
|
33
|
+
}
|
|
34
|
+
async function loadAccount(index) {
|
|
35
|
+
const stored = await storage.get(accountKey(index));
|
|
36
|
+
if (!stored)
|
|
37
|
+
return null;
|
|
38
|
+
return deserializeAccountRecord(stored);
|
|
39
|
+
}
|
|
40
|
+
async function persistAccount(index, account) {
|
|
41
|
+
await storage.put(accountKey(index), serializeAccountRecord(account));
|
|
42
|
+
}
|
|
43
|
+
async function list() {
|
|
44
|
+
const indices = await getDerivedIndices();
|
|
45
|
+
const accounts = [];
|
|
46
|
+
for (const index of indices) {
|
|
47
|
+
const account = await loadAccount(index);
|
|
48
|
+
if (account) {
|
|
49
|
+
accounts.push({
|
|
50
|
+
index,
|
|
51
|
+
masterPublicKey: account.masterPublicKey,
|
|
52
|
+
address: account.address,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return accounts;
|
|
57
|
+
}
|
|
58
|
+
async function get(index) {
|
|
59
|
+
const indices = await getDerivedIndices();
|
|
60
|
+
if (!indices.includes(index))
|
|
61
|
+
return null;
|
|
62
|
+
return loadAccount(index);
|
|
63
|
+
}
|
|
64
|
+
async function create(index) {
|
|
65
|
+
const indices = await getDerivedIndices();
|
|
66
|
+
// Determine the index to use
|
|
67
|
+
let targetIndex;
|
|
68
|
+
if (index !== undefined) {
|
|
69
|
+
if (indices.includes(index)) {
|
|
70
|
+
throw new ValidationError(`Account at index ${index} already exists`);
|
|
71
|
+
}
|
|
72
|
+
targetIndex = index;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Use next available index
|
|
76
|
+
targetIndex = indices.length > 0 ? Math.max(...indices) + 1 : 0;
|
|
77
|
+
}
|
|
78
|
+
// Derive the account
|
|
79
|
+
const masterSeed = await getMasterSeed();
|
|
80
|
+
const account = deriveAccount(masterSeed, targetIndex);
|
|
81
|
+
// Persist the account (storage handles buffer isolation)
|
|
82
|
+
await persistAccount(targetIndex, account);
|
|
83
|
+
// Update the indices list
|
|
84
|
+
const newIndices = [...indices, targetIndex].sort((a, b) => a - b);
|
|
85
|
+
await setDerivedIndices(newIndices);
|
|
86
|
+
// If this is the first account, set it as active
|
|
87
|
+
if (indices.length === 0) {
|
|
88
|
+
await setActive(targetIndex);
|
|
89
|
+
}
|
|
90
|
+
return account;
|
|
91
|
+
}
|
|
92
|
+
async function getActiveIndex() {
|
|
93
|
+
const stored = await storage.get(ACTIVE_ACCOUNT_INDEX_KEY);
|
|
94
|
+
if (!stored)
|
|
95
|
+
return null;
|
|
96
|
+
return decodeIndex(stored);
|
|
97
|
+
}
|
|
98
|
+
async function getActive() {
|
|
99
|
+
const activeIndex = await getActiveIndex();
|
|
100
|
+
if (activeIndex === null)
|
|
101
|
+
return null;
|
|
102
|
+
return loadAccount(activeIndex);
|
|
103
|
+
}
|
|
104
|
+
async function setActive(index) {
|
|
105
|
+
const indices = await getDerivedIndices();
|
|
106
|
+
if (!indices.includes(index)) {
|
|
107
|
+
throw new ValidationError(`Cannot set active: account at index ${index} does not exist`);
|
|
108
|
+
}
|
|
109
|
+
await storage.put(ACTIVE_ACCOUNT_INDEX_KEY, encodeIndex(index));
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
list,
|
|
113
|
+
get,
|
|
114
|
+
create,
|
|
115
|
+
getActive,
|
|
116
|
+
getActiveIndex,
|
|
117
|
+
setActive,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Storage } from "../types.js";
|
|
2
|
+
import { type MasterSeedCrypto } from "./account.js";
|
|
3
|
+
export type SeedServiceDeps = {
|
|
4
|
+
storage: Storage;
|
|
5
|
+
rng: (n: number) => Uint8Array;
|
|
6
|
+
crypto?: MasterSeedCrypto;
|
|
7
|
+
};
|
|
8
|
+
export type SeedService = {
|
|
9
|
+
/**
|
|
10
|
+
* Check if a wallet exists (has mnemonic stored).
|
|
11
|
+
*/
|
|
12
|
+
exists(): Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new wallet. Generates a BIP-39 mnemonic and derives the master seed.
|
|
15
|
+
* Returns the mnemonic so the user can back it up.
|
|
16
|
+
* @throws If a wallet already exists (use import with overwrite instead)
|
|
17
|
+
*/
|
|
18
|
+
create(): Promise<{
|
|
19
|
+
mnemonic: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Import an existing BIP-39 mnemonic.
|
|
23
|
+
* @throws If the mnemonic is invalid
|
|
24
|
+
* @throws If a wallet already exists and overwrite is false
|
|
25
|
+
*/
|
|
26
|
+
importMnemonic(mnemonic: string, opts?: {
|
|
27
|
+
overwrite?: boolean;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Export the stored mnemonic for backup.
|
|
31
|
+
* @throws If no wallet exists
|
|
32
|
+
*/
|
|
33
|
+
exportMnemonic(): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the master seed (for account derivation).
|
|
36
|
+
* @throws If no wallet exists
|
|
37
|
+
*/
|
|
38
|
+
getMasterSeed(): Promise<Uint8Array>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete all wallet data. This is destructive and cannot be undone.
|
|
41
|
+
*/
|
|
42
|
+
delete(): Promise<void>;
|
|
43
|
+
};
|
|
44
|
+
export declare function createSeedService(deps: SeedServiceDeps): SeedService;
|
|
45
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../account/seed.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAOL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAOtB,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC/B,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,MAAM,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAExC;;;;OAIG;IACH,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;OAGG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAErC;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAgHpE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
import { generateMasterSeed, importMasterMnemonic, loadMasterMnemonic, loadMasterSeed, MASTER_MNEMONIC_KEY, MASTER_SEED_KEY, } from "./account.js";
|
|
3
|
+
import { ACCOUNT_KEY_PREFIX, ACTIVE_ACCOUNT_INDEX_KEY, DERIVED_ACCOUNTS_KEY, } from "./accounts.js";
|
|
4
|
+
export function createSeedService(deps) {
|
|
5
|
+
const { storage, rng, crypto } = deps;
|
|
6
|
+
async function exists() {
|
|
7
|
+
const mnemonic = await loadMasterMnemonic(storage, crypto);
|
|
8
|
+
return mnemonic !== null;
|
|
9
|
+
}
|
|
10
|
+
async function create() {
|
|
11
|
+
// Check if wallet already exists
|
|
12
|
+
const walletExists = await exists();
|
|
13
|
+
if (walletExists) {
|
|
14
|
+
throw new ValidationError("Wallet already exists. Use import with overwrite option to replace it.");
|
|
15
|
+
}
|
|
16
|
+
// Generate new mnemonic and seed
|
|
17
|
+
await generateMasterSeed({
|
|
18
|
+
storage,
|
|
19
|
+
rng,
|
|
20
|
+
crypto,
|
|
21
|
+
mnemonicPassphrase: "",
|
|
22
|
+
overwrite: false,
|
|
23
|
+
});
|
|
24
|
+
// Load and return the mnemonic so user can back it up
|
|
25
|
+
const mnemonic = await loadMasterMnemonic(storage, crypto);
|
|
26
|
+
if (!mnemonic) {
|
|
27
|
+
throw new ValidationError("Failed to create wallet: mnemonic not stored");
|
|
28
|
+
}
|
|
29
|
+
return { mnemonic };
|
|
30
|
+
}
|
|
31
|
+
async function importMnemonic(mnemonic, opts) {
|
|
32
|
+
const overwrite = opts?.overwrite ?? false;
|
|
33
|
+
// Check if wallet already exists
|
|
34
|
+
if (!overwrite) {
|
|
35
|
+
const walletExists = await exists();
|
|
36
|
+
if (walletExists) {
|
|
37
|
+
throw new ValidationError("Wallet already exists. Use overwrite option to replace it.");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Import the mnemonic first
|
|
41
|
+
await importMasterMnemonic({
|
|
42
|
+
storage,
|
|
43
|
+
mnemonic,
|
|
44
|
+
crypto,
|
|
45
|
+
overwrite,
|
|
46
|
+
password: "",
|
|
47
|
+
});
|
|
48
|
+
// Clear account data after successful import to avoid data loss on failure
|
|
49
|
+
if (overwrite) {
|
|
50
|
+
await clearAccountData();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function exportMnemonic() {
|
|
54
|
+
const mnemonic = await loadMasterMnemonic(storage, crypto);
|
|
55
|
+
if (!mnemonic) {
|
|
56
|
+
throw new ValidationError("No wallet exists. Create or import a wallet first.");
|
|
57
|
+
}
|
|
58
|
+
return mnemonic;
|
|
59
|
+
}
|
|
60
|
+
async function getMasterSeed() {
|
|
61
|
+
const seed = await loadMasterSeed(storage, crypto);
|
|
62
|
+
if (!seed) {
|
|
63
|
+
throw new ValidationError("No wallet exists. Create or import a wallet first.");
|
|
64
|
+
}
|
|
65
|
+
return seed;
|
|
66
|
+
}
|
|
67
|
+
async function clearAccountData() {
|
|
68
|
+
// Delete all account records by prefix
|
|
69
|
+
const accountRecords = await storage.iter({ prefix: ACCOUNT_KEY_PREFIX });
|
|
70
|
+
for (const { key } of accountRecords) {
|
|
71
|
+
await storage.delete(key);
|
|
72
|
+
}
|
|
73
|
+
// Clear metadata keys
|
|
74
|
+
await storage.delete(DERIVED_ACCOUNTS_KEY);
|
|
75
|
+
await storage.delete(ACTIVE_ACCOUNT_INDEX_KEY);
|
|
76
|
+
}
|
|
77
|
+
async function deleteWallet() {
|
|
78
|
+
// Clear all wallet data
|
|
79
|
+
await storage.delete(MASTER_MNEMONIC_KEY);
|
|
80
|
+
await storage.delete(MASTER_SEED_KEY);
|
|
81
|
+
await clearAccountData();
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
exists,
|
|
85
|
+
create,
|
|
86
|
+
importMnemonic,
|
|
87
|
+
exportMnemonic,
|
|
88
|
+
getMasterSeed,
|
|
89
|
+
delete: deleteWallet,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { formatUint256 } from "../utils/bigint.js";
|
|
2
|
+
import type { Account } from "./account.js";
|
|
3
|
+
export { formatUint256 };
|
|
4
|
+
export declare function serializeAccountRecord(account: Account): Uint8Array;
|
|
5
|
+
export declare function deserializeAccountRecord(payload: Uint8Array): Account;
|
|
6
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../account/serialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,CAAC;AAQzB,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAmBnE;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CA6BrE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { formatUint256 } from "../utils/bigint.js";
|
|
2
|
+
import { ACCOUNT_RECORD_VERSION, BIGINT_RADIX, } from "../wallet/types.js";
|
|
3
|
+
export { formatUint256 };
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
const encodeBigInt = (value) => value.toString(BIGINT_RADIX);
|
|
7
|
+
const decodeBigInt = (value) => BigInt(`0x${value}`);
|
|
8
|
+
export function serializeAccountRecord(account) {
|
|
9
|
+
const record = {
|
|
10
|
+
version: ACCOUNT_RECORD_VERSION,
|
|
11
|
+
spendingKeyPair: {
|
|
12
|
+
privateKey: Array.from(account.spendingKeyPair.privateKey),
|
|
13
|
+
pubkey: [
|
|
14
|
+
encodeBigInt(account.spendingKeyPair.pubkey[0]),
|
|
15
|
+
encodeBigInt(account.spendingKeyPair.pubkey[1]),
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
viewingKeyPair: {
|
|
19
|
+
privateKey: Array.from(account.viewingKeyPair.privateKey),
|
|
20
|
+
pubkey: Array.from(account.viewingKeyPair.pubkey),
|
|
21
|
+
},
|
|
22
|
+
nullifyingKey: encodeBigInt(account.nullifyingKey),
|
|
23
|
+
masterPublicKey: encodeBigInt(account.masterPublicKey),
|
|
24
|
+
address: account.address,
|
|
25
|
+
};
|
|
26
|
+
return encoder.encode(JSON.stringify(record));
|
|
27
|
+
}
|
|
28
|
+
export function deserializeAccountRecord(payload) {
|
|
29
|
+
const parsed = JSON.parse(decoder.decode(payload));
|
|
30
|
+
if (parsed.version !== ACCOUNT_RECORD_VERSION) {
|
|
31
|
+
throw new Error(`unsupported wallet account version ${parsed.version}`);
|
|
32
|
+
}
|
|
33
|
+
const spendingPubkey = [
|
|
34
|
+
decodeBigInt(parsed.spendingKeyPair.pubkey[0]),
|
|
35
|
+
decodeBigInt(parsed.spendingKeyPair.pubkey[1]),
|
|
36
|
+
];
|
|
37
|
+
const viewingPubkey = Uint8Array.from(parsed.viewingKeyPair.pubkey);
|
|
38
|
+
const masterPublicKey = decodeBigInt(parsed.masterPublicKey);
|
|
39
|
+
const address = parsed.address;
|
|
40
|
+
return {
|
|
41
|
+
spendingKeyPair: {
|
|
42
|
+
privateKey: Uint8Array.from(parsed.spendingKeyPair.privateKey),
|
|
43
|
+
pubkey: spendingPubkey,
|
|
44
|
+
},
|
|
45
|
+
viewingKeyPair: {
|
|
46
|
+
privateKey: Uint8Array.from(parsed.viewingKeyPair.privateKey),
|
|
47
|
+
pubkey: viewingPubkey,
|
|
48
|
+
},
|
|
49
|
+
nullifyingKey: decodeBigInt(parsed.nullifyingKey),
|
|
50
|
+
masterPublicKey,
|
|
51
|
+
address,
|
|
52
|
+
};
|
|
53
|
+
}
|