@aztec/bot 3.0.0-canary.a9708bd → 3.0.0-devnet.20251212
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/dest/amm_bot.d.ts +9 -9
- package/dest/amm_bot.d.ts.map +1 -1
- package/dest/amm_bot.js +23 -20
- package/dest/base_bot.d.ts +11 -8
- package/dest/base_bot.d.ts.map +1 -1
- package/dest/base_bot.js +18 -18
- package/dest/bot.d.ts +8 -9
- package/dest/bot.d.ts.map +1 -1
- package/dest/bot.js +11 -12
- package/dest/config.d.ts +58 -54
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +30 -24
- package/dest/factory.d.ts +14 -32
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +129 -115
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/interface.d.ts +2 -2
- package/dest/interface.d.ts.map +1 -1
- package/dest/interface.js +1 -1
- package/dest/rpc.d.ts +1 -1
- package/dest/runner.d.ts +12 -13
- package/dest/runner.d.ts.map +1 -1
- package/dest/runner.js +18 -32
- package/dest/store/bot_store.d.ts +44 -0
- package/dest/store/bot_store.d.ts.map +1 -0
- package/dest/store/bot_store.js +107 -0
- package/dest/store/index.d.ts +2 -0
- package/dest/store/index.d.ts.map +1 -0
- package/dest/store/index.js +1 -0
- package/dest/utils.d.ts +4 -4
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +5 -5
- package/package.json +16 -13
- package/src/amm_bot.ts +39 -31
- package/src/base_bot.ts +24 -22
- package/src/bot.ts +25 -14
- package/src/config.ts +32 -30
- package/src/factory.ts +162 -157
- package/src/index.ts +1 -0
- package/src/interface.ts +1 -1
- package/src/runner.ts +19 -23
- package/src/store/bot_store.ts +141 -0
- package/src/store/index.ts +1 -0
- package/src/utils.ts +10 -5
package/src/factory.ts
CHANGED
|
@@ -1,122 +1,95 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
|
|
2
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
3
|
+
import { AztecAddress } from '@aztec/aztec.js/addresses';
|
|
3
4
|
import {
|
|
4
|
-
type AccountWallet,
|
|
5
|
-
AztecAddress,
|
|
6
5
|
BatchCall,
|
|
7
6
|
ContractBase,
|
|
8
7
|
ContractFunctionInteraction,
|
|
9
8
|
type DeployMethod,
|
|
10
9
|
type DeployOptions,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from '@aztec/
|
|
18
|
-
import {
|
|
19
|
-
import { Fr } from '@aztec/foundation/
|
|
10
|
+
} from '@aztec/aztec.js/contracts';
|
|
11
|
+
import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
|
|
12
|
+
import type { L2AmountClaim } from '@aztec/aztec.js/ethereum';
|
|
13
|
+
import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
|
|
14
|
+
import { createLogger } from '@aztec/aztec.js/log';
|
|
15
|
+
import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging';
|
|
16
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
17
|
+
import { createExtendedL1Client } from '@aztec/ethereum/client';
|
|
18
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
20
19
|
import { Timer } from '@aztec/foundation/timer';
|
|
21
20
|
import { AMMContract } from '@aztec/noir-contracts.js/AMM';
|
|
22
21
|
import { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
|
|
23
22
|
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
23
|
+
import { GasSettings } from '@aztec/stdlib/gas';
|
|
24
24
|
import type { AztecNode, AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
25
25
|
import { deriveSigningKey } from '@aztec/stdlib/keys';
|
|
26
|
-
import {
|
|
26
|
+
import { TestWallet } from '@aztec/test-wallet/server';
|
|
27
27
|
|
|
28
|
-
import { type BotConfig, SupportedTokenContracts
|
|
28
|
+
import { type BotConfig, SupportedTokenContracts } from './config.js';
|
|
29
|
+
import type { BotStore } from './store/index.js';
|
|
29
30
|
import { getBalances, getPrivateBalance, isStandardTokenContract } from './utils.js';
|
|
30
31
|
|
|
31
32
|
const MINT_BALANCE = 1e12;
|
|
32
33
|
const MIN_BALANCE = 1e3;
|
|
33
34
|
|
|
34
35
|
export class BotFactory {
|
|
35
|
-
private pxe: PXE;
|
|
36
|
-
private node?: AztecNode;
|
|
37
|
-
private nodeAdmin?: AztecNodeAdmin;
|
|
38
36
|
private log = createLogger('bot');
|
|
39
37
|
|
|
40
38
|
constructor(
|
|
41
39
|
private readonly config: BotConfig,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
if (config.senderPrivateKey && config.senderPrivateKey.getValue() && !dependencies.node) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`Either a node client or node url must be provided for bridging L1 fee juice to deploy an account with private key`,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
if (!dependencies.pxe && !config.pxeUrl) {
|
|
55
|
-
throw new Error(`Either a PXE client or a PXE URL must be provided`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
this.node = dependencies.node;
|
|
59
|
-
this.nodeAdmin = dependencies.nodeAdmin;
|
|
60
|
-
|
|
61
|
-
if (dependencies.pxe) {
|
|
62
|
-
this.log.info(`Using local PXE`);
|
|
63
|
-
this.pxe = dependencies.pxe;
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
this.log.info(`Using remote PXE at ${config.pxeUrl!}`);
|
|
67
|
-
this.pxe = createPXEClient(config.pxeUrl!, getVersions(), makeTracedFetch([1, 2, 3], false));
|
|
68
|
-
}
|
|
40
|
+
private readonly wallet: TestWallet,
|
|
41
|
+
private readonly store: BotStore,
|
|
42
|
+
private readonly aztecNode: AztecNode,
|
|
43
|
+
private readonly aztecNodeAdmin?: AztecNodeAdmin,
|
|
44
|
+
) {}
|
|
69
45
|
|
|
70
46
|
/**
|
|
71
47
|
* Initializes a new bot by setting up the sender account, registering the recipient,
|
|
72
48
|
* deploying the token contract, and minting tokens if necessary.
|
|
73
49
|
*/
|
|
74
|
-
public async setup() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
50
|
+
public async setup(): Promise<{
|
|
51
|
+
wallet: TestWallet;
|
|
52
|
+
defaultAccountAddress: AztecAddress;
|
|
53
|
+
token: TokenContract | PrivateTokenContract;
|
|
54
|
+
node: AztecNode;
|
|
55
|
+
recipient: AztecAddress;
|
|
56
|
+
}> {
|
|
57
|
+
const recipient = (await this.wallet.createAccount()).address;
|
|
58
|
+
const defaultAccountAddress = await this.setupAccount();
|
|
59
|
+
const token = await this.setupToken(defaultAccountAddress);
|
|
79
60
|
await this.mintTokens(token, defaultAccountAddress);
|
|
80
|
-
return { wallet, defaultAccountAddress, token,
|
|
61
|
+
return { wallet: this.wallet, defaultAccountAddress, token, node: this.aztecNode, recipient };
|
|
81
62
|
}
|
|
82
63
|
|
|
83
|
-
public async setupAmm() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
);
|
|
93
|
-
const token1 = await this.setupTokenContract(
|
|
94
|
-
wallet,
|
|
95
|
-
wallet.getAddress(),
|
|
96
|
-
this.config.tokenSalt,
|
|
97
|
-
'BotToken1',
|
|
98
|
-
'BOT1',
|
|
99
|
-
);
|
|
64
|
+
public async setupAmm(): Promise<{
|
|
65
|
+
wallet: TestWallet;
|
|
66
|
+
defaultAccountAddress: AztecAddress;
|
|
67
|
+
amm: AMMContract;
|
|
68
|
+
token0: TokenContract;
|
|
69
|
+
token1: TokenContract;
|
|
70
|
+
node: AztecNode;
|
|
71
|
+
}> {
|
|
72
|
+
const defaultAccountAddress = await this.setupAccount();
|
|
73
|
+
const token0 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken0', 'BOT0');
|
|
74
|
+
const token1 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken1', 'BOT1');
|
|
100
75
|
const liquidityToken = await this.setupTokenContract(
|
|
101
|
-
|
|
102
|
-
wallet.getAddress(),
|
|
76
|
+
defaultAccountAddress,
|
|
103
77
|
this.config.tokenSalt,
|
|
104
78
|
'BotLPToken',
|
|
105
79
|
'BOTLP',
|
|
106
80
|
);
|
|
107
81
|
const amm = await this.setupAmmContract(
|
|
108
|
-
|
|
109
|
-
wallet.getAddress(),
|
|
82
|
+
defaultAccountAddress,
|
|
110
83
|
this.config.tokenSalt,
|
|
111
84
|
token0,
|
|
112
85
|
token1,
|
|
113
86
|
liquidityToken,
|
|
114
87
|
);
|
|
115
88
|
|
|
116
|
-
await this.fundAmm(
|
|
89
|
+
await this.fundAmm(defaultAccountAddress, defaultAccountAddress, amm, token0, token1, liquidityToken);
|
|
117
90
|
this.log.info(`AMM initialized and funded`);
|
|
118
91
|
|
|
119
|
-
return { wallet, defaultAccountAddress, amm, token0, token1,
|
|
92
|
+
return { wallet: this.wallet, defaultAccountAddress, amm, token0, token1, node: this.aztecNode };
|
|
120
93
|
}
|
|
121
94
|
|
|
122
95
|
/**
|
|
@@ -124,64 +97,65 @@ export class BotFactory {
|
|
|
124
97
|
* @returns The sender wallet.
|
|
125
98
|
*/
|
|
126
99
|
private async setupAccount() {
|
|
127
|
-
const privateKey = this.config.senderPrivateKey
|
|
100
|
+
const privateKey = this.config.senderPrivateKey?.getValue();
|
|
128
101
|
if (privateKey) {
|
|
102
|
+
this.log.info(`Setting up account with provided private key`);
|
|
129
103
|
return await this.setupAccountWithPrivateKey(privateKey);
|
|
130
104
|
} else {
|
|
105
|
+
this.log.info(`Setting up test account`);
|
|
131
106
|
return await this.setupTestAccount();
|
|
132
107
|
}
|
|
133
108
|
}
|
|
134
109
|
|
|
135
|
-
private async setupAccountWithPrivateKey(
|
|
110
|
+
private async setupAccountWithPrivateKey(secret: Fr) {
|
|
136
111
|
const salt = this.config.senderSalt ?? Fr.ONE;
|
|
137
|
-
const signingKey = deriveSigningKey(
|
|
138
|
-
const
|
|
139
|
-
|
|
112
|
+
const signingKey = deriveSigningKey(secret);
|
|
113
|
+
const accountData = {
|
|
114
|
+
secret,
|
|
115
|
+
salt,
|
|
116
|
+
contract: new SchnorrAccountContract(signingKey!),
|
|
117
|
+
};
|
|
118
|
+
const accountManager = await this.wallet.createAccount(accountData);
|
|
119
|
+
const isInit = (await this.wallet.getContractMetadata(accountManager.address)).isContractInitialized;
|
|
140
120
|
if (isInit) {
|
|
141
|
-
this.log.info(`Account at ${
|
|
121
|
+
this.log.info(`Account at ${accountManager.address.toString()} already initialized`);
|
|
142
122
|
const timer = new Timer();
|
|
143
|
-
const
|
|
144
|
-
this.log.info(`Account at ${
|
|
145
|
-
|
|
123
|
+
const address = accountManager.address;
|
|
124
|
+
this.log.info(`Account at ${address} registered. duration=${timer.ms()}`);
|
|
125
|
+
await this.store.deleteBridgeClaim(address);
|
|
126
|
+
return address;
|
|
146
127
|
} else {
|
|
147
|
-
const address =
|
|
128
|
+
const address = accountManager.address;
|
|
148
129
|
this.log.info(`Deploying account at ${address}`);
|
|
149
130
|
|
|
150
|
-
const claim = await this.
|
|
131
|
+
const claim = await this.getOrCreateBridgeClaim(address);
|
|
151
132
|
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const
|
|
133
|
+
const paymentMethod = new FeeJuicePaymentMethodWithClaim(accountManager.address, claim);
|
|
134
|
+
const deployMethod = await accountManager.getDeployMethod();
|
|
135
|
+
const maxFeesPerGas = (await this.aztecNode.getCurrentBaseFees()).mul(1 + this.config.baseFeePadding);
|
|
136
|
+
const gasSettings = GasSettings.default({ maxFeesPerGas });
|
|
137
|
+
const sentTx = deployMethod.send({ from: AztecAddress.ZERO, fee: { gasSettings, paymentMethod } });
|
|
156
138
|
const txHash = await sentTx.getTxHash();
|
|
157
|
-
// docs:end:claim_and_deploy
|
|
158
139
|
this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
|
|
159
140
|
await this.withNoMinTxsPerBlock(() => sentTx.wait({ timeout: this.config.txMinedWaitSeconds }));
|
|
160
141
|
this.log.info(`Account deployed at ${address}`);
|
|
161
|
-
return wallet;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
142
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
} else {
|
|
170
|
-
this.log.info('Registering funded test account');
|
|
171
|
-
const [account] = await getInitialTestAccounts();
|
|
172
|
-
const manager = await getSchnorrAccount(this.pxe, account.secret, account.signingKey, account.salt);
|
|
173
|
-
wallet = await manager.register();
|
|
174
|
-
this.log.info(`Funded test account registered: ${wallet.getAddress()}`);
|
|
143
|
+
// Clean up the consumed bridge claim
|
|
144
|
+
await this.store.deleteBridgeClaim(address);
|
|
145
|
+
|
|
146
|
+
return accountManager.address;
|
|
175
147
|
}
|
|
176
|
-
return wallet;
|
|
177
148
|
}
|
|
178
149
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
150
|
+
private async setupTestAccount() {
|
|
151
|
+
const [initialAccountData] = await getInitialTestAccountsData();
|
|
152
|
+
const accountData = {
|
|
153
|
+
secret: initialAccountData.secret,
|
|
154
|
+
salt: initialAccountData.salt,
|
|
155
|
+
contract: new SchnorrAccountContract(initialAccountData.signingKey),
|
|
156
|
+
};
|
|
157
|
+
const accountManager = await this.wallet.createAccount(accountData);
|
|
158
|
+
return accountManager.address;
|
|
185
159
|
}
|
|
186
160
|
|
|
187
161
|
/**
|
|
@@ -189,7 +163,7 @@ export class BotFactory {
|
|
|
189
163
|
* @param wallet - Wallet to deploy the token contract from.
|
|
190
164
|
* @returns The TokenContract instance.
|
|
191
165
|
*/
|
|
192
|
-
private async setupToken(
|
|
166
|
+
private async setupToken(sender: AztecAddress): Promise<TokenContract | PrivateTokenContract> {
|
|
193
167
|
let deploy: DeployMethod<TokenContract | PrivateTokenContract>;
|
|
194
168
|
const deployOpts: DeployOptions = {
|
|
195
169
|
from: sender,
|
|
@@ -197,9 +171,9 @@ export class BotFactory {
|
|
|
197
171
|
universalDeploy: true,
|
|
198
172
|
};
|
|
199
173
|
if (this.config.contract === SupportedTokenContracts.TokenContract) {
|
|
200
|
-
deploy = TokenContract.deploy(wallet, sender, 'BotToken', 'BOT', 18);
|
|
174
|
+
deploy = TokenContract.deploy(this.wallet, sender, 'BotToken', 'BOT', 18);
|
|
201
175
|
} else if (this.config.contract === SupportedTokenContracts.PrivateTokenContract) {
|
|
202
|
-
deploy = PrivateTokenContract.deploy(wallet, MINT_BALANCE, sender);
|
|
176
|
+
deploy = PrivateTokenContract.deploy(this.wallet, MINT_BALANCE, sender);
|
|
203
177
|
deployOpts.skipInstancePublication = true;
|
|
204
178
|
deployOpts.skipClassPublication = true;
|
|
205
179
|
deployOpts.skipInitialization = false;
|
|
@@ -208,7 +182,7 @@ export class BotFactory {
|
|
|
208
182
|
}
|
|
209
183
|
|
|
210
184
|
const address = (await deploy.getInstance(deployOpts)).address;
|
|
211
|
-
if ((await this.
|
|
185
|
+
if ((await this.wallet.getContractMetadata(address)).isContractPublished) {
|
|
212
186
|
this.log.info(`Token at ${address.toString()} already deployed`);
|
|
213
187
|
return deploy.register();
|
|
214
188
|
} else {
|
|
@@ -226,7 +200,6 @@ export class BotFactory {
|
|
|
226
200
|
* @returns The TokenContract instance.
|
|
227
201
|
*/
|
|
228
202
|
private setupTokenContract(
|
|
229
|
-
wallet: AccountWallet,
|
|
230
203
|
deployer: AztecAddress,
|
|
231
204
|
contractAddressSalt: Fr,
|
|
232
205
|
name: string,
|
|
@@ -234,12 +207,11 @@ export class BotFactory {
|
|
|
234
207
|
decimals = 18,
|
|
235
208
|
): Promise<TokenContract> {
|
|
236
209
|
const deployOpts: DeployOptions = { from: deployer, contractAddressSalt, universalDeploy: true };
|
|
237
|
-
const deploy = TokenContract.deploy(wallet, deployer, name, ticker, decimals);
|
|
210
|
+
const deploy = TokenContract.deploy(this.wallet, deployer, name, ticker, decimals);
|
|
238
211
|
return this.registerOrDeployContract('Token - ' + name, deploy, deployOpts);
|
|
239
212
|
}
|
|
240
213
|
|
|
241
214
|
private async setupAmmContract(
|
|
242
|
-
wallet: AccountWallet,
|
|
243
215
|
deployer: AztecAddress,
|
|
244
216
|
contractAddressSalt: Fr,
|
|
245
217
|
token0: TokenContract,
|
|
@@ -247,7 +219,7 @@ export class BotFactory {
|
|
|
247
219
|
lpToken: TokenContract,
|
|
248
220
|
): Promise<AMMContract> {
|
|
249
221
|
const deployOpts: DeployOptions = { from: deployer, contractAddressSalt, universalDeploy: true };
|
|
250
|
-
const deploy = AMMContract.deploy(wallet, token0.address, token1.address, lpToken.address);
|
|
222
|
+
const deploy = AMMContract.deploy(this.wallet, token0.address, token1.address, lpToken.address);
|
|
251
223
|
const amm = await this.registerOrDeployContract('AMM', deploy, deployOpts);
|
|
252
224
|
|
|
253
225
|
this.log.info(`AMM deployed at ${amm.address}`);
|
|
@@ -260,7 +232,7 @@ export class BotFactory {
|
|
|
260
232
|
}
|
|
261
233
|
|
|
262
234
|
private async fundAmm(
|
|
263
|
-
|
|
235
|
+
defaultAccountAddress: AztecAddress,
|
|
264
236
|
liquidityProvider: AztecAddress,
|
|
265
237
|
amm: AMMContract,
|
|
266
238
|
token0: TokenContract,
|
|
@@ -289,26 +261,30 @@ export class BotFactory {
|
|
|
289
261
|
);
|
|
290
262
|
|
|
291
263
|
// Add authwitnesses for the transfers in AMM::add_liquidity function
|
|
292
|
-
const token0Authwit = await wallet.createAuthWit({
|
|
264
|
+
const token0Authwit = await this.wallet.createAuthWit(defaultAccountAddress, {
|
|
293
265
|
caller: amm.address,
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
266
|
+
call: await token0.methods
|
|
267
|
+
.transfer_to_public_and_prepare_private_balance_increase(
|
|
268
|
+
liquidityProvider,
|
|
269
|
+
amm.address,
|
|
270
|
+
amount0Max,
|
|
271
|
+
authwitNonce,
|
|
272
|
+
)
|
|
273
|
+
.getFunctionCall(),
|
|
300
274
|
});
|
|
301
|
-
const token1Authwit = await wallet.createAuthWit({
|
|
275
|
+
const token1Authwit = await this.wallet.createAuthWit(defaultAccountAddress, {
|
|
302
276
|
caller: amm.address,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
277
|
+
call: await token1.methods
|
|
278
|
+
.transfer_to_public_and_prepare_private_balance_increase(
|
|
279
|
+
liquidityProvider,
|
|
280
|
+
amm.address,
|
|
281
|
+
amount1Max,
|
|
282
|
+
authwitNonce,
|
|
283
|
+
)
|
|
284
|
+
.getFunctionCall(),
|
|
309
285
|
});
|
|
310
286
|
|
|
311
|
-
const mintTx = new BatchCall(wallet, [
|
|
287
|
+
const mintTx = new BatchCall(this.wallet, [
|
|
312
288
|
token0.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
|
|
313
289
|
token1.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
|
|
314
290
|
]).send({ from: liquidityProvider });
|
|
@@ -329,7 +305,7 @@ export class BotFactory {
|
|
|
329
305
|
|
|
330
306
|
const [newT0Bal, newT1Bal, newLPBal] = await getPrivateBalances();
|
|
331
307
|
this.log.info(
|
|
332
|
-
`Updated private balances of ${
|
|
308
|
+
`Updated private balances of ${defaultAccountAddress} after minting and funding AMM: token0=${newT0Bal}, token1=${newT1Bal}, lp=${newLPBal}`,
|
|
333
309
|
);
|
|
334
310
|
}
|
|
335
311
|
|
|
@@ -339,7 +315,7 @@ export class BotFactory {
|
|
|
339
315
|
deployOpts: DeployOptions,
|
|
340
316
|
): Promise<T> {
|
|
341
317
|
const address = (await deploy.getInstance(deployOpts)).address;
|
|
342
|
-
if ((await this.
|
|
318
|
+
if ((await this.wallet.getContractMetadata(address)).isContractPublished) {
|
|
343
319
|
this.log.info(`Contract ${name} at ${address.toString()} already deployed`);
|
|
344
320
|
return deploy.register();
|
|
345
321
|
} else {
|
|
@@ -390,7 +366,40 @@ export class BotFactory {
|
|
|
390
366
|
await this.withNoMinTxsPerBlock(() => sentTx.wait({ timeout: this.config.txMinedWaitSeconds }));
|
|
391
367
|
}
|
|
392
368
|
|
|
393
|
-
|
|
369
|
+
/**
|
|
370
|
+
* Gets or creates a bridge claim for the recipient.
|
|
371
|
+
* Checks if a claim already exists in the store and reuses it if valid.
|
|
372
|
+
* Only creates a new bridge if fee juice balance is below threshold.
|
|
373
|
+
*/
|
|
374
|
+
private async getOrCreateBridgeClaim(recipient: AztecAddress): Promise<L2AmountClaim> {
|
|
375
|
+
// Check if we have an existing claim in the store
|
|
376
|
+
const existingClaim = await this.store.getBridgeClaim(recipient);
|
|
377
|
+
if (existingClaim) {
|
|
378
|
+
this.log.info(`Found existing bridge claim for ${recipient.toString()}, checking validity...`);
|
|
379
|
+
|
|
380
|
+
// Check if the message is ready on L2
|
|
381
|
+
try {
|
|
382
|
+
const messageHash = Fr.fromHexString(existingClaim.claim.messageHash);
|
|
383
|
+
await this.withNoMinTxsPerBlock(() =>
|
|
384
|
+
waitForL1ToL2MessageReady(this.aztecNode, messageHash, {
|
|
385
|
+
timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
|
|
386
|
+
forPublicConsumption: false,
|
|
387
|
+
}),
|
|
388
|
+
);
|
|
389
|
+
return existingClaim.claim;
|
|
390
|
+
} catch (err) {
|
|
391
|
+
this.log.warn(`Failed to verify existing claim, creating new one: ${err}`);
|
|
392
|
+
await this.store.deleteBridgeClaim(recipient);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const claim = await this.bridgeL1FeeJuice(recipient);
|
|
397
|
+
await this.store.saveBridgeClaim(recipient, claim);
|
|
398
|
+
|
|
399
|
+
return claim;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private async bridgeL1FeeJuice(recipient: AztecAddress): Promise<L2AmountClaim> {
|
|
394
403
|
const l1RpcUrls = this.config.l1RpcUrls;
|
|
395
404
|
if (!l1RpcUrls?.length) {
|
|
396
405
|
throw new Error('L1 Rpc url is required to bridge the fee juice to fund the deployment of the account.');
|
|
@@ -402,43 +411,39 @@ export class BotFactory {
|
|
|
402
411
|
);
|
|
403
412
|
}
|
|
404
413
|
|
|
405
|
-
const { l1ChainId } = await this.
|
|
414
|
+
const { l1ChainId } = await this.aztecNode.getNodeInfo();
|
|
406
415
|
const chain = createEthereumChain(l1RpcUrls, l1ChainId);
|
|
407
416
|
const extendedClient = createExtendedL1Client(chain.rpcUrls, mnemonicOrPrivateKey, chain.chainInfo);
|
|
408
417
|
|
|
409
|
-
const portal = await L1FeeJuicePortalManager.new(this.
|
|
418
|
+
const portal = await L1FeeJuicePortalManager.new(this.aztecNode, extendedClient, this.log);
|
|
410
419
|
const mintAmount = await portal.getTokenManager().getMintAmount();
|
|
411
420
|
const claim = await portal.bridgeTokensPublic(recipient, mintAmount, true /* mint */);
|
|
412
421
|
|
|
413
|
-
|
|
414
|
-
|
|
422
|
+
await this.withNoMinTxsPerBlock(() =>
|
|
423
|
+
waitForL1ToL2MessageReady(this.aztecNode, Fr.fromHexString(claim.messageHash), {
|
|
424
|
+
timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
|
|
425
|
+
forPublicConsumption: false,
|
|
426
|
+
}),
|
|
427
|
+
);
|
|
415
428
|
|
|
416
429
|
this.log.info(`Created a claim for ${mintAmount} L1 fee juice to ${recipient}.`, claim);
|
|
417
430
|
|
|
418
|
-
|
|
419
|
-
await this.advanceL2Block();
|
|
420
|
-
await this.advanceL2Block();
|
|
421
|
-
|
|
422
|
-
return claim;
|
|
431
|
+
return claim as L2AmountClaim;
|
|
423
432
|
}
|
|
424
433
|
|
|
425
434
|
private async withNoMinTxsPerBlock<T>(fn: () => Promise<T>): Promise<T> {
|
|
426
|
-
if (!this.
|
|
435
|
+
if (!this.aztecNodeAdmin || !this.config.flushSetupTransactions) {
|
|
436
|
+
this.log.verbose(`No node admin client or flushing not requested (not setting minTxsPerBlock to 0)`);
|
|
427
437
|
return fn();
|
|
428
438
|
}
|
|
429
|
-
const { minTxsPerBlock } = await this.
|
|
430
|
-
|
|
439
|
+
const { minTxsPerBlock } = await this.aztecNodeAdmin.getConfig();
|
|
440
|
+
this.log.warn(`Setting sequencer minTxsPerBlock to 0 from ${minTxsPerBlock} to flush setup transactions`);
|
|
441
|
+
await this.aztecNodeAdmin.setConfig({ minTxsPerBlock: 0 });
|
|
431
442
|
try {
|
|
432
443
|
return await fn();
|
|
433
444
|
} finally {
|
|
434
|
-
|
|
445
|
+
this.log.warn(`Restoring sequencer minTxsPerBlock to ${minTxsPerBlock}`);
|
|
446
|
+
await this.aztecNodeAdmin.setConfig({ minTxsPerBlock });
|
|
435
447
|
}
|
|
436
448
|
}
|
|
437
|
-
|
|
438
|
-
private async advanceL2Block() {
|
|
439
|
-
await this.withNoMinTxsPerBlock(async () => {
|
|
440
|
-
const initialBlockNumber = await this.node!.getBlockNumber();
|
|
441
|
-
await retryUntil(async () => (await this.node!.getBlockNumber()) >= initialBlockNumber + 1);
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
449
|
}
|
package/src/index.ts
CHANGED
package/src/interface.ts
CHANGED
package/src/runner.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLogger } from '@aztec/aztec.js/log';
|
|
2
|
+
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
2
3
|
import { omit } from '@aztec/foundation/collection';
|
|
3
4
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
4
|
-
import {
|
|
5
|
-
import { type TelemetryClient, type Traceable, type Tracer,
|
|
5
|
+
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
6
|
+
import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
7
|
+
import type { TestWallet } from '@aztec/test-wallet/server';
|
|
6
8
|
|
|
7
9
|
import { AmmBot } from './amm_bot.js';
|
|
8
10
|
import type { BaseBot } from './base_bot.js';
|
|
9
11
|
import { Bot } from './bot.js';
|
|
10
|
-
import {
|
|
12
|
+
import type { BotConfig } from './config.js';
|
|
11
13
|
import type { BotInfo, BotRunnerApi } from './interface.js';
|
|
14
|
+
import { BotStore } from './store/index.js';
|
|
12
15
|
|
|
13
16
|
export class BotRunner implements BotRunnerApi, Traceable {
|
|
14
17
|
private log = createLogger('bot');
|
|
15
18
|
private bot?: Promise<BaseBot>;
|
|
16
|
-
private pxe?: PXE;
|
|
17
|
-
private node: AztecNode;
|
|
18
|
-
private nodeAdmin?: AztecNodeAdmin;
|
|
19
19
|
private runningPromise: RunningPromise;
|
|
20
20
|
private consecutiveErrors = 0;
|
|
21
21
|
private healthy = true;
|
|
@@ -24,19 +24,14 @@ export class BotRunner implements BotRunnerApi, Traceable {
|
|
|
24
24
|
|
|
25
25
|
public constructor(
|
|
26
26
|
private config: BotConfig,
|
|
27
|
-
|
|
27
|
+
private readonly wallet: TestWallet,
|
|
28
|
+
private readonly aztecNode: AztecNode,
|
|
29
|
+
private readonly telemetry: TelemetryClient,
|
|
30
|
+
private readonly aztecNodeAdmin: AztecNodeAdmin | undefined,
|
|
31
|
+
private readonly store: BotStore,
|
|
28
32
|
) {
|
|
29
|
-
this.tracer =
|
|
30
|
-
|
|
31
|
-
if (!dependencies.node && !config.nodeUrl) {
|
|
32
|
-
throw new Error(`Missing node URL in config or dependencies`);
|
|
33
|
-
}
|
|
34
|
-
const versions = getVersions();
|
|
35
|
-
const fetch = makeTracedFetch([1, 2, 3], true);
|
|
36
|
-
this.node = dependencies.node ?? createAztecNodeClient(config.nodeUrl!, versions, fetch);
|
|
37
|
-
this.nodeAdmin =
|
|
38
|
-
dependencies.nodeAdmin ??
|
|
39
|
-
(config.nodeAdminUrl ? createAztecNodeAdminClient(config.nodeAdminUrl, versions, fetch) : undefined);
|
|
33
|
+
this.tracer = telemetry.getTracer('Bot');
|
|
34
|
+
|
|
40
35
|
this.runningPromise = new RunningPromise(() => this.#work(), this.log, config.txIntervalSeconds * 1000);
|
|
41
36
|
}
|
|
42
37
|
|
|
@@ -74,6 +69,7 @@ export class BotRunner implements BotRunnerApi, Traceable {
|
|
|
74
69
|
this.log.verbose(`Stopping bot`);
|
|
75
70
|
await this.runningPromise.stop();
|
|
76
71
|
}
|
|
72
|
+
await this.store.close();
|
|
77
73
|
this.log.info(`Stopped bot`);
|
|
78
74
|
}
|
|
79
75
|
|
|
@@ -144,15 +140,15 @@ export class BotRunner implements BotRunnerApi, Traceable {
|
|
|
144
140
|
if (!this.bot) {
|
|
145
141
|
throw new Error(`Bot is not initialized`);
|
|
146
142
|
}
|
|
147
|
-
const botAddress = await this.bot.then(b => b.
|
|
143
|
+
const botAddress = await this.bot.then(b => b.defaultAccountAddress);
|
|
148
144
|
return { botAddress };
|
|
149
145
|
}
|
|
150
146
|
|
|
151
147
|
async #createBot() {
|
|
152
148
|
try {
|
|
153
149
|
this.bot = this.config.ammTxs
|
|
154
|
-
? AmmBot.create(this.config,
|
|
155
|
-
: Bot.create(this.config,
|
|
150
|
+
? AmmBot.create(this.config, this.wallet, this.aztecNode, this.aztecNodeAdmin, this.store)
|
|
151
|
+
: Bot.create(this.config, this.wallet, this.aztecNode, this.aztecNodeAdmin, this.store);
|
|
156
152
|
await this.bot;
|
|
157
153
|
} catch (err) {
|
|
158
154
|
this.log.error(`Error setting up bot: ${err}`);
|
|
@@ -163,7 +159,7 @@ export class BotRunner implements BotRunnerApi, Traceable {
|
|
|
163
159
|
@trackSpan('Bot.work')
|
|
164
160
|
async #work() {
|
|
165
161
|
if (this.config.maxPendingTxs > 0) {
|
|
166
|
-
const pendingTxCount = await this.
|
|
162
|
+
const pendingTxCount = await this.aztecNode.getPendingTxCount();
|
|
167
163
|
if (pendingTxCount >= this.config.maxPendingTxs) {
|
|
168
164
|
this.log.verbose(`Not sending bot tx since node has ${pendingTxCount} pending txs`);
|
|
169
165
|
return;
|