Skip to content

Commit cc8bd80

Browse files
authored
feat: cli wallet improvements (#10425)
`cli-wallet` now supports an integrated PXE, so it can connect to a real-er network directly. A new command was also added to register a recipient so the new note discovery and syncing process is supported. Also found a bug in the synchronizer that prevented PXE from recovering when starting from a pre-seeded db (it always set its own header to the one of the genesis block, regardless of stored state)
1 parent 676f673 commit cc8bd80

20 files changed

+277
-61
lines changed

yarn-project/aztec.js/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export {
5353
generatePublicKey,
5454
readFieldCompressedString,
5555
waitForPXE,
56+
waitForNode,
5657
type AztecAddressLike,
5758
type EthAddressLike,
5859
type EventSelectorLike,

yarn-project/aztec.js/src/utils/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './abi_types.js';
44
export * from './cheat_codes.js';
55
export * from './authwit.js';
66
export * from './pxe.js';
7+
export * from './node.js';
78
export * from './anvil_test_watcher.js';
89
export * from './field_compressed_string.js';
910
export * from './portal_manager.js';
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { type AztecNode } from '@aztec/circuit-types';
2+
import { type DebugLogger } from '@aztec/foundation/log';
3+
import { retryUntil } from '@aztec/foundation/retry';
4+
5+
export const waitForNode = async (node: AztecNode, logger?: DebugLogger) => {
6+
await retryUntil(async () => {
7+
try {
8+
logger?.verbose('Attempting to contact Aztec node...');
9+
await node.getNodeInfo();
10+
logger?.verbose('Contacted Aztec node');
11+
return true;
12+
} catch (error) {
13+
logger?.verbose('Failed to contact Aztec Node');
14+
}
15+
return undefined;
16+
}, 'RPC Get Node Info');
17+
};

yarn-project/cli-wallet/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"@aztec/foundation": "workspace:^",
7676
"@aztec/kv-store": "workspace:^",
7777
"@aztec/noir-contracts.js": "workspace:^",
78+
"@aztec/pxe": "workspace:^",
7879
"commander": "^12.1.0",
7980
"inquirer": "^10.1.8",
8081
"source-map-support": "^0.5.21",

yarn-project/cli-wallet/src/bin/index.ts

+29-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { Fr, computeSecretHash, fileURLToPath } from '@aztec/aztec.js';
2+
import { LOCALHOST } from '@aztec/cli/cli-utils';
23
import { type LogFn, createConsoleLogger, createDebugLogger } from '@aztec/foundation/log';
34
import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
5+
import { type PXEService } from '@aztec/pxe';
46

5-
import { Argument, Command } from 'commander';
7+
import { Argument, Command, Option } from 'commander';
68
import { readFileSync } from 'fs';
7-
import { dirname, resolve } from 'path';
9+
import { dirname, join, resolve } from 'path';
810

911
import { injectCommands } from '../cmds/index.js';
1012
import { Aliases, WalletDB } from '../storage/wallet_db.js';
1113
import { createAliasOption } from '../utils/options/index.js';
14+
import { PXEWrapper } from '../utils/pxe_wrapper.js';
1215

1316
const userLog = createConsoleLogger();
1417
const debugLogger = createDebugLogger('aztec:wallet');
@@ -66,18 +69,39 @@ async function main() {
6669
const walletVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version;
6770

6871
const db = WalletDB.getInstance();
72+
const pxeWrapper = new PXEWrapper();
6973

7074
const program = new Command('wallet');
7175
program
7276
.description('Aztec wallet')
7377
.version(walletVersion)
7478
.option('-d, --data-dir <string>', 'Storage directory for wallet data', WALLET_DATA_DIRECTORY)
75-
.hook('preSubcommand', command => {
76-
const dataDir = command.optsWithGlobals().dataDir;
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 } = command.optsWithGlobals();
92+
if (!remotePxe) {
93+
debugLogger.info('Using local PXE service');
94+
await pxeWrapper.init(nodeUrl, join(dataDir, 'pxe'));
95+
}
7796
db.init(AztecLmdbStore.open(dataDir));
97+
})
98+
.hook('postAction', async () => {
99+
if (pxeWrapper.getPXE()) {
100+
await (pxeWrapper.getPXE() as PXEService).stop();
101+
}
78102
});
79103

80-
injectCommands(program, userLog, debugLogger, db);
104+
injectCommands(program, userLog, debugLogger, db, pxeWrapper);
81105
injectInternalCommands(program, userLog, db);
82106
await program.parseAsync(process.argv);
83107
}

yarn-project/cli-wallet/src/cmds/bridge_fee_juice.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { L1FeeJuicePortalManager, createCompatibleClient } from '@aztec/aztec.js';
1+
import { L1FeeJuicePortalManager, type PXE } from '@aztec/aztec.js';
22
import { prettyPrintJSON } from '@aztec/cli/utils';
33
import { createEthereumChain, createL1Clients } from '@aztec/ethereum';
44
import { type AztecAddress } from '@aztec/foundation/aztec-address';
@@ -8,7 +8,7 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log';
88
export async function bridgeL1FeeJuice(
99
amount: bigint,
1010
recipient: AztecAddress,
11-
rpcUrl: string,
11+
pxe: PXE,
1212
l1RpcUrl: string,
1313
chainId: number,
1414
privateKey: string | undefined,
@@ -24,15 +24,12 @@ export async function bridgeL1FeeJuice(
2424
const chain = createEthereumChain(l1RpcUrl, chainId);
2525
const { publicClient, walletClient } = createL1Clients(chain.rpcUrl, privateKey ?? mnemonic, chain.chainInfo);
2626

27-
// Prepare L2 client
28-
const client = await createCompatibleClient(rpcUrl, debugLogger);
29-
3027
const {
3128
protocolContractAddresses: { feeJuice: feeJuiceAddress },
32-
} = await client.getPXEInfo();
29+
} = await pxe.getPXEInfo();
3330

3431
// Setup portal manager
35-
const portal = await L1FeeJuicePortalManager.new(client, publicClient, walletClient, debugLogger);
32+
const portal = await L1FeeJuicePortalManager.new(pxe, publicClient, walletClient, debugLogger);
3633
const { claimAmount, claimSecret, messageHash, messageLeafIndex } = await portal.bridgeTokensPublic(
3734
recipient,
3835
amount,
@@ -69,7 +66,7 @@ export async function bridgeL1FeeJuice(
6966
const delayedCheck = (delay: number) => {
7067
return new Promise(resolve => {
7168
setTimeout(async () => {
72-
const witness = await client.getL1ToL2MembershipWitness(
69+
const witness = await pxe.getL1ToL2MembershipWitness(
7370
feeJuiceAddress,
7471
Fr.fromString(messageHash),
7572
claimSecret,

yarn-project/cli-wallet/src/cmds/create_account.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export async function createAccount(
2727
client,
2828
undefined /* address, we don't have it yet */,
2929
undefined /* db, as we want to create from scratch */,
30-
accountType,
3130
secretKey,
31+
accountType,
3232
Fr.ZERO,
3333
publicKey,
3434
);

0 commit comments

Comments
 (0)