@shieldedtech/moth-wallet 0.2.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 +62 -0
- package/dist/contract/args-parser.d.ts +29 -0
- package/dist/contract/args-parser.d.ts.map +1 -0
- package/dist/contract/args-parser.js +123 -0
- package/dist/contract/args-parser.js.map +1 -0
- package/dist/contract/artifact-loader.d.ts +26 -0
- package/dist/contract/artifact-loader.d.ts.map +1 -0
- package/dist/contract/artifact-loader.js +129 -0
- package/dist/contract/artifact-loader.js.map +1 -0
- package/dist/contract/call.d.ts +32 -0
- package/dist/contract/call.d.ts.map +1 -0
- package/dist/contract/call.js +245 -0
- package/dist/contract/call.js.map +1 -0
- package/dist/contract/deploy.d.ts +36 -0
- package/dist/contract/deploy.d.ts.map +1 -0
- package/dist/contract/deploy.js +388 -0
- package/dist/contract/deploy.js.map +1 -0
- package/dist/contract/fungible-token.d.ts +40 -0
- package/dist/contract/fungible-token.d.ts.map +1 -0
- package/dist/contract/fungible-token.js +88 -0
- package/dist/contract/fungible-token.js.map +1 -0
- package/dist/contract/initial-private-state.d.ts +18 -0
- package/dist/contract/initial-private-state.d.ts.map +1 -0
- package/dist/contract/initial-private-state.js +44 -0
- package/dist/contract/initial-private-state.js.map +1 -0
- package/dist/contract/maintenance.d.ts +72 -0
- package/dist/contract/maintenance.d.ts.map +1 -0
- package/dist/contract/maintenance.js +430 -0
- package/dist/contract/maintenance.js.map +1 -0
- package/dist/contract/state.d.ts +16 -0
- package/dist/contract/state.d.ts.map +1 -0
- package/dist/contract/state.js +18 -0
- package/dist/contract/state.js.map +1 -0
- package/dist/contract/witness-loader.d.ts +3 -0
- package/dist/contract/witness-loader.d.ts.map +1 -0
- package/dist/contract/witness-loader.js +27 -0
- package/dist/contract/witness-loader.js.map +1 -0
- package/dist/daemon/api-keys.d.ts +66 -0
- package/dist/daemon/api-keys.d.ts.map +1 -0
- package/dist/daemon/api-keys.js +222 -0
- package/dist/daemon/api-keys.js.map +1 -0
- package/dist/daemon/audit-log.d.ts +65 -0
- package/dist/daemon/audit-log.d.ts.map +1 -0
- package/dist/daemon/audit-log.js +73 -0
- package/dist/daemon/audit-log.js.map +1 -0
- package/dist/daemon/client.d.ts +63 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +214 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/confirmation-queue.d.ts +46 -0
- package/dist/daemon/confirmation-queue.d.ts.map +1 -0
- package/dist/daemon/confirmation-queue.js +92 -0
- package/dist/daemon/confirmation-queue.js.map +1 -0
- package/dist/daemon/index.d.ts +23 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +26 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/protocol.d.ts +40 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +104 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/server.d.ts +158 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +297 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/wallet-handlers.d.ts +37 -0
- package/dist/daemon/wallet-handlers.d.ts.map +1 -0
- package/dist/daemon/wallet-handlers.js +533 -0
- package/dist/daemon/wallet-handlers.js.map +1 -0
- package/dist/daemon/wallet-rpc-parsers.d.ts +14 -0
- package/dist/daemon/wallet-rpc-parsers.d.ts.map +1 -0
- package/dist/daemon/wallet-rpc-parsers.js +259 -0
- package/dist/daemon/wallet-rpc-parsers.js.map +1 -0
- package/dist/daemon/wallet-rpc-types.d.ts +138 -0
- package/dist/daemon/wallet-rpc-types.d.ts.map +1 -0
- package/dist/daemon/wallet-rpc-types.js +11 -0
- package/dist/daemon/wallet-rpc-types.js.map +1 -0
- package/dist/diagnostics/fs-timing-store.d.ts +29 -0
- package/dist/diagnostics/fs-timing-store.d.ts.map +1 -0
- package/dist/diagnostics/fs-timing-store.js +81 -0
- package/dist/diagnostics/fs-timing-store.js.map +1 -0
- package/dist/diagnostics/timings.d.ts +64 -0
- package/dist/diagnostics/timings.d.ts.map +1 -0
- package/dist/diagnostics/timings.js +100 -0
- package/dist/diagnostics/timings.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/network/indexer-client.d.ts +66 -0
- package/dist/network/indexer-client.d.ts.map +1 -0
- package/dist/network/indexer-client.js +112 -0
- package/dist/network/indexer-client.js.map +1 -0
- package/dist/network/node-client.d.ts +27 -0
- package/dist/network/node-client.d.ts.map +1 -0
- package/dist/network/node-client.js +94 -0
- package/dist/network/node-client.js.map +1 -0
- package/dist/proof/client.d.ts +15 -0
- package/dist/proof/client.d.ts.map +1 -0
- package/dist/proof/client.js +77 -0
- package/dist/proof/client.js.map +1 -0
- package/dist/proof/provider.d.ts +12 -0
- package/dist/proof/provider.d.ts.map +1 -0
- package/dist/proof/provider.js +96 -0
- package/dist/proof/provider.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/midnight-provider.d.ts +11 -0
- package/dist/providers/midnight-provider.d.ts.map +1 -0
- package/dist/providers/midnight-provider.js +30 -0
- package/dist/providers/midnight-provider.js.map +1 -0
- package/dist/storage/adapter.d.ts +8 -0
- package/dist/storage/adapter.d.ts.map +1 -0
- package/dist/storage/adapter.js +2 -0
- package/dist/storage/adapter.js.map +1 -0
- package/dist/storage/fs-adapter.d.ts +14 -0
- package/dist/storage/fs-adapter.d.ts.map +1 -0
- package/dist/storage/fs-adapter.js +126 -0
- package/dist/storage/fs-adapter.js.map +1 -0
- package/dist/storage/safe-path.d.ts +13 -0
- package/dist/storage/safe-path.d.ts.map +1 -0
- package/dist/storage/safe-path.js +35 -0
- package/dist/storage/safe-path.js.map +1 -0
- package/dist/sync/activity.d.ts +53 -0
- package/dist/sync/activity.d.ts.map +1 -0
- package/dist/sync/activity.js +92 -0
- package/dist/sync/activity.js.map +1 -0
- package/dist/sync/dust-registration-estimate.d.ts +54 -0
- package/dist/sync/dust-registration-estimate.d.ts.map +1 -0
- package/dist/sync/dust-registration-estimate.js +103 -0
- package/dist/sync/dust-registration-estimate.js.map +1 -0
- package/dist/sync/node-sync-store.d.ts +10 -0
- package/dist/sync/node-sync-store.d.ts.map +1 -0
- package/dist/sync/node-sync-store.js +42 -0
- package/dist/sync/node-sync-store.js.map +1 -0
- package/dist/sync/operations.d.ts +138 -0
- package/dist/sync/operations.d.ts.map +1 -0
- package/dist/sync/operations.js +395 -0
- package/dist/sync/operations.js.map +1 -0
- package/dist/sync/preseed-parts.d.ts +18 -0
- package/dist/sync/preseed-parts.d.ts.map +1 -0
- package/dist/sync/preseed-parts.js +33 -0
- package/dist/sync/preseed-parts.js.map +1 -0
- package/dist/sync/preseed.d.ts +95 -0
- package/dist/sync/preseed.d.ts.map +1 -0
- package/dist/sync/preseed.js +365 -0
- package/dist/sync/preseed.js.map +1 -0
- package/dist/sync/progress.d.ts +45 -0
- package/dist/sync/progress.d.ts.map +1 -0
- package/dist/sync/progress.js +51 -0
- package/dist/sync/progress.js.map +1 -0
- package/dist/sync/sdk-dedup.d.ts +53 -0
- package/dist/sync/sdk-dedup.d.ts.map +1 -0
- package/dist/sync/sdk-dedup.js +134 -0
- package/dist/sync/sdk-dedup.js.map +1 -0
- package/dist/sync/sync-store.d.ts +33 -0
- package/dist/sync/sync-store.d.ts.map +1 -0
- package/dist/sync/sync-store.js +45 -0
- package/dist/sync/sync-store.js.map +1 -0
- package/dist/sync/wallet-sync.d.ts +153 -0
- package/dist/sync/wallet-sync.d.ts.map +1 -0
- package/dist/sync/wallet-sync.js +943 -0
- package/dist/sync/wallet-sync.js.map +1 -0
- package/dist/types/errors.d.ts +18 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +33 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/exit-codes.d.ts +8 -0
- package/dist/types/exit-codes.d.ts.map +1 -0
- package/dist/types/exit-codes.js +7 -0
- package/dist/types/exit-codes.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/network.d.ts +65 -0
- package/dist/types/network.d.ts.map +1 -0
- package/dist/types/network.js +108 -0
- package/dist/types/network.js.map +1 -0
- package/dist/types/tokens.d.ts +3 -0
- package/dist/types/tokens.d.ts.map +1 -0
- package/dist/types/tokens.js +11 -0
- package/dist/types/tokens.js.map +1 -0
- package/dist/types/transaction.d.ts +13 -0
- package/dist/types/transaction.d.ts.map +1 -0
- package/dist/types/transaction.js +2 -0
- package/dist/types/transaction.js.map +1 -0
- package/dist/types/wallet.d.ts +82 -0
- package/dist/types/wallet.d.ts.map +1 -0
- package/dist/types/wallet.js +2 -0
- package/dist/types/wallet.js.map +1 -0
- package/dist/wallet/address-validate.d.ts +7 -0
- package/dist/wallet/address-validate.d.ts.map +1 -0
- package/dist/wallet/address-validate.js +28 -0
- package/dist/wallet/address-validate.js.map +1 -0
- package/dist/wallet/address.d.ts +32 -0
- package/dist/wallet/address.d.ts.map +1 -0
- package/dist/wallet/address.js +107 -0
- package/dist/wallet/address.js.map +1 -0
- package/dist/wallet/app-secret.d.ts +15 -0
- package/dist/wallet/app-secret.d.ts.map +1 -0
- package/dist/wallet/app-secret.js +45 -0
- package/dist/wallet/app-secret.js.map +1 -0
- package/dist/wallet/balance-format.d.ts +12 -0
- package/dist/wallet/balance-format.d.ts.map +1 -0
- package/dist/wallet/balance-format.js +51 -0
- package/dist/wallet/balance-format.js.map +1 -0
- package/dist/wallet/batch-transfer.d.ts +36 -0
- package/dist/wallet/batch-transfer.d.ts.map +1 -0
- package/dist/wallet/batch-transfer.js +93 -0
- package/dist/wallet/batch-transfer.js.map +1 -0
- package/dist/wallet/keystore.d.ts +16 -0
- package/dist/wallet/keystore.d.ts.map +1 -0
- package/dist/wallet/keystore.js +76 -0
- package/dist/wallet/keystore.js.map +1 -0
- package/dist/wallet/manager.d.ts +77 -0
- package/dist/wallet/manager.d.ts.map +1 -0
- package/dist/wallet/manager.js +474 -0
- package/dist/wallet/manager.js.map +1 -0
- package/dist/wallet/mnemonic.d.ts +5 -0
- package/dist/wallet/mnemonic.d.ts.map +1 -0
- package/dist/wallet/mnemonic.js +28 -0
- package/dist/wallet/mnemonic.js.map +1 -0
- package/dist/wallet/sign-message.d.ts +20 -0
- package/dist/wallet/sign-message.d.ts.map +1 -0
- package/dist/wallet/sign-message.js +58 -0
- package/dist/wallet/sign-message.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { WalletError } from '../types/errors.js';
|
|
2
|
+
import { generateMnemonic24, validateMnemonic, mnemonicToSeed } from './mnemonic.js';
|
|
3
|
+
import { encryptKeystore, decryptKeystore, keystoreNeedsUpgrade } from './keystore.js';
|
|
4
|
+
import { deriveAllAddressesFromSeed, deriveRawKeys, Roles } from './address.js';
|
|
5
|
+
import { deriveWalletKeys } from '../sync/operations.js';
|
|
6
|
+
import { removeWalletSyncArtifacts } from '../sync/wallet-sync.js';
|
|
7
|
+
const CONFIG_KEY = 'config.json';
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
activeWallet: null,
|
|
10
|
+
wallets: [],
|
|
11
|
+
defaultNetwork: 'devnet',
|
|
12
|
+
configVersion: 1,
|
|
13
|
+
};
|
|
14
|
+
const encoder = new TextEncoder();
|
|
15
|
+
const decoder = new TextDecoder();
|
|
16
|
+
function walletKey(name) {
|
|
17
|
+
return `wallets/${name}.keystore`;
|
|
18
|
+
}
|
|
19
|
+
// Unencrypted metadata — name, network, and the public receive address. The
|
|
20
|
+
// bech32m address is public (it's what you hand out to receive funds), so it's
|
|
21
|
+
// safe to store in the clear; it lets the wallet list show a real address
|
|
22
|
+
// without unlocking. No private keys or seed material are stored here.
|
|
23
|
+
function metaKey(name) {
|
|
24
|
+
return `wallets/${name}.meta`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Read the per-network birthday, migrating the legacy single value.
|
|
28
|
+
*
|
|
29
|
+
* The old `birthday` belonged to whichever network the wallet was on when it
|
|
30
|
+
* was written, which is `meta.network` — it was discarded on any switch, so a
|
|
31
|
+
* stored one cannot refer to anywhere else.
|
|
32
|
+
*/
|
|
33
|
+
function birthdayFor(meta, network) {
|
|
34
|
+
if (meta.birthdays && meta.birthdays[network] !== undefined)
|
|
35
|
+
return meta.birthdays[network];
|
|
36
|
+
if (meta.birthday !== undefined && meta.network === network)
|
|
37
|
+
return meta.birthday;
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
export class WalletManager {
|
|
41
|
+
storage;
|
|
42
|
+
constructor(storage) {
|
|
43
|
+
this.storage = storage;
|
|
44
|
+
}
|
|
45
|
+
async loadConfig() {
|
|
46
|
+
const data = await this.storage.read(CONFIG_KEY);
|
|
47
|
+
// Deep-copy the default: a shallow `{ ...DEFAULT_CONFIG }` shares the
|
|
48
|
+
// `wallets` array with the module-level constant, so the first generate()
|
|
49
|
+
// on empty storage would push into DEFAULT_CONFIG itself and every later
|
|
50
|
+
// fresh manager would then see that wallet as already existing.
|
|
51
|
+
if (!data)
|
|
52
|
+
return { ...DEFAULT_CONFIG, wallets: [...DEFAULT_CONFIG.wallets] };
|
|
53
|
+
return JSON.parse(decoder.decode(data));
|
|
54
|
+
}
|
|
55
|
+
async saveConfig(config) {
|
|
56
|
+
await this.storage.write(CONFIG_KEY, encoder.encode(JSON.stringify(config, null, 2)));
|
|
57
|
+
}
|
|
58
|
+
async saveMeta(meta) {
|
|
59
|
+
await this.storage.write(metaKey(meta.name), encoder.encode(JSON.stringify(meta)));
|
|
60
|
+
}
|
|
61
|
+
async loadMeta(name) {
|
|
62
|
+
const data = await this.storage.read(metaKey(name));
|
|
63
|
+
if (!data)
|
|
64
|
+
return null;
|
|
65
|
+
return JSON.parse(decoder.decode(data));
|
|
66
|
+
}
|
|
67
|
+
validateName(name) {
|
|
68
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
69
|
+
throw new WalletError('WALLET_ERROR', `Invalid wallet name "${name}": must match [a-zA-Z0-9_-]+`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
seedToHex(seed) {
|
|
73
|
+
return Array.from(seed).map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
74
|
+
}
|
|
75
|
+
deriveAddressesFromSeed(seedHex) {
|
|
76
|
+
return deriveAllAddressesFromSeed(seedHex);
|
|
77
|
+
}
|
|
78
|
+
/** Public night receive address, preferring the wallet's own network. */
|
|
79
|
+
primaryAddress(addresses, network) {
|
|
80
|
+
const bech32m = addresses.nightExternal.bech32m;
|
|
81
|
+
return ((network ? bech32m[network] : undefined) ??
|
|
82
|
+
bech32m['devnet'] ??
|
|
83
|
+
bech32m['preprod'] ??
|
|
84
|
+
Object.values(bech32m)[0] ??
|
|
85
|
+
'');
|
|
86
|
+
}
|
|
87
|
+
async generate(name, passphrase, network = 'devnet', birthday,
|
|
88
|
+
// Optionally persist a caller-supplied phrase instead of a fresh one. The
|
|
89
|
+
// setup flow shows the words before asking for a password, then hands the
|
|
90
|
+
// same phrase back here so the stored wallet matches what the user wrote down.
|
|
91
|
+
mnemonic) {
|
|
92
|
+
this.validateName(name);
|
|
93
|
+
const config = await this.loadConfig();
|
|
94
|
+
if (config.wallets.includes(name)) {
|
|
95
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" already exists`);
|
|
96
|
+
}
|
|
97
|
+
if (mnemonic !== undefined && !validateMnemonic(mnemonic)) {
|
|
98
|
+
throw new WalletError('INVALID_INPUT', 'Invalid BIP-39 mnemonic');
|
|
99
|
+
}
|
|
100
|
+
const phrase = mnemonic ?? generateMnemonic24();
|
|
101
|
+
const seed = await mnemonicToSeed(phrase);
|
|
102
|
+
const seedHex = this.seedToHex(seed);
|
|
103
|
+
const addresses = this.deriveAddressesFromSeed(seedHex);
|
|
104
|
+
const address = this.primaryAddress(addresses, network);
|
|
105
|
+
const keystore = await encryptKeystore(phrase, passphrase);
|
|
106
|
+
await this.storage.write(walletKey(name), encoder.encode(JSON.stringify(keystore)));
|
|
107
|
+
const meta = {
|
|
108
|
+
name,
|
|
109
|
+
network,
|
|
110
|
+
createdAt: new Date().toISOString(),
|
|
111
|
+
address,
|
|
112
|
+
createdHere: true,
|
|
113
|
+
...(birthday !== undefined ? { birthdays: { [network]: birthday } } : {}),
|
|
114
|
+
};
|
|
115
|
+
await this.saveMeta(meta);
|
|
116
|
+
config.wallets.push(name);
|
|
117
|
+
if (!config.activeWallet)
|
|
118
|
+
config.activeWallet = name;
|
|
119
|
+
await this.saveConfig(config);
|
|
120
|
+
seed.fill(0);
|
|
121
|
+
return { name, address, addresses, network, active: config.activeWallet === name, mnemonic: phrase, birthday };
|
|
122
|
+
}
|
|
123
|
+
async import(name, mnemonic, passphrase, network = 'devnet') {
|
|
124
|
+
this.validateName(name);
|
|
125
|
+
if (!validateMnemonic(mnemonic)) {
|
|
126
|
+
throw new WalletError('INVALID_INPUT', 'Invalid BIP-39 mnemonic');
|
|
127
|
+
}
|
|
128
|
+
const config = await this.loadConfig();
|
|
129
|
+
if (config.wallets.includes(name)) {
|
|
130
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" already exists`);
|
|
131
|
+
}
|
|
132
|
+
const seed = await mnemonicToSeed(mnemonic);
|
|
133
|
+
const seedHex = this.seedToHex(seed);
|
|
134
|
+
const addresses = this.deriveAddressesFromSeed(seedHex);
|
|
135
|
+
const address = this.primaryAddress(addresses, network);
|
|
136
|
+
const keystore = await encryptKeystore(mnemonic, passphrase);
|
|
137
|
+
await this.storage.write(walletKey(name), encoder.encode(JSON.stringify(keystore)));
|
|
138
|
+
const meta = { name, network, createdAt: new Date().toISOString(), address, createdHere: false };
|
|
139
|
+
await this.saveMeta(meta);
|
|
140
|
+
config.wallets.push(name);
|
|
141
|
+
if (!config.activeWallet)
|
|
142
|
+
config.activeWallet = name;
|
|
143
|
+
await this.saveConfig(config);
|
|
144
|
+
seed.fill(0);
|
|
145
|
+
return { name, address, addresses, network, active: config.activeWallet === name };
|
|
146
|
+
}
|
|
147
|
+
async importFromSeed(name, hexSeed, passphrase, network = 'devnet') {
|
|
148
|
+
const addresses = this.deriveAddressesFromSeed(hexSeed);
|
|
149
|
+
const address = this.primaryAddress(addresses, network);
|
|
150
|
+
const keystore = await encryptKeystore(`seed:${hexSeed}`, passphrase);
|
|
151
|
+
this.validateName(name);
|
|
152
|
+
const config = await this.loadConfig();
|
|
153
|
+
if (config.wallets.includes(name)) {
|
|
154
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" already exists`);
|
|
155
|
+
}
|
|
156
|
+
await this.storage.write(walletKey(name), encoder.encode(JSON.stringify(keystore)));
|
|
157
|
+
const meta = { name, network, createdAt: new Date().toISOString(), address, createdHere: false };
|
|
158
|
+
await this.saveMeta(meta);
|
|
159
|
+
config.wallets.push(name);
|
|
160
|
+
if (!config.activeWallet)
|
|
161
|
+
config.activeWallet = name;
|
|
162
|
+
await this.saveConfig(config);
|
|
163
|
+
return { name, address, addresses, network, active: config.activeWallet === name };
|
|
164
|
+
}
|
|
165
|
+
/** Read and revive a wallet's keystore from storage (JSON round-trips
|
|
166
|
+
* Uint8Array fields as index-keyed objects). */
|
|
167
|
+
async readKeystore(name) {
|
|
168
|
+
const keystoreData = await this.storage.read(walletKey(name));
|
|
169
|
+
if (!keystoreData) {
|
|
170
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" not found`);
|
|
171
|
+
}
|
|
172
|
+
const keystore = JSON.parse(decoder.decode(keystoreData));
|
|
173
|
+
return {
|
|
174
|
+
...keystore,
|
|
175
|
+
salt: new Uint8Array(Object.values(keystore.salt)),
|
|
176
|
+
nonce: new Uint8Array(Object.values(keystore.nonce)),
|
|
177
|
+
ciphertext: new Uint8Array(Object.values(keystore.ciphertext)),
|
|
178
|
+
tag: new Uint8Array(Object.values(keystore.tag)),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async unlock(name, passphrase) {
|
|
182
|
+
const restored = await this.readKeystore(name);
|
|
183
|
+
// Validate field lengths before attempting decryption (CWE-20).
|
|
184
|
+
// Prevents crafted keystores from reaching the cipher with invalid parameters.
|
|
185
|
+
if (restored.salt.length !== 32)
|
|
186
|
+
throw new WalletError('WALLET_ERROR', 'Corrupted keystore: invalid salt length');
|
|
187
|
+
if (restored.nonce.length !== 12)
|
|
188
|
+
throw new WalletError('WALLET_ERROR', 'Corrupted keystore: invalid nonce length');
|
|
189
|
+
if (restored.tag.length !== 16)
|
|
190
|
+
throw new WalletError('WALLET_ERROR', 'Corrupted keystore: invalid auth tag length');
|
|
191
|
+
if (restored.ciphertext.length === 0)
|
|
192
|
+
throw new WalletError('WALLET_ERROR', 'Corrupted keystore: empty ciphertext');
|
|
193
|
+
const decrypted = await decryptKeystore(restored, passphrase);
|
|
194
|
+
// Transparent KDF upgrade: re-encrypt with stronger scrypt parameters if needed.
|
|
195
|
+
// This runs once per v1 keystore, after the first successful unlock.
|
|
196
|
+
if (keystoreNeedsUpgrade(restored)) {
|
|
197
|
+
try {
|
|
198
|
+
const upgraded = await encryptKeystore(decrypted, passphrase);
|
|
199
|
+
const blob = new TextEncoder().encode(JSON.stringify(upgraded));
|
|
200
|
+
// Must be walletKey(name) (`wallets/<name>.keystore`), not
|
|
201
|
+
// `wallets/<name>`: the latter wrote to a phantom key, so the upgrade
|
|
202
|
+
// never persisted and re-ran on every unlock. unlock() reads
|
|
203
|
+
// walletKey(name), so write the re-encrypted keystore back there.
|
|
204
|
+
await this.storage.write(walletKey(name), blob);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Non-fatal — the wallet still works with the old parameters
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Derive the seed into the typed key bundle, then drop the raw
|
|
211
|
+
// string immediately. The seedHex variable stays scoped to this
|
|
212
|
+
// function — never escapes to the UnlockedWallet object.
|
|
213
|
+
// See docs/spec/wallet-service/05-key-management.md D-KM-3.
|
|
214
|
+
let seedHex;
|
|
215
|
+
if (decrypted.startsWith('seed:')) {
|
|
216
|
+
seedHex = decrypted.slice(5);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const seed = await mnemonicToSeed(decrypted);
|
|
220
|
+
seedHex = this.seedToHex(seed);
|
|
221
|
+
seed.fill(0);
|
|
222
|
+
}
|
|
223
|
+
const addresses = this.deriveAddressesFromSeed(seedHex);
|
|
224
|
+
const meta = await this.loadMeta(name);
|
|
225
|
+
const network = meta?.network ?? (await this.loadConfig()).defaultNetwork;
|
|
226
|
+
const address = this.primaryAddress(addresses, network);
|
|
227
|
+
// Backfill the public address for wallets created before it was stored (or
|
|
228
|
+
// re-derive it after a network change), so the account list can show it
|
|
229
|
+
// without another unlock.
|
|
230
|
+
if (meta && meta.address !== address) {
|
|
231
|
+
await this.saveMeta({ ...meta, address });
|
|
232
|
+
}
|
|
233
|
+
const rawKeys = deriveRawKeys(seedHex);
|
|
234
|
+
const keys = {
|
|
235
|
+
nightExternal: rawKeys[Roles.NightExternal],
|
|
236
|
+
nightInternal: rawKeys[Roles.NightInternal],
|
|
237
|
+
dust: rawKeys[Roles.Dust],
|
|
238
|
+
zswap: rawKeys[Roles.Zswap],
|
|
239
|
+
metadata: rawKeys[Roles.Metadata],
|
|
240
|
+
};
|
|
241
|
+
const walletKeys = deriveWalletKeys(seedHex);
|
|
242
|
+
// Seed is no longer needed — overwrite the local variable.
|
|
243
|
+
seedHex = '';
|
|
244
|
+
let locked = false;
|
|
245
|
+
// Actually scrub key material — not just flip a flag. Zero the raw
|
|
246
|
+
// byte arrays and clear() the WASM-held secret keys so a compromised
|
|
247
|
+
// process can't recover them after lock. Best-effort and idempotent:
|
|
248
|
+
// a clear() throw (e.g. already freed) must not stop the rest.
|
|
249
|
+
const lock = () => {
|
|
250
|
+
if (locked)
|
|
251
|
+
return;
|
|
252
|
+
locked = true;
|
|
253
|
+
for (const b of [
|
|
254
|
+
keys.nightExternal,
|
|
255
|
+
keys.nightInternal,
|
|
256
|
+
keys.dust,
|
|
257
|
+
keys.zswap,
|
|
258
|
+
keys.metadata,
|
|
259
|
+
walletKeys.nightExternalKey,
|
|
260
|
+
]) {
|
|
261
|
+
try {
|
|
262
|
+
b.fill(0);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
/* not a writable view — ignore */
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
walletKeys.shieldedSecretKeys.clear();
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
/* already cleared/freed */
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
walletKeys.dustSecretKey.clear();
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
/* already cleared/freed */
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
return {
|
|
282
|
+
name,
|
|
283
|
+
label: meta?.label,
|
|
284
|
+
network,
|
|
285
|
+
address,
|
|
286
|
+
addresses,
|
|
287
|
+
keys,
|
|
288
|
+
walletKeys,
|
|
289
|
+
lock,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Recover the raw BIP-39 hex seed for a wallet.
|
|
294
|
+
*
|
|
295
|
+
* This is the ONE deliberate exception to Option A's derive-and-drop
|
|
296
|
+
* (D-KM-3): the common `unlock()` path derives `walletKeys` and drops the
|
|
297
|
+
* seed so `UnlockedWallet` is seed-free, and the daemon/CLI/multi-tenant
|
|
298
|
+
* host never see raw seed material. But the browser extension's offscreen
|
|
299
|
+
* document is the key-holder, and Chrome tears it down and recreates it at
|
|
300
|
+
* will — the WASM `walletKeys` cannot cross the runtime-message boundary, so
|
|
301
|
+
* the offscreen needs a *serializable* secret the background can re-supply to
|
|
302
|
+
* rebuild the key bundle after each restart. That secret is the seed.
|
|
303
|
+
*
|
|
304
|
+
* Kept off `unlock()` on purpose so the seed-free invariant holds for every
|
|
305
|
+
* caller that doesn't explicitly opt in here.
|
|
306
|
+
* See docs/spec/wallet-service/05-key-management.md D-KM-3.
|
|
307
|
+
*/
|
|
308
|
+
async exportSeedHex(name, passphrase) {
|
|
309
|
+
const restored = await this.readKeystore(name);
|
|
310
|
+
const decrypted = await decryptKeystore(restored, passphrase);
|
|
311
|
+
if (decrypted.startsWith('seed:'))
|
|
312
|
+
return decrypted.slice(5);
|
|
313
|
+
const seed = await mnemonicToSeed(decrypted);
|
|
314
|
+
const seedHex = this.seedToHex(seed);
|
|
315
|
+
seed.fill(0);
|
|
316
|
+
return seedHex;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Recover the wallet's backup secret for a user-facing reveal: the original
|
|
320
|
+
* BIP-39 mnemonic when the wallet has one, or the raw hex seed for wallets
|
|
321
|
+
* imported from hex (no mnemonic ever existed). Passphrase-gated by the
|
|
322
|
+
* keystore decrypt itself — a wrong passphrase rejects. Same deliberate
|
|
323
|
+
* D-KM-3 opt-in rationale as exportSeedHex above.
|
|
324
|
+
*/
|
|
325
|
+
async exportPhrase(name, passphrase) {
|
|
326
|
+
const restored = await this.readKeystore(name);
|
|
327
|
+
const decrypted = await decryptKeystore(restored, passphrase);
|
|
328
|
+
if (decrypted.startsWith('seed:'))
|
|
329
|
+
return { kind: 'seed', value: decrypted.slice(5) };
|
|
330
|
+
return { kind: 'mnemonic', value: decrypted };
|
|
331
|
+
}
|
|
332
|
+
async remove(name) {
|
|
333
|
+
const config = await this.loadConfig();
|
|
334
|
+
if (!config.wallets.includes(name)) {
|
|
335
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" not found`);
|
|
336
|
+
}
|
|
337
|
+
// Read meta BEFORE deleting it so we know which network's sync
|
|
338
|
+
// artifacts to clean. A wallet records exactly one network at
|
|
339
|
+
// generation; subsequent unlocks always run on that same id.
|
|
340
|
+
let networkId = null;
|
|
341
|
+
try {
|
|
342
|
+
const metaBuf = await this.storage.read(metaKey(name));
|
|
343
|
+
if (metaBuf) {
|
|
344
|
+
const meta = JSON.parse(new TextDecoder().decode(metaBuf));
|
|
345
|
+
networkId = meta.network ?? null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
/* meta unreadable — proceed; cache cleanup is best-effort anyway */
|
|
350
|
+
}
|
|
351
|
+
await this.storage.delete(walletKey(name));
|
|
352
|
+
await this.storage.delete(metaKey(name));
|
|
353
|
+
// Clean per-wallet sync artifacts (~/.moth/sync/<network>/<name>/
|
|
354
|
+
// and the matching .sock). Without this, regenerating a wallet
|
|
355
|
+
// under the same name would silently inherit stale sync state
|
|
356
|
+
// belonging to the prior seed — a real footgun observed during
|
|
357
|
+
// 2026-06-22 debugging. See docs/spec/wallet-service/COMMANDS.md
|
|
358
|
+
// §"Wallet lifecycle" for the full list of what remove touches.
|
|
359
|
+
if (networkId) {
|
|
360
|
+
await removeWalletSyncArtifacts(name, networkId);
|
|
361
|
+
}
|
|
362
|
+
config.wallets = config.wallets.filter(w => w !== name);
|
|
363
|
+
if (config.activeWallet === name) {
|
|
364
|
+
config.activeWallet = config.wallets[0] ?? null;
|
|
365
|
+
}
|
|
366
|
+
await this.saveConfig(config);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* List wallets. Returns the name, network and public receive address (stored
|
|
370
|
+
* in the clear at create/import time). The full per-role address set and any
|
|
371
|
+
* key material still require unlock — only the primary night address is here.
|
|
372
|
+
*/
|
|
373
|
+
async list() {
|
|
374
|
+
const config = await this.loadConfig();
|
|
375
|
+
const wallets = [];
|
|
376
|
+
const emptyAddr = { hex: '', bech32m: {} };
|
|
377
|
+
const lockedAddresses = {
|
|
378
|
+
nightExternal: emptyAddr, nightInternal: emptyAddr,
|
|
379
|
+
dust: emptyAddr, zswap: emptyAddr, metadata: emptyAddr,
|
|
380
|
+
};
|
|
381
|
+
for (const name of config.wallets) {
|
|
382
|
+
const meta = await this.loadMeta(name);
|
|
383
|
+
wallets.push({
|
|
384
|
+
name,
|
|
385
|
+
address: meta?.address ?? '(locked)',
|
|
386
|
+
addresses: lockedAddresses,
|
|
387
|
+
network: meta?.network ?? config.defaultNetwork,
|
|
388
|
+
active: config.activeWallet === name,
|
|
389
|
+
birthday: meta ? birthdayFor(meta, meta.network) : undefined,
|
|
390
|
+
label: meta?.label,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return wallets;
|
|
394
|
+
}
|
|
395
|
+
async getActive() {
|
|
396
|
+
const config = await this.loadConfig();
|
|
397
|
+
return config.activeWallet;
|
|
398
|
+
}
|
|
399
|
+
async setActive(name) {
|
|
400
|
+
const config = await this.loadConfig();
|
|
401
|
+
if (!config.wallets.includes(name)) {
|
|
402
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" not found`);
|
|
403
|
+
}
|
|
404
|
+
config.activeWallet = name;
|
|
405
|
+
await this.saveConfig(config);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Set or clear a wallet's display label. Labels are presentation-only
|
|
409
|
+
* metadata: the wallet keeps its immutable `name` (the storage key), so
|
|
410
|
+
* keystores, sync caches and sessions all stay valid across renames.
|
|
411
|
+
* An empty (or whitespace-only) label reverts to showing the name.
|
|
412
|
+
*/
|
|
413
|
+
async setLabel(name, label) {
|
|
414
|
+
const meta = await this.loadMeta(name);
|
|
415
|
+
if (!meta) {
|
|
416
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" not found`);
|
|
417
|
+
}
|
|
418
|
+
const trimmed = label.trim();
|
|
419
|
+
const { label: _cleared, ...rest } = meta;
|
|
420
|
+
await this.saveMeta(trimmed ? { ...rest, label: trimmed } : rest);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Move a wallet to another network. Only this wallet's metadata changes —
|
|
424
|
+
* other wallets keep their own networks. The public address and chain
|
|
425
|
+
* birthday are network-scoped, so the old values are discarded. A caller
|
|
426
|
+
* that already has the unlocked seed may provide the newly derived public
|
|
427
|
+
* address to keep the locked account list immediately useful.
|
|
428
|
+
*/
|
|
429
|
+
async setNetwork(name, network, address, birthday) {
|
|
430
|
+
const meta = await this.loadMeta(name);
|
|
431
|
+
if (!meta) {
|
|
432
|
+
throw new WalletError('WALLET_ERROR', `Wallet "${name}" not found`);
|
|
433
|
+
}
|
|
434
|
+
if (meta.network === network) {
|
|
435
|
+
if (address !== undefined && address !== meta.address)
|
|
436
|
+
await this.saveMeta({ ...meta, address });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
// The legacy single `birthday` is folded into the per-network map before it
|
|
440
|
+
// is dropped, so a wallet written before `birthdays` existed keeps the value
|
|
441
|
+
// for the network it earned it on. Dropping it outright — which is what this
|
|
442
|
+
// used to do — left the wallet with no birthday anywhere, and the pre-seed
|
|
443
|
+
// guard (`reference.height <= birthday`) can never pass without one, so
|
|
444
|
+
// every sync after a switch walked from genesis.
|
|
445
|
+
const birthdays = { ...(meta.birthdays ?? {}) };
|
|
446
|
+
if (meta.birthday !== undefined && birthdays[meta.network] === undefined) {
|
|
447
|
+
birthdays[meta.network] = meta.birthday;
|
|
448
|
+
}
|
|
449
|
+
// First arrival at `network`: record the caller-supplied first-existence
|
|
450
|
+
// height. Two guards, both load-bearing:
|
|
451
|
+
//
|
|
452
|
+
// createdHere — an imported wallet may hold funds on any chain at any
|
|
453
|
+
// height, so it never gets a birthday and always scans from genesis. A
|
|
454
|
+
// wallet written before this field existed has it undefined, which reads
|
|
455
|
+
// as imported: the conservative answer, since the cost of being wrong that
|
|
456
|
+
// way is a slow sync, and the cost of the other way is invisible funds.
|
|
457
|
+
//
|
|
458
|
+
// birthdays[network] === undefined — only the FIRST arrival counts.
|
|
459
|
+
// Returning to a network reuses the height recorded then, because the
|
|
460
|
+
// wallet may have transacted there before leaving; overwriting it with a
|
|
461
|
+
// later tip would skip that history.
|
|
462
|
+
if (birthday !== undefined && meta.createdHere === true && birthdays[network] === undefined) {
|
|
463
|
+
birthdays[network] = birthday;
|
|
464
|
+
}
|
|
465
|
+
const { address: _staleAddress, birthday: _staleBirthday, ...rest } = meta;
|
|
466
|
+
await this.saveMeta({
|
|
467
|
+
...rest,
|
|
468
|
+
network,
|
|
469
|
+
...(Object.keys(birthdays).length > 0 ? { birthdays } : {}),
|
|
470
|
+
...(address ? { address } : {}),
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/wallet/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function generateMnemonic24(): string;
|
|
2
|
+
export declare function validateMnemonic(mnemonic: string): boolean;
|
|
3
|
+
export declare function mnemonicToSeed(mnemonic: string): Promise<Uint8Array>;
|
|
4
|
+
export declare function hexSeedToUint8Array(hex: string): Uint8Array;
|
|
5
|
+
//# sourceMappingURL=mnemonic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mnemonic.d.ts","sourceRoot":"","sources":["../../src/wallet/mnemonic.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG1D;AAGD,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE1E;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAY3D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as bip39 from '@scure/bip39';
|
|
2
|
+
import { generateMnemonicWords, joinMnemonicWords, validateMnemonic as sdkValidateMnemonic, } from '@midnightntwrk/wallet-sdk/hd';
|
|
3
|
+
export function generateMnemonic24() {
|
|
4
|
+
return joinMnemonicWords(generateMnemonicWords(256));
|
|
5
|
+
}
|
|
6
|
+
export function validateMnemonic(mnemonic) {
|
|
7
|
+
if (!mnemonic || mnemonic.trim().length === 0)
|
|
8
|
+
return false;
|
|
9
|
+
return sdkValidateMnemonic(mnemonic);
|
|
10
|
+
}
|
|
11
|
+
// SDK gap: @midnightntwrk/wallet-sdk-* does not expose mnemonic → seed.
|
|
12
|
+
export async function mnemonicToSeed(mnemonic) {
|
|
13
|
+
return bip39.mnemonicToSeedSync(mnemonic);
|
|
14
|
+
}
|
|
15
|
+
export function hexSeedToUint8Array(hex) {
|
|
16
|
+
if (!/^[0-9a-fA-F]+$/.test(hex)) {
|
|
17
|
+
throw new Error('Invalid hex string: contains non-hex characters');
|
|
18
|
+
}
|
|
19
|
+
if (hex.length % 2 !== 0) {
|
|
20
|
+
throw new Error('Invalid hex string: odd length');
|
|
21
|
+
}
|
|
22
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
23
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
24
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
25
|
+
}
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=mnemonic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mnemonic.js","sourceRoot":"","sources":["../../src/wallet/mnemonic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,IAAI,mBAAmB,GACxC,MAAM,8BAA8B,CAAC;AAEtC,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,mBAAmB,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,OAAO,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type SignEncoding = 'hex' | 'base64' | 'text';
|
|
2
|
+
export interface SignedMessage {
|
|
3
|
+
/** The original data string, echoed back so the caller can correlate. */
|
|
4
|
+
data: string;
|
|
5
|
+
/** Signature in the keystore's native hex encoding. connector-api 4.0.1
|
|
6
|
+
* leaves the wire format unspecified, so we return the ledger encoding. */
|
|
7
|
+
signature: string;
|
|
8
|
+
/** Verifying (public) key in the keystore's native hex encoding. */
|
|
9
|
+
verifyingKey: string;
|
|
10
|
+
}
|
|
11
|
+
/** The exact byte sequence signed for a message: the domain prefix ++ data.
|
|
12
|
+
* Exposed so verifiers (and tests) can reconstruct what was signed. */
|
|
13
|
+
export declare function signedMessageBytes(data: Uint8Array): Uint8Array;
|
|
14
|
+
/**
|
|
15
|
+
* Sign `data` (interpreted per `encoding`) with the seed's unshielded key,
|
|
16
|
+
* returning the signature and verifying key. Only `keyType: 'unshielded'` is
|
|
17
|
+
* supported by the connector, so no key type is threaded here.
|
|
18
|
+
*/
|
|
19
|
+
export declare function signMessage(seedHex: string, networkId: string, data: string, encoding: SignEncoding): SignedMessage;
|
|
20
|
+
//# sourceMappingURL=sign-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-message.d.ts","sourceRoot":"","sources":["../../src/wallet/sign-message.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;gFAC4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;CACtB;AAuBD;wEACwE;AACxE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAM/D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,YAAY,GACrB,aAAa,CASf"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Message signing for the dApp connector's `signData`. Signs arbitrary data
|
|
2
|
+
// with the wallet's unshielded (NightExternal) key, applying the Midnight
|
|
3
|
+
// domain-separation prefix so a signed message can never also be a valid
|
|
4
|
+
// transaction: the unshielded key authorizes transfers too, and ledger's
|
|
5
|
+
// signData explicitly warns against signing uncontrolled data without such
|
|
6
|
+
// separation.
|
|
7
|
+
//
|
|
8
|
+
// Per the Midnight dApp connector spec, the bytes actually signed are
|
|
9
|
+
// utf8(`midnight_signed_message:${byteLength}:`) ++ decodedData
|
|
10
|
+
// where byteLength is the length of the decoded data in bytes.
|
|
11
|
+
import { createKeystore } from '@midnightntwrk/wallet-sdk/unshielded';
|
|
12
|
+
import { Roles, deriveRawKeys } from './address.js';
|
|
13
|
+
const MESSAGE_PREFIX = 'midnight_signed_message';
|
|
14
|
+
/** Decode the request payload into the raw bytes to be signed. */
|
|
15
|
+
function decodeData(data, encoding) {
|
|
16
|
+
switch (encoding) {
|
|
17
|
+
case 'text':
|
|
18
|
+
// JS strings are UTF-16; normalize to UTF-8 as the spec requires.
|
|
19
|
+
return new TextEncoder().encode(data);
|
|
20
|
+
case 'hex': {
|
|
21
|
+
const hex = data.startsWith('0x') ? data.slice(2) : data;
|
|
22
|
+
if (hex.length % 2 !== 0 || /[^0-9a-fA-F]/.test(hex))
|
|
23
|
+
throw new Error('Invalid hex data');
|
|
24
|
+
return Uint8Array.from(Buffer.from(hex, 'hex'));
|
|
25
|
+
}
|
|
26
|
+
case 'base64': {
|
|
27
|
+
const clean = data.replace(/\s/g, '');
|
|
28
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(clean))
|
|
29
|
+
throw new Error('Invalid base64 data');
|
|
30
|
+
return Uint8Array.from(Buffer.from(clean, 'base64'));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** The exact byte sequence signed for a message: the domain prefix ++ data.
|
|
35
|
+
* Exposed so verifiers (and tests) can reconstruct what was signed. */
|
|
36
|
+
export function signedMessageBytes(data) {
|
|
37
|
+
const prefix = new TextEncoder().encode(`${MESSAGE_PREFIX}:${data.length}:`);
|
|
38
|
+
const out = new Uint8Array(prefix.length + data.length);
|
|
39
|
+
out.set(prefix, 0);
|
|
40
|
+
out.set(data, prefix.length);
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sign `data` (interpreted per `encoding`) with the seed's unshielded key,
|
|
45
|
+
* returning the signature and verifying key. Only `keyType: 'unshielded'` is
|
|
46
|
+
* supported by the connector, so no key type is threaded here.
|
|
47
|
+
*/
|
|
48
|
+
export function signMessage(seedHex, networkId, data, encoding) {
|
|
49
|
+
const payload = signedMessageBytes(decodeData(data, encoding));
|
|
50
|
+
const keys = deriveRawKeys(seedHex);
|
|
51
|
+
const keystore = createKeystore(keys[Roles.NightExternal], networkId);
|
|
52
|
+
return {
|
|
53
|
+
data,
|
|
54
|
+
signature: String(keystore.signData(payload)),
|
|
55
|
+
verifyingKey: String(keystore.getPublicKey()),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sign-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-message.js","sourceRoot":"","sources":["../../src/wallet/sign-message.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,yEAAyE;AACzE,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,sEAAsE;AACtE,kEAAkE;AAClE,+DAA+D;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAcpD,MAAM,cAAc,GAAG,yBAAyB,CAAC;AAEjD,kEAAkE;AAClE,SAAS,UAAU,CAAC,IAAY,EAAE,QAAsB;IACtD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,kEAAkE;YAClE,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACzD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC1F,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QAClD,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YAClF,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC;AAED;wEACwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,cAAc,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnB,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,OAAe,EACf,SAAiB,EACjB,IAAY,EACZ,QAAsB;IAEtB,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC,CAAC;IACtE,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC7C,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC"}
|