@aztec/bot 0.0.0-test.1 → 0.0.1-fake-ceab37513c
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 +33 -0
- package/dest/amm_bot.d.ts.map +1 -0
- package/dest/amm_bot.js +94 -0
- package/dest/base_bot.d.ts +18 -0
- package/dest/base_bot.d.ts.map +1 -0
- package/dest/base_bot.js +80 -0
- package/dest/bot.d.ts +10 -14
- package/dest/bot.d.ts.map +1 -1
- package/dest/bot.js +21 -82
- package/dest/config.d.ts +51 -30
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +40 -19
- package/dest/factory.d.ts +27 -6
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +200 -75
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -1
- package/dest/interface.d.ts +11 -0
- package/dest/interface.d.ts.map +1 -1
- package/dest/interface.js +5 -0
- package/dest/rpc.d.ts +0 -6
- package/dest/rpc.d.ts.map +1 -1
- package/dest/rpc.js +0 -11
- package/dest/runner.d.ts +6 -1
- package/dest/runner.d.ts.map +1 -1
- package/dest/runner.js +31 -9
- package/dest/utils.d.ts +6 -3
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +12 -3
- package/package.json +22 -21
- package/src/amm_bot.ts +116 -0
- package/src/base_bot.ts +94 -0
- package/src/bot.ts +36 -98
- package/src/config.ts +52 -22
- package/src/factory.ts +256 -78
- package/src/index.ts +2 -1
- package/src/interface.ts +9 -0
- package/src/rpc.ts +0 -13
- package/src/runner.ts +32 -11
- package/src/utils.ts +12 -6
package/src/bot.ts
CHANGED
|
@@ -1,40 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
FeeJuicePaymentMethod,
|
|
5
|
-
type SendMethodOptions,
|
|
6
|
-
type Wallet,
|
|
7
|
-
createLogger,
|
|
8
|
-
} from '@aztec/aztec.js';
|
|
9
|
-
import { timesParallel } from '@aztec/foundation/collection';
|
|
10
|
-
import type { EasyPrivateTokenContract } from '@aztec/noir-contracts.js/EasyPrivateToken';
|
|
1
|
+
import { type AztecAddress, BatchCall, SentTx, type Wallet } from '@aztec/aztec.js';
|
|
2
|
+
import { times } from '@aztec/foundation/collection';
|
|
3
|
+
import type { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
|
|
11
4
|
import type { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
12
|
-
import type {
|
|
13
|
-
import { Gas } from '@aztec/stdlib/gas';
|
|
14
|
-
import type { AztecNode, PXE } from '@aztec/stdlib/interfaces/client';
|
|
5
|
+
import type { AztecNode, AztecNodeAdmin, PXE } from '@aztec/stdlib/interfaces/client';
|
|
15
6
|
|
|
7
|
+
import { BaseBot } from './base_bot.js';
|
|
16
8
|
import type { BotConfig } from './config.js';
|
|
17
9
|
import { BotFactory } from './factory.js';
|
|
18
10
|
import { getBalances, getPrivateBalance, isStandardTokenContract } from './utils.js';
|
|
19
11
|
|
|
20
12
|
const TRANSFER_AMOUNT = 1;
|
|
21
13
|
|
|
22
|
-
export class Bot {
|
|
23
|
-
private log = createLogger('bot');
|
|
24
|
-
|
|
25
|
-
private attempts: number = 0;
|
|
26
|
-
private successes: number = 0;
|
|
27
|
-
|
|
14
|
+
export class Bot extends BaseBot {
|
|
28
15
|
protected constructor(
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
pxe: PXE,
|
|
17
|
+
wallet: Wallet,
|
|
18
|
+
defaultAccountAddress: AztecAddress,
|
|
19
|
+
public readonly token: TokenContract | PrivateTokenContract,
|
|
31
20
|
public readonly recipient: AztecAddress,
|
|
32
|
-
|
|
33
|
-
) {
|
|
21
|
+
config: BotConfig,
|
|
22
|
+
) {
|
|
23
|
+
super(pxe, wallet, defaultAccountAddress, config);
|
|
24
|
+
}
|
|
34
25
|
|
|
35
|
-
static async create(
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
static async create(
|
|
27
|
+
config: BotConfig,
|
|
28
|
+
dependencies: { pxe?: PXE; node?: AztecNode; nodeAdmin?: AztecNodeAdmin },
|
|
29
|
+
): Promise<Bot> {
|
|
30
|
+
const { pxe, wallet, defaultAccountAddress, token, recipient } = await new BotFactory(config, dependencies).setup();
|
|
31
|
+
return new Bot(pxe, wallet, defaultAccountAddress, token, recipient, config);
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
public updateConfig(config: Partial<BotConfig>) {
|
|
@@ -42,84 +36,47 @@ export class Bot {
|
|
|
42
36
|
this.config = { ...this.config, ...config };
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
this.
|
|
47
|
-
const logCtx = { runId: Date.now() * 1000 + Math.floor(Math.random() * 1000) };
|
|
48
|
-
const { privateTransfersPerTx, publicTransfersPerTx, feePaymentMethod, followChain, txMinedWaitSeconds } =
|
|
49
|
-
this.config;
|
|
39
|
+
protected async createAndSendTx(logCtx: object): Promise<SentTx> {
|
|
40
|
+
const { privateTransfersPerTx, publicTransfersPerTx, feePaymentMethod } = this.config;
|
|
50
41
|
const { token, recipient, wallet } = this;
|
|
51
|
-
const sender = wallet.getAddress();
|
|
52
42
|
|
|
53
43
|
this.log.verbose(
|
|
54
44
|
`Preparing tx with ${feePaymentMethod} fee with ${privateTransfersPerTx} private and ${publicTransfersPerTx} public transfers`,
|
|
55
45
|
logCtx,
|
|
56
46
|
);
|
|
57
47
|
|
|
58
|
-
const calls
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)),
|
|
69
|
-
);
|
|
70
|
-
} else {
|
|
71
|
-
calls.push(
|
|
72
|
-
...(await timesParallel(privateTransfersPerTx, () =>
|
|
73
|
-
token.methods.transfer(TRANSFER_AMOUNT, sender, recipient).request(),
|
|
74
|
-
)),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
48
|
+
const calls = isStandardTokenContract(token)
|
|
49
|
+
? [
|
|
50
|
+
times(privateTransfersPerTx, () => token.methods.transfer(recipient, TRANSFER_AMOUNT)),
|
|
51
|
+
times(publicTransfersPerTx, () =>
|
|
52
|
+
token.methods.transfer_in_public(this.defaultAccountAddress, recipient, TRANSFER_AMOUNT, 0),
|
|
53
|
+
),
|
|
54
|
+
].flat()
|
|
55
|
+
: times(privateTransfersPerTx, () =>
|
|
56
|
+
token.methods.transfer(TRANSFER_AMOUNT, this.defaultAccountAddress, recipient),
|
|
57
|
+
);
|
|
77
58
|
|
|
78
59
|
const opts = this.getSendMethodOpts();
|
|
79
60
|
const batch = new BatchCall(wallet, calls);
|
|
80
61
|
|
|
81
62
|
this.log.verbose(`Simulating transaction with ${calls.length}`, logCtx);
|
|
82
|
-
await batch.simulate();
|
|
63
|
+
await batch.simulate({ from: this.defaultAccountAddress });
|
|
83
64
|
|
|
84
65
|
this.log.verbose(`Proving transaction`, logCtx);
|
|
85
66
|
const provenTx = await batch.prove(opts);
|
|
86
|
-
|
|
87
|
-
this.log.verbose(`Sending tx`, logCtx);
|
|
88
|
-
const tx = provenTx.send();
|
|
89
|
-
|
|
90
|
-
const txHash = await tx.getTxHash();
|
|
91
|
-
|
|
92
|
-
if (followChain === 'NONE') {
|
|
93
|
-
this.log.info(`Transaction ${txHash} sent, not waiting for it to be mined`);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
this.log.verbose(
|
|
98
|
-
`Awaiting tx ${txHash} to be on the ${followChain} chain (timeout ${txMinedWaitSeconds}s)`,
|
|
99
|
-
logCtx,
|
|
100
|
-
);
|
|
101
|
-
const receipt = await tx.wait({
|
|
102
|
-
timeout: txMinedWaitSeconds,
|
|
103
|
-
provenTimeout: txMinedWaitSeconds,
|
|
104
|
-
proven: followChain === 'PROVEN',
|
|
105
|
-
});
|
|
106
|
-
this.log.info(
|
|
107
|
-
`Tx #${this.attempts} ${receipt.txHash} successfully mined in block ${receipt.blockNumber} (stats: ${this.successes}/${this.attempts} success)`,
|
|
108
|
-
logCtx,
|
|
109
|
-
);
|
|
110
|
-
this.successes++;
|
|
67
|
+
return provenTx.send();
|
|
111
68
|
}
|
|
112
69
|
|
|
113
70
|
public async getBalances() {
|
|
114
71
|
if (isStandardTokenContract(this.token)) {
|
|
115
72
|
return {
|
|
116
|
-
sender: await getBalances(this.token, this.
|
|
73
|
+
sender: await getBalances(this.token, this.defaultAccountAddress),
|
|
117
74
|
recipient: await getBalances(this.token, this.recipient),
|
|
118
75
|
};
|
|
119
76
|
} else {
|
|
120
77
|
return {
|
|
121
78
|
sender: {
|
|
122
|
-
privateBalance: await getPrivateBalance(this.token, this.
|
|
79
|
+
privateBalance: await getPrivateBalance(this.token, this.defaultAccountAddress),
|
|
123
80
|
publicBalance: 0n,
|
|
124
81
|
},
|
|
125
82
|
recipient: {
|
|
@@ -129,23 +86,4 @@ export class Bot {
|
|
|
129
86
|
};
|
|
130
87
|
}
|
|
131
88
|
}
|
|
132
|
-
|
|
133
|
-
private getSendMethodOpts(): SendMethodOptions {
|
|
134
|
-
const sender = this.wallet.getAddress();
|
|
135
|
-
const { l2GasLimit, daGasLimit, skipPublicSimulation } = this.config;
|
|
136
|
-
const paymentMethod = new FeeJuicePaymentMethod(sender);
|
|
137
|
-
|
|
138
|
-
let gasSettings, estimateGas;
|
|
139
|
-
if (l2GasLimit !== undefined && l2GasLimit > 0 && daGasLimit !== undefined && daGasLimit > 0) {
|
|
140
|
-
gasSettings = { gasLimits: Gas.from({ l2Gas: l2GasLimit, daGas: daGasLimit }) };
|
|
141
|
-
estimateGas = false;
|
|
142
|
-
this.log.verbose(`Using gas limits ${l2GasLimit} L2 gas ${daGasLimit} DA gas`);
|
|
143
|
-
} else {
|
|
144
|
-
estimateGas = true;
|
|
145
|
-
this.log.verbose(`Estimating gas for transaction`);
|
|
146
|
-
}
|
|
147
|
-
const baseFeePadding = 2; // Send 3x the current base fee
|
|
148
|
-
this.log.verbose(skipPublicSimulation ? `Skipping public simulation` : `Simulating public transfers`);
|
|
149
|
-
return { fee: { estimateGas, paymentMethod, gasSettings, baseFeePadding }, skipPublicSimulation };
|
|
150
|
-
}
|
|
151
89
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
|
+
SecretValue,
|
|
3
4
|
booleanConfigHelper,
|
|
4
5
|
getConfigFromMappings,
|
|
5
6
|
getDefaultConfig,
|
|
6
7
|
numberConfigHelper,
|
|
7
8
|
optionalNumberConfigHelper,
|
|
9
|
+
secretFrConfigHelper,
|
|
10
|
+
secretStringConfigHelper,
|
|
8
11
|
} from '@aztec/foundation/config';
|
|
9
12
|
import { Fr } from '@aztec/foundation/fields';
|
|
10
13
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
@@ -19,25 +22,31 @@ type BotFollowChain = (typeof BotFollowChain)[number];
|
|
|
19
22
|
|
|
20
23
|
export enum SupportedTokenContracts {
|
|
21
24
|
TokenContract = 'TokenContract',
|
|
22
|
-
|
|
25
|
+
PrivateTokenContract = 'PrivateTokenContract',
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export type BotConfig = {
|
|
26
29
|
/** The URL to the Aztec node to check for tx pool status. */
|
|
27
30
|
nodeUrl: string | undefined;
|
|
31
|
+
/** The URL to the Aztec node admin API to force-flush txs if configured. */
|
|
32
|
+
nodeAdminUrl: string | undefined;
|
|
28
33
|
/** URL to the PXE for sending txs, or undefined if an in-proc PXE is used. */
|
|
29
34
|
pxeUrl: string | undefined;
|
|
30
35
|
/** Url of the ethereum host. */
|
|
31
36
|
l1RpcUrls: string[] | undefined;
|
|
32
37
|
/** The mnemonic for the account to bridge fee juice from L1. */
|
|
33
|
-
l1Mnemonic: string | undefined;
|
|
38
|
+
l1Mnemonic: SecretValue<string> | undefined;
|
|
34
39
|
/** The private key for the account to bridge fee juice from L1. */
|
|
35
|
-
l1PrivateKey: string | undefined;
|
|
40
|
+
l1PrivateKey: SecretValue<string> | undefined;
|
|
41
|
+
/** How long to wait for L1 to L2 messages to become available on L2 */
|
|
42
|
+
l1ToL2MessageTimeoutSeconds: number;
|
|
36
43
|
/** Signing private key for the sender account. */
|
|
37
|
-
senderPrivateKey: Fr | undefined;
|
|
44
|
+
senderPrivateKey: SecretValue<Fr> | undefined;
|
|
45
|
+
/** Optional salt to use to instantiate the sender account */
|
|
46
|
+
senderSalt: Fr | undefined;
|
|
38
47
|
/** Encryption secret for a recipient account. */
|
|
39
|
-
recipientEncryptionSecret: Fr
|
|
40
|
-
/** Salt for the token contract
|
|
48
|
+
recipientEncryptionSecret: SecretValue<Fr>;
|
|
49
|
+
/** Salt for the token contract instantiation. */
|
|
41
50
|
tokenSalt: Fr;
|
|
42
51
|
/** Every how many seconds should a new tx be sent. */
|
|
43
52
|
txIntervalSeconds: number;
|
|
@@ -57,8 +66,6 @@ export type BotConfig = {
|
|
|
57
66
|
maxPendingTxs: number;
|
|
58
67
|
/** Whether to flush after sending each 'setup' transaction */
|
|
59
68
|
flushSetupTransactions: boolean;
|
|
60
|
-
/** Whether to skip public simulation of txs before sending them. */
|
|
61
|
-
skipPublicSimulation: boolean;
|
|
62
69
|
/** L2 gas limit for the tx (empty to have the bot trigger an estimate gas). */
|
|
63
70
|
l2GasLimit: number | undefined;
|
|
64
71
|
/** DA gas limit for the tx (empty to have the bot trigger an estimate gas). */
|
|
@@ -69,17 +76,22 @@ export type BotConfig = {
|
|
|
69
76
|
maxConsecutiveErrors: number;
|
|
70
77
|
/** Stops the bot if service becomes unhealthy */
|
|
71
78
|
stopWhenUnhealthy: boolean;
|
|
79
|
+
/** Deploy an AMM contract and do swaps instead of transfers */
|
|
80
|
+
ammTxs: boolean;
|
|
72
81
|
};
|
|
73
82
|
|
|
74
83
|
export const BotConfigSchema = z
|
|
75
84
|
.object({
|
|
76
85
|
nodeUrl: z.string().optional(),
|
|
86
|
+
nodeAdminUrl: z.string().optional(),
|
|
77
87
|
pxeUrl: z.string().optional(),
|
|
78
88
|
l1RpcUrls: z.array(z.string()).optional(),
|
|
79
|
-
l1Mnemonic: z.string().optional(),
|
|
80
|
-
l1PrivateKey: z.string().optional(),
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
l1Mnemonic: schemas.SecretValue(z.string()).optional(),
|
|
90
|
+
l1PrivateKey: schemas.SecretValue(z.string()).optional(),
|
|
91
|
+
l1ToL2MessageTimeoutSeconds: z.number(),
|
|
92
|
+
senderPrivateKey: schemas.SecretValue(schemas.Fr).optional(),
|
|
93
|
+
senderSalt: schemas.Fr.optional(),
|
|
94
|
+
recipientEncryptionSecret: schemas.SecretValue(schemas.Fr),
|
|
83
95
|
tokenSalt: schemas.Fr,
|
|
84
96
|
txIntervalSeconds: z.number(),
|
|
85
97
|
privateTransfersPerTx: z.number().int().nonnegative(),
|
|
@@ -90,22 +102,24 @@ export const BotConfigSchema = z
|
|
|
90
102
|
followChain: z.enum(BotFollowChain),
|
|
91
103
|
maxPendingTxs: z.number().int().nonnegative(),
|
|
92
104
|
flushSetupTransactions: z.boolean(),
|
|
93
|
-
skipPublicSimulation: z.boolean(),
|
|
94
105
|
l2GasLimit: z.number().int().nonnegative().optional(),
|
|
95
106
|
daGasLimit: z.number().int().nonnegative().optional(),
|
|
96
107
|
contract: z.nativeEnum(SupportedTokenContracts),
|
|
97
108
|
maxConsecutiveErrors: z.number().int().nonnegative(),
|
|
98
109
|
stopWhenUnhealthy: z.boolean(),
|
|
110
|
+
ammTxs: z.boolean().default(false),
|
|
99
111
|
})
|
|
100
112
|
.transform(config => ({
|
|
101
113
|
nodeUrl: undefined,
|
|
114
|
+
nodeAdminUrl: undefined,
|
|
102
115
|
pxeUrl: undefined,
|
|
103
116
|
l1RpcUrls: undefined,
|
|
117
|
+
senderSalt: undefined,
|
|
118
|
+
l2GasLimit: undefined,
|
|
119
|
+
daGasLimit: undefined,
|
|
104
120
|
l1Mnemonic: undefined,
|
|
105
121
|
l1PrivateKey: undefined,
|
|
106
122
|
senderPrivateKey: undefined,
|
|
107
|
-
l2GasLimit: undefined,
|
|
108
|
-
daGasLimit: undefined,
|
|
109
123
|
...config,
|
|
110
124
|
})) satisfies ZodFor<BotConfig>;
|
|
111
125
|
|
|
@@ -114,6 +128,10 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
|
|
|
114
128
|
env: 'AZTEC_NODE_URL',
|
|
115
129
|
description: 'The URL to the Aztec node to check for tx pool status.',
|
|
116
130
|
},
|
|
131
|
+
nodeAdminUrl: {
|
|
132
|
+
env: 'AZTEC_NODE_ADMIN_URL',
|
|
133
|
+
description: 'The URL to the Aztec node admin API to force-flush txs if configured.',
|
|
134
|
+
},
|
|
117
135
|
pxeUrl: {
|
|
118
136
|
env: 'BOT_PXE_URL',
|
|
119
137
|
description: 'URL to the PXE for sending txs, or undefined if an in-proc PXE is used.',
|
|
@@ -126,21 +144,33 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
|
|
|
126
144
|
l1Mnemonic: {
|
|
127
145
|
env: 'BOT_L1_MNEMONIC',
|
|
128
146
|
description: 'The mnemonic for the account to bridge fee juice from L1.',
|
|
147
|
+
...secretStringConfigHelper(),
|
|
129
148
|
},
|
|
130
149
|
l1PrivateKey: {
|
|
131
150
|
env: 'BOT_L1_PRIVATE_KEY',
|
|
132
151
|
description: 'The private key for the account to bridge fee juice from L1.',
|
|
152
|
+
...secretStringConfigHelper(),
|
|
153
|
+
},
|
|
154
|
+
l1ToL2MessageTimeoutSeconds: {
|
|
155
|
+
env: 'BOT_L1_TO_L2_TIMEOUT_SECONDS',
|
|
156
|
+
description: 'How long to wait for L1 to L2 messages to become available on L2',
|
|
157
|
+
...numberConfigHelper(3600),
|
|
133
158
|
},
|
|
134
159
|
senderPrivateKey: {
|
|
135
160
|
env: 'BOT_PRIVATE_KEY',
|
|
136
161
|
description: 'Signing private key for the sender account.',
|
|
162
|
+
...secretFrConfigHelper(),
|
|
163
|
+
},
|
|
164
|
+
senderSalt: {
|
|
165
|
+
env: 'BOT_ACCOUNT_SALT',
|
|
166
|
+
description: 'The salt to use to deploys the sender account.',
|
|
137
167
|
parseEnv: (val: string) => (val ? Fr.fromHexString(val) : undefined),
|
|
138
168
|
},
|
|
139
169
|
recipientEncryptionSecret: {
|
|
140
170
|
env: 'BOT_RECIPIENT_ENCRYPTION_SECRET',
|
|
141
171
|
description: 'Encryption secret for a recipient account.',
|
|
142
|
-
|
|
143
|
-
|
|
172
|
+
printDefault: sv => sv?.getValue(),
|
|
173
|
+
...secretFrConfigHelper(Fr.fromHexString('0xcafecafe')),
|
|
144
174
|
},
|
|
145
175
|
tokenSalt: {
|
|
146
176
|
env: 'BOT_TOKEN_SALT',
|
|
@@ -200,11 +230,6 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
|
|
|
200
230
|
description: 'Make a request for the sequencer to build a block after each setup transaction.',
|
|
201
231
|
...booleanConfigHelper(false),
|
|
202
232
|
},
|
|
203
|
-
skipPublicSimulation: {
|
|
204
|
-
env: 'BOT_SKIP_PUBLIC_SIMULATION',
|
|
205
|
-
description: 'Whether to skip public simulation of txs before sending them.',
|
|
206
|
-
...booleanConfigHelper(false),
|
|
207
|
-
},
|
|
208
233
|
l2GasLimit: {
|
|
209
234
|
env: 'BOT_L2_GAS_LIMIT',
|
|
210
235
|
description: 'L2 gas limit for the tx (empty to have the bot trigger an estimate gas).',
|
|
@@ -240,6 +265,11 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
|
|
|
240
265
|
description: 'Stops the bot if service becomes unhealthy',
|
|
241
266
|
...booleanConfigHelper(false),
|
|
242
267
|
},
|
|
268
|
+
ammTxs: {
|
|
269
|
+
env: 'BOT_AMM_TXS',
|
|
270
|
+
description: 'Deploy an AMM and send swaps to it',
|
|
271
|
+
...booleanConfigHelper(false),
|
|
272
|
+
},
|
|
243
273
|
};
|
|
244
274
|
|
|
245
275
|
export function getBotConfigFromEnv(): BotConfig {
|