@aztec/cli-wallet 0.0.0-test.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.
Files changed (94) hide show
  1. package/README.md +2 -0
  2. package/dest/bin/index.d.ts +2 -0
  3. package/dest/bin/index.d.ts.map +1 -0
  4. package/dest/bin/index.js +75 -0
  5. package/dest/cmds/add_authwit.d.ts +4 -0
  6. package/dest/cmds/add_authwit.d.ts.map +1 -0
  7. package/dest/cmds/add_authwit.js +4 -0
  8. package/dest/cmds/authorize_action.d.ts +4 -0
  9. package/dest/cmds/authorize_action.d.ts.map +1 -0
  10. package/dest/cmds/authorize_action.js +17 -0
  11. package/dest/cmds/bridge_fee_juice.d.ts +6 -0
  12. package/dest/cmds/bridge_fee_juice.d.ts.map +1 -0
  13. package/dest/cmds/bridge_fee_juice.js +52 -0
  14. package/dest/cmds/cancel_tx.d.ts +11 -0
  15. package/dest/cmds/cancel_tx.d.ts.map +1 -0
  16. package/dest/cmds/cancel_tx.js +38 -0
  17. package/dest/cmds/check_tx.d.ts +4 -0
  18. package/dest/cmds/check_tx.d.ts.map +1 -0
  19. package/dest/cmds/check_tx.js +11 -0
  20. package/dest/cmds/create_account.d.ts +12 -0
  21. package/dest/cmds/create_account.d.ts.map +1 -0
  22. package/dest/cmds/create_account.js +94 -0
  23. package/dest/cmds/create_authwit.d.ts +4 -0
  24. package/dest/cmds/create_authwit.d.ts.map +1 -0
  25. package/dest/cmds/create_authwit.js +16 -0
  26. package/dest/cmds/deploy.d.ts +6 -0
  27. package/dest/cmds/deploy.d.ts.map +1 -0
  28. package/dest/cmds/deploy.js +83 -0
  29. package/dest/cmds/deploy_account.d.ts +9 -0
  30. package/dest/cmds/deploy_account.d.ts.map +1 -0
  31. package/dest/cmds/deploy_account.js +80 -0
  32. package/dest/cmds/import_test_accounts.d.ts +5 -0
  33. package/dest/cmds/import_test_accounts.d.ts.map +1 -0
  34. package/dest/cmds/import_test_accounts.js +42 -0
  35. package/dest/cmds/index.d.ts +6 -0
  36. package/dest/cmds/index.d.ts.map +1 -0
  37. package/dest/cmds/index.js +223 -0
  38. package/dest/cmds/register_contract.d.ts +4 -0
  39. package/dest/cmds/register_contract.d.ts.map +1 -0
  40. package/dest/cmds/register_contract.js +14 -0
  41. package/dest/cmds/register_sender.d.ts +4 -0
  42. package/dest/cmds/register_sender.d.ts.map +1 -0
  43. package/dest/cmds/register_sender.js +4 -0
  44. package/dest/cmds/send.d.ts +11 -0
  45. package/dest/cmds/send.d.ts.map +1 -0
  46. package/dest/cmds/send.js +49 -0
  47. package/dest/cmds/simulate.d.ts +4 -0
  48. package/dest/cmds/simulate.d.ts.map +1 -0
  49. package/dest/cmds/simulate.js +26 -0
  50. package/dest/storage/wallet_db.d.ts +65 -0
  51. package/dest/storage/wallet_db.d.ts.map +1 -0
  52. package/dest/storage/wallet_db.js +209 -0
  53. package/dest/utils/accounts.d.ts +11 -0
  54. package/dest/utils/accounts.d.ts.map +1 -0
  55. package/dest/utils/accounts.js +87 -0
  56. package/dest/utils/ecdsa.d.ts +4 -0
  57. package/dest/utils/ecdsa.d.ts.map +1 -0
  58. package/dest/utils/ecdsa.js +13 -0
  59. package/dest/utils/options/fees.d.ts +41 -0
  60. package/dest/utils/options/fees.d.ts.map +1 -0
  61. package/dest/utils/options/fees.js +283 -0
  62. package/dest/utils/options/index.d.ts +3 -0
  63. package/dest/utils/options/index.d.ts.map +1 -0
  64. package/dest/utils/options/index.js +2 -0
  65. package/dest/utils/options/options.d.ts +20 -0
  66. package/dest/utils/options/options.d.ts.map +1 -0
  67. package/dest/utils/options/options.js +122 -0
  68. package/dest/utils/pxe_wrapper.d.ts +10 -0
  69. package/dest/utils/pxe_wrapper.d.ts.map +1 -0
  70. package/dest/utils/pxe_wrapper.js +21 -0
  71. package/package.json +102 -0
  72. package/src/bin/index.ts +127 -0
  73. package/src/cmds/add_authwit.ts +13 -0
  74. package/src/cmds/authorize_action.ts +36 -0
  75. package/src/cmds/bridge_fee_juice.ts +88 -0
  76. package/src/cmds/cancel_tx.ts +62 -0
  77. package/src/cmds/check_tx.ts +12 -0
  78. package/src/cmds/create_account.ts +120 -0
  79. package/src/cmds/create_authwit.ts +35 -0
  80. package/src/cmds/deploy.ts +113 -0
  81. package/src/cmds/deploy_account.ts +92 -0
  82. package/src/cmds/import_test_accounts.ts +47 -0
  83. package/src/cmds/index.ts +641 -0
  84. package/src/cmds/register_contract.ts +20 -0
  85. package/src/cmds/register_sender.ts +7 -0
  86. package/src/cmds/send.ts +62 -0
  87. package/src/cmds/simulate.ts +42 -0
  88. package/src/storage/wallet_db.ts +243 -0
  89. package/src/utils/accounts.ts +102 -0
  90. package/src/utils/ecdsa.ts +15 -0
  91. package/src/utils/options/fees.ts +365 -0
  92. package/src/utils/options/index.ts +2 -0
  93. package/src/utils/options/options.ts +175 -0
  94. package/src/utils/pxe_wrapper.ts +26 -0
@@ -0,0 +1,62 @@
1
+ import { type AccountWalletWithSecretKey, type AztecAddress, Contract, Fr } from '@aztec/aztec.js';
2
+ import { prepTx } from '@aztec/cli/utils';
3
+ import type { LogFn } from '@aztec/foundation/log';
4
+ import { GasSettings } from '@aztec/stdlib/gas';
5
+
6
+ import { type IFeeOpts, printGasEstimates } from '../utils/options/fees.js';
7
+
8
+ export async function send(
9
+ wallet: AccountWalletWithSecretKey,
10
+ functionName: string,
11
+ functionArgsIn: any[],
12
+ contractArtifactPath: string,
13
+ contractAddress: AztecAddress,
14
+ wait: boolean,
15
+ cancellable: boolean,
16
+ feeOpts: IFeeOpts,
17
+ log: LogFn,
18
+ ) {
19
+ const { functionArgs, contractArtifact } = await prepTx(contractArtifactPath, functionName, functionArgsIn, log);
20
+
21
+ const contract = await Contract.at(contractAddress, contractArtifact, wallet);
22
+ const call = contract.methods[functionName](...functionArgs);
23
+
24
+ const gasLimits = await call.estimateGas({ ...(await feeOpts.toSendOpts(wallet)) });
25
+ printGasEstimates(feeOpts, gasLimits, log);
26
+
27
+ if (feeOpts.estimateOnly) {
28
+ return;
29
+ }
30
+
31
+ const nonce = Fr.random();
32
+ const tx = call.send({ ...(await feeOpts.toSendOpts(wallet)), nonce, cancellable });
33
+ const txHash = await tx.getTxHash();
34
+ log(`\nTransaction hash: ${txHash.toString()}`);
35
+ if (wait) {
36
+ try {
37
+ await tx.wait();
38
+
39
+ log('Transaction has been mined');
40
+
41
+ const receipt = await tx.getReceipt();
42
+ log(` Tx fee: ${receipt.transactionFee}`);
43
+ log(` Status: ${receipt.status}`);
44
+ log(` Block number: ${receipt.blockNumber}`);
45
+ log(` Block hash: ${receipt.blockHash?.toString()}`);
46
+ } catch (err: any) {
47
+ log(`Transaction failed\n ${err.message}`);
48
+ }
49
+ } else {
50
+ log('Transaction pending. Check status with check-tx');
51
+ }
52
+ const gasSettings = GasSettings.from({
53
+ ...feeOpts.gasSettings,
54
+ ...gasLimits,
55
+ });
56
+ return {
57
+ txHash,
58
+ nonce,
59
+ cancellable,
60
+ gasSettings,
61
+ };
62
+ }
@@ -0,0 +1,42 @@
1
+ import { type AccountWalletWithSecretKey, type AztecAddress, Contract, type ProfileResult } from '@aztec/aztec.js';
2
+ import { prepTx } from '@aztec/cli/utils';
3
+ import type { LogFn } from '@aztec/foundation/log';
4
+
5
+ import { format } from 'util';
6
+
7
+ function printProfileResult(result: ProfileResult, log: LogFn) {
8
+ log(format('\nSimulation result:'));
9
+ log(format('Return value:', JSON.stringify(result.returnValues, null, 2)));
10
+
11
+ log(format('\nGate count per circuit:'));
12
+ let acc = 0;
13
+ result.gateCounts.forEach(r => {
14
+ acc += r.gateCount;
15
+ log(format(' ', r.circuitName.padEnd(50), 'Gates:', r.gateCount.toLocaleString(), '\tAcc:', acc.toLocaleString()));
16
+ });
17
+
18
+ log(format('\nTotal gates:', acc.toLocaleString()));
19
+ }
20
+
21
+ export async function simulate(
22
+ wallet: AccountWalletWithSecretKey,
23
+ functionName: string,
24
+ functionArgsIn: any[],
25
+ contractArtifactPath: string,
26
+ contractAddress: AztecAddress,
27
+ profile: boolean,
28
+ log: LogFn,
29
+ ) {
30
+ const { functionArgs, contractArtifact } = await prepTx(contractArtifactPath, functionName, functionArgsIn, log);
31
+
32
+ const contract = await Contract.at(contractAddress, contractArtifact, wallet);
33
+ const call = contract.methods[functionName](...functionArgs);
34
+
35
+ if (profile) {
36
+ const result = await call.simulateWithProfile();
37
+ printProfileResult(result, log);
38
+ } else {
39
+ const result = await call.simulate();
40
+ log(format('\nSimulation result: ', result, '\n'));
41
+ }
42
+ }
@@ -0,0 +1,243 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import type { LogFn } from '@aztec/foundation/log';
3
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
4
+ import type { AuthWitness } from '@aztec/stdlib/auth-witness';
5
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
6
+ import { GasSettings } from '@aztec/stdlib/gas';
7
+ import type { TxHash } from '@aztec/stdlib/tx';
8
+
9
+ import type { AccountType } from '../utils/accounts.js';
10
+ import { extractECDSAPublicKeyFromBase64String } from '../utils/ecdsa.js';
11
+
12
+ export const Aliases = ['accounts', 'contracts', 'artifacts', 'secrets', 'transactions', 'authwits'] as const;
13
+ export type AliasType = (typeof Aliases)[number];
14
+
15
+ export class WalletDB {
16
+ #accounts!: AztecAsyncMap<string, Buffer>;
17
+ #aliases!: AztecAsyncMap<string, Buffer>;
18
+ #bridgedFeeJuice!: AztecAsyncMap<string, Buffer>;
19
+ #transactions!: AztecAsyncMap<string, Buffer>;
20
+
21
+ private static instance: WalletDB;
22
+
23
+ private aliasCache = new Map<string, string>();
24
+
25
+ static getInstance() {
26
+ if (!WalletDB.instance) {
27
+ WalletDB.instance = new WalletDB();
28
+ }
29
+
30
+ return WalletDB.instance;
31
+ }
32
+
33
+ async init(store: AztecAsyncKVStore) {
34
+ this.#accounts = store.openMap('accounts');
35
+ this.#aliases = store.openMap('aliases');
36
+ this.#bridgedFeeJuice = store.openMap('bridgedFeeJuice');
37
+ this.#transactions = store.openMap('transactions');
38
+
39
+ await this.refreshAliasCache();
40
+ }
41
+
42
+ private async refreshAliasCache() {
43
+ this.aliasCache = new Map((await this.listAliases()).map(({ key, value }) => [key, value]));
44
+ }
45
+
46
+ async pushBridgedFeeJuice(recipient: AztecAddress, secret: Fr, amount: bigint, leafIndex: bigint, log: LogFn) {
47
+ let stackPointer = (await this.#bridgedFeeJuice.getAsync(`${recipient.toString()}:stackPointer`))?.readInt8() || 0;
48
+ stackPointer++;
49
+ await this.#bridgedFeeJuice.set(
50
+ `${recipient.toString()}:${stackPointer}`,
51
+ Buffer.from(`${amount.toString()}:${secret.toString()}:${leafIndex.toString()}`),
52
+ );
53
+ await this.#bridgedFeeJuice.set(`${recipient.toString()}:stackPointer`, Buffer.from([stackPointer]));
54
+ log(`Pushed ${amount} fee juice for recipient ${recipient.toString()}. Stack pointer ${stackPointer}`);
55
+ }
56
+
57
+ async popBridgedFeeJuice(recipient: AztecAddress, log: LogFn) {
58
+ let stackPointer = (await this.#bridgedFeeJuice.getAsync(`${recipient.toString()}:stackPointer`))?.readInt8() || 0;
59
+ const result = await this.#bridgedFeeJuice.getAsync(`${recipient.toString()}:${stackPointer}`);
60
+ if (!result) {
61
+ throw new Error(
62
+ `No stored fee juice available for recipient ${recipient.toString()}. Please provide claim amount and secret. Stack pointer ${stackPointer}`,
63
+ );
64
+ }
65
+ const [amountStr, secretStr, leafIndexStr] = result.toString().split(':');
66
+ await this.#bridgedFeeJuice.set(`${recipient.toString()}:stackPointer`, Buffer.from([--stackPointer]));
67
+ log(`Retrieved ${amountStr} fee juice for recipient ${recipient.toString()}. Stack pointer ${stackPointer}`);
68
+ return { amount: BigInt(amountStr), secret: secretStr, leafIndex: BigInt(leafIndexStr) };
69
+ }
70
+
71
+ async storeAccount(
72
+ address: AztecAddress,
73
+ {
74
+ type,
75
+ secretKey,
76
+ salt,
77
+ alias,
78
+ publicKey,
79
+ }: { type: AccountType; secretKey: Fr; salt: Fr; alias: string | undefined; publicKey: string | undefined },
80
+ log: LogFn,
81
+ ) {
82
+ if (alias) {
83
+ await this.#aliases.set(`accounts:${alias}`, Buffer.from(address.toString()));
84
+ }
85
+ await this.#accounts.set(`${address.toString()}:type`, Buffer.from(type));
86
+ await this.#accounts.set(`${address.toString()}:sk`, secretKey.toBuffer());
87
+ await this.#accounts.set(`${address.toString()}:salt`, salt.toBuffer());
88
+ if (type === 'ecdsasecp256r1ssh' && publicKey) {
89
+ const publicSigningKey = extractECDSAPublicKeyFromBase64String(publicKey);
90
+ await this.storeAccountMetadata(address, 'publicSigningKey', publicSigningKey);
91
+ }
92
+ await this.#aliases.set('accounts:last', Buffer.from(address.toString()));
93
+ log(`Account stored in database with alias${alias ? `es last & ${alias}` : ' last'}`);
94
+
95
+ await this.refreshAliasCache();
96
+ }
97
+
98
+ async storeSender(address: AztecAddress, alias: string, log: LogFn) {
99
+ await this.#aliases.set(`accounts:${alias}`, Buffer.from(address.toString()));
100
+ log(`Account stored in database with alias ${alias} as a sender`);
101
+
102
+ await this.refreshAliasCache();
103
+ }
104
+
105
+ async storeContract(address: AztecAddress, artifactPath: string, log: LogFn, alias?: string) {
106
+ if (alias) {
107
+ await this.#aliases.set(`contracts:${alias}`, Buffer.from(address.toString()));
108
+ await this.#aliases.set(`artifacts:${alias}`, Buffer.from(artifactPath));
109
+ }
110
+ await this.#aliases.set(`contracts:last`, Buffer.from(address.toString()));
111
+ await this.#aliases.set(`artifacts:last`, Buffer.from(artifactPath));
112
+ await this.#aliases.set(`artifacts:${address.toString()}`, Buffer.from(artifactPath));
113
+ log(`Contract stored in database with alias${alias ? `es last & ${alias}` : ' last'}`);
114
+
115
+ await this.refreshAliasCache();
116
+ }
117
+
118
+ async storeAuthwitness(authWit: AuthWitness, log: LogFn, alias?: string) {
119
+ if (alias) {
120
+ await this.#aliases.set(`authwits:${alias}`, Buffer.from(authWit.toString()));
121
+ }
122
+ await this.#aliases.set(`authwits:last`, Buffer.from(authWit.toString()));
123
+ log(`Authorization witness stored in database with alias${alias ? `es last & ${alias}` : ' last'}`);
124
+
125
+ await this.refreshAliasCache();
126
+ }
127
+
128
+ async storeTx(
129
+ {
130
+ txHash,
131
+ nonce,
132
+ cancellable,
133
+ gasSettings,
134
+ }: { txHash: TxHash; nonce: Fr; cancellable: boolean; gasSettings: GasSettings },
135
+ log: LogFn,
136
+ alias?: string,
137
+ ) {
138
+ if (alias) {
139
+ await this.#aliases.set(`transactions:${alias}`, Buffer.from(txHash.toString()));
140
+ }
141
+ await this.#transactions.set(`${txHash.toString()}:nonce`, nonce.toBuffer());
142
+ await this.#transactions.set(`${txHash.toString()}:cancellable`, Buffer.from(cancellable ? 'true' : 'false'));
143
+ await this.#transactions.set(`${txHash.toString()}:gasSettings`, gasSettings.toBuffer());
144
+ await this.#aliases.set(`transactions:last`, Buffer.from(txHash.toString()));
145
+ log(`Transaction hash stored in database with alias${alias ? `es last & ${alias}` : ' last'}`);
146
+
147
+ await this.refreshAliasCache();
148
+ }
149
+
150
+ async retrieveTxData(txHash: TxHash) {
151
+ const nonceBuffer = await this.#transactions.getAsync(`${txHash.toString()}:nonce`);
152
+ if (!nonceBuffer) {
153
+ throw new Error(
154
+ `Could not find ${txHash.toString()}:nonce. Transaction with hash "${txHash.toString()}" does not exist on this wallet.`,
155
+ );
156
+ }
157
+ const nonce = Fr.fromBuffer(nonceBuffer);
158
+ const cancellable = (await this.#transactions.getAsync(`${txHash.toString()}:cancellable`))!.toString() === 'true';
159
+ const gasBuffer = (await this.#transactions.getAsync(`${txHash.toString()}:gasSettings`))!;
160
+ return { txHash, nonce, cancellable, gasSettings: GasSettings.fromBuffer(gasBuffer) };
161
+ }
162
+
163
+ tryRetrieveAlias(arg: string) {
164
+ try {
165
+ return this.retrieveAliasFromCache(arg);
166
+ } catch (e) {
167
+ return arg;
168
+ }
169
+ }
170
+
171
+ public retrieveAliasFromCache(arg: string) {
172
+ if (Aliases.find(alias => arg.startsWith(`${alias}:`))) {
173
+ const [type, ...alias] = arg.split(':');
174
+ const aliasKey = `${type}:${alias.join(':') ?? 'last'}`;
175
+ const data = this.aliasCache.get(aliasKey);
176
+ if (!data) {
177
+ throw new Error(`Could not find alias ${arg}`);
178
+ }
179
+ return data.toString();
180
+ } else {
181
+ throw new Error(`Aliases must start with one of ${Aliases.join(', ')}`);
182
+ }
183
+ }
184
+
185
+ async retrieveAlias(arg: string) {
186
+ if (Aliases.find(alias => arg.startsWith(`${alias}:`))) {
187
+ const [type, ...alias] = arg.split(':');
188
+ const data = await this.#aliases.getAsync(`${type}:${alias.join(':') ?? 'last'}`);
189
+ if (!data) {
190
+ throw new Error(`Could not find alias ${arg}`);
191
+ }
192
+ return data.toString();
193
+ } else {
194
+ throw new Error(`Aliases must start with one of ${Aliases.join(', ')}`);
195
+ }
196
+ }
197
+
198
+ async listAliases(type?: AliasType) {
199
+ const result = [];
200
+ if (type && !Aliases.includes(type)) {
201
+ throw new Error(`Unknown alias type ${type}`);
202
+ }
203
+ for await (const [key, value] of this.#aliases.entriesAsync()) {
204
+ if (!type || key.startsWith(`${type}:`)) {
205
+ result.push({ key, value: value.toString() });
206
+ }
207
+ }
208
+ return result;
209
+ }
210
+
211
+ async storeAccountMetadata(aliasOrAddress: AztecAddress | string, metadataKey: string, metadata: Buffer) {
212
+ const { address } = await this.retrieveAccount(aliasOrAddress);
213
+ await this.#accounts.set(`${address.toString()}:${metadataKey}`, metadata);
214
+ }
215
+
216
+ async retrieveAccountMetadata(aliasOrAddress: AztecAddress | string, metadataKey: string) {
217
+ const { address } = await this.retrieveAccount(aliasOrAddress);
218
+ const result = await this.#accounts.getAsync(`${address.toString()}:${metadataKey}`);
219
+ if (!result) {
220
+ throw new Error(`Could not find metadata with key ${metadataKey} for account ${aliasOrAddress}`);
221
+ }
222
+ return result;
223
+ }
224
+
225
+ async retrieveAccount(address: AztecAddress | string) {
226
+ const secretKeyBuffer = await this.#accounts.getAsync(`${address.toString()}:sk`);
227
+ if (!secretKeyBuffer) {
228
+ throw new Error(`Could not find ${address}:sk. Account "${address.toString}" does not exist on this wallet.`);
229
+ }
230
+ const secretKey = Fr.fromBuffer(secretKeyBuffer);
231
+ const salt = Fr.fromBuffer((await this.#accounts.getAsync(`${address.toString()}:salt`))!);
232
+ const type = (await this.#accounts.getAsync(`${address.toString()}:type`))!.toString('utf8') as AccountType;
233
+ return { address, secretKey, salt, type };
234
+ }
235
+
236
+ async storeAlias(type: AliasType, key: string, value: Buffer, log: LogFn) {
237
+ await this.#aliases.set(`${type}:${key}`, value);
238
+ await this.refreshAliasCache();
239
+ log(`Data stored in database with alias ${type}:${key}`);
240
+
241
+ await this.refreshAliasCache();
242
+ }
243
+ }
@@ -0,0 +1,102 @@
1
+ import { getIdentities } from '@aztec/accounts/utils';
2
+ import type { AccountManager, AccountWalletWithSecretKey } from '@aztec/aztec.js';
3
+ import { Fr } from '@aztec/foundation/fields';
4
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
5
+ import type { PXE } from '@aztec/stdlib/interfaces/client';
6
+ import { deriveSigningKey } from '@aztec/stdlib/keys';
7
+
8
+ import type { WalletDB } from '../storage/wallet_db.js';
9
+ import { extractECDSAPublicKeyFromBase64String } from './ecdsa.js';
10
+
11
+ export const AccountTypes = ['schnorr', 'ecdsasecp256r1ssh', 'ecdsasecp256k1'] as const;
12
+ export type AccountType = (typeof AccountTypes)[number];
13
+
14
+ export async function createOrRetrieveAccount(
15
+ pxe: PXE,
16
+ address?: AztecAddress,
17
+ db?: WalletDB,
18
+ secretKey?: Fr,
19
+ type: AccountType = 'schnorr',
20
+ salt?: Fr,
21
+ publicKey?: string | undefined,
22
+ ): Promise<AccountManager> {
23
+ let account;
24
+
25
+ salt ??= Fr.ZERO;
26
+
27
+ if (db && address) {
28
+ ({ type, secretKey, salt } = await db.retrieveAccount(address));
29
+ }
30
+
31
+ if (!salt) {
32
+ throw new Error('Cannot retrieve/create wallet without salt');
33
+ }
34
+
35
+ if (!secretKey) {
36
+ throw new Error('Cannot retrieve/create wallet without secret key');
37
+ }
38
+
39
+ switch (type) {
40
+ case 'schnorr': {
41
+ const { getSchnorrAccount } = await import('@aztec/accounts/schnorr');
42
+ account = getSchnorrAccount(pxe, secretKey, deriveSigningKey(secretKey), salt);
43
+ break;
44
+ }
45
+ case 'ecdsasecp256r1ssh': {
46
+ let publicSigningKey;
47
+ if (db && address) {
48
+ publicSigningKey = await db.retrieveAccountMetadata(address, 'publicSigningKey');
49
+ } else if (publicKey) {
50
+ const identities = await getIdentities();
51
+ const foundIdentity = identities.find(
52
+ identity => identity.type === 'ecdsa-sha2-nistp256' && identity.publicKey === publicKey,
53
+ );
54
+ if (!foundIdentity) {
55
+ throw new Error(`Identity for public key ${publicKey} not found in the SSH agent`);
56
+ }
57
+ publicSigningKey = extractECDSAPublicKeyFromBase64String(foundIdentity.publicKey);
58
+ } else {
59
+ throw new Error('Public key must be provided for ECDSA SSH account');
60
+ }
61
+
62
+ const { getEcdsaRSSHAccount } = await import('@aztec/accounts/ecdsa');
63
+ account = getEcdsaRSSHAccount(pxe, secretKey, publicSigningKey, salt);
64
+ break;
65
+ }
66
+ default: {
67
+ throw new Error(`Unsupported account type: ${type}`);
68
+ }
69
+ }
70
+
71
+ return account;
72
+ }
73
+
74
+ export async function addScopeToWallet(wallet: AccountWalletWithSecretKey, scope: AztecAddress, db?: WalletDB) {
75
+ const address = wallet.getAddress().toString();
76
+ const currentScopes = wallet.getScopes() ?? [];
77
+ const deduplicatedScopes = Array.from(
78
+ new Set([address, ...currentScopes, scope].map(scope => scope.toString())).values(),
79
+ );
80
+ if (db) {
81
+ await db.storeAccountMetadata(wallet.getAddress(), 'scopes', Buffer.from(deduplicatedScopes.join(',')));
82
+ }
83
+ wallet.setScopes(deduplicatedScopes.map(scope => AztecAddress.fromString(scope)));
84
+ }
85
+
86
+ export async function getWalletWithScopes(account: AccountManager, db?: WalletDB) {
87
+ const wallet = await account.getWallet();
88
+ if (db) {
89
+ const address = wallet.getAddress().toString();
90
+ let storedScopes: string[] = [];
91
+ try {
92
+ storedScopes = ((await db.retrieveAccountMetadata(wallet.getAddress(), 'scopes')) ?? '').toString().split(',');
93
+ // eslint-disable-next-line no-empty
94
+ } catch {}
95
+ const currentScopes = wallet.getScopes()?.map(scopes => scopes.toString()) ?? [];
96
+ const deduplicatedScopes = Array.from(new Set([address, ...currentScopes, ...storedScopes]).values()).map(scope =>
97
+ AztecAddress.fromString(scope),
98
+ );
99
+ wallet.setScopes(deduplicatedScopes);
100
+ }
101
+ return wallet;
102
+ }
@@ -0,0 +1,15 @@
1
+ export function extractECDSAPublicKeyFromBase64String(base64PublicKey: string): Buffer {
2
+ const buffer = Buffer.from(base64PublicKey, 'base64');
3
+ let keyOffset = 0;
4
+ const typeLen = buffer.readUInt32BE(keyOffset);
5
+ keyOffset += 4;
6
+ keyOffset += typeLen;
7
+
8
+ const curveLen = buffer.readUInt32BE(keyOffset);
9
+ keyOffset += 4;
10
+ keyOffset += curveLen;
11
+
12
+ const keyLen = buffer.readUInt32BE(keyOffset);
13
+ keyOffset += 5; // 4+1 to remove the prefix
14
+ return buffer.subarray(keyOffset, keyOffset + keyLen - 1);
15
+ }