@aztec/cli-wallet 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2
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 +2 -0
- package/dest/bin/index.js +75 -0
- package/dest/cmds/add_authwit.js +4 -0
- package/dest/cmds/add_note.js +14 -0
- package/dest/cmds/authorize_action.js +17 -0
- package/dest/cmds/bridge_fee_juice.js +52 -0
- package/dest/cmds/cancel_tx.js +38 -0
- package/dest/cmds/check_tx.js +11 -0
- package/dest/cmds/create_account.js +98 -0
- package/dest/cmds/create_authwit.js +16 -0
- package/dest/cmds/deploy.js +83 -0
- package/dest/cmds/deploy_account.js +84 -0
- package/dest/cmds/index.js +227 -0
- package/dest/cmds/register_contract.js +14 -0
- package/dest/cmds/register_sender.js +4 -0
- package/dest/cmds/send.js +49 -0
- package/dest/cmds/simulate.js +26 -0
- package/dest/storage/wallet_db.js +180 -0
- package/dest/utils/accounts.js +87 -0
- package/dest/utils/ecdsa.js +13 -0
- package/dest/utils/options/fees.js +189 -0
- package/dest/utils/options/index.js +2 -0
- package/dest/utils/options/options.js +122 -0
- package/dest/utils/pxe_wrapper.js +21 -0
- package/package.json +103 -0
- package/src/bin/index.ts +121 -0
- package/src/cmds/add_authwit.ts +13 -0
- package/src/cmds/add_note.ts +30 -0
- package/src/cmds/authorize_action.ts +36 -0
- package/src/cmds/bridge_fee_juice.ts +88 -0
- package/src/cmds/cancel_tx.ts +61 -0
- package/src/cmds/check_tx.ts +12 -0
- package/src/cmds/create_account.ts +120 -0
- package/src/cmds/create_authwit.ts +35 -0
- package/src/cmds/deploy.ts +113 -0
- package/src/cmds/deploy_account.ts +92 -0
- package/src/cmds/index.ts +674 -0
- package/src/cmds/register_contract.ts +20 -0
- package/src/cmds/register_sender.ts +7 -0
- package/src/cmds/send.ts +62 -0
- package/src/cmds/simulate.ts +42 -0
- package/src/storage/wallet_db.ts +205 -0
- package/src/utils/accounts.ts +102 -0
- package/src/utils/ecdsa.ts +15 -0
- package/src/utils/options/fees.ts +234 -0
- package/src/utils/options/index.ts +2 -0
- package/src/utils/options/options.ts +175 -0
- package/src/utils/pxe_wrapper.ts +26 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { AztecAddress, Fr, Gas, GasFees, GasSettings } from '@aztec/circuits.js';
|
|
2
|
+
import { Option } from 'commander';
|
|
3
|
+
import { aliasedAddressParser } from './options.js';
|
|
4
|
+
export function printGasEstimates(feeOpts, gasEstimates, log) {
|
|
5
|
+
log(`Estimated gas usage: ${formatGasEstimate(gasEstimates)}`);
|
|
6
|
+
log(`Maximum total tx fee: ${getEstimatedCost(gasEstimates, feeOpts.gasSettings.maxFeesPerGas)}`);
|
|
7
|
+
}
|
|
8
|
+
function formatGasEstimate(estimate) {
|
|
9
|
+
return `da=${estimate.gasLimits.daGas},l2=${estimate.gasLimits.l2Gas},teardownDA=${estimate.teardownGasLimits.daGas},teardownL2=${estimate.teardownGasLimits.l2Gas}`;
|
|
10
|
+
}
|
|
11
|
+
function getEstimatedCost(estimate, maxFeesPerGas) {
|
|
12
|
+
return GasSettings.default({
|
|
13
|
+
...estimate,
|
|
14
|
+
maxFeesPerGas
|
|
15
|
+
}).getFeeLimit().toBigInt();
|
|
16
|
+
}
|
|
17
|
+
export class FeeOpts {
|
|
18
|
+
estimateOnly;
|
|
19
|
+
gasSettings;
|
|
20
|
+
paymentMethodFactory;
|
|
21
|
+
estimateGas;
|
|
22
|
+
constructor(estimateOnly, gasSettings, paymentMethodFactory, estimateGas){
|
|
23
|
+
this.estimateOnly = estimateOnly;
|
|
24
|
+
this.gasSettings = gasSettings;
|
|
25
|
+
this.paymentMethodFactory = paymentMethodFactory;
|
|
26
|
+
this.estimateGas = estimateGas;
|
|
27
|
+
}
|
|
28
|
+
async toSendOpts(sender) {
|
|
29
|
+
return {
|
|
30
|
+
fee: {
|
|
31
|
+
estimateGas: this.estimateGas,
|
|
32
|
+
gasSettings: this.gasSettings,
|
|
33
|
+
paymentMethod: await this.paymentMethodFactory(sender)
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
static paymentMethodOption() {
|
|
38
|
+
return new Option('--payment <method=name,asset=address,fpc=address,claimSecret=string,claimAmount=string,feeRecipient=string>', 'Fee payment method and arguments. Valid methods are: none, fee_juice, fpc-public, fpc-private.');
|
|
39
|
+
}
|
|
40
|
+
static getOptions() {
|
|
41
|
+
return [
|
|
42
|
+
new Option('--gas-limits <da=100,l2=100,teardownDA=10,teardownL2=10>', 'Gas limits for the tx.'),
|
|
43
|
+
FeeOpts.paymentMethodOption(),
|
|
44
|
+
new Option('--max-fees-per-gas <da=100,l2=100>', 'Maximum fees per gas unit for DA and L2 computation.'),
|
|
45
|
+
new Option('--max-priority-fees-per-gas <da=0,l2=0>', 'Maximum priority fees per gas unit for DA and L2 computation.'),
|
|
46
|
+
new Option('--no-estimate-gas', 'Whether to automatically estimate gas limits for the tx.'),
|
|
47
|
+
new Option('--estimate-gas-only', 'Only report gas estimation for the tx, do not send it.')
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
static async fromCli(args, pxe, log, db) {
|
|
51
|
+
const estimateOnly = args.estimateGasOnly;
|
|
52
|
+
const gasLimits = args.gasLimits ? parseGasLimits(args.gasLimits) : {};
|
|
53
|
+
const maxFeesPerGas = args.maxFeesPerGas ? parseGasFees(args.maxFeesPerGas) : await pxe.getCurrentBaseFees();
|
|
54
|
+
const maxPriorityFeesPerGas = args.maxPriorityFeesPerGas ? parseGasFees(args.maxPriorityFeesPerGas) : undefined;
|
|
55
|
+
const gasSettings = GasSettings.default({
|
|
56
|
+
...gasLimits,
|
|
57
|
+
maxFeesPerGas,
|
|
58
|
+
maxPriorityFeesPerGas
|
|
59
|
+
});
|
|
60
|
+
if (!args.gasLimits && !args.payment) {
|
|
61
|
+
return new NoFeeOpts(estimateOnly, gasSettings);
|
|
62
|
+
}
|
|
63
|
+
const defaultPaymentMethod = async ()=>{
|
|
64
|
+
const { NoFeePaymentMethod } = await import('@aztec/aztec.js/fee');
|
|
65
|
+
return new NoFeePaymentMethod();
|
|
66
|
+
};
|
|
67
|
+
return new FeeOpts(estimateOnly, gasSettings, args.payment ? parsePaymentMethod(args.payment, log, db) : defaultPaymentMethod, !!args.estimateGas);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class NoFeeOpts {
|
|
71
|
+
estimateOnly;
|
|
72
|
+
gasSettings;
|
|
73
|
+
constructor(estimateOnly, gasSettings){
|
|
74
|
+
this.estimateOnly = estimateOnly;
|
|
75
|
+
this.gasSettings = gasSettings;
|
|
76
|
+
}
|
|
77
|
+
toSendOpts() {
|
|
78
|
+
return Promise.resolve({});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function parsePaymentMethod(payment, log, db) {
|
|
82
|
+
const parsed = payment.split(',').reduce((acc, item)=>{
|
|
83
|
+
const [dimension, value] = item.split('=');
|
|
84
|
+
acc[dimension] = value ?? 1;
|
|
85
|
+
return acc;
|
|
86
|
+
}, {});
|
|
87
|
+
const getFpcOpts = (parsed, db)=>{
|
|
88
|
+
if (!parsed.fpc) {
|
|
89
|
+
throw new Error('Missing "fpc" in payment option');
|
|
90
|
+
}
|
|
91
|
+
if (!parsed.asset) {
|
|
92
|
+
throw new Error('Missing "asset" in payment option');
|
|
93
|
+
}
|
|
94
|
+
const fpc = aliasedAddressParser('contracts', parsed.fpc, db);
|
|
95
|
+
return [
|
|
96
|
+
AztecAddress.fromString(parsed.asset),
|
|
97
|
+
fpc
|
|
98
|
+
];
|
|
99
|
+
};
|
|
100
|
+
return async (sender)=>{
|
|
101
|
+
switch(parsed.method){
|
|
102
|
+
case 'none':
|
|
103
|
+
{
|
|
104
|
+
log('Using no fee payment');
|
|
105
|
+
const { NoFeePaymentMethod } = await import('@aztec/aztec.js/fee');
|
|
106
|
+
return new NoFeePaymentMethod();
|
|
107
|
+
}
|
|
108
|
+
case 'native':
|
|
109
|
+
{
|
|
110
|
+
if (parsed.claim || parsed.claimSecret && parsed.claimAmount && parsed.messageLeafIndex) {
|
|
111
|
+
let claimAmount, claimSecret, messageLeafIndex;
|
|
112
|
+
if (parsed.claim && db) {
|
|
113
|
+
({ amount: claimAmount, secret: claimSecret, leafIndex: messageLeafIndex } = await db.popBridgedFeeJuice(sender.getAddress(), log));
|
|
114
|
+
} else {
|
|
115
|
+
({ claimAmount, claimSecret, messageLeafIndex } = parsed);
|
|
116
|
+
}
|
|
117
|
+
log(`Using Fee Juice for fee payments with claim for ${claimAmount} tokens`);
|
|
118
|
+
const { FeeJuicePaymentMethodWithClaim } = await import('@aztec/aztec.js/fee');
|
|
119
|
+
return new FeeJuicePaymentMethodWithClaim(sender.getAddress(), {
|
|
120
|
+
claimAmount: (typeof claimAmount === 'string' ? Fr.fromHexString(claimAmount) : new Fr(claimAmount)).toBigInt(),
|
|
121
|
+
claimSecret: Fr.fromHexString(claimSecret),
|
|
122
|
+
messageLeafIndex: BigInt(messageLeafIndex)
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
log(`Using Fee Juice for fee payment`);
|
|
126
|
+
const { FeeJuicePaymentMethod } = await import('@aztec/aztec.js/fee');
|
|
127
|
+
return new FeeJuicePaymentMethod(sender.getAddress());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
case 'fpc-public':
|
|
131
|
+
{
|
|
132
|
+
const [asset, fpc] = getFpcOpts(parsed, db);
|
|
133
|
+
log(`Using public fee payment with asset ${asset} via paymaster ${fpc}`);
|
|
134
|
+
const { PublicFeePaymentMethod } = await import('@aztec/aztec.js/fee');
|
|
135
|
+
return new PublicFeePaymentMethod(fpc, sender);
|
|
136
|
+
}
|
|
137
|
+
case 'fpc-private':
|
|
138
|
+
{
|
|
139
|
+
const [asset, fpc] = getFpcOpts(parsed, db);
|
|
140
|
+
log(`Using private fee payment with asset ${asset} via paymaster ${fpc}`);
|
|
141
|
+
const { PrivateFeePaymentMethod } = await import('@aztec/aztec.js/fee');
|
|
142
|
+
return new PrivateFeePaymentMethod(fpc, sender);
|
|
143
|
+
}
|
|
144
|
+
case undefined:
|
|
145
|
+
throw new Error('Missing "method" in payment option');
|
|
146
|
+
default:
|
|
147
|
+
throw new Error(`Invalid fee payment method: ${payment}`);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function parseGasLimits(gasLimits) {
|
|
152
|
+
const parsed = gasLimits.split(',').reduce((acc, limit)=>{
|
|
153
|
+
const [dimension, value] = limit.split('=');
|
|
154
|
+
acc[dimension] = parseInt(value, 10);
|
|
155
|
+
return acc;
|
|
156
|
+
}, {});
|
|
157
|
+
const expected = [
|
|
158
|
+
'da',
|
|
159
|
+
'l2',
|
|
160
|
+
'teardownDA',
|
|
161
|
+
'teardownL2'
|
|
162
|
+
];
|
|
163
|
+
for (const dimension of expected){
|
|
164
|
+
if (!(dimension in parsed)) {
|
|
165
|
+
throw new Error(`Missing gas limit for ${dimension}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
gasLimits: new Gas(parsed.da, parsed.l2),
|
|
170
|
+
teardownGasLimits: new Gas(parsed.teardownDA, parsed.teardownL2)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
export function parseGasFees(gasFees) {
|
|
174
|
+
const parsed = gasFees.split(',').reduce((acc, fee)=>{
|
|
175
|
+
const [dimension, value] = fee.split('=');
|
|
176
|
+
acc[dimension] = parseInt(value, 10);
|
|
177
|
+
return acc;
|
|
178
|
+
}, {});
|
|
179
|
+
const expected = [
|
|
180
|
+
'da',
|
|
181
|
+
'l2'
|
|
182
|
+
];
|
|
183
|
+
for (const dimension of expected){
|
|
184
|
+
if (!(dimension in parsed)) {
|
|
185
|
+
throw new Error(`Missing gas fee for ${dimension}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return new GasFees(parsed.da, parsed.l2);
|
|
189
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { AuthWitness } from '@aztec/circuit-types';
|
|
2
|
+
import { parseAztecAddress, parseSecretKey, parseTxHash } from '@aztec/cli/utils';
|
|
3
|
+
import { Option } from 'commander';
|
|
4
|
+
import { readdir, stat } from 'fs/promises';
|
|
5
|
+
import { AccountTypes } from '../accounts.js';
|
|
6
|
+
const TARGET_DIR = 'target';
|
|
7
|
+
export const ARTIFACT_DESCRIPTION = "Path to a compiled Aztec contract's artifact in JSON format. If executed inside a nargo workspace, a package and contract name can be specified as package@contract";
|
|
8
|
+
export function integerArgParser(value, argName, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
9
|
+
const parsed = parseInt(value, 10);
|
|
10
|
+
if (parsed < min) {
|
|
11
|
+
throw new Error(`${argName} must be greater than ${min}`);
|
|
12
|
+
}
|
|
13
|
+
if (parsed > max) {
|
|
14
|
+
throw new Error(`${argName} must be less than ${max}`);
|
|
15
|
+
}
|
|
16
|
+
return parsed;
|
|
17
|
+
}
|
|
18
|
+
export function aliasedTxHashParser(txHash, db) {
|
|
19
|
+
try {
|
|
20
|
+
return parseTxHash(txHash);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
const prefixed = txHash.includes(':') ? txHash : `transactions:${txHash}`;
|
|
23
|
+
const rawTxHash = db ? db.tryRetrieveAlias(prefixed) : txHash;
|
|
24
|
+
return parseTxHash(rawTxHash);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function aliasedAuthWitParser(witness, db) {
|
|
28
|
+
try {
|
|
29
|
+
return AuthWitness.fromString(witness);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
const prefixed = witness.includes(':') ? witness : `authwits:${witness}`;
|
|
32
|
+
const rawAuthWitness = db ? db.tryRetrieveAlias(prefixed) : witness;
|
|
33
|
+
return AuthWitness.fromString(rawAuthWitness);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function aliasedAddressParser(defaultPrefix, address, db) {
|
|
37
|
+
if (address.startsWith('0x')) {
|
|
38
|
+
return parseAztecAddress(address);
|
|
39
|
+
} else {
|
|
40
|
+
const prefixed = address.includes(':') ? address : `${defaultPrefix}:${address}`;
|
|
41
|
+
const rawAddress = db ? db.tryRetrieveAlias(prefixed) : address;
|
|
42
|
+
return parseAztecAddress(rawAddress);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function aliasedSecretKeyParser(sk, db) {
|
|
46
|
+
if (sk.startsWith('0x')) {
|
|
47
|
+
return parseSecretKey(sk);
|
|
48
|
+
} else {
|
|
49
|
+
const prefixed = `${sk.startsWith('accounts') ? '' : 'accounts'}:${sk.endsWith(':sk') ? sk : `${sk}:sk`}`;
|
|
50
|
+
const rawSk = db ? db.tryRetrieveAlias(prefixed) : sk;
|
|
51
|
+
return parseSecretKey(rawSk);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function createAliasOption(description, hide) {
|
|
55
|
+
return new Option(`-a, --alias <string>`, description).hideHelp(hide);
|
|
56
|
+
}
|
|
57
|
+
export function createAccountOption(description, hide, db) {
|
|
58
|
+
return new Option(`-f, --from <string>`, description).hideHelp(hide).argParser((address)=>aliasedAddressParser('accounts', address, db));
|
|
59
|
+
}
|
|
60
|
+
export function createTypeOption(mandatory) {
|
|
61
|
+
return new Option('-t, --type <string>', 'Type of account to create').choices(AccountTypes).default('schnorr').conflicts('account-or-address').makeOptionMandatory(mandatory);
|
|
62
|
+
}
|
|
63
|
+
export function createArgsOption(isConstructor, db) {
|
|
64
|
+
return new Option('--args [args...]', `${isConstructor ? 'Constructor' : 'Function'} arguments`).argParser((arg, prev)=>{
|
|
65
|
+
const next = db?.tryRetrieveAlias(arg) || arg;
|
|
66
|
+
prev.push(next);
|
|
67
|
+
return prev;
|
|
68
|
+
}).default([]);
|
|
69
|
+
}
|
|
70
|
+
export function createContractAddressOption(db) {
|
|
71
|
+
return new Option('-ca, --contract-address <address>', 'Aztec address of the contract.').argParser((address)=>aliasedAddressParser('contracts', address, db)).makeOptionMandatory(true);
|
|
72
|
+
}
|
|
73
|
+
export function artifactPathParser(filePath, db) {
|
|
74
|
+
if (filePath.includes('@')) {
|
|
75
|
+
const [pkg, contractName] = filePath.split('@');
|
|
76
|
+
return contractArtifactFromWorkspace(pkg, contractName);
|
|
77
|
+
} else if (!new RegExp(/^(\.|\/|[A-Z]:).*\.json$/).test(filePath)) {
|
|
78
|
+
filePath = db ? db.tryRetrieveAlias(`artifacts:${filePath}`) : filePath;
|
|
79
|
+
}
|
|
80
|
+
if (!filePath) {
|
|
81
|
+
throw new Error('This command has to be called from a nargo workspace or contract artifact path should be provided');
|
|
82
|
+
}
|
|
83
|
+
return Promise.resolve(filePath);
|
|
84
|
+
}
|
|
85
|
+
export async function artifactPathFromPromiseOrAlias(artifactPathPromise, contractAddress, db) {
|
|
86
|
+
let artifactPath = await artifactPathPromise;
|
|
87
|
+
if (db && !artifactPath) {
|
|
88
|
+
artifactPath = db.tryRetrieveAlias(`artifacts:${contractAddress.toString()}`);
|
|
89
|
+
if (!artifactPath) {
|
|
90
|
+
throw new Error(`No artifact found for contract address ${contractAddress}, please provide it via the -c option`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return artifactPath;
|
|
94
|
+
}
|
|
95
|
+
export function createArtifactOption(db) {
|
|
96
|
+
return new Option('-c, --contract-artifact <fileLocation>', ARTIFACT_DESCRIPTION).argParser((filePath)=>artifactPathParser(filePath, db)).makeOptionMandatory(false);
|
|
97
|
+
}
|
|
98
|
+
export function createProfileOption() {
|
|
99
|
+
return new Option('-p, --profile', 'Run the real prover and get the gate count for each function in the transaction.').default(false);
|
|
100
|
+
}
|
|
101
|
+
async function contractArtifactFromWorkspace(pkg, contractName) {
|
|
102
|
+
const cwd = process.cwd();
|
|
103
|
+
try {
|
|
104
|
+
await stat(`${cwd}/Nargo.toml`);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
throw new Error('Invalid contract artifact argument provided. To use this option, command should be called from a nargo workspace');
|
|
107
|
+
}
|
|
108
|
+
const filesInTarget = await readdir(`${cwd}/${TARGET_DIR}`);
|
|
109
|
+
const bestMatch = filesInTarget.filter((file)=>{
|
|
110
|
+
if (pkg && contractName) {
|
|
111
|
+
return file === `${pkg}-${contractName}.json`;
|
|
112
|
+
} else {
|
|
113
|
+
return file.endsWith('.json') && (file.includes(pkg || '') || file.includes(contractName || ''));
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (bestMatch.length === 0) {
|
|
117
|
+
throw new Error('No contract artifacts found in target directory with the specified criteria');
|
|
118
|
+
} else if (bestMatch.length > 1) {
|
|
119
|
+
throw new Error(`Multiple contract artifacts found in target directory with the specified criteria ${bestMatch.join(', ')}`);
|
|
120
|
+
}
|
|
121
|
+
return `${cwd}/${TARGET_DIR}/${bestMatch[0]}`;
|
|
122
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createAztecNodeClient } from '@aztec/circuit-types';
|
|
2
|
+
import { createPXEService, getPXEServiceConfig } from '@aztec/pxe';
|
|
3
|
+
/*
|
|
4
|
+
* Wrapper class for PXE service, avoids initialization issues due to
|
|
5
|
+
* closures when providing PXE service to injected commander.js commands
|
|
6
|
+
*/ export class PXEWrapper {
|
|
7
|
+
static pxe;
|
|
8
|
+
static node;
|
|
9
|
+
getPXE() {
|
|
10
|
+
return PXEWrapper.pxe;
|
|
11
|
+
}
|
|
12
|
+
getNode() {
|
|
13
|
+
return PXEWrapper.node;
|
|
14
|
+
}
|
|
15
|
+
async init(nodeUrl, dataDir, overridePXEServiceConfig) {
|
|
16
|
+
PXEWrapper.node = createAztecNodeClient(nodeUrl);
|
|
17
|
+
const pxeConfig = Object.assign(getPXEServiceConfig(), overridePXEServiceConfig);
|
|
18
|
+
pxeConfig.dataDirectory = dataDir;
|
|
19
|
+
PXEWrapper.pxe = await createPXEService(PXEWrapper.node, pxeConfig);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aztec/cli-wallet",
|
|
3
|
+
"version": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./dest/cmds/index.js",
|
|
7
|
+
"./cli": "./dest/bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"typedocOptions": {
|
|
10
|
+
"entryPoints": [
|
|
11
|
+
"./src/cmds/index.ts"
|
|
12
|
+
],
|
|
13
|
+
"name": "Aztec CLI wallet",
|
|
14
|
+
"tsconfig": "./tsconfig.json"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"aztec-wallet": "./dest/bin/index.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"start": "node --no-warnings ./dest/bin",
|
|
21
|
+
"start:debug": "node --inspect=0.0.0.0:9221 --no-warnings ./dest/bin",
|
|
22
|
+
"dev": "LOG_LEVEL=debug && node ./dest/bin",
|
|
23
|
+
"build": "yarn clean && tsc -b",
|
|
24
|
+
"build:dev": "tsc -b --watch",
|
|
25
|
+
"clean": "rm -rf ./dest .tsbuildinfo",
|
|
26
|
+
"formatting": "run -T prettier --check ./src && run -T eslint ./src",
|
|
27
|
+
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
|
|
28
|
+
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
|
|
29
|
+
},
|
|
30
|
+
"inherits": [
|
|
31
|
+
"../package.common.json"
|
|
32
|
+
],
|
|
33
|
+
"jest": {
|
|
34
|
+
"preset": "ts-jest/presets/default-esm",
|
|
35
|
+
"moduleNameMapper": {
|
|
36
|
+
"^(\\.{1,2}/.*)\\.[cm]?js$": "$1"
|
|
37
|
+
},
|
|
38
|
+
"testRegex": "./src/.*\\.test\\.(js|mjs|ts)$",
|
|
39
|
+
"rootDir": "./src",
|
|
40
|
+
"extensionsToTreatAsEsm": [
|
|
41
|
+
".ts"
|
|
42
|
+
],
|
|
43
|
+
"transform": {
|
|
44
|
+
"^.+\\.tsx?$": [
|
|
45
|
+
"@swc/jest",
|
|
46
|
+
{
|
|
47
|
+
"jsc": {
|
|
48
|
+
"parser": {
|
|
49
|
+
"syntax": "typescript",
|
|
50
|
+
"decorators": true
|
|
51
|
+
},
|
|
52
|
+
"transform": {
|
|
53
|
+
"decoratorVersion": "2022-03"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"reporters": [
|
|
60
|
+
"default"
|
|
61
|
+
],
|
|
62
|
+
"testTimeout": 30000,
|
|
63
|
+
"setupFiles": [
|
|
64
|
+
"../../foundation/src/jest/setup.mjs"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@aztec/accounts": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
69
|
+
"@aztec/aztec.js": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
70
|
+
"@aztec/circuit-types": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
71
|
+
"@aztec/circuits.js": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
72
|
+
"@aztec/cli": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
73
|
+
"@aztec/ethereum": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
74
|
+
"@aztec/foundation": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
75
|
+
"@aztec/kv-store": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
76
|
+
"@aztec/noir-contracts.js": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
77
|
+
"@aztec/pxe": "0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2",
|
|
78
|
+
"commander": "^12.1.0",
|
|
79
|
+
"inquirer": "^10.1.8",
|
|
80
|
+
"source-map-support": "^0.5.21",
|
|
81
|
+
"tslib": "^2.4.0"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@jest/globals": "^29.5.0",
|
|
85
|
+
"@types/jest": "^29.5.0",
|
|
86
|
+
"@types/node": "^18.7.23",
|
|
87
|
+
"@types/source-map-support": "^0.5.10",
|
|
88
|
+
"jest": "^29.5.0",
|
|
89
|
+
"jest-mock-extended": "^3.0.5",
|
|
90
|
+
"ts-jest": "^29.1.0",
|
|
91
|
+
"ts-node": "^10.9.1",
|
|
92
|
+
"typescript": "^5.0.4"
|
|
93
|
+
},
|
|
94
|
+
"files": [
|
|
95
|
+
"dest",
|
|
96
|
+
"src",
|
|
97
|
+
"!*.test.*"
|
|
98
|
+
],
|
|
99
|
+
"types": "./dest/index.d.ts",
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=18"
|
|
102
|
+
}
|
|
103
|
+
}
|
package/src/bin/index.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Fr, computeSecretHash, fileURLToPath } from '@aztec/aztec.js';
|
|
2
|
+
import { LOCALHOST } from '@aztec/cli/cli-utils';
|
|
3
|
+
import { type LogFn, createConsoleLogger, createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
|
|
5
|
+
|
|
6
|
+
import { Argument, Command, Option } from 'commander';
|
|
7
|
+
import { mkdirSync, readFileSync } from 'fs';
|
|
8
|
+
import { dirname, join, resolve } from 'path';
|
|
9
|
+
|
|
10
|
+
import { injectCommands } from '../cmds/index.js';
|
|
11
|
+
import { Aliases, WalletDB } from '../storage/wallet_db.js';
|
|
12
|
+
import { createAliasOption } from '../utils/options/index.js';
|
|
13
|
+
import { PXEWrapper } from '../utils/pxe_wrapper.js';
|
|
14
|
+
|
|
15
|
+
const userLog = createConsoleLogger();
|
|
16
|
+
const debugLogger = createLogger('wallet');
|
|
17
|
+
|
|
18
|
+
const { WALLET_DATA_DIRECTORY = '~/.aztec/wallet', PXE_PROVER = 'none' } = process.env;
|
|
19
|
+
|
|
20
|
+
function injectInternalCommands(program: Command, log: LogFn, db: WalletDB) {
|
|
21
|
+
program
|
|
22
|
+
.command('alias')
|
|
23
|
+
.description('Aliases information for easy reference.')
|
|
24
|
+
.addArgument(new Argument('<type>', 'Type of alias to create').choices(Aliases))
|
|
25
|
+
.argument('<key>', 'Key to alias.')
|
|
26
|
+
.argument('<value>', 'Value to assign to the alias.')
|
|
27
|
+
.action(async (type, key, value) => {
|
|
28
|
+
value = db.tryRetrieveAlias(value) || value;
|
|
29
|
+
await db.storeAlias(type, key, value, log);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('get-alias')
|
|
34
|
+
.description('Shows stored aliases')
|
|
35
|
+
.addArgument(new Argument('[alias]', 'Alias to retrieve'))
|
|
36
|
+
.action(alias => {
|
|
37
|
+
if (alias?.includes(':')) {
|
|
38
|
+
const value = db.retrieveAlias(alias);
|
|
39
|
+
log(value);
|
|
40
|
+
} else {
|
|
41
|
+
const aliases = db.listAliases(alias);
|
|
42
|
+
for (const { key, value } of aliases) {
|
|
43
|
+
log(`${key} -> ${value}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
program
|
|
49
|
+
.command('create-secret')
|
|
50
|
+
.description('Creates an aliased secret to use in other commands')
|
|
51
|
+
.addOption(createAliasOption('Key to alias the secret with', false).makeOptionMandatory(true))
|
|
52
|
+
.action(async (_options, command) => {
|
|
53
|
+
const options = command.optsWithGlobals();
|
|
54
|
+
const { alias } = options;
|
|
55
|
+
const value = Fr.random();
|
|
56
|
+
const hash = computeSecretHash(value);
|
|
57
|
+
|
|
58
|
+
await db.storeAlias('secrets', alias, Buffer.from(value.toString()), log);
|
|
59
|
+
await db.storeAlias('secrets', `${alias}:hash`, Buffer.from(hash.toString()), log);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return program;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** CLI wallet main entrypoint */
|
|
66
|
+
async function main() {
|
|
67
|
+
const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json');
|
|
68
|
+
const walletVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version;
|
|
69
|
+
|
|
70
|
+
const db = WalletDB.getInstance();
|
|
71
|
+
const pxeWrapper = new PXEWrapper();
|
|
72
|
+
|
|
73
|
+
const program = new Command('wallet');
|
|
74
|
+
program
|
|
75
|
+
.description('Aztec wallet')
|
|
76
|
+
.version(walletVersion)
|
|
77
|
+
.option('-d, --data-dir <string>', 'Storage directory for wallet data', WALLET_DATA_DIRECTORY)
|
|
78
|
+
.option('-p, --prover <string>', 'wasm|native|none', PXE_PROVER)
|
|
79
|
+
.addOption(
|
|
80
|
+
new Option('--remote-pxe', 'Connect to an external PXE RPC server, instead of the local one')
|
|
81
|
+
.env('REMOTE_PXE')
|
|
82
|
+
.default(false)
|
|
83
|
+
.conflicts('rpc-url'),
|
|
84
|
+
)
|
|
85
|
+
.addOption(
|
|
86
|
+
new Option('-n, --node-url <string>', 'URL of the Aztec node to connect to')
|
|
87
|
+
.env('AZTEC_NODE_URL')
|
|
88
|
+
.default(`http://${LOCALHOST}:8080`),
|
|
89
|
+
)
|
|
90
|
+
.hook('preSubcommand', async command => {
|
|
91
|
+
const { dataDir, remotePxe, nodeUrl, prover } = command.optsWithGlobals();
|
|
92
|
+
|
|
93
|
+
if (!remotePxe) {
|
|
94
|
+
debugLogger.info('Using local PXE service');
|
|
95
|
+
|
|
96
|
+
const bbBinaryPath =
|
|
97
|
+
prover === 'native'
|
|
98
|
+
? resolve(dirname(fileURLToPath(import.meta.url)), '../../../../barretenberg/cpp/build/bin/bb')
|
|
99
|
+
: undefined;
|
|
100
|
+
const bbWorkingDirectory = dataDir + '/bb';
|
|
101
|
+
const proverEnabled = prover !== 'none';
|
|
102
|
+
|
|
103
|
+
mkdirSync(bbWorkingDirectory, { recursive: true });
|
|
104
|
+
|
|
105
|
+
await pxeWrapper.init(nodeUrl, join(dataDir, 'pxe'), {
|
|
106
|
+
...(proverEnabled && { proverEnabled, bbBinaryPath, bbWorkingDirectory }), // only override if we're profiling
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
db.init(AztecLmdbStore.open(dataDir));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
injectCommands(program, userLog, debugLogger, db, pxeWrapper);
|
|
113
|
+
injectInternalCommands(program, userLog, db);
|
|
114
|
+
await program.parseAsync(process.argv);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main().catch(err => {
|
|
118
|
+
debugLogger.error(`Error in command execution`);
|
|
119
|
+
debugLogger.error(err + '\n' + err.stack);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AccountWalletWithSecretKey, type AuthWitness, type AztecAddress } from '@aztec/aztec.js';
|
|
2
|
+
import { type LogFn } from '@aztec/foundation/log';
|
|
3
|
+
|
|
4
|
+
export async function addAuthwit(
|
|
5
|
+
wallet: AccountWalletWithSecretKey,
|
|
6
|
+
authwit: AuthWitness,
|
|
7
|
+
authorizer: AztecAddress,
|
|
8
|
+
log: LogFn,
|
|
9
|
+
) {
|
|
10
|
+
await wallet.addAuthWitness(authwit);
|
|
11
|
+
|
|
12
|
+
log(`Added authorization witness from ${authorizer}`);
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type AccountWalletWithSecretKey, type AztecAddress } from '@aztec/aztec.js';
|
|
2
|
+
import { ExtendedNote, Note, type TxHash } from '@aztec/circuit-types';
|
|
3
|
+
import { getContractArtifact, parseFields } from '@aztec/cli/utils';
|
|
4
|
+
import { type LogFn } from '@aztec/foundation/log';
|
|
5
|
+
|
|
6
|
+
export async function addNote(
|
|
7
|
+
wallet: AccountWalletWithSecretKey,
|
|
8
|
+
address: AztecAddress,
|
|
9
|
+
contractAddress: AztecAddress,
|
|
10
|
+
noteName: string,
|
|
11
|
+
storageFieldName: string,
|
|
12
|
+
artifactPath: string,
|
|
13
|
+
txHash: TxHash,
|
|
14
|
+
noteBody: string[],
|
|
15
|
+
log: LogFn,
|
|
16
|
+
) {
|
|
17
|
+
const fields = parseFields(noteBody);
|
|
18
|
+
const note = new Note(fields);
|
|
19
|
+
const contractArtifact = await getContractArtifact(artifactPath, log);
|
|
20
|
+
|
|
21
|
+
const contractNote = contractArtifact.notes[noteName];
|
|
22
|
+
const storageField = contractArtifact.storageLayout[storageFieldName];
|
|
23
|
+
|
|
24
|
+
if (!contractNote) {
|
|
25
|
+
throw new Error(`Note ${noteName} not found in contract ${contractArtifact.name}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const extendedNote = new ExtendedNote(note, address, contractAddress, storageField.slot, contractNote.id, txHash);
|
|
29
|
+
await wallet.addNote(extendedNote);
|
|
30
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type AccountWalletWithSecretKey, type AztecAddress, Contract } from '@aztec/aztec.js';
|
|
2
|
+
import { prepTx } from '@aztec/cli/utils';
|
|
3
|
+
import { type LogFn } from '@aztec/foundation/log';
|
|
4
|
+
|
|
5
|
+
export async function authorizeAction(
|
|
6
|
+
wallet: AccountWalletWithSecretKey,
|
|
7
|
+
functionName: string,
|
|
8
|
+
caller: AztecAddress,
|
|
9
|
+
functionArgsIn: any[],
|
|
10
|
+
contractArtifactPath: string,
|
|
11
|
+
contractAddress: AztecAddress,
|
|
12
|
+
log: LogFn,
|
|
13
|
+
) {
|
|
14
|
+
const { functionArgs, contractArtifact, isPrivate } = await prepTx(
|
|
15
|
+
contractArtifactPath,
|
|
16
|
+
functionName,
|
|
17
|
+
functionArgsIn,
|
|
18
|
+
log,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
if (isPrivate) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
'Cannot authorize private function. To allow a third party to call a private function, please create an authorization witness via the create-authwit command',
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const contract = await Contract.at(contractAddress, contractArtifact, wallet);
|
|
28
|
+
const action = contract.methods[functionName](...functionArgs);
|
|
29
|
+
|
|
30
|
+
const setAuthwitnessInteraction = await wallet.setPublicAuthWit({ caller, action }, true);
|
|
31
|
+
const witness = await setAuthwitnessInteraction.send().wait();
|
|
32
|
+
|
|
33
|
+
log(`Authorized action ${functionName} on contract ${contractAddress} for caller ${caller}`);
|
|
34
|
+
|
|
35
|
+
return witness;
|
|
36
|
+
}
|