@talismn/keyring 0.0.0-pr2277-20251211070508 → 0.0.0-pr2295-20260110031023

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.
@@ -1,147 +1,171 @@
1
- import { isEthereumAddress, isSolanaAddress, detectAddressEncoding, isBitcoinAddress, getAccountPlatformFromCurve, getAccountPlatformFromAddress, pbkdf2, utf8, isValidMnemonic, mnemonicToEntropy, entropyToMnemonic, isAddressEqual, normalizeAddress, entropyToSeed, deriveKeypair, getPublicKeyFromSecret, addressEncodingFromCurve, addressFromPublicKey, base58, blake3 } from '@talismn/crypto';
2
-
3
- const isAccountOfType = (account, type) => {
1
+ // src/types/utils.ts
2
+ import {
3
+ detectAddressEncoding,
4
+ getAccountPlatformFromAddress,
5
+ getAccountPlatformFromCurve,
6
+ isBitcoinAddress,
7
+ isEthereumAddress,
8
+ isSolanaAddress
9
+ } from "@talismn/crypto";
10
+ var isAccountOfType = (account, type) => {
4
11
  return account?.type === type;
5
12
  };
6
- const isAccountInTypes = (account, types) => {
13
+ var isAccountInTypes = (account, types) => {
7
14
  return !!account && types.includes(account.type);
8
15
  };
9
- const ACCOUNT_TYPES_OWNED = ["keypair", "ledger-ethereum", "ledger-polkadot", "ledger-solana", "polkadot-vault"];
10
- const ACCOUNT_TYPES_EXTERNAL = ["contact", "watch-only", "ledger-ethereum", "ledger-polkadot", "ledger-solana", "polkadot-vault", "signet"];
11
- const isAccountExternal = account => {
16
+ var ACCOUNT_TYPES_OWNED = [
17
+ "keypair",
18
+ "ledger-ethereum",
19
+ "ledger-polkadot",
20
+ "ledger-solana",
21
+ "polkadot-vault"
22
+ ];
23
+ var ACCOUNT_TYPES_EXTERNAL = [
24
+ "contact",
25
+ "watch-only",
26
+ "ledger-ethereum",
27
+ "ledger-polkadot",
28
+ "ledger-solana",
29
+ "polkadot-vault",
30
+ "signet"
31
+ ];
32
+ var isAccountExternal = (account) => {
12
33
  return isAccountInTypes(account, ACCOUNT_TYPES_EXTERNAL);
13
34
  };
14
- const isAccountOwned = account => {
35
+ var isAccountOwned = (account) => {
15
36
  return isAccountInTypes(account, ACCOUNT_TYPES_OWNED);
16
37
  };
17
- const isAccountPortfolio = account => {
38
+ var isAccountPortfolio = (account) => {
18
39
  return isAccountOwned(account) || isAccountOfType(account, "watch-only") && account.isPortfolio;
19
40
  };
20
- const isAccountNotContact = acc => acc.type !== "contact";
21
- const isAccountAddressEthereum = account => {
41
+ var isAccountNotContact = (acc) => acc.type !== "contact";
42
+ var isAccountAddressEthereum = (account) => {
22
43
  return !!account && isEthereumAddress(account.address);
23
44
  };
24
- const isAccountPlatformEthereum = account => {
45
+ var isAccountPlatformEthereum = (account) => {
25
46
  return !!account && account.type !== "ledger-polkadot" && isEthereumAddress(account.address);
26
47
  };
27
- const isAccountPlatformSolana = account => {
48
+ var isAccountPlatformSolana = (account) => {
28
49
  return !!account && isSolanaAddress(account.address);
29
50
  };
30
- const isAccountPlatformPolkadot = account => {
51
+ var isAccountPlatformPolkadot = (account) => {
31
52
  return !!account && account.type !== "ledger-ethereum" && (isAccountAddressEthereum(account) || isAccountAddressSs58(account));
32
53
  };
33
- const isAccountAddressSs58 = account => {
54
+ var isAccountAddressSs58 = (account) => {
34
55
  return !!account && detectAddressEncoding(account.address) === "ss58";
35
56
  };
36
- const isAccountLedgerPolkadot = account => {
57
+ var isAccountLedgerPolkadot = (account) => {
37
58
  return isAccountOfType(account, "ledger-polkadot");
38
59
  };
39
- const isAccountLedgerPolkadotGeneric = account => {
60
+ var isAccountLedgerPolkadotGeneric = (account) => {
40
61
  return isAccountOfType(account, "ledger-polkadot") && !account.genesisHash;
41
62
  };
42
- const isAccountLedgerPolkadotLegacy = account => {
63
+ var isAccountLedgerPolkadotLegacy = (account) => {
43
64
  return isAccountOfType(account, "ledger-polkadot") && !!account.genesisHash;
44
65
  };
45
- const isAccountBitcoin = account => {
66
+ var isAccountBitcoin = (account) => {
46
67
  return !!account && isBitcoinAddress(account.address);
47
68
  };
48
- const getAccountGenesisHash = account => {
49
- if (!account) return undefined;
50
- return "genesisHash" in account ? account.genesisHash || undefined : undefined;
69
+ var getAccountGenesisHash = (account) => {
70
+ if (!account) return void 0;
71
+ return "genesisHash" in account ? account.genesisHash || void 0 : void 0;
51
72
  };
52
- const getAccountSignetUrl = account => {
53
- return isAccountOfType(account, "signet") ? account.url : undefined;
73
+ var getAccountSignetUrl = (account) => {
74
+ return isAccountOfType(account, "signet") ? account.url : void 0;
54
75
  };
55
- const getAccountPlatform = account => {
56
- if (!account) return undefined;
76
+ var getAccountPlatform = (account) => {
77
+ if (!account) return void 0;
57
78
  return "curve" in account ? getAccountPlatformFromCurve(account.curve) : getAccountPlatformFromAddress(account.address);
58
79
  };
59
80
 
60
- // Derive a key generated with PBKDF2 that will be used for AES-GCM encryption
61
- const deriveKey = async (password, salt) =>
62
- // Deriving 32-byte key using PBKDF2 with 100,000 iterations and SHA-256
63
- await crypto.subtle.importKey("raw", await pbkdf2("SHA-256", new TextEncoder().encode(password), salt, 100_000,
64
- // 100,000 iterations
65
- 32 // 32 bytes (32 * 8 == 256 bits)
66
- ), {
67
- name: "AES-GCM",
68
- length: 256
69
- }, false, ["encrypt", "decrypt"]);
70
- const encryptData = async (data, password) => {
81
+ // src/keyring/Keyring.ts
82
+ import {
83
+ addressEncodingFromCurve,
84
+ addressFromPublicKey,
85
+ base58,
86
+ blake3,
87
+ deriveKeypair,
88
+ entropyToMnemonic,
89
+ entropyToSeed,
90
+ getPublicKeyFromSecret,
91
+ isAddressEqual,
92
+ isValidMnemonic,
93
+ mnemonicToEntropy,
94
+ normalizeAddress,
95
+ utf8
96
+ } from "@talismn/crypto";
97
+
98
+ // src/keyring/encryption.ts
99
+ import { pbkdf2 } from "@talismn/crypto";
100
+ var deriveKey = async (password, salt) => (
101
+ // Deriving 32-byte key using PBKDF2 with 100,000 iterations and SHA-256
102
+ await crypto.subtle.importKey(
103
+ "raw",
104
+ await pbkdf2(
105
+ "SHA-256",
106
+ new TextEncoder().encode(password),
107
+ salt,
108
+ 1e5,
109
+ // 100,000 iterations
110
+ 32
111
+ // 32 bytes (32 * 8 == 256 bits)
112
+ ),
113
+ { name: "AES-GCM", length: 256 },
114
+ false,
115
+ ["encrypt", "decrypt"]
116
+ )
117
+ );
118
+ var encryptData = async (data, password) => {
71
119
  try {
72
- const salt = crypto.getRandomValues(new Uint8Array(16)); // 16 bytes of salt
73
- const iv = crypto.getRandomValues(new Uint8Array(12)); // 12-byte IV for AES-GCM
120
+ const salt = crypto.getRandomValues(new Uint8Array(16));
121
+ const iv = crypto.getRandomValues(new Uint8Array(12));
74
122
  const key = await deriveKey(password, salt);
75
-
76
- // encrypt
77
- const encryptedSeed = await crypto.subtle.encrypt({
78
- name: "AES-GCM",
79
- iv
80
- }, key, data);
81
-
82
- // Combine salt, IV, and encrypted seed
123
+ const encryptedSeed = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data);
83
124
  const combined = new Uint8Array(salt.length + iv.length + encryptedSeed.byteLength);
84
125
  combined.set(salt, 0);
85
126
  combined.set(iv, salt.length);
86
127
  combined.set(new Uint8Array(encryptedSeed), salt.length + iv.length);
87
-
88
- // Base64 encode the combined data
89
128
  return btoa(String.fromCharCode(...combined));
90
129
  } catch (cause) {
91
- throw new Error("Failed to encrypt data", {
92
- cause
93
- });
130
+ throw new Error("Failed to encrypt data", { cause });
94
131
  }
95
132
  };
96
- const decryptData = async (encryptedData, password) => {
133
+ var decryptData = async (encryptedData, password) => {
97
134
  try {
98
- // Decode Base64 and parse the combined data
99
- const combined = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0));
100
-
101
- // Extract salt, IV, and encrypted seed
102
- const salt = combined.slice(0, 16); // First 16 bytes
103
- const iv = combined.slice(16, 28); // Next 12 bytes
104
- const encryptedSeed = combined.slice(28); // Remaining bytes
105
-
135
+ const combined = Uint8Array.from(atob(encryptedData), (c) => c.charCodeAt(0));
136
+ const salt = combined.slice(0, 16);
137
+ const iv = combined.slice(16, 28);
138
+ const encryptedSeed = combined.slice(28);
106
139
  const key = await deriveKey(password, salt);
107
-
108
- // Decrypt the seed
109
- const decryptedSeed = await crypto.subtle.decrypt({
110
- name: "AES-GCM",
111
- iv
112
- }, key, encryptedSeed);
140
+ const decryptedSeed = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, encryptedSeed);
113
141
  return new Uint8Array(decryptedSeed);
114
142
  } catch (cause) {
115
- throw new Error("Failed to decrypt data", {
116
- cause
117
- });
143
+ throw new Error("Failed to decrypt data", { cause });
118
144
  }
119
145
  };
120
- const changeEncryptedDataPassword = async (encryptedData, oldPassword, newPassword) => {
146
+ var changeEncryptedDataPassword = async (encryptedData, oldPassword, newPassword) => {
121
147
  try {
122
148
  const decrypted = await decryptData(encryptedData, oldPassword);
123
149
  return await encryptData(decrypted, newPassword);
124
150
  } catch (cause) {
125
- throw new Error("Failed to change password on encrypted data", {
126
- cause
127
- });
151
+ throw new Error("Failed to change password on encrypted data", { cause });
128
152
  }
129
153
  };
130
154
 
131
- // we dont want to reference @talismn/util in the keyring, so we copy this here
132
-
133
- const REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/;
134
- const isHexString = value => {
155
+ // src/keyring/utils.ts
156
+ var REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/;
157
+ var isHexString = (value) => {
135
158
  return typeof value === "string" && REGEX_HEX_STRING.test(value);
136
159
  };
137
160
 
138
- class Keyring {
161
+ // src/keyring/Keyring.ts
162
+ var Keyring = class _Keyring {
139
163
  #data;
140
164
  constructor(data) {
141
165
  this.#data = structuredClone(data);
142
166
  }
143
167
  static create() {
144
- return new Keyring({
168
+ return new _Keyring({
145
169
  passwordCheck: null,
146
170
  // well-known data encrypted using the password, used to ensure all secrets of the keyring are encrypted with the same password
147
171
  mnemonics: [],
@@ -150,21 +174,15 @@ class Keyring {
150
174
  }
151
175
  static load(data) {
152
176
  if (!data.accounts || !data.mnemonics) throw new Error("Invalid data");
153
-
154
- // automatic upgrade : set default values for newly introduced properties
155
177
  for (const account of data.accounts) {
156
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
157
- // @ts-expect-error
158
178
  if (account.type === "ledger-polkadot" && !account.curve) account.curve = "ed25519";
159
179
  }
160
- return new Keyring(data);
180
+ return new _Keyring(data);
161
181
  }
162
182
  async checkPassword(password, reset = false) {
163
183
  if (typeof password !== "string" || !password) throw new Error("password is required");
164
184
  const passwordHash = oneWayHash(password);
165
185
  const PASSWORD_CHECK_PHRASE = "PASSWORD_CHECK_PHRASE";
166
-
167
- // run through same complexity as for other secrets, to make it so it s not easier to brute force passwordCheck than other secrets
168
186
  if (!this.#data.passwordCheck || reset) {
169
187
  const bytes = utf8.decode(PASSWORD_CHECK_PHRASE);
170
188
  this.#data.passwordCheck = await encryptData(bytes, passwordHash);
@@ -182,32 +200,31 @@ class Keyring {
182
200
  return structuredClone(this.#data);
183
201
  }
184
202
  async export(password, jsonPassword) {
185
- const keyring = new Keyring(structuredClone(this.#data));
186
- for (const mnemonic of keyring.#data.mnemonics) mnemonic.entropy = await changeEncryptedDataPassword(mnemonic.entropy, password, jsonPassword);
187
- for (const account of keyring.#data.accounts) if (account.type === "keypair") account.secretKey = await changeEncryptedDataPassword(account.secretKey, password, jsonPassword);
188
-
189
- // reset password check
203
+ const keyring = new _Keyring(structuredClone(this.#data));
204
+ for (const mnemonic of keyring.#data.mnemonics)
205
+ mnemonic.entropy = await changeEncryptedDataPassword(mnemonic.entropy, password, jsonPassword);
206
+ for (const account of keyring.#data.accounts)
207
+ if (account.type === "keypair")
208
+ account.secretKey = await changeEncryptedDataPassword(
209
+ account.secretKey,
210
+ password,
211
+ jsonPassword
212
+ );
190
213
  await keyring.checkPassword(jsonPassword, true);
191
214
  return keyring.toJson();
192
215
  }
193
216
  getMnemonics() {
194
217
  return this.#data.mnemonics.map(mnemonicFromStorage);
195
218
  }
196
- async addMnemonic({
197
- name,
198
- mnemonic,
199
- confirmed
200
- }, password) {
219
+ async addMnemonic({ name, mnemonic, confirmed }, password) {
201
220
  if (typeof name !== "string" || !name) throw new Error("name is required");
202
221
  if (typeof mnemonic !== "string") throw new Error("mnemonic is required");
203
222
  if (typeof confirmed !== "boolean") throw new Error("confirmed is required");
204
223
  if (!isValidMnemonic(mnemonic)) throw new Error("Invalid mnemonic");
205
224
  await this.checkPassword(password);
206
225
  const entropy = mnemonicToEntropy(mnemonic);
207
-
208
- // id is a hash of the entropy, helps us prevent having duplicates and allows automatic remapping of accounts/mnemonics if mnemonics are deleted then re-added
209
226
  const id = oneWayHash(entropy);
210
- if (this.#data.mnemonics.find(s => s.id === id)) throw new Error("Mnemonic already exists");
227
+ if (this.#data.mnemonics.find((s) => s.id === id)) throw new Error("Mnemonic already exists");
211
228
  const storage = {
212
229
  id,
213
230
  name,
@@ -219,32 +236,29 @@ class Keyring {
219
236
  return mnemonicFromStorage(storage);
220
237
  }
221
238
  getMnemonic(id) {
222
- const mnemonic = this.#data.mnemonics.find(s => s.id === id);
239
+ const mnemonic = this.#data.mnemonics.find((s) => s.id === id);
223
240
  return mnemonic ? mnemonicFromStorage(mnemonic) : null;
224
241
  }
225
- updateMnemonic(id, {
226
- name,
227
- confirmed
228
- }) {
229
- const mnemonic = this.#data.mnemonics.find(s => s.id === id);
242
+ updateMnemonic(id, { name, confirmed }) {
243
+ const mnemonic = this.#data.mnemonics.find((s) => s.id === id);
230
244
  if (!mnemonic) throw new Error("Mnemonic not found");
231
- if (name !== undefined) {
245
+ if (name !== void 0) {
232
246
  if (typeof name !== "string" || !name) throw new Error("name must be a string");
233
247
  mnemonic.name = name;
234
248
  }
235
- if (confirmed !== undefined) {
249
+ if (confirmed !== void 0) {
236
250
  if (typeof confirmed !== "boolean") throw new Error("confirmed must be a boolean");
237
251
  mnemonic.confirmed = confirmed;
238
252
  }
239
253
  return mnemonicFromStorage(mnemonic);
240
254
  }
241
255
  removeMnemonic(id) {
242
- const index = this.#data.mnemonics.findIndex(mnemonic => mnemonic.id == id);
256
+ const index = this.#data.mnemonics.findIndex((mnemonic) => mnemonic.id == id);
243
257
  if (index === -1) throw new Error("Mnemonic not found");
244
258
  this.#data.mnemonics.splice(index, 1);
245
259
  }
246
260
  async getMnemonicText(id, password) {
247
- const mnemonic = this.#data.mnemonics.find(s => s.id === id);
261
+ const mnemonic = this.#data.mnemonics.find((s) => s.id === id);
248
262
  if (!mnemonic) throw new Error("Mnemonic not found");
249
263
  const entropy = await decryptData(mnemonic.entropy, password);
250
264
  return entropyToMnemonic(entropy);
@@ -252,31 +266,26 @@ class Keyring {
252
266
  getExistingMnemonicId(mnemonic) {
253
267
  const entropy = mnemonicToEntropy(mnemonic);
254
268
  const mnemonicId = oneWayHash(entropy);
255
- return this.#data.mnemonics.some(s => s.id === mnemonicId) ? mnemonicId : null;
269
+ return this.#data.mnemonics.some((s) => s.id === mnemonicId) ? mnemonicId : null;
256
270
  }
257
271
  getAccounts() {
258
272
  return this.#data.accounts.map(accountFromStorage);
259
273
  }
260
274
  getAccount(address) {
261
- const account = this.#data.accounts.find(s => isAddressEqual(s.address, address));
275
+ const account = this.#data.accounts.find((s) => isAddressEqual(s.address, address));
262
276
  return account ? accountFromStorage(account) : null;
263
277
  }
264
- updateAccount(address, {
265
- name,
266
- isPortfolio,
267
- genesisHash
268
- }) {
269
- const account = this.#data.accounts.find(s => s.address === address);
278
+ updateAccount(address, { name, isPortfolio, genesisHash }) {
279
+ const account = this.#data.accounts.find((s) => s.address === address);
270
280
  if (!account) throw new Error("Account not found");
271
281
  if (name) {
272
282
  if (typeof name !== "string" || !name) throw new Error("name is required");
273
283
  account.name = name;
274
284
  }
275
- if (account.type === "watch-only" && isPortfolio !== undefined) {
285
+ if (account.type === "watch-only" && isPortfolio !== void 0) {
276
286
  if (typeof isPortfolio !== "boolean") throw new Error("isPortfolio must be a boolean");
277
287
  account.isPortfolio = isPortfolio;
278
288
  }
279
- // allow updating genesisHash only for contacts
280
289
  if (account.type === "contact") {
281
290
  if (genesisHash) {
282
291
  if (!isHexString(genesisHash)) throw new Error("genesisHash must be a hex string");
@@ -286,13 +295,12 @@ class Keyring {
286
295
  return accountFromStorage(account);
287
296
  }
288
297
  removeAccount(address) {
289
- const index = this.#data.accounts.findIndex(s => isAddressEqual(s.address, address));
298
+ const index = this.#data.accounts.findIndex((s) => isAddressEqual(s.address, address));
290
299
  if (index === -1) throw new Error("Account not found");
291
300
  this.#data.accounts.splice(index, 1);
292
301
  }
293
302
  addAccountExternal(options) {
294
- const address = normalizeAddress(options.address); // breaks if invalid address
295
-
303
+ const address = normalizeAddress(options.address);
296
304
  if (this.getAccount(address)) throw new Error("Account already exists");
297
305
  const account = {
298
306
  ...options,
@@ -303,7 +311,6 @@ class Keyring {
303
311
  this.#data.accounts.push(account);
304
312
  return accountFromStorage(account);
305
313
  }
306
-
307
314
  /**
308
315
  * Needs to be called before deriving an account from a mnemonic.
309
316
  *
@@ -316,42 +323,34 @@ class Keyring {
316
323
  async ensureMnemonic(options, password) {
317
324
  await this.checkPassword(password);
318
325
  switch (options.type) {
319
- case "new-mnemonic":
320
- {
321
- const {
322
- mnemonic,
323
- mnemonicName: name,
324
- confirmed
325
- } = options;
326
- if (typeof name !== "string" || !name) throw new Error("mnemonicName is required");
327
- if (typeof confirmed !== "boolean") throw new Error("confirmed is required");
328
- const mnemonicId = this.getExistingMnemonicId(mnemonic);
329
- if (mnemonicId) return mnemonicId;
330
- const {
331
- id
332
- } = await this.addMnemonic({
326
+ case "new-mnemonic": {
327
+ const { mnemonic, mnemonicName: name, confirmed } = options;
328
+ if (typeof name !== "string" || !name) throw new Error("mnemonicName is required");
329
+ if (typeof confirmed !== "boolean") throw new Error("confirmed is required");
330
+ const mnemonicId = this.getExistingMnemonicId(mnemonic);
331
+ if (mnemonicId) return mnemonicId;
332
+ const { id } = await this.addMnemonic(
333
+ {
333
334
  name,
334
335
  mnemonic,
335
336
  confirmed
336
- }, password);
337
- return id;
338
- }
339
- case "existing-mnemonic":
340
- {
341
- if (typeof options.mnemonicId !== "string" || !options.mnemonicId) throw new Error("mnemonicId must be a string");
342
- return options.mnemonicId;
343
- }
337
+ },
338
+ password
339
+ );
340
+ return id;
341
+ }
342
+ case "existing-mnemonic": {
343
+ if (typeof options.mnemonicId !== "string" || !options.mnemonicId)
344
+ throw new Error("mnemonicId must be a string");
345
+ return options.mnemonicId;
346
+ }
344
347
  }
345
348
  }
346
349
  async addAccountDerive(options, password) {
347
350
  await this.checkPassword(password);
348
- const {
349
- curve,
350
- derivationPath,
351
- name
352
- } = options;
351
+ const { curve, derivationPath, name } = options;
353
352
  const mnemonicId = await this.ensureMnemonic(options, password);
354
- const mnemonic = this.#data.mnemonics.find(s => s.id === mnemonicId);
353
+ const mnemonic = this.#data.mnemonics.find((s) => s.id === mnemonicId);
355
354
  if (!mnemonic) throw new Error("Mnemonic not found");
356
355
  const entropy = await decryptData(mnemonic.entropy, password);
357
356
  const seed = await entropyToSeed(entropy, curve);
@@ -370,11 +369,7 @@ class Keyring {
370
369
  this.#data.accounts.push(account);
371
370
  return accountFromStorage(account);
372
371
  }
373
- async addAccountKeypair({
374
- curve,
375
- name,
376
- secretKey
377
- }, password) {
372
+ async addAccountKeypair({ curve, name, secretKey }, password) {
378
373
  await this.checkPassword(password);
379
374
  const publicKey = getPublicKeyFromSecret(secretKey, curve);
380
375
  const encoding = addressEncodingFromCurve(curve);
@@ -394,7 +389,7 @@ class Keyring {
394
389
  getAccountSecretKey(address, password) {
395
390
  if (typeof address !== "string" || !address) throw new Error("address is required");
396
391
  if (typeof password !== "string" || !password) throw new Error("password is required");
397
- const account = this.#data.accounts.find(a => a.address === normalizeAddress(address));
392
+ const account = this.#data.accounts.find((a) => a.address === normalizeAddress(address));
398
393
  if (!account) throw new Error("Account not found");
399
394
  if (account.type !== "keypair") throw new Error("Secret key unavailable");
400
395
  return decryptData(account.secretKey, password);
@@ -402,30 +397,47 @@ class Keyring {
402
397
  async getDerivedAddress(mnemonicId, derivationPath, curve, password) {
403
398
  if (typeof mnemonicId !== "string" || !mnemonicId) throw new Error("mnemonicId is required");
404
399
  if (typeof password !== "string" || !password) throw new Error("password is required");
405
- const mnemonic = this.#data.mnemonics.find(s => s.id === mnemonicId);
400
+ const mnemonic = this.#data.mnemonics.find((s) => s.id === mnemonicId);
406
401
  if (!mnemonic) throw new Error("Mnemonic not found");
407
402
  const entropy = await decryptData(mnemonic.entropy, password);
408
403
  const seed = await entropyToSeed(entropy, curve);
409
404
  const pair = deriveKeypair(seed, derivationPath, curve);
410
405
  return pair.address;
411
406
  }
412
- }
413
- const oneWayHash = bytes => {
407
+ };
408
+ var oneWayHash = (bytes) => {
414
409
  if (typeof bytes === "string") bytes = utf8.decode(bytes);
415
-
416
- // cryptographically secure one way hash
417
- // outputs 44 characters without special characters
418
410
  return base58.encode(blake3(bytes));
419
411
  };
420
- const mnemonicFromStorage = data => {
412
+ var mnemonicFromStorage = (data) => {
421
413
  const copy = structuredClone(data);
422
414
  if ("entropy" in copy) delete copy.entropy;
423
415
  return Object.freeze(copy);
424
416
  };
425
- const accountFromStorage = data => {
417
+ var accountFromStorage = (data) => {
426
418
  const copy = structuredClone(data);
427
419
  if ("secretKey" in copy) delete copy.secretKey;
428
420
  return Object.freeze(copy);
429
421
  };
430
-
431
- export { Keyring, getAccountGenesisHash, getAccountPlatform, getAccountSignetUrl, isAccountAddressEthereum, isAccountAddressSs58, isAccountBitcoin, isAccountExternal, isAccountInTypes, isAccountLedgerPolkadot, isAccountLedgerPolkadotGeneric, isAccountLedgerPolkadotLegacy, isAccountNotContact, isAccountOfType, isAccountOwned, isAccountPlatformEthereum, isAccountPlatformPolkadot, isAccountPlatformSolana, isAccountPortfolio };
422
+ export {
423
+ Keyring,
424
+ getAccountGenesisHash,
425
+ getAccountPlatform,
426
+ getAccountSignetUrl,
427
+ isAccountAddressEthereum,
428
+ isAccountAddressSs58,
429
+ isAccountBitcoin,
430
+ isAccountExternal,
431
+ isAccountInTypes,
432
+ isAccountLedgerPolkadot,
433
+ isAccountLedgerPolkadotGeneric,
434
+ isAccountLedgerPolkadotLegacy,
435
+ isAccountNotContact,
436
+ isAccountOfType,
437
+ isAccountOwned,
438
+ isAccountPlatformEthereum,
439
+ isAccountPlatformPolkadot,
440
+ isAccountPlatformSolana,
441
+ isAccountPortfolio
442
+ };
443
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/utils.ts","../src/keyring/Keyring.ts","../src/keyring/encryption.ts","../src/keyring/utils.ts"],"sourcesContent":["import {\n detectAddressEncoding,\n getAccountPlatformFromAddress,\n getAccountPlatformFromCurve,\n isBitcoinAddress,\n isEthereumAddress,\n isSolanaAddress,\n} from \"@talismn/crypto\"\n\nimport type { Account, AccountLedgerPolkadot, AccountType } from \"./account\"\n\nexport type AccountOfType<Type extends AccountType> = Extract<Account, { type: Type }>\n\nexport const isAccountOfType = <Type extends AccountType>(\n account: Account | null | undefined,\n type: Type,\n): account is AccountOfType<Type> => {\n return account?.type === type\n}\n\nexport const isAccountInTypes = <Types extends AccountType[]>(\n account: Account | null | undefined,\n types: Types,\n): account is AccountOfType<Types[number]> => {\n return !!account && types.includes(account.type)\n}\n\nconst ACCOUNT_TYPES_OWNED = [\n \"keypair\",\n \"ledger-ethereum\",\n \"ledger-polkadot\",\n \"ledger-solana\",\n \"polkadot-vault\",\n] as const\n\nconst ACCOUNT_TYPES_EXTERNAL = [\n \"contact\",\n \"watch-only\",\n \"ledger-ethereum\",\n \"ledger-polkadot\",\n \"ledger-solana\",\n \"polkadot-vault\",\n \"signet\",\n] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_ADDRESS_ETHEREUM = [\n \"contact\",\n \"watch-only\",\n \"keypair\",\n \"ledger-ethereum\",\n \"ledger-polkadot\",\n] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_PLATFORM_ETHEREUM = [\n \"contact\",\n \"watch-only\",\n \"keypair\",\n \"ledger-ethereum\",\n] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_PLATFORM_POLKADOT = [\n \"contact\",\n \"watch-only\",\n \"keypair\",\n \"ledger-polkadot\",\n \"polkadot-vault\",\n \"signet\",\n] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_ADDRESS_SS58 = [\n \"contact\",\n \"watch-only\",\n \"keypair\",\n \"ledger-polkadot\",\n \"polkadot-vault\",\n \"signet\",\n] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_PLATFORM_SOLANA = [\"contact\", \"watch-only\", \"keypair\", \"ledger-solana\"] as const\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst ACCOUNT_TYPES_BITCOIN = [\"contact\", \"watch-only\"] as const\n\nexport const isAccountExternal = (\n account: Account | null | undefined,\n): account is AccountOfType<(typeof ACCOUNT_TYPES_EXTERNAL)[number]> => {\n return isAccountInTypes(account, ACCOUNT_TYPES_EXTERNAL as unknown as AccountType[])\n}\n\nexport const isAccountOwned = (\n account: Account | null | undefined,\n): account is AccountOfType<(typeof ACCOUNT_TYPES_OWNED)[number]> => {\n return isAccountInTypes(account, ACCOUNT_TYPES_OWNED as unknown as AccountType[])\n}\n\nexport const isAccountPortfolio = (account: Account | null | undefined): account is Account => {\n return isAccountOwned(account) || (isAccountOfType(account, \"watch-only\") && account.isPortfolio)\n}\n\nexport const isAccountNotContact = (acc: Account) => acc.type !== \"contact\"\n\ntype AccountAddressEthereum = Extract<\n Account,\n { type: (typeof ACCOUNT_TYPES_ADDRESS_ETHEREUM)[number] }\n> & {\n address: `0x${string}`\n}\nexport const isAccountAddressEthereum = (\n account: Account | null | undefined,\n): account is AccountAddressEthereum => {\n return !!account && isEthereumAddress(account.address)\n}\n\ntype AccountPlatformEthereum = Extract<\n Account,\n { type: (typeof ACCOUNT_TYPES_PLATFORM_ETHEREUM)[number] }\n> & {\n address: `0x${string}`\n}\nexport const isAccountPlatformEthereum = (\n account: Account | null | undefined,\n): account is AccountPlatformEthereum => {\n return !!account && account.type !== \"ledger-polkadot\" && isEthereumAddress(account.address)\n}\n\ntype AccountPlatformSolana = Extract<\n Account,\n { type: (typeof ACCOUNT_TYPES_PLATFORM_SOLANA)[number] }\n>\n\nexport const isAccountPlatformSolana = (\n account: Account | null | undefined,\n): account is AccountPlatformSolana => {\n return !!account && isSolanaAddress(account.address)\n}\n\ntype AccountPlatformPolkadot = Extract<\n Account,\n { type: (typeof ACCOUNT_TYPES_PLATFORM_POLKADOT)[number] }\n>\nexport const isAccountPlatformPolkadot = (\n account: Account | null | undefined,\n): account is AccountPlatformPolkadot => {\n return (\n !!account &&\n account.type !== \"ledger-ethereum\" &&\n (isAccountAddressEthereum(account) || isAccountAddressSs58(account))\n )\n}\n\ntype AccountAddressSs58 = Extract<\n Account,\n { type: (typeof ACCOUNT_TYPES_ADDRESS_SS58)[number] }\n> & {\n genesisHash?: `0x${string}`\n}\nexport const isAccountAddressSs58 = (\n account: Account | null | undefined,\n): account is AccountAddressSs58 => {\n return !!account && detectAddressEncoding(account.address) === \"ss58\"\n}\n\nexport const isAccountLedgerPolkadot = (\n account: Account | null | undefined,\n): account is AccountLedgerPolkadot => {\n return isAccountOfType(account, \"ledger-polkadot\")\n}\n\nexport const isAccountLedgerPolkadotGeneric = (\n account: Account | null | undefined,\n): account is AccountLedgerPolkadot & { genesisHash: undefined } => {\n return isAccountOfType(account, \"ledger-polkadot\") && !account.genesisHash\n}\n\nexport const isAccountLedgerPolkadotLegacy = (\n account: Account | null | undefined,\n): account is AccountLedgerPolkadot & { genesisHash: `0x${string}` } => {\n return isAccountOfType(account, \"ledger-polkadot\") && !!account.genesisHash\n}\n\ntype AccountBitcoin = Extract<Account, { type: (typeof ACCOUNT_TYPES_BITCOIN)[number] }>\nexport const isAccountBitcoin = (\n account: Account | null | undefined,\n): account is AccountBitcoin => {\n return !!account && isBitcoinAddress(account.address)\n}\n\nexport const getAccountGenesisHash = (account: Account | null | undefined) => {\n if (!account) return undefined\n return \"genesisHash\" in account ? account.genesisHash || undefined : undefined\n}\n\nexport const getAccountSignetUrl = (account: Account | null | undefined) => {\n return isAccountOfType(account, \"signet\") ? account.url : undefined\n}\n\nexport const getAccountPlatform = (account: Account | null | undefined) => {\n if (!account) return undefined\n return \"curve\" in account\n ? getAccountPlatformFromCurve(account.curve)\n : getAccountPlatformFromAddress(account.address)\n}\n","import {\n addressEncodingFromCurve,\n addressFromPublicKey,\n base58,\n blake3,\n deriveKeypair,\n entropyToMnemonic,\n entropyToSeed,\n getPublicKeyFromSecret,\n isAddressEqual,\n isValidMnemonic,\n KeypairCurve,\n mnemonicToEntropy,\n normalizeAddress,\n utf8,\n} from \"@talismn/crypto\"\n\nimport type { Account, Mnemonic } from \"../types\"\nimport type {\n AddAccountDeriveOptions,\n AddAccountExternalOptions,\n AddAccountKeypairOptions,\n AddMnemonicOptions,\n UpdateAccountOptions,\n UpdateMnemonicOptions,\n} from \"../types/keyring\"\nimport type { AccountStorage, MnemonicStorage } from \"./types\"\nimport { isAccountExternal } from \"../types\"\nimport { changeEncryptedDataPassword, decryptData, encryptData } from \"./encryption\"\nimport { isHexString } from \"./utils\"\n\nexport type KeyringStorage = {\n passwordCheck: string | null // well-known data encrypted using the password, used to ensure all secrets of the keyring are encrypted with the same password\n mnemonics: MnemonicStorage[]\n accounts: AccountStorage[]\n}\n\nexport class Keyring {\n #data: KeyringStorage\n\n protected constructor(data: KeyringStorage) {\n this.#data = structuredClone(data)\n }\n\n public static create(): Keyring {\n return new Keyring({\n passwordCheck: null, // well-known data encrypted using the password, used to ensure all secrets of the keyring are encrypted with the same password\n mnemonics: [],\n accounts: [],\n })\n }\n\n public static load(data: KeyringStorage): Keyring {\n if (!data.accounts || !data.mnemonics) throw new Error(\"Invalid data\")\n\n // automatic upgrade : set default values for newly introduced properties\n for (const account of data.accounts) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n if (account.type === \"ledger-polkadot\" && !account.curve) account.curve = \"ed25519\"\n }\n\n return new Keyring(data)\n }\n\n private async checkPassword(password: string, reset = false) {\n if (typeof password !== \"string\" || !password) throw new Error(\"password is required\")\n\n const passwordHash = oneWayHash(password)\n const PASSWORD_CHECK_PHRASE = \"PASSWORD_CHECK_PHRASE\"\n\n // run through same complexity as for other secrets, to make it so it s not easier to brute force passwordCheck than other secrets\n if (!this.#data.passwordCheck || reset) {\n const bytes = utf8.decode(PASSWORD_CHECK_PHRASE)\n this.#data.passwordCheck = await encryptData(bytes, passwordHash)\n } else {\n try {\n const bytes = await decryptData(this.#data.passwordCheck, passwordHash)\n const text = utf8.encode(bytes)\n if (text !== PASSWORD_CHECK_PHRASE) throw new Error(\"Invalid password\")\n } catch {\n throw new Error(\"Invalid password\")\n }\n }\n }\n\n public toJson() {\n return structuredClone(this.#data)\n }\n\n public async export(password: string, jsonPassword: string): Promise<KeyringStorage> {\n const keyring = new Keyring(structuredClone(this.#data))\n\n for (const mnemonic of keyring.#data.mnemonics)\n mnemonic.entropy = await changeEncryptedDataPassword(mnemonic.entropy, password, jsonPassword)\n\n for (const account of keyring.#data.accounts)\n if (account.type === \"keypair\")\n account.secretKey = await changeEncryptedDataPassword(\n account.secretKey,\n password,\n jsonPassword,\n )\n\n // reset password check\n await keyring.checkPassword(jsonPassword, true)\n\n return keyring.toJson()\n }\n\n public getMnemonics(): Mnemonic[] {\n return this.#data.mnemonics.map(mnemonicFromStorage)\n }\n\n public async addMnemonic(\n { name, mnemonic, confirmed }: AddMnemonicOptions,\n password: string,\n ): Promise<Mnemonic> {\n if (typeof name !== \"string\" || !name) throw new Error(\"name is required\")\n if (typeof mnemonic !== \"string\") throw new Error(\"mnemonic is required\")\n if (typeof confirmed !== \"boolean\") throw new Error(\"confirmed is required\")\n if (!isValidMnemonic(mnemonic)) throw new Error(\"Invalid mnemonic\")\n\n await this.checkPassword(password)\n\n const entropy = mnemonicToEntropy(mnemonic)\n\n // id is a hash of the entropy, helps us prevent having duplicates and allows automatic remapping of accounts/mnemonics if mnemonics are deleted then re-added\n const id = oneWayHash(entropy)\n\n if (this.#data.mnemonics.find((s) => s.id === id)) throw new Error(\"Mnemonic already exists\")\n\n const storage: MnemonicStorage = {\n id,\n name,\n entropy: await encryptData(entropy, password),\n confirmed,\n createdAt: Date.now(),\n }\n\n this.#data.mnemonics.push(storage)\n\n return mnemonicFromStorage(storage)\n }\n\n public getMnemonic(id: string): Mnemonic | null {\n const mnemonic = this.#data.mnemonics.find((s) => s.id === id)\n return mnemonic ? mnemonicFromStorage(mnemonic) : null\n }\n\n public updateMnemonic(id: string, { name, confirmed }: UpdateMnemonicOptions) {\n const mnemonic = this.#data.mnemonics.find((s) => s.id === id)\n if (!mnemonic) throw new Error(\"Mnemonic not found\")\n if (name !== undefined) {\n if (typeof name !== \"string\" || !name) throw new Error(\"name must be a string\")\n mnemonic.name = name\n }\n if (confirmed !== undefined) {\n if (typeof confirmed !== \"boolean\") throw new Error(\"confirmed must be a boolean\")\n mnemonic.confirmed = confirmed\n }\n return mnemonicFromStorage(mnemonic)\n }\n\n public removeMnemonic(id: string) {\n const index = this.#data.mnemonics.findIndex((mnemonic) => mnemonic.id == id)\n if (index === -1) throw new Error(\"Mnemonic not found\")\n this.#data.mnemonics.splice(index, 1)\n }\n\n async getMnemonicText(id: string, password: string): Promise<string> {\n const mnemonic = this.#data.mnemonics.find((s) => s.id === id)\n if (!mnemonic) throw new Error(\"Mnemonic not found\")\n\n const entropy = await decryptData(mnemonic.entropy, password)\n\n return entropyToMnemonic(entropy)\n }\n\n public getExistingMnemonicId(mnemonic: string): string | null {\n const entropy = mnemonicToEntropy(mnemonic)\n const mnemonicId = oneWayHash(entropy)\n return this.#data.mnemonics.some((s) => s.id === mnemonicId) ? mnemonicId : null\n }\n\n public getAccounts(): Account[] {\n return this.#data.accounts.map(accountFromStorage)\n }\n\n public getAccount(address: string): Account | null {\n const account = this.#data.accounts.find((s) => isAddressEqual(s.address, address))\n return account ? accountFromStorage(account) : null\n }\n\n public updateAccount(address: string, { name, isPortfolio, genesisHash }: UpdateAccountOptions) {\n const account = this.#data.accounts.find((s) => s.address === address)\n if (!account) throw new Error(\"Account not found\")\n\n if (name) {\n if (typeof name !== \"string\" || !name) throw new Error(\"name is required\")\n account.name = name\n }\n if (account.type === \"watch-only\" && isPortfolio !== undefined) {\n if (typeof isPortfolio !== \"boolean\") throw new Error(\"isPortfolio must be a boolean\")\n account.isPortfolio = isPortfolio\n }\n // allow updating genesisHash only for contacts\n if (account.type === \"contact\") {\n if (genesisHash) {\n if (!isHexString(genesisHash)) throw new Error(\"genesisHash must be a hex string\")\n account.genesisHash = genesisHash\n } else delete account.genesisHash\n }\n\n return accountFromStorage(account)\n }\n\n public removeAccount(address: string) {\n const index = this.#data.accounts.findIndex((s) => isAddressEqual(s.address, address))\n if (index === -1) throw new Error(\"Account not found\")\n this.#data.accounts.splice(index, 1)\n }\n\n public addAccountExternal(options: AddAccountExternalOptions): Account {\n const address = normalizeAddress(options.address) // breaks if invalid address\n\n if (this.getAccount(address)) throw new Error(\"Account already exists\")\n\n const account: AccountStorage = {\n ...options,\n address,\n createdAt: Date.now(),\n }\n\n if (!isAccountExternal(account)) throw new Error(\"Invalid account type\")\n\n this.#data.accounts.push(account)\n\n return accountFromStorage(account)\n }\n\n /**\n * Needs to be called before deriving an account from a mnemonic.\n *\n * This will ensure that it is present (or add it if possible) in the keyring before actually creating the account.\n *\n * @param options\n * @param password\n * @returns the id of the mnemonic\n */\n private async ensureMnemonic(options: AddAccountDeriveOptions, password: string) {\n await this.checkPassword(password)\n\n switch (options.type) {\n case \"new-mnemonic\": {\n const { mnemonic, mnemonicName: name, confirmed } = options\n\n if (typeof name !== \"string\" || !name) throw new Error(\"mnemonicName is required\")\n if (typeof confirmed !== \"boolean\") throw new Error(\"confirmed is required\")\n\n const mnemonicId = this.getExistingMnemonicId(mnemonic)\n if (mnemonicId) return mnemonicId\n\n const { id } = await this.addMnemonic(\n {\n name,\n mnemonic,\n confirmed,\n },\n password,\n )\n\n return id\n }\n case \"existing-mnemonic\": {\n if (typeof options.mnemonicId !== \"string\" || !options.mnemonicId)\n throw new Error(\"mnemonicId must be a string\")\n\n return options.mnemonicId\n }\n }\n }\n\n public async addAccountDerive(\n options: AddAccountDeriveOptions,\n password: string,\n ): Promise<Account> {\n await this.checkPassword(password)\n\n const { curve, derivationPath, name } = options\n\n const mnemonicId = await this.ensureMnemonic(options, password)\n\n const mnemonic = this.#data.mnemonics.find((s) => s.id === mnemonicId)\n if (!mnemonic) throw new Error(\"Mnemonic not found\")\n\n const entropy = await decryptData(mnemonic.entropy, password)\n const seed = await entropyToSeed(entropy, curve)\n const pair = deriveKeypair(seed, derivationPath, curve)\n\n if (this.getAccount(pair.address)) throw new Error(\"Account already exists\")\n\n const account: AccountStorage = {\n type: \"keypair\",\n curve,\n name,\n address: normalizeAddress(pair.address),\n secretKey: await encryptData(pair.secretKey, password),\n mnemonicId,\n derivationPath,\n createdAt: Date.now(),\n }\n\n this.#data.accounts.push(account)\n\n return accountFromStorage(account)\n }\n\n public async addAccountKeypair(\n { curve, name, secretKey }: AddAccountKeypairOptions,\n password: string,\n ): Promise<Account> {\n await this.checkPassword(password)\n\n const publicKey = getPublicKeyFromSecret(secretKey, curve)\n const encoding = addressEncodingFromCurve(curve)\n const address = addressFromPublicKey(publicKey, encoding)\n\n if (this.getAccount(address)) throw new Error(\"Account already exists\")\n\n const account: AccountStorage = {\n type: \"keypair\",\n curve,\n name,\n address: normalizeAddress(address),\n secretKey: await encryptData(secretKey, password),\n createdAt: Date.now(),\n }\n\n this.#data.accounts.push(account)\n\n return accountFromStorage(account)\n }\n\n public getAccountSecretKey(address: string, password: string): Promise<Uint8Array> {\n if (typeof address !== \"string\" || !address) throw new Error(\"address is required\")\n if (typeof password !== \"string\" || !password) throw new Error(\"password is required\")\n\n const account = this.#data.accounts.find((a) => a.address === normalizeAddress(address))\n if (!account) throw new Error(\"Account not found\")\n if (account.type !== \"keypair\") throw new Error(\"Secret key unavailable\")\n\n return decryptData(account.secretKey, password)\n }\n\n public async getDerivedAddress(\n mnemonicId: string,\n derivationPath: string,\n curve: KeypairCurve,\n password: string,\n ): Promise<string> {\n if (typeof mnemonicId !== \"string\" || !mnemonicId) throw new Error(\"mnemonicId is required\")\n if (typeof password !== \"string\" || !password) throw new Error(\"password is required\")\n\n const mnemonic = this.#data.mnemonics.find((s) => s.id === mnemonicId)\n if (!mnemonic) throw new Error(\"Mnemonic not found\")\n\n const entropy = await decryptData(mnemonic.entropy, password)\n const seed = await entropyToSeed(entropy, curve)\n const pair = deriveKeypair(seed, derivationPath, curve)\n\n return pair.address\n }\n}\n\nconst oneWayHash = (bytes: Uint8Array | string) => {\n if (typeof bytes === \"string\") bytes = utf8.decode(bytes)\n\n // cryptographically secure one way hash\n // outputs 44 characters without special characters\n return base58.encode(blake3(bytes))\n}\n\nconst mnemonicFromStorage = (data: MnemonicStorage): Mnemonic => {\n const copy = structuredClone(data) as Mnemonic\n if (\"entropy\" in copy) delete copy.entropy\n return Object.freeze(copy)\n}\n\nconst accountFromStorage = (data: AccountStorage): Account => {\n const copy = structuredClone(data) as Account\n if (\"secretKey\" in copy) delete copy.secretKey\n return Object.freeze(copy)\n}\n","import { pbkdf2 } from \"@talismn/crypto\"\n\n// Derive a key generated with PBKDF2 that will be used for AES-GCM encryption\nconst deriveKey = async (password: string, salt: Uint8Array): Promise<CryptoKey> =>\n // Deriving 32-byte key using PBKDF2 with 100,000 iterations and SHA-256\n await crypto.subtle.importKey(\n \"raw\",\n await pbkdf2(\n \"SHA-256\",\n new TextEncoder().encode(password),\n salt,\n 100_000, // 100,000 iterations\n 32, // 32 bytes (32 * 8 == 256 bits)\n ),\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n )\n\nexport const encryptData = async (data: Uint8Array, password: string): Promise<string> => {\n try {\n const salt = crypto.getRandomValues(new Uint8Array(16)) // 16 bytes of salt\n const iv = crypto.getRandomValues(new Uint8Array(12)) // 12-byte IV for AES-GCM\n const key = await deriveKey(password, salt)\n\n // encrypt\n const encryptedSeed = await crypto.subtle.encrypt({ name: \"AES-GCM\", iv }, key, data)\n\n // Combine salt, IV, and encrypted seed\n const combined = new Uint8Array(salt.length + iv.length + encryptedSeed.byteLength)\n combined.set(salt, 0)\n combined.set(iv, salt.length)\n combined.set(new Uint8Array(encryptedSeed), salt.length + iv.length)\n\n // Base64 encode the combined data\n return btoa(String.fromCharCode(...combined))\n } catch (cause) {\n throw new Error(\"Failed to encrypt data\", { cause })\n }\n}\n\nexport const decryptData = async (encryptedData: string, password: string): Promise<Uint8Array> => {\n try {\n // Decode Base64 and parse the combined data\n const combined = Uint8Array.from(atob(encryptedData), (c) => c.charCodeAt(0))\n\n // Extract salt, IV, and encrypted seed\n const salt = combined.slice(0, 16) // First 16 bytes\n const iv = combined.slice(16, 28) // Next 12 bytes\n const encryptedSeed = combined.slice(28) // Remaining bytes\n\n const key = await deriveKey(password, salt)\n\n // Decrypt the seed\n const decryptedSeed = await crypto.subtle.decrypt({ name: \"AES-GCM\", iv }, key, encryptedSeed)\n\n return new Uint8Array(decryptedSeed)\n } catch (cause) {\n throw new Error(\"Failed to decrypt data\", { cause })\n }\n}\n\nexport const changeEncryptedDataPassword = async (\n encryptedData: string,\n oldPassword: string,\n newPassword: string,\n) => {\n try {\n const decrypted = await decryptData(encryptedData, oldPassword)\n return await encryptData(decrypted, newPassword)\n } catch (cause) {\n throw new Error(\"Failed to change password on encrypted data\", { cause })\n }\n}\n","// we dont want to reference @talismn/util in the keyring, so we copy this here\ntype HexString = `0x${string}`\n\nexport const REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/\n\nexport const isHexString = (value: unknown): value is HexString => {\n return typeof value === \"string\" && REGEX_HEX_STRING.test(value)\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMA,IAAM,kBAAkB,CAC7B,SACA,SACmC;AACnC,SAAO,SAAS,SAAS;AAC3B;AAEO,IAAM,mBAAmB,CAC9B,SACA,UAC4C;AAC5C,SAAO,CAAC,CAAC,WAAW,MAAM,SAAS,QAAQ,IAAI;AACjD;AAEA,IAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA6CO,IAAM,oBAAoB,CAC/B,YACsE;AACtE,SAAO,iBAAiB,SAAS,sBAAkD;AACrF;AAEO,IAAM,iBAAiB,CAC5B,YACmE;AACnE,SAAO,iBAAiB,SAAS,mBAA+C;AAClF;AAEO,IAAM,qBAAqB,CAAC,YAA4D;AAC7F,SAAO,eAAe,OAAO,KAAM,gBAAgB,SAAS,YAAY,KAAK,QAAQ;AACvF;AAEO,IAAM,sBAAsB,CAAC,QAAiB,IAAI,SAAS;AAQ3D,IAAM,2BAA2B,CACtC,YACsC;AACtC,SAAO,CAAC,CAAC,WAAW,kBAAkB,QAAQ,OAAO;AACvD;AAQO,IAAM,4BAA4B,CACvC,YACuC;AACvC,SAAO,CAAC,CAAC,WAAW,QAAQ,SAAS,qBAAqB,kBAAkB,QAAQ,OAAO;AAC7F;AAOO,IAAM,0BAA0B,CACrC,YACqC;AACrC,SAAO,CAAC,CAAC,WAAW,gBAAgB,QAAQ,OAAO;AACrD;AAMO,IAAM,4BAA4B,CACvC,YACuC;AACvC,SACE,CAAC,CAAC,WACF,QAAQ,SAAS,sBAChB,yBAAyB,OAAO,KAAK,qBAAqB,OAAO;AAEtE;AAQO,IAAM,uBAAuB,CAClC,YACkC;AAClC,SAAO,CAAC,CAAC,WAAW,sBAAsB,QAAQ,OAAO,MAAM;AACjE;AAEO,IAAM,0BAA0B,CACrC,YACqC;AACrC,SAAO,gBAAgB,SAAS,iBAAiB;AACnD;AAEO,IAAM,iCAAiC,CAC5C,YACkE;AAClE,SAAO,gBAAgB,SAAS,iBAAiB,KAAK,CAAC,QAAQ;AACjE;AAEO,IAAM,gCAAgC,CAC3C,YACsE;AACtE,SAAO,gBAAgB,SAAS,iBAAiB,KAAK,CAAC,CAAC,QAAQ;AAClE;AAGO,IAAM,mBAAmB,CAC9B,YAC8B;AAC9B,SAAO,CAAC,CAAC,WAAW,iBAAiB,QAAQ,OAAO;AACtD;AAEO,IAAM,wBAAwB,CAAC,YAAwC;AAC5E,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,iBAAiB,UAAU,QAAQ,eAAe,SAAY;AACvE;AAEO,IAAM,sBAAsB,CAAC,YAAwC;AAC1E,SAAO,gBAAgB,SAAS,QAAQ,IAAI,QAAQ,MAAM;AAC5D;AAEO,IAAM,qBAAqB,CAAC,YAAwC;AACzE,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,WAAW,UACd,4BAA4B,QAAQ,KAAK,IACzC,8BAA8B,QAAQ,OAAO;AACnD;;;AC9MA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACfP,SAAS,cAAc;AAGvB,IAAM,YAAY,OAAO,UAAkB;AAAA;AAAA,EAEzC,MAAM,OAAO,OAAO;AAAA,IAClB;AAAA,IACA,MAAM;AAAA,MACJ;AAAA,MACA,IAAI,YAAY,EAAE,OAAO,QAAQ;AAAA,MACjC;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,IACF;AAAA,IACA,EAAE,MAAM,WAAW,QAAQ,IAAI;AAAA,IAC/B;AAAA,IACA,CAAC,WAAW,SAAS;AAAA,EACvB;AAAA;AAEK,IAAM,cAAc,OAAO,MAAkB,aAAsC;AACxF,MAAI;AACF,UAAM,OAAO,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC;AACtD,UAAM,KAAK,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC;AACpD,UAAM,MAAM,MAAM,UAAU,UAAU,IAAI;AAG1C,UAAM,gBAAgB,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,GAAG,GAAG,KAAK,IAAI;AAGpF,UAAM,WAAW,IAAI,WAAW,KAAK,SAAS,GAAG,SAAS,cAAc,UAAU;AAClF,aAAS,IAAI,MAAM,CAAC;AACpB,aAAS,IAAI,IAAI,KAAK,MAAM;AAC5B,aAAS,IAAI,IAAI,WAAW,aAAa,GAAG,KAAK,SAAS,GAAG,MAAM;AAGnE,WAAO,KAAK,OAAO,aAAa,GAAG,QAAQ,CAAC;AAAA,EAC9C,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,0BAA0B,EAAE,MAAM,CAAC;AAAA,EACrD;AACF;AAEO,IAAM,cAAc,OAAO,eAAuB,aAA0C;AACjG,MAAI;AAEF,UAAM,WAAW,WAAW,KAAK,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAG5E,UAAM,OAAO,SAAS,MAAM,GAAG,EAAE;AACjC,UAAM,KAAK,SAAS,MAAM,IAAI,EAAE;AAChC,UAAM,gBAAgB,SAAS,MAAM,EAAE;AAEvC,UAAM,MAAM,MAAM,UAAU,UAAU,IAAI;AAG1C,UAAM,gBAAgB,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,GAAG,GAAG,KAAK,aAAa;AAE7F,WAAO,IAAI,WAAW,aAAa;AAAA,EACrC,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,0BAA0B,EAAE,MAAM,CAAC;AAAA,EACrD;AACF;AAEO,IAAM,8BAA8B,OACzC,eACA,aACA,gBACG;AACH,MAAI;AACF,UAAM,YAAY,MAAM,YAAY,eAAe,WAAW;AAC9D,WAAO,MAAM,YAAY,WAAW,WAAW;AAAA,EACjD,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,+CAA+C,EAAE,MAAM,CAAC;AAAA,EAC1E;AACF;;;ACtEO,IAAM,mBAAmB;AAEzB,IAAM,cAAc,CAAC,UAAuC;AACjE,SAAO,OAAO,UAAU,YAAY,iBAAiB,KAAK,KAAK;AACjE;;;AF8BO,IAAM,UAAN,MAAM,SAAQ;AAAA,EACnB;AAAA,EAEU,YAAY,MAAsB;AAC1C,SAAK,QAAQ,gBAAgB,IAAI;AAAA,EACnC;AAAA,EAEA,OAAc,SAAkB;AAC9B,WAAO,IAAI,SAAQ;AAAA,MACjB,eAAe;AAAA;AAAA,MACf,WAAW,CAAC;AAAA,MACZ,UAAU,CAAC;AAAA,IACb,CAAC;AAAA,EACH;AAAA,EAEA,OAAc,KAAK,MAA+B;AAChD,QAAI,CAAC,KAAK,YAAY,CAAC,KAAK,UAAW,OAAM,IAAI,MAAM,cAAc;AAGrE,eAAW,WAAW,KAAK,UAAU;AAGnC,UAAI,QAAQ,SAAS,qBAAqB,CAAC,QAAQ,MAAO,SAAQ,QAAQ;AAAA,IAC5E;AAEA,WAAO,IAAI,SAAQ,IAAI;AAAA,EACzB;AAAA,EAEA,MAAc,cAAc,UAAkB,QAAQ,OAAO;AAC3D,QAAI,OAAO,aAAa,YAAY,CAAC,SAAU,OAAM,IAAI,MAAM,sBAAsB;AAErF,UAAM,eAAe,WAAW,QAAQ;AACxC,UAAM,wBAAwB;AAG9B,QAAI,CAAC,KAAK,MAAM,iBAAiB,OAAO;AACtC,YAAM,QAAQ,KAAK,OAAO,qBAAqB;AAC/C,WAAK,MAAM,gBAAgB,MAAM,YAAY,OAAO,YAAY;AAAA,IAClE,OAAO;AACL,UAAI;AACF,cAAM,QAAQ,MAAM,YAAY,KAAK,MAAM,eAAe,YAAY;AACtE,cAAM,OAAO,KAAK,OAAO,KAAK;AAC9B,YAAI,SAAS,sBAAuB,OAAM,IAAI,MAAM,kBAAkB;AAAA,MACxE,QAAQ;AACN,cAAM,IAAI,MAAM,kBAAkB;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA,EAEO,SAAS;AACd,WAAO,gBAAgB,KAAK,KAAK;AAAA,EACnC;AAAA,EAEA,MAAa,OAAO,UAAkB,cAA+C;AACnF,UAAM,UAAU,IAAI,SAAQ,gBAAgB,KAAK,KAAK,CAAC;AAEvD,eAAW,YAAY,QAAQ,MAAM;AACnC,eAAS,UAAU,MAAM,4BAA4B,SAAS,SAAS,UAAU,YAAY;AAE/F,eAAW,WAAW,QAAQ,MAAM;AAClC,UAAI,QAAQ,SAAS;AACnB,gBAAQ,YAAY,MAAM;AAAA,UACxB,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAGJ,UAAM,QAAQ,cAAc,cAAc,IAAI;AAE9C,WAAO,QAAQ,OAAO;AAAA,EACxB;AAAA,EAEO,eAA2B;AAChC,WAAO,KAAK,MAAM,UAAU,IAAI,mBAAmB;AAAA,EACrD;AAAA,EAEA,MAAa,YACX,EAAE,MAAM,UAAU,UAAU,GAC5B,UACmB;AACnB,QAAI,OAAO,SAAS,YAAY,CAAC,KAAM,OAAM,IAAI,MAAM,kBAAkB;AACzE,QAAI,OAAO,aAAa,SAAU,OAAM,IAAI,MAAM,sBAAsB;AACxE,QAAI,OAAO,cAAc,UAAW,OAAM,IAAI,MAAM,uBAAuB;AAC3E,QAAI,CAAC,gBAAgB,QAAQ,EAAG,OAAM,IAAI,MAAM,kBAAkB;AAElE,UAAM,KAAK,cAAc,QAAQ;AAEjC,UAAM,UAAU,kBAAkB,QAAQ;AAG1C,UAAM,KAAK,WAAW,OAAO;AAE7B,QAAI,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAG,OAAM,IAAI,MAAM,yBAAyB;AAE5F,UAAM,UAA2B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,SAAS,MAAM,YAAY,SAAS,QAAQ;AAAA,MAC5C;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,MAAM,UAAU,KAAK,OAAO;AAEjC,WAAO,oBAAoB,OAAO;AAAA,EACpC;AAAA,EAEO,YAAY,IAA6B;AAC9C,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7D,WAAO,WAAW,oBAAoB,QAAQ,IAAI;AAAA,EACpD;AAAA,EAEO,eAAe,IAAY,EAAE,MAAM,UAAU,GAA0B;AAC5E,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7D,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,oBAAoB;AACnD,QAAI,SAAS,QAAW;AACtB,UAAI,OAAO,SAAS,YAAY,CAAC,KAAM,OAAM,IAAI,MAAM,uBAAuB;AAC9E,eAAS,OAAO;AAAA,IAClB;AACA,QAAI,cAAc,QAAW;AAC3B,UAAI,OAAO,cAAc,UAAW,OAAM,IAAI,MAAM,6BAA6B;AACjF,eAAS,YAAY;AAAA,IACvB;AACA,WAAO,oBAAoB,QAAQ;AAAA,EACrC;AAAA,EAEO,eAAe,IAAY;AAChC,UAAM,QAAQ,KAAK,MAAM,UAAU,UAAU,CAAC,aAAa,SAAS,MAAM,EAAE;AAC5E,QAAI,UAAU,GAAI,OAAM,IAAI,MAAM,oBAAoB;AACtD,SAAK,MAAM,UAAU,OAAO,OAAO,CAAC;AAAA,EACtC;AAAA,EAEA,MAAM,gBAAgB,IAAY,UAAmC;AACnE,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7D,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,oBAAoB;AAEnD,UAAM,UAAU,MAAM,YAAY,SAAS,SAAS,QAAQ;AAE5D,WAAO,kBAAkB,OAAO;AAAA,EAClC;AAAA,EAEO,sBAAsB,UAAiC;AAC5D,UAAM,UAAU,kBAAkB,QAAQ;AAC1C,UAAM,aAAa,WAAW,OAAO;AACrC,WAAO,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU,IAAI,aAAa;AAAA,EAC9E;AAAA,EAEO,cAAyB;AAC9B,WAAO,KAAK,MAAM,SAAS,IAAI,kBAAkB;AAAA,EACnD;AAAA,EAEO,WAAW,SAAiC;AACjD,UAAM,UAAU,KAAK,MAAM,SAAS,KAAK,CAAC,MAAM,eAAe,EAAE,SAAS,OAAO,CAAC;AAClF,WAAO,UAAU,mBAAmB,OAAO,IAAI;AAAA,EACjD;AAAA,EAEO,cAAc,SAAiB,EAAE,MAAM,aAAa,YAAY,GAAyB;AAC9F,UAAM,UAAU,KAAK,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO;AACrE,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mBAAmB;AAEjD,QAAI,MAAM;AACR,UAAI,OAAO,SAAS,YAAY,CAAC,KAAM,OAAM,IAAI,MAAM,kBAAkB;AACzE,cAAQ,OAAO;AAAA,IACjB;AACA,QAAI,QAAQ,SAAS,gBAAgB,gBAAgB,QAAW;AAC9D,UAAI,OAAO,gBAAgB,UAAW,OAAM,IAAI,MAAM,+BAA+B;AACrF,cAAQ,cAAc;AAAA,IACxB;AAEA,QAAI,QAAQ,SAAS,WAAW;AAC9B,UAAI,aAAa;AACf,YAAI,CAAC,YAAY,WAAW,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACjF,gBAAQ,cAAc;AAAA,MACxB,MAAO,QAAO,QAAQ;AAAA,IACxB;AAEA,WAAO,mBAAmB,OAAO;AAAA,EACnC;AAAA,EAEO,cAAc,SAAiB;AACpC,UAAM,QAAQ,KAAK,MAAM,SAAS,UAAU,CAAC,MAAM,eAAe,EAAE,SAAS,OAAO,CAAC;AACrF,QAAI,UAAU,GAAI,OAAM,IAAI,MAAM,mBAAmB;AACrD,SAAK,MAAM,SAAS,OAAO,OAAO,CAAC;AAAA,EACrC;AAAA,EAEO,mBAAmB,SAA6C;AACrE,UAAM,UAAU,iBAAiB,QAAQ,OAAO;AAEhD,QAAI,KAAK,WAAW,OAAO,EAAG,OAAM,IAAI,MAAM,wBAAwB;AAEtE,UAAM,UAA0B;AAAA,MAC9B,GAAG;AAAA,MACH;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,QAAI,CAAC,kBAAkB,OAAO,EAAG,OAAM,IAAI,MAAM,sBAAsB;AAEvE,SAAK,MAAM,SAAS,KAAK,OAAO;AAEhC,WAAO,mBAAmB,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,eAAe,SAAkC,UAAkB;AAC/E,UAAM,KAAK,cAAc,QAAQ;AAEjC,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,gBAAgB;AACnB,cAAM,EAAE,UAAU,cAAc,MAAM,UAAU,IAAI;AAEpD,YAAI,OAAO,SAAS,YAAY,CAAC,KAAM,OAAM,IAAI,MAAM,0BAA0B;AACjF,YAAI,OAAO,cAAc,UAAW,OAAM,IAAI,MAAM,uBAAuB;AAE3E,cAAM,aAAa,KAAK,sBAAsB,QAAQ;AACtD,YAAI,WAAY,QAAO;AAEvB,cAAM,EAAE,GAAG,IAAI,MAAM,KAAK;AAAA,UACxB;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,qBAAqB;AACxB,YAAI,OAAO,QAAQ,eAAe,YAAY,CAAC,QAAQ;AACrD,gBAAM,IAAI,MAAM,6BAA6B;AAE/C,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAa,iBACX,SACA,UACkB;AAClB,UAAM,KAAK,cAAc,QAAQ;AAEjC,UAAM,EAAE,OAAO,gBAAgB,KAAK,IAAI;AAExC,UAAM,aAAa,MAAM,KAAK,eAAe,SAAS,QAAQ;AAE9D,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AACrE,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,oBAAoB;AAEnD,UAAM,UAAU,MAAM,YAAY,SAAS,SAAS,QAAQ;AAC5D,UAAM,OAAO,MAAM,cAAc,SAAS,KAAK;AAC/C,UAAM,OAAO,cAAc,MAAM,gBAAgB,KAAK;AAEtD,QAAI,KAAK,WAAW,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,wBAAwB;AAE3E,UAAM,UAA0B;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,iBAAiB,KAAK,OAAO;AAAA,MACtC,WAAW,MAAM,YAAY,KAAK,WAAW,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,MAAM,SAAS,KAAK,OAAO;AAEhC,WAAO,mBAAmB,OAAO;AAAA,EACnC;AAAA,EAEA,MAAa,kBACX,EAAE,OAAO,MAAM,UAAU,GACzB,UACkB;AAClB,UAAM,KAAK,cAAc,QAAQ;AAEjC,UAAM,YAAY,uBAAuB,WAAW,KAAK;AACzD,UAAM,WAAW,yBAAyB,KAAK;AAC/C,UAAM,UAAU,qBAAqB,WAAW,QAAQ;AAExD,QAAI,KAAK,WAAW,OAAO,EAAG,OAAM,IAAI,MAAM,wBAAwB;AAEtE,UAAM,UAA0B;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,iBAAiB,OAAO;AAAA,MACjC,WAAW,MAAM,YAAY,WAAW,QAAQ;AAAA,MAChD,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,MAAM,SAAS,KAAK,OAAO;AAEhC,WAAO,mBAAmB,OAAO;AAAA,EACnC;AAAA,EAEO,oBAAoB,SAAiB,UAAuC;AACjF,QAAI,OAAO,YAAY,YAAY,CAAC,QAAS,OAAM,IAAI,MAAM,qBAAqB;AAClF,QAAI,OAAO,aAAa,YAAY,CAAC,SAAU,OAAM,IAAI,MAAM,sBAAsB;AAErF,UAAM,UAAU,KAAK,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,YAAY,iBAAiB,OAAO,CAAC;AACvF,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mBAAmB;AACjD,QAAI,QAAQ,SAAS,UAAW,OAAM,IAAI,MAAM,wBAAwB;AAExE,WAAO,YAAY,QAAQ,WAAW,QAAQ;AAAA,EAChD;AAAA,EAEA,MAAa,kBACX,YACA,gBACA,OACA,UACiB;AACjB,QAAI,OAAO,eAAe,YAAY,CAAC,WAAY,OAAM,IAAI,MAAM,wBAAwB;AAC3F,QAAI,OAAO,aAAa,YAAY,CAAC,SAAU,OAAM,IAAI,MAAM,sBAAsB;AAErF,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AACrE,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,oBAAoB;AAEnD,UAAM,UAAU,MAAM,YAAY,SAAS,SAAS,QAAQ;AAC5D,UAAM,OAAO,MAAM,cAAc,SAAS,KAAK;AAC/C,UAAM,OAAO,cAAc,MAAM,gBAAgB,KAAK;AAEtD,WAAO,KAAK;AAAA,EACd;AACF;AAEA,IAAM,aAAa,CAAC,UAA+B;AACjD,MAAI,OAAO,UAAU,SAAU,SAAQ,KAAK,OAAO,KAAK;AAIxD,SAAO,OAAO,OAAO,OAAO,KAAK,CAAC;AACpC;AAEA,IAAM,sBAAsB,CAAC,SAAoC;AAC/D,QAAM,OAAO,gBAAgB,IAAI;AACjC,MAAI,aAAa,KAAM,QAAO,KAAK;AACnC,SAAO,OAAO,OAAO,IAAI;AAC3B;AAEA,IAAM,qBAAqB,CAAC,SAAkC;AAC5D,QAAM,OAAO,gBAAgB,IAAI;AACjC,MAAI,eAAe,KAAM,QAAO,KAAK;AACrC,SAAO,OAAO,OAAO,IAAI;AAC3B;","names":[]}