@aztec/aztec 4.0.0-nightly.20250907 → 4.0.0-nightly.20260107
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 +1 -1
- package/dest/bin/index.d.ts +1 -1
- package/dest/bin/index.js +11 -10
- package/dest/cli/aztec_start_action.d.ts +1 -1
- package/dest/cli/aztec_start_action.d.ts.map +1 -1
- package/dest/cli/aztec_start_action.js +9 -25
- package/dest/cli/aztec_start_options.d.ts +1 -1
- package/dest/cli/aztec_start_options.d.ts.map +1 -1
- package/dest/cli/aztec_start_options.js +22 -39
- package/dest/cli/cli.d.ts +1 -1
- package/dest/cli/cli.d.ts.map +1 -1
- package/dest/cli/cli.js +46 -1
- package/dest/cli/cmds/start_archiver.d.ts +1 -1
- package/dest/cli/cmds/start_archiver.d.ts.map +1 -1
- package/dest/cli/cmds/start_archiver.js +9 -9
- package/dest/cli/cmds/start_bot.d.ts +4 -7
- package/dest/cli/cmds/start_bot.d.ts.map +1 -1
- package/dest/cli/cmds/start_bot.js +25 -14
- package/dest/cli/cmds/start_node.d.ts +1 -1
- package/dest/cli/cmds/start_node.d.ts.map +1 -1
- package/dest/cli/cmds/start_node.js +13 -21
- package/dest/cli/cmds/start_p2p_bootstrap.d.ts +1 -1
- package/dest/cli/cmds/start_p2p_bootstrap.js +1 -1
- package/dest/cli/cmds/start_prover_agent.d.ts +1 -1
- package/dest/cli/cmds/start_prover_agent.d.ts.map +1 -1
- package/dest/cli/cmds/start_prover_agent.js +11 -2
- package/dest/cli/cmds/start_prover_broker.d.ts +1 -1
- package/dest/cli/cmds/start_prover_broker.d.ts.map +1 -1
- package/dest/cli/cmds/start_prover_broker.js +8 -3
- package/dest/cli/cmds/start_prover_node.d.ts +1 -1
- package/dest/cli/cmds/start_prover_node.d.ts.map +1 -1
- package/dest/cli/cmds/start_prover_node.js +16 -7
- package/dest/cli/cmds/start_txe.d.ts +1 -1
- package/dest/cli/index.d.ts +1 -1
- package/dest/cli/preload_crs.d.ts +1 -1
- package/dest/cli/release_version.d.ts +1 -1
- package/dest/cli/util.d.ts +12 -10
- package/dest/cli/util.d.ts.map +1 -1
- package/dest/cli/util.js +7 -7
- package/dest/cli/versioning.d.ts +1 -1
- package/dest/cli/versioning.js +3 -3
- package/dest/examples/token.d.ts +1 -1
- package/dest/examples/token.js +18 -16
- package/dest/examples/util.d.ts +3 -3
- package/dest/examples/util.d.ts.map +1 -1
- package/dest/examples/util.js +1 -1
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/local-network/banana_fpc.d.ts +10 -0
- package/dest/local-network/banana_fpc.d.ts.map +1 -0
- package/dest/{sandbox → local-network}/banana_fpc.js +15 -19
- package/dest/local-network/index.d.ts +4 -0
- package/dest/local-network/index.d.ts.map +1 -0
- package/dest/local-network/index.js +3 -0
- package/dest/local-network/local-network.d.ts +72 -0
- package/dest/local-network/local-network.d.ts.map +1 -0
- package/dest/{sandbox/sandbox.js → local-network/local-network.js} +43 -57
- package/dest/local-network/sponsored_fpc.d.ts +5 -0
- package/dest/local-network/sponsored_fpc.d.ts.map +1 -0
- package/dest/{sandbox → local-network}/sponsored_fpc.js +7 -8
- package/dest/mnemonic.d.ts +1 -1
- package/dest/splash.d.ts +1 -1
- package/dest/testing/anvil_test_watcher.d.ts +4 -4
- package/dest/testing/anvil_test_watcher.d.ts.map +1 -1
- package/dest/testing/anvil_test_watcher.js +19 -18
- package/dest/testing/cheat_codes.d.ts +7 -10
- package/dest/testing/cheat_codes.d.ts.map +1 -1
- package/dest/testing/cheat_codes.js +9 -10
- package/dest/testing/index.d.ts +1 -2
- package/dest/testing/index.d.ts.map +1 -1
- package/dest/testing/index.js +0 -1
- package/package.json +39 -37
- package/src/bin/index.ts +12 -10
- package/src/cli/aztec_start_action.ts +9 -22
- package/src/cli/aztec_start_options.ts +23 -40
- package/src/cli/cli.ts +46 -1
- package/src/cli/cmds/start_archiver.ts +9 -9
- package/src/cli/cmds/start_bot.ts +36 -13
- package/src/cli/cmds/start_node.ts +16 -17
- package/src/cli/cmds/start_p2p_bootstrap.ts +1 -1
- package/src/cli/cmds/start_prover_agent.ts +7 -2
- package/src/cli/cmds/start_prover_broker.ts +17 -3
- package/src/cli/cmds/start_prover_node.ts +13 -8
- package/src/cli/util.ts +12 -10
- package/src/cli/versioning.ts +3 -3
- package/src/examples/token.ts +20 -17
- package/src/examples/util.ts +2 -2
- package/src/index.ts +5 -5
- package/src/{sandbox → local-network}/banana_fpc.ts +16 -21
- package/src/local-network/index.ts +7 -0
- package/src/{sandbox/sandbox.ts → local-network/local-network.ts} +68 -99
- package/src/local-network/sponsored_fpc.ts +26 -0
- package/src/testing/anvil_test_watcher.ts +18 -19
- package/src/testing/cheat_codes.ts +13 -13
- package/src/testing/index.ts +0 -1
- package/dest/cli/chain_l2_config.d.ts +0 -31
- package/dest/cli/chain_l2_config.d.ts.map +0 -1
- package/dest/cli/chain_l2_config.js +0 -261
- package/dest/cli/cmds/start_blob_sink.d.ts +0 -3
- package/dest/cli/cmds/start_blob_sink.d.ts.map +0 -1
- package/dest/cli/cmds/start_blob_sink.js +0 -33
- package/dest/cli/cmds/start_pxe.d.ts +0 -16
- package/dest/cli/cmds/start_pxe.d.ts.map +0 -1
- package/dest/cli/cmds/start_pxe.js +0 -31
- package/dest/cli/get_l1_config.d.ts +0 -7
- package/dest/cli/get_l1_config.d.ts.map +0 -1
- package/dest/cli/get_l1_config.js +0 -13
- package/dest/sandbox/banana_fpc.d.ts +0 -11
- package/dest/sandbox/banana_fpc.d.ts.map +0 -1
- package/dest/sandbox/index.d.ts +0 -4
- package/dest/sandbox/index.d.ts.map +0 -1
- package/dest/sandbox/index.js +0 -3
- package/dest/sandbox/sandbox.d.ts +0 -83
- package/dest/sandbox/sandbox.d.ts.map +0 -1
- package/dest/sandbox/sponsored_fpc.d.ts +0 -4
- package/dest/sandbox/sponsored_fpc.d.ts.map +0 -1
- package/dest/testing/aztec_cheat_codes.d.ts +0 -59
- package/dest/testing/aztec_cheat_codes.d.ts.map +0 -1
- package/dest/testing/aztec_cheat_codes.js +0 -62
- package/src/cli/chain_l2_config.ts +0 -341
- package/src/cli/cmds/start_blob_sink.ts +0 -57
- package/src/cli/cmds/start_pxe.ts +0 -49
- package/src/cli/get_l1_config.ts +0 -19
- package/src/sandbox/index.ts +0 -4
- package/src/sandbox/sponsored_fpc.ts +0 -27
- package/src/testing/aztec_cheat_codes.ts +0 -77
|
@@ -45,10 +45,15 @@ export async function startProverAgent(
|
|
|
45
45
|
|
|
46
46
|
await preloadCrsDataForServerSideProving(config, userLog);
|
|
47
47
|
|
|
48
|
-
const fetch = makeTracedFetch(
|
|
48
|
+
const fetch = makeTracedFetch(
|
|
49
|
+
// retry connections every 3s, up to 30s before giving up
|
|
50
|
+
[1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3],
|
|
51
|
+
false,
|
|
52
|
+
makeUndiciFetch(new Agent({ connections: 10 })),
|
|
53
|
+
);
|
|
49
54
|
const broker = createProvingJobBrokerClient(config.proverBrokerUrl, getVersions(), fetch);
|
|
50
55
|
|
|
51
|
-
const telemetry = initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'));
|
|
56
|
+
const telemetry = await initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'));
|
|
52
57
|
const prover = await buildServerCircuitProver(config, telemetry);
|
|
53
58
|
const proofStore = new InlineProofStore();
|
|
54
59
|
const agents = times(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getL1Config } from '@aztec/cli/config';
|
|
2
|
+
import { getPublicClient } from '@aztec/ethereum/client';
|
|
1
3
|
import type { NamespacedApiHandlers } from '@aztec/foundation/json-rpc/server';
|
|
2
4
|
import type { LogFn } from '@aztec/foundation/log';
|
|
3
5
|
import {
|
|
@@ -10,8 +12,7 @@ import { getProverNodeBrokerConfigFromEnv } from '@aztec/prover-node';
|
|
|
10
12
|
import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
|
|
11
13
|
import { getConfigEnvVars as getTelemetryClientConfig, initTelemetryClient } from '@aztec/telemetry-client';
|
|
12
14
|
|
|
13
|
-
import {
|
|
14
|
-
import { extractRelevantOptions } from '../util.js';
|
|
15
|
+
import { extractRelevantOptions, setupUpdateMonitor } from '../util.js';
|
|
15
16
|
|
|
16
17
|
export async function startProverBroker(
|
|
17
18
|
options: any,
|
|
@@ -33,6 +34,7 @@ export async function startProverBroker(
|
|
|
33
34
|
throw new Error('L1 registry address is required to start Aztec Node without --deploy-aztec-contracts option');
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
const followsCanonicalRollup = typeof config.rollupVersion !== 'number';
|
|
36
38
|
const { addresses, config: rollupConfig } = await getL1Config(
|
|
37
39
|
config.l1Contracts.registryAddress,
|
|
38
40
|
config.l1RpcUrls,
|
|
@@ -43,8 +45,20 @@ export async function startProverBroker(
|
|
|
43
45
|
config.l1Contracts = addresses;
|
|
44
46
|
config.rollupVersion = rollupConfig.rollupVersion;
|
|
45
47
|
|
|
46
|
-
const client = initTelemetryClient(getTelemetryClientConfig());
|
|
48
|
+
const client = await initTelemetryClient(getTelemetryClientConfig());
|
|
47
49
|
const broker = await createAndStartProvingBroker(config, client);
|
|
50
|
+
|
|
51
|
+
if (options.autoUpdate !== 'disabled' && options.autoUpdateUrl) {
|
|
52
|
+
await setupUpdateMonitor(
|
|
53
|
+
options.autoUpdate,
|
|
54
|
+
new URL(options.autoUpdateUrl),
|
|
55
|
+
followsCanonicalRollup,
|
|
56
|
+
getPublicClient(config),
|
|
57
|
+
config.l1Contracts.registryAddress,
|
|
58
|
+
signalHandlers,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
48
62
|
services.proverBroker = [broker, ProvingJobBrokerSchema];
|
|
49
63
|
signalHandlers.push(() => broker.stop());
|
|
50
64
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Fr } from '@aztec/aztec.js';
|
|
1
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
2
|
+
import { Fr } from '@aztec/aztec.js/fields';
|
|
3
3
|
import { getSponsoredFPCAddress } from '@aztec/cli/cli-utils';
|
|
4
|
-
import {
|
|
4
|
+
import { getL1Config } from '@aztec/cli/config';
|
|
5
|
+
import { getPublicClient } from '@aztec/ethereum/client';
|
|
5
6
|
import type { NamespacedApiHandlers } from '@aztec/foundation/json-rpc/server';
|
|
6
7
|
import { Agent, makeUndiciFetch } from '@aztec/foundation/json-rpc/undici';
|
|
7
8
|
import type { LogFn } from '@aztec/foundation/log';
|
|
@@ -16,7 +17,6 @@ import { P2PApiSchema, ProverNodeApiSchema, type ProvingJobBroker } from '@aztec
|
|
|
16
17
|
import { initTelemetryClient, makeTracedFetch, telemetryClientConfigMappings } from '@aztec/telemetry-client';
|
|
17
18
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
18
19
|
|
|
19
|
-
import { getL1Config } from '../get_l1_config.js';
|
|
20
20
|
import { extractRelevantOptions, preloadCrsDataForVerifying, setupUpdateMonitor } from '../util.js';
|
|
21
21
|
import { getVersions } from '../versioning.js';
|
|
22
22
|
import { startProverBroker } from './start_prover_broker.js';
|
|
@@ -52,7 +52,7 @@ export async function startProverNode(
|
|
|
52
52
|
proverConfig.l1Contracts = addresses;
|
|
53
53
|
proverConfig = { ...proverConfig, ...config };
|
|
54
54
|
|
|
55
|
-
const testAccounts = proverConfig.testAccounts ? (await
|
|
55
|
+
const testAccounts = proverConfig.testAccounts ? (await getInitialTestAccountsData()).map(a => a.address) : [];
|
|
56
56
|
const sponsoredFPCAccounts = proverConfig.sponsoredFPC ? [await getSponsoredFPCAddress()] : [];
|
|
57
57
|
const initialFundedAccounts = testAccounts.concat(sponsoredFPCAccounts);
|
|
58
58
|
|
|
@@ -67,13 +67,18 @@ export async function startProverNode(
|
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const telemetry = initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'));
|
|
70
|
+
const telemetry = await initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'));
|
|
71
71
|
|
|
72
72
|
let broker: ProvingJobBroker;
|
|
73
73
|
if (proverConfig.proverBrokerUrl) {
|
|
74
|
-
// at 1TPS we'd enqueue ~1k
|
|
74
|
+
// at 1TPS we'd enqueue ~1k chonk verifier proofs and ~1k AVM proofs immediately
|
|
75
75
|
// set a lower connection limit such that we don't overload the server
|
|
76
|
-
|
|
76
|
+
// Keep retrying up to 30s
|
|
77
|
+
const fetch = makeTracedFetch(
|
|
78
|
+
[1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3],
|
|
79
|
+
false,
|
|
80
|
+
makeUndiciFetch(new Agent({ connections: 100 })),
|
|
81
|
+
);
|
|
77
82
|
broker = createProvingJobBrokerClient(proverConfig.proverBrokerUrl, getVersions(proverConfig), fetch);
|
|
78
83
|
} else if (options.proverBroker) {
|
|
79
84
|
({ broker } = await startProverBroker(options, signalHandlers, services, userLog));
|
package/src/cli/util.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { AztecNodeConfig } from '@aztec/aztec-node';
|
|
2
|
-
import type { AccountManager
|
|
3
|
-
import type { ViemClient } from '@aztec/ethereum';
|
|
2
|
+
import type { AccountManager } from '@aztec/aztec.js/wallet';
|
|
3
|
+
import type { ViemClient } from '@aztec/ethereum/types';
|
|
4
4
|
import type { ConfigMappingsType } from '@aztec/foundation/config';
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
7
|
import { type LogFn, createLogger } from '@aztec/foundation/log';
|
|
6
8
|
import type { SharedNodeConfig } from '@aztec/node-lib/config';
|
|
7
|
-
import type { PXEService } from '@aztec/pxe/server';
|
|
8
9
|
import type { ProverConfig } from '@aztec/stdlib/interfaces/server';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { getTelemetryClient } from '@aztec/telemetry-client/start';
|
|
11
|
+
import type { TestWallet } from '@aztec/test-wallet/server';
|
|
11
12
|
|
|
12
13
|
import chalk from 'chalk';
|
|
13
14
|
import type { Command } from 'commander';
|
|
@@ -67,7 +68,7 @@ export const installSignalHandlers = (logFn: LogFn, cb?: Array<() => Promise<voi
|
|
|
67
68
|
/**
|
|
68
69
|
* Creates logs for the initial accounts
|
|
69
70
|
* @param accounts - The initial accounts
|
|
70
|
-
* @param
|
|
71
|
+
* @param wallet - A TestWallet instance to get the registered accounts
|
|
71
72
|
* @returns A string array containing the initial accounts details
|
|
72
73
|
*/
|
|
73
74
|
export async function createAccountLogs(
|
|
@@ -81,13 +82,13 @@ export async function createAccountLogs(
|
|
|
81
82
|
*/
|
|
82
83
|
secretKey: Fr;
|
|
83
84
|
}[],
|
|
84
|
-
|
|
85
|
+
wallet: TestWallet,
|
|
85
86
|
) {
|
|
86
|
-
const registeredAccounts = await
|
|
87
|
+
const registeredAccounts = await wallet.getAccounts();
|
|
87
88
|
const accountLogStrings = [`Initial Accounts:\n\n`];
|
|
88
89
|
for (const accountWithSecretKey of accountsWithSecretKeys) {
|
|
89
90
|
const completeAddress = await accountWithSecretKey.account.getCompleteAddress();
|
|
90
|
-
if (registeredAccounts.find(a => a.equals(completeAddress))) {
|
|
91
|
+
if (registeredAccounts.find(a => a.item.equals(completeAddress.address))) {
|
|
91
92
|
accountLogStrings.push(` Address: ${completeAddress.address.toString()}\n`);
|
|
92
93
|
accountLogStrings.push(` Partial Address: ${completeAddress.partialAddress.toString()}\n`);
|
|
93
94
|
accountLogStrings.push(` Secret Key: ${accountWithSecretKey.secretKey.toString()}\n`);
|
|
@@ -271,7 +272,7 @@ export const extractRelevantOptions = <T>(
|
|
|
271
272
|
};
|
|
272
273
|
|
|
273
274
|
/**
|
|
274
|
-
* Downloads just enough points to be able to verify
|
|
275
|
+
* Downloads just enough points to be able to verify Chonk proofs.
|
|
275
276
|
* @param opts - Whether proof are to be verifier
|
|
276
277
|
* @param log - Logging function
|
|
277
278
|
*/
|
|
@@ -310,6 +311,7 @@ export async function setupUpdateMonitor(
|
|
|
310
311
|
updateNodeConfig?: (config: object) => Promise<void>,
|
|
311
312
|
) {
|
|
312
313
|
const logger = createLogger('update-check');
|
|
314
|
+
const { UpdateChecker } = await import('@aztec/stdlib/update-checker');
|
|
313
315
|
const checker = await UpdateChecker.new({
|
|
314
316
|
baseURL: updatesLocation,
|
|
315
317
|
publicClient,
|
package/src/cli/versioning.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
2
|
-
import {
|
|
2
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
3
3
|
import type { ChainConfig } from '@aztec/stdlib/config';
|
|
4
4
|
import { type ComponentsVersions, getComponentsVersionsFromConfig } from '@aztec/stdlib/versioning';
|
|
5
5
|
|
|
6
6
|
export function getVersions(config?: ChainConfig): Partial<ComponentsVersions> {
|
|
7
7
|
return config
|
|
8
|
-
? getComponentsVersionsFromConfig(config,
|
|
8
|
+
? getComponentsVersionsFromConfig(config, protocolContractsHash, getVKTreeRoot())
|
|
9
9
|
: {
|
|
10
10
|
l2CircuitsVkTreeRoot: getVKTreeRoot().toString(),
|
|
11
|
-
|
|
11
|
+
l2ProtocolContractsHash: protocolContractsHash.toString(),
|
|
12
12
|
};
|
|
13
13
|
}
|
package/src/examples/token.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
2
|
+
import { createAztecNodeClient } from '@aztec/aztec.js/node';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
5
|
+
import { TestWallet } from '@aztec/test-wallet/server';
|
|
5
6
|
|
|
6
7
|
const logger = createLogger('example:token');
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
+
const nodeUrl = 'http://localhost:8080';
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const node = createAztecNodeClient(nodeUrl);
|
|
11
12
|
|
|
12
13
|
const ALICE_MINT_BALANCE = 333n;
|
|
13
14
|
const TRANSFER_AMOUNT = 33n;
|
|
@@ -18,40 +19,42 @@ const TRANSFER_AMOUNT = 33n;
|
|
|
18
19
|
async function main() {
|
|
19
20
|
logger.info('Running token contract test on HTTP interface.');
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const wallet = await TestWallet.create(node);
|
|
23
|
+
|
|
24
|
+
// During local network setup we deploy a few accounts. Below we add them to our wallet.
|
|
25
|
+
const [aliceInitialAccountData, bobInitialAccountData] = await getInitialTestAccountsData();
|
|
26
|
+
await wallet.createSchnorrAccount(aliceInitialAccountData.secret, aliceInitialAccountData.salt);
|
|
27
|
+
await wallet.createSchnorrAccount(bobInitialAccountData.secret, bobInitialAccountData.salt);
|
|
28
|
+
|
|
29
|
+
const alice = aliceInitialAccountData.address;
|
|
30
|
+
const bob = bobInitialAccountData.address;
|
|
24
31
|
|
|
25
32
|
logger.info(`Fetched Alice and Bob accounts: ${alice.toString()}, ${bob.toString()}`);
|
|
26
33
|
|
|
27
34
|
logger.info('Deploying Token...');
|
|
28
|
-
const token = await TokenContract.deploy(
|
|
35
|
+
const token = await TokenContract.deploy(wallet, alice, 'TokenName', 'TokenSymbol', 18)
|
|
29
36
|
.send({ from: alice })
|
|
30
37
|
.deployed();
|
|
31
38
|
logger.info('Token deployed');
|
|
32
39
|
|
|
33
|
-
// Create the contract abstraction and link it to Alice's and Bob's wallet for future signing
|
|
34
|
-
const tokenAlice = await TokenContract.at(token.address, aliceWallet);
|
|
35
|
-
const tokenBob = await TokenContract.at(token.address, bobWallet);
|
|
36
|
-
|
|
37
40
|
// Mint tokens to Alice
|
|
38
41
|
logger.info(`Minting ${ALICE_MINT_BALANCE} more coins to Alice...`);
|
|
39
|
-
await
|
|
42
|
+
await token.methods.mint_to_private(alice, ALICE_MINT_BALANCE).send({ from: alice }).wait();
|
|
40
43
|
|
|
41
44
|
logger.info(`${ALICE_MINT_BALANCE} tokens were successfully minted by Alice and transferred to private`);
|
|
42
45
|
|
|
43
|
-
const balanceAfterMint = await
|
|
46
|
+
const balanceAfterMint = await token.methods.balance_of_private(alice).simulate({ from: alice });
|
|
44
47
|
logger.info(`Tokens successfully minted. New Alice's balance: ${balanceAfterMint}`);
|
|
45
48
|
|
|
46
49
|
// We will now transfer tokens from Alice to Bob
|
|
47
50
|
logger.info(`Transferring ${TRANSFER_AMOUNT} tokens from Alice to Bob...`);
|
|
48
|
-
await
|
|
51
|
+
await token.methods.transfer(bob, TRANSFER_AMOUNT).send({ from: alice }).wait();
|
|
49
52
|
|
|
50
53
|
// Check the new balances
|
|
51
|
-
const aliceBalance = await
|
|
54
|
+
const aliceBalance = await token.methods.balance_of_private(alice).simulate({ from: alice });
|
|
52
55
|
logger.info(`Alice's balance ${aliceBalance}`);
|
|
53
56
|
|
|
54
|
-
const bobBalance = await
|
|
57
|
+
const bobBalance = await token.methods.balance_of_private(bob).simulate({ from: bob });
|
|
55
58
|
logger.info(`Bob's balance ${bobBalance}`);
|
|
56
59
|
}
|
|
57
60
|
|
package/src/examples/util.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { EthAddress } from '@aztec/aztec.js';
|
|
2
|
-
import type { ExtendedViemWalletClient } from '@aztec/ethereum';
|
|
1
|
+
import { EthAddress } from '@aztec/aztec.js/addresses';
|
|
2
|
+
import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
|
|
3
3
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
4
4
|
|
|
5
5
|
import type { Abi, Narrow } from 'abitype';
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from './
|
|
2
|
+
createLocalNetwork,
|
|
3
|
+
registerDeployedBananaCoinInWalletAndGetAddress,
|
|
4
|
+
registerDeployedBananaFPCInWalletAndGetAddress,
|
|
5
|
+
registerDeployedSponsoredFPCInWalletAndGetAddress,
|
|
6
|
+
} from './local-network/index.js';
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { type InitialAccountData,
|
|
2
|
-
import type { Wallet } from '@aztec/aztec.js';
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import { type InitialAccountData, getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
2
|
+
import type { Wallet } from '@aztec/aztec.js/wallet';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import type { LogFn } from '@aztec/foundation/log';
|
|
5
5
|
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
|
|
6
6
|
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
7
7
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
8
|
import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
|
|
9
|
-
import type { PXE } from '@aztec/stdlib/interfaces/client';
|
|
10
9
|
|
|
11
10
|
const BANANA_COIN_SALT = new Fr(0);
|
|
12
11
|
const bananaCoinArgs = {
|
|
@@ -46,14 +45,14 @@ export async function getBananaFPCAddress(initialAccounts: InitialAccountData[])
|
|
|
46
45
|
return (await getBananaFPCInstance(initialAccounts)).address;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
export async function setupBananaFPC(initialAccounts: InitialAccountData[],
|
|
48
|
+
export async function setupBananaFPC(initialAccounts: InitialAccountData[], wallet: Wallet, log: LogFn) {
|
|
50
49
|
const bananaCoinAddress = await getBananaCoinAddress(initialAccounts);
|
|
51
50
|
const admin = getBananaAdmin(initialAccounts);
|
|
52
51
|
const [bananaCoin, fpc] = await Promise.all([
|
|
53
|
-
TokenContract.deploy(
|
|
52
|
+
TokenContract.deploy(wallet, admin, bananaCoinArgs.name, bananaCoinArgs.symbol, bananaCoinArgs.decimal)
|
|
54
53
|
.send({ from: admin, contractAddressSalt: BANANA_COIN_SALT, universalDeploy: true })
|
|
55
54
|
.deployed(),
|
|
56
|
-
FPCContract.deploy(
|
|
55
|
+
FPCContract.deploy(wallet, bananaCoinAddress, admin)
|
|
57
56
|
.send({ from: admin, contractAddressSalt: BANANA_FPC_SALT, universalDeploy: true })
|
|
58
57
|
.deployed(),
|
|
59
58
|
]);
|
|
@@ -62,22 +61,18 @@ export async function setupBananaFPC(initialAccounts: InitialAccountData[], depl
|
|
|
62
61
|
log(`FPC: ${fpc.address}`);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
export async function
|
|
66
|
-
const initialAccounts = await
|
|
67
|
-
const bananaCoin = await
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
return bananaCoin;
|
|
64
|
+
export async function registerDeployedBananaCoinInWalletAndGetAddress(wallet: Wallet) {
|
|
65
|
+
const initialAccounts = await getInitialTestAccountsData();
|
|
66
|
+
const bananaCoin = await getBananaCoinInstance(initialAccounts);
|
|
67
|
+
// The following is no-op if the contract is already registered
|
|
68
|
+
await wallet.registerContract(bananaCoin, TokenContract.artifact);
|
|
69
|
+
return bananaCoin.address;
|
|
73
70
|
}
|
|
74
71
|
|
|
75
|
-
export async function
|
|
76
|
-
const initialAccounts = await
|
|
72
|
+
export async function registerDeployedBananaFPCInWalletAndGetAddress(wallet: Wallet) {
|
|
73
|
+
const initialAccounts = await getInitialTestAccountsData();
|
|
77
74
|
const fpc = await getBananaFPCInstance(initialAccounts);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
throw new Error('BananaFPC not deployed.');
|
|
81
|
-
}
|
|
75
|
+
// The following is no-op if the contract is already registered
|
|
76
|
+
await wallet.registerContract(fpc, FPCContract.artifact);
|
|
82
77
|
return fpc.address;
|
|
83
78
|
}
|
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --no-warnings
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { type AztecNodeConfig,
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
3
|
+
import { AztecNodeService } from '@aztec/aztec-node';
|
|
4
|
+
import { type AztecNodeConfig, getConfigEnvVars } from '@aztec/aztec-node/config';
|
|
5
|
+
import { Fr } from '@aztec/aztec.js/fields';
|
|
6
|
+
import { createLogger } from '@aztec/aztec.js/log';
|
|
7
|
+
import { type BlobClientInterface, createBlobClient } from '@aztec/blob-client/client';
|
|
8
8
|
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
getL1ContractsConfigEnvVars,
|
|
15
|
-
waitForPublicClient,
|
|
16
|
-
} from '@aztec/ethereum';
|
|
9
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
10
|
+
import { waitForPublicClient } from '@aztec/ethereum/client';
|
|
11
|
+
import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
|
|
12
|
+
import { NULL_KEY } from '@aztec/ethereum/constants';
|
|
13
|
+
import { deployAztecL1Contracts } from '@aztec/ethereum/deploy-aztec-l1-contracts';
|
|
17
14
|
import { EthCheatCodes } from '@aztec/ethereum/test';
|
|
18
15
|
import { SecretValue } from '@aztec/foundation/config';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
16
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
17
|
+
import type { LogFn } from '@aztec/foundation/log';
|
|
21
18
|
import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
|
|
22
19
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
23
|
-
import {
|
|
24
|
-
import { type PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe/server';
|
|
25
|
-
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
20
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
26
21
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
27
22
|
import {
|
|
28
23
|
type TelemetryClient,
|
|
29
24
|
getConfigEnvVars as getTelemetryClientConfig,
|
|
30
25
|
initTelemetryClient,
|
|
31
26
|
} from '@aztec/telemetry-client';
|
|
27
|
+
import { TestWallet, deployFundedSchnorrAccounts } from '@aztec/test-wallet/server';
|
|
32
28
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
33
29
|
|
|
34
|
-
import { type
|
|
30
|
+
import { type Hex, createPublicClient, fallback, http as httpViemTransport } from 'viem';
|
|
35
31
|
import { mnemonicToAccount, privateKeyToAddress } from 'viem/accounts';
|
|
36
32
|
import { foundry } from 'viem/chains';
|
|
37
33
|
|
|
@@ -41,53 +37,37 @@ import { AnvilTestWatcher } from '../testing/anvil_test_watcher.js';
|
|
|
41
37
|
import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js';
|
|
42
38
|
import { getSponsoredFPCAddress } from './sponsored_fpc.js';
|
|
43
39
|
|
|
44
|
-
const logger = createLogger('
|
|
40
|
+
const logger = createLogger('local-network');
|
|
45
41
|
|
|
46
42
|
const localAnvil = foundry;
|
|
47
43
|
|
|
48
44
|
/**
|
|
49
|
-
* Function to deploy our L1 contracts to the
|
|
45
|
+
* Function to deploy our L1 contracts to the local network L1
|
|
50
46
|
* @param aztecNodeConfig - The Aztec Node Config
|
|
51
47
|
* @param hdAccount - Account for publishing L1 contracts
|
|
52
48
|
*/
|
|
53
49
|
export async function deployContractsToL1(
|
|
54
50
|
aztecNodeConfig: AztecNodeConfig,
|
|
55
|
-
|
|
56
|
-
contractDeployLogger = logger,
|
|
51
|
+
privateKey: Hex,
|
|
57
52
|
opts: {
|
|
58
53
|
assumeProvenThroughBlockNumber?: number;
|
|
59
|
-
salt?: number;
|
|
60
54
|
genesisArchiveRoot?: Fr;
|
|
61
55
|
feeJuicePortalInitialBalance?: bigint;
|
|
62
56
|
} = {},
|
|
63
57
|
) {
|
|
64
|
-
const chain =
|
|
65
|
-
aztecNodeConfig.l1RpcUrls.length > 0
|
|
66
|
-
? createEthereumChain(aztecNodeConfig.l1RpcUrls, aztecNodeConfig.l1ChainId)
|
|
67
|
-
: { chainInfo: localAnvil };
|
|
68
|
-
|
|
69
58
|
await waitForPublicClient(aztecNodeConfig);
|
|
70
59
|
|
|
71
|
-
const l1Contracts = await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
salt: opts.salt,
|
|
83
|
-
feeJuicePortalInitialBalance: opts.feeJuicePortalInitialBalance,
|
|
84
|
-
aztecTargetCommitteeSize: 0, // no committee in sandbox
|
|
85
|
-
slasherFlavor: 'none', // no slashing in sandbox
|
|
86
|
-
realVerifier: false,
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
await deployMulticall3(l1Contracts.l1Client, logger);
|
|
60
|
+
const l1Contracts = await deployAztecL1Contracts(aztecNodeConfig.l1RpcUrls[0], privateKey, foundry.id, {
|
|
61
|
+
...getL1ContractsConfigEnvVars(), // TODO: We should not need to be loading config from env again, caller should handle this
|
|
62
|
+
...aztecNodeConfig,
|
|
63
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
64
|
+
protocolContractsHash,
|
|
65
|
+
genesisArchiveRoot: opts.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT),
|
|
66
|
+
feeJuicePortalInitialBalance: opts.feeJuicePortalInitialBalance,
|
|
67
|
+
aztecTargetCommitteeSize: 0, // no committee in local network
|
|
68
|
+
slasherFlavor: 'none', // no slashing in local network
|
|
69
|
+
realVerifier: false,
|
|
70
|
+
});
|
|
91
71
|
|
|
92
72
|
aztecNodeConfig.l1Contracts = l1Contracts.l1ContractAddresses;
|
|
93
73
|
aztecNodeConfig.rollupVersion = l1Contracts.rollupVersion;
|
|
@@ -95,31 +75,27 @@ export async function deployContractsToL1(
|
|
|
95
75
|
return aztecNodeConfig.l1Contracts;
|
|
96
76
|
}
|
|
97
77
|
|
|
98
|
-
/**
|
|
99
|
-
export type
|
|
78
|
+
/** Local network settings. */
|
|
79
|
+
export type LocalNetworkConfig = AztecNodeConfig & {
|
|
100
80
|
/** Mnemonic used to derive the L1 deployer private key.*/
|
|
101
81
|
l1Mnemonic: string;
|
|
102
|
-
/**
|
|
103
|
-
deployAztecContractsSalt: string;
|
|
104
|
-
/** Whether to expose PXE service on sandbox start.*/
|
|
105
|
-
noPXE: boolean;
|
|
106
|
-
/** Whether to deploy test accounts on sandbox start.*/
|
|
82
|
+
/** Whether to deploy test accounts on local network start.*/
|
|
107
83
|
testAccounts: boolean;
|
|
108
84
|
};
|
|
109
85
|
|
|
110
86
|
/**
|
|
111
87
|
* Create and start a new Aztec Node and PXE. Deploys L1 contracts.
|
|
112
88
|
* Does not start any HTTP services nor populate any initial accounts.
|
|
113
|
-
* @param config - Optional
|
|
89
|
+
* @param config - Optional local network settings.
|
|
114
90
|
*/
|
|
115
|
-
export async function
|
|
116
|
-
//
|
|
91
|
+
export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {}, userLog: LogFn) {
|
|
92
|
+
// local network is meant for test envs. We should only need one l1RpcUrl
|
|
117
93
|
const l1RpcUrl = config.l1RpcUrls?.[0];
|
|
118
94
|
if (!l1RpcUrl) {
|
|
119
95
|
throw new Error('An L1 RPC URL is required');
|
|
120
96
|
}
|
|
121
97
|
if ((config.l1RpcUrls?.length || 0) > 1) {
|
|
122
|
-
logger.warn(`Multiple L1 RPC URLs provided.
|
|
98
|
+
logger.warn(`Multiple L1 RPC URLs provided. Local networks will only use the first one: ${l1RpcUrl}`);
|
|
123
99
|
}
|
|
124
100
|
const aztecNodeConfig: AztecNodeConfig = { ...getConfigEnvVars(), ...config };
|
|
125
101
|
const hdAccount = mnemonicToAccount(config.l1Mnemonic || DefaultMnemonic);
|
|
@@ -145,7 +121,7 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}, userLog
|
|
|
145
121
|
userLog(`Not setting up test accounts as we are connecting to a network`);
|
|
146
122
|
} else {
|
|
147
123
|
userLog(`Setting up test accounts`);
|
|
148
|
-
return await
|
|
124
|
+
return await getInitialTestAccountsData();
|
|
149
125
|
}
|
|
150
126
|
}
|
|
151
127
|
return [];
|
|
@@ -161,12 +137,15 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}, userLog
|
|
|
161
137
|
let watcher: AnvilTestWatcher | undefined = undefined;
|
|
162
138
|
const dateProvider = new TestDateProvider();
|
|
163
139
|
if (!aztecNodeConfig.p2pEnabled) {
|
|
164
|
-
const l1ContractAddresses = await deployContractsToL1(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
140
|
+
const l1ContractAddresses = await deployContractsToL1(
|
|
141
|
+
aztecNodeConfig,
|
|
142
|
+
aztecNodeConfig.validatorPrivateKeys.getValue()[0],
|
|
143
|
+
{
|
|
144
|
+
assumeProvenThroughBlockNumber: Number.MAX_SAFE_INTEGER,
|
|
145
|
+
genesisArchiveRoot,
|
|
146
|
+
feeJuicePortalInitialBalance: fundingNeeded,
|
|
147
|
+
},
|
|
148
|
+
);
|
|
170
149
|
|
|
171
150
|
const chain =
|
|
172
151
|
aztecNodeConfig.l1RpcUrls.length > 0
|
|
@@ -179,39 +158,39 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}, userLog
|
|
|
179
158
|
});
|
|
180
159
|
|
|
181
160
|
watcher = new AnvilTestWatcher(
|
|
182
|
-
new EthCheatCodes([l1RpcUrl]),
|
|
161
|
+
new EthCheatCodes([l1RpcUrl], dateProvider),
|
|
183
162
|
l1ContractAddresses.rollupAddress,
|
|
184
163
|
publicClient,
|
|
185
164
|
dateProvider,
|
|
186
165
|
);
|
|
187
|
-
watcher.
|
|
166
|
+
watcher.setisLocalNetwork(true);
|
|
188
167
|
await watcher.start();
|
|
189
168
|
}
|
|
190
169
|
|
|
191
|
-
const telemetry = initTelemetryClient(getTelemetryClientConfig());
|
|
192
|
-
// Create a local blob
|
|
193
|
-
const
|
|
194
|
-
const node = await createAztecNode(
|
|
195
|
-
aztecNodeConfig,
|
|
196
|
-
{ telemetry, blobSinkClient, dateProvider },
|
|
197
|
-
{ prefilledPublicData },
|
|
198
|
-
);
|
|
199
|
-
const pxeServiceConfig = { proverEnabled: aztecNodeConfig.realProofs };
|
|
200
|
-
const pxe = await createAztecPXE(node, pxeServiceConfig);
|
|
170
|
+
const telemetry = await initTelemetryClient(getTelemetryClientConfig());
|
|
171
|
+
// Create a local blob client client inside the local network, no http connectivity
|
|
172
|
+
const blobClient = createBlobClient();
|
|
173
|
+
const node = await createAztecNode(aztecNodeConfig, { telemetry, blobClient, dateProvider }, { prefilledPublicData });
|
|
201
174
|
|
|
202
175
|
if (initialAccounts.length) {
|
|
176
|
+
const PXEConfig = { proverEnabled: aztecNodeConfig.realProofs };
|
|
177
|
+
const wallet = await TestWallet.create(node, PXEConfig);
|
|
178
|
+
|
|
203
179
|
userLog('Setting up funded test accounts...');
|
|
204
|
-
const
|
|
205
|
-
const accountsWithSecrets =
|
|
206
|
-
account,
|
|
180
|
+
const accountManagers = await deployFundedSchnorrAccounts(wallet, node, initialAccounts);
|
|
181
|
+
const accountsWithSecrets = accountManagers.map((manager, i) => ({
|
|
182
|
+
account: manager,
|
|
207
183
|
secretKey: initialAccounts[i].secret,
|
|
208
184
|
}));
|
|
209
|
-
const accLogs = await createAccountLogs(accountsWithSecrets,
|
|
185
|
+
const accLogs = await createAccountLogs(accountsWithSecrets, wallet);
|
|
210
186
|
userLog(accLogs.join(''));
|
|
211
187
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
await
|
|
188
|
+
await setupBananaFPC(initialAccounts, wallet, userLog);
|
|
189
|
+
|
|
190
|
+
userLog(`SponsoredFPC: ${await getSponsoredFPCAddress()}`);
|
|
191
|
+
|
|
192
|
+
// We no longer need the wallet once we've setup the accounts so we stop the underlying PXE job queue
|
|
193
|
+
await wallet.stop();
|
|
215
194
|
}
|
|
216
195
|
|
|
217
196
|
const stop = async () => {
|
|
@@ -219,7 +198,7 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}, userLog
|
|
|
219
198
|
await watcher?.stop();
|
|
220
199
|
};
|
|
221
200
|
|
|
222
|
-
return { node,
|
|
201
|
+
return { node, stop };
|
|
223
202
|
}
|
|
224
203
|
|
|
225
204
|
/**
|
|
@@ -228,7 +207,7 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}, userLog
|
|
|
228
207
|
*/
|
|
229
208
|
export async function createAztecNode(
|
|
230
209
|
config: Partial<AztecNodeConfig> = {},
|
|
231
|
-
deps: { telemetry?: TelemetryClient;
|
|
210
|
+
deps: { telemetry?: TelemetryClient; blobClient?: BlobClientInterface; dateProvider?: DateProvider } = {},
|
|
232
211
|
options: { prefilledPublicData?: PublicDataTreeLeaf[] } = {},
|
|
233
212
|
) {
|
|
234
213
|
// TODO(#12272): will clean this up. This is criminal.
|
|
@@ -241,13 +220,3 @@ export async function createAztecNode(
|
|
|
241
220
|
const node = await AztecNodeService.createAndSync(aztecNodeConfig, deps, options);
|
|
242
221
|
return node;
|
|
243
222
|
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Create and start a new Aztec PXE HTTP Server
|
|
247
|
-
* @param config - Optional PXE settings.
|
|
248
|
-
*/
|
|
249
|
-
export async function createAztecPXE(node: AztecNode, config: Partial<PXEServiceConfig> = {}) {
|
|
250
|
-
const pxeServiceConfig: PXEServiceConfig = { ...getPXEServiceConfig(), ...config };
|
|
251
|
-
const pxe = await createPXEService(node, pxeServiceConfig);
|
|
252
|
-
return pxe;
|
|
253
|
-
}
|