@aztec/bot 0.0.0-test.0
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 +3 -0
- package/dest/bot.d.ts +33 -0
- package/dest/bot.d.ts.map +1 -0
- package/dest/bot.js +122 -0
- package/dest/config.d.ts +186 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/config.js +191 -0
- package/dest/factory.d.ts +50 -0
- package/dest/factory.d.ts.map +1 -0
- package/dest/factory.js +229 -0
- package/dest/index.d.ts +6 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +5 -0
- package/dest/interface.d.ts +12 -0
- package/dest/interface.d.ts.map +1 -0
- package/dest/interface.js +10 -0
- package/dest/rpc.d.ts +10 -0
- package/dest/rpc.d.ts.map +1 -0
- package/dest/rpc.js +19 -0
- package/dest/runner.d.ts +49 -0
- package/dest/runner.d.ts.map +1 -0
- package/dest/runner.js +158 -0
- package/dest/utils.d.ts +16 -0
- package/dest/utils.d.ts.map +1 -0
- package/dest/utils.js +20 -0
- package/package.json +89 -0
- package/src/bot.ts +151 -0
- package/src/config.ts +258 -0
- package/src/factory.ts +259 -0
- package/src/index.ts +11 -0
- package/src/interface.ts +23 -0
- package/src/rpc.ts +21 -0
- package/src/runner.ts +167 -0
- package/src/utils.ts +27 -0
package/README.md
ADDED
package/dest/bot.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type AztecAddress, type Wallet } from '@aztec/aztec.js';
|
|
2
|
+
import type { EasyPrivateTokenContract } from '@aztec/noir-contracts.js/EasyPrivateToken';
|
|
3
|
+
import type { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
4
|
+
import type { AztecNode, PXE } from '@aztec/stdlib/interfaces/client';
|
|
5
|
+
import type { BotConfig } from './config.js';
|
|
6
|
+
export declare class Bot {
|
|
7
|
+
readonly wallet: Wallet;
|
|
8
|
+
readonly token: TokenContract | EasyPrivateTokenContract;
|
|
9
|
+
readonly recipient: AztecAddress;
|
|
10
|
+
config: BotConfig;
|
|
11
|
+
private log;
|
|
12
|
+
private attempts;
|
|
13
|
+
private successes;
|
|
14
|
+
protected constructor(wallet: Wallet, token: TokenContract | EasyPrivateTokenContract, recipient: AztecAddress, config: BotConfig);
|
|
15
|
+
static create(config: BotConfig, dependencies?: {
|
|
16
|
+
pxe?: PXE;
|
|
17
|
+
node?: AztecNode;
|
|
18
|
+
}): Promise<Bot>;
|
|
19
|
+
updateConfig(config: Partial<BotConfig>): void;
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
getBalances(): Promise<{
|
|
22
|
+
sender: {
|
|
23
|
+
privateBalance: bigint;
|
|
24
|
+
publicBalance: bigint;
|
|
25
|
+
};
|
|
26
|
+
recipient: {
|
|
27
|
+
privateBalance: bigint;
|
|
28
|
+
publicBalance: bigint;
|
|
29
|
+
};
|
|
30
|
+
}>;
|
|
31
|
+
private getSendMethodOpts;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EAIjB,KAAK,MAAM,EAEZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM7C,qBAAa,GAAG;aAOI,MAAM,EAAE,MAAM;aACd,KAAK,EAAE,aAAa,GAAG,wBAAwB;aAC/C,SAAS,EAAE,YAAY;IAChC,MAAM,EAAE,SAAS;IAT1B,OAAO,CAAC,GAAG,CAAuB;IAElC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAa;IAE9B,SAAS,aACS,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,GAAG,wBAAwB,EAC/C,SAAS,EAAE,YAAY,EAChC,MAAM,EAAE,SAAS;WAGb,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,GAAE;QAAE,GAAG,CAAC,EAAE,GAAG,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAO,GAAG,OAAO,CAAC,GAAG,CAAC;IAKjG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;IAKjC,GAAG;IAoEH,WAAW;;;;;;;;;;IAoBxB,OAAO,CAAC,iBAAiB;CAkB1B"}
|
package/dest/bot.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { BatchCall, FeeJuicePaymentMethod, createLogger } from '@aztec/aztec.js';
|
|
2
|
+
import { timesParallel } from '@aztec/foundation/collection';
|
|
3
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
4
|
+
import { BotFactory } from './factory.js';
|
|
5
|
+
import { getBalances, getPrivateBalance, isStandardTokenContract } from './utils.js';
|
|
6
|
+
const TRANSFER_AMOUNT = 1;
|
|
7
|
+
export class Bot {
|
|
8
|
+
wallet;
|
|
9
|
+
token;
|
|
10
|
+
recipient;
|
|
11
|
+
config;
|
|
12
|
+
log;
|
|
13
|
+
attempts;
|
|
14
|
+
successes;
|
|
15
|
+
constructor(wallet, token, recipient, config){
|
|
16
|
+
this.wallet = wallet;
|
|
17
|
+
this.token = token;
|
|
18
|
+
this.recipient = recipient;
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.log = createLogger('bot');
|
|
21
|
+
this.attempts = 0;
|
|
22
|
+
this.successes = 0;
|
|
23
|
+
}
|
|
24
|
+
static async create(config, dependencies = {}) {
|
|
25
|
+
const { wallet, token, recipient } = await new BotFactory(config, dependencies).setup();
|
|
26
|
+
return new Bot(wallet, token, recipient, config);
|
|
27
|
+
}
|
|
28
|
+
updateConfig(config) {
|
|
29
|
+
this.log.info(`Updating bot config ${Object.keys(config).join(', ')}`);
|
|
30
|
+
this.config = {
|
|
31
|
+
...this.config,
|
|
32
|
+
...config
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async run() {
|
|
36
|
+
this.attempts++;
|
|
37
|
+
const logCtx = {
|
|
38
|
+
runId: Date.now() * 1000 + Math.floor(Math.random() * 1000)
|
|
39
|
+
};
|
|
40
|
+
const { privateTransfersPerTx, publicTransfersPerTx, feePaymentMethod, followChain, txMinedWaitSeconds } = this.config;
|
|
41
|
+
const { token, recipient, wallet } = this;
|
|
42
|
+
const sender = wallet.getAddress();
|
|
43
|
+
this.log.verbose(`Preparing tx with ${feePaymentMethod} fee with ${privateTransfersPerTx} private and ${publicTransfersPerTx} public transfers`, logCtx);
|
|
44
|
+
const calls = [];
|
|
45
|
+
if (isStandardTokenContract(token)) {
|
|
46
|
+
calls.push(...await timesParallel(privateTransfersPerTx, ()=>token.methods.transfer(recipient, TRANSFER_AMOUNT).request()));
|
|
47
|
+
calls.push(...await timesParallel(publicTransfersPerTx, ()=>token.methods.transfer_in_public(sender, recipient, TRANSFER_AMOUNT, 0).request()));
|
|
48
|
+
} else {
|
|
49
|
+
calls.push(...await timesParallel(privateTransfersPerTx, ()=>token.methods.transfer(TRANSFER_AMOUNT, sender, recipient).request()));
|
|
50
|
+
}
|
|
51
|
+
const opts = this.getSendMethodOpts();
|
|
52
|
+
const batch = new BatchCall(wallet, calls);
|
|
53
|
+
this.log.verbose(`Simulating transaction with ${calls.length}`, logCtx);
|
|
54
|
+
await batch.simulate();
|
|
55
|
+
this.log.verbose(`Proving transaction`, logCtx);
|
|
56
|
+
const provenTx = await batch.prove(opts);
|
|
57
|
+
this.log.verbose(`Sending tx`, logCtx);
|
|
58
|
+
const tx = provenTx.send();
|
|
59
|
+
const txHash = await tx.getTxHash();
|
|
60
|
+
if (followChain === 'NONE') {
|
|
61
|
+
this.log.info(`Transaction ${txHash} sent, not waiting for it to be mined`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.log.verbose(`Awaiting tx ${txHash} to be on the ${followChain} chain (timeout ${txMinedWaitSeconds}s)`, logCtx);
|
|
65
|
+
const receipt = await tx.wait({
|
|
66
|
+
timeout: txMinedWaitSeconds,
|
|
67
|
+
provenTimeout: txMinedWaitSeconds,
|
|
68
|
+
proven: followChain === 'PROVEN'
|
|
69
|
+
});
|
|
70
|
+
this.log.info(`Tx #${this.attempts} ${receipt.txHash} successfully mined in block ${receipt.blockNumber} (stats: ${this.successes}/${this.attempts} success)`, logCtx);
|
|
71
|
+
this.successes++;
|
|
72
|
+
}
|
|
73
|
+
async getBalances() {
|
|
74
|
+
if (isStandardTokenContract(this.token)) {
|
|
75
|
+
return {
|
|
76
|
+
sender: await getBalances(this.token, this.wallet.getAddress()),
|
|
77
|
+
recipient: await getBalances(this.token, this.recipient)
|
|
78
|
+
};
|
|
79
|
+
} else {
|
|
80
|
+
return {
|
|
81
|
+
sender: {
|
|
82
|
+
privateBalance: await getPrivateBalance(this.token, this.wallet.getAddress()),
|
|
83
|
+
publicBalance: 0n
|
|
84
|
+
},
|
|
85
|
+
recipient: {
|
|
86
|
+
privateBalance: await getPrivateBalance(this.token, this.recipient),
|
|
87
|
+
publicBalance: 0n
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
getSendMethodOpts() {
|
|
93
|
+
const sender = this.wallet.getAddress();
|
|
94
|
+
const { l2GasLimit, daGasLimit, skipPublicSimulation } = this.config;
|
|
95
|
+
const paymentMethod = new FeeJuicePaymentMethod(sender);
|
|
96
|
+
let gasSettings, estimateGas;
|
|
97
|
+
if (l2GasLimit !== undefined && l2GasLimit > 0 && daGasLimit !== undefined && daGasLimit > 0) {
|
|
98
|
+
gasSettings = {
|
|
99
|
+
gasLimits: Gas.from({
|
|
100
|
+
l2Gas: l2GasLimit,
|
|
101
|
+
daGas: daGasLimit
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
estimateGas = false;
|
|
105
|
+
this.log.verbose(`Using gas limits ${l2GasLimit} L2 gas ${daGasLimit} DA gas`);
|
|
106
|
+
} else {
|
|
107
|
+
estimateGas = true;
|
|
108
|
+
this.log.verbose(`Estimating gas for transaction`);
|
|
109
|
+
}
|
|
110
|
+
const baseFeePadding = 2; // Send 3x the current base fee
|
|
111
|
+
this.log.verbose(skipPublicSimulation ? `Skipping public simulation` : `Simulating public transfers`);
|
|
112
|
+
return {
|
|
113
|
+
fee: {
|
|
114
|
+
estimateGas,
|
|
115
|
+
paymentMethod,
|
|
116
|
+
gasSettings,
|
|
117
|
+
baseFeePadding
|
|
118
|
+
},
|
|
119
|
+
skipPublicSimulation
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
package/dest/config.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { type ConfigMappingsType } from '@aztec/foundation/config';
|
|
2
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { type ZodFor } from '@aztec/stdlib/schemas';
|
|
4
|
+
import type { ComponentsVersions } from '@aztec/stdlib/versioning';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
declare const BotFollowChain: readonly ["NONE", "PENDING", "PROVEN"];
|
|
7
|
+
type BotFollowChain = (typeof BotFollowChain)[number];
|
|
8
|
+
export declare enum SupportedTokenContracts {
|
|
9
|
+
TokenContract = "TokenContract",
|
|
10
|
+
EasyPrivateTokenContract = "EasyPrivateTokenContract"
|
|
11
|
+
}
|
|
12
|
+
export type BotConfig = {
|
|
13
|
+
/** The URL to the Aztec node to check for tx pool status. */
|
|
14
|
+
nodeUrl: string | undefined;
|
|
15
|
+
/** URL to the PXE for sending txs, or undefined if an in-proc PXE is used. */
|
|
16
|
+
pxeUrl: string | undefined;
|
|
17
|
+
/** Url of the ethereum host. */
|
|
18
|
+
l1RpcUrls: string[] | undefined;
|
|
19
|
+
/** The mnemonic for the account to bridge fee juice from L1. */
|
|
20
|
+
l1Mnemonic: string | undefined;
|
|
21
|
+
/** The private key for the account to bridge fee juice from L1. */
|
|
22
|
+
l1PrivateKey: string | undefined;
|
|
23
|
+
/** Signing private key for the sender account. */
|
|
24
|
+
senderPrivateKey: Fr | undefined;
|
|
25
|
+
/** Encryption secret for a recipient account. */
|
|
26
|
+
recipientEncryptionSecret: Fr;
|
|
27
|
+
/** Salt for the token contract deployment. */
|
|
28
|
+
tokenSalt: Fr;
|
|
29
|
+
/** Every how many seconds should a new tx be sent. */
|
|
30
|
+
txIntervalSeconds: number;
|
|
31
|
+
/** How many private token transfers are executed per tx. */
|
|
32
|
+
privateTransfersPerTx: number;
|
|
33
|
+
/** How many public token transfers are executed per tx. */
|
|
34
|
+
publicTransfersPerTx: number;
|
|
35
|
+
/** How to handle fee payments. */
|
|
36
|
+
feePaymentMethod: 'fee_juice';
|
|
37
|
+
/** True to not automatically setup or start the bot on initialization. */
|
|
38
|
+
noStart: boolean;
|
|
39
|
+
/** How long to wait for a tx to be mined before reporting an error. */
|
|
40
|
+
txMinedWaitSeconds: number;
|
|
41
|
+
/** Whether to wait for txs to be proven, to be mined, or no wait at all. */
|
|
42
|
+
followChain: BotFollowChain;
|
|
43
|
+
/** Do not send a tx if the node's tx pool already has this many pending txs. */
|
|
44
|
+
maxPendingTxs: number;
|
|
45
|
+
/** Whether to flush after sending each 'setup' transaction */
|
|
46
|
+
flushSetupTransactions: boolean;
|
|
47
|
+
/** Whether to skip public simulation of txs before sending them. */
|
|
48
|
+
skipPublicSimulation: boolean;
|
|
49
|
+
/** L2 gas limit for the tx (empty to have the bot trigger an estimate gas). */
|
|
50
|
+
l2GasLimit: number | undefined;
|
|
51
|
+
/** DA gas limit for the tx (empty to have the bot trigger an estimate gas). */
|
|
52
|
+
daGasLimit: number | undefined;
|
|
53
|
+
/** Token contract to use */
|
|
54
|
+
contract: SupportedTokenContracts;
|
|
55
|
+
/** The maximum number of consecutive errors before the bot shuts down */
|
|
56
|
+
maxConsecutiveErrors: number;
|
|
57
|
+
/** Stops the bot if service becomes unhealthy */
|
|
58
|
+
stopWhenUnhealthy: boolean;
|
|
59
|
+
};
|
|
60
|
+
export declare const BotConfigSchema: z.ZodEffects<z.ZodObject<{
|
|
61
|
+
nodeUrl: z.ZodOptional<z.ZodString>;
|
|
62
|
+
pxeUrl: z.ZodOptional<z.ZodString>;
|
|
63
|
+
l1RpcUrls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
64
|
+
l1Mnemonic: z.ZodOptional<z.ZodString>;
|
|
65
|
+
l1PrivateKey: z.ZodOptional<z.ZodString>;
|
|
66
|
+
senderPrivateKey: z.ZodOptional<ZodFor<Fr>>;
|
|
67
|
+
recipientEncryptionSecret: ZodFor<Fr>;
|
|
68
|
+
tokenSalt: ZodFor<Fr>;
|
|
69
|
+
txIntervalSeconds: z.ZodNumber;
|
|
70
|
+
privateTransfersPerTx: z.ZodNumber;
|
|
71
|
+
publicTransfersPerTx: z.ZodNumber;
|
|
72
|
+
feePaymentMethod: z.ZodLiteral<"fee_juice">;
|
|
73
|
+
noStart: z.ZodBoolean;
|
|
74
|
+
txMinedWaitSeconds: z.ZodNumber;
|
|
75
|
+
followChain: z.ZodEnum<["NONE", "PENDING", "PROVEN"]>;
|
|
76
|
+
maxPendingTxs: z.ZodNumber;
|
|
77
|
+
flushSetupTransactions: z.ZodBoolean;
|
|
78
|
+
skipPublicSimulation: z.ZodBoolean;
|
|
79
|
+
l2GasLimit: z.ZodOptional<z.ZodNumber>;
|
|
80
|
+
daGasLimit: z.ZodOptional<z.ZodNumber>;
|
|
81
|
+
contract: z.ZodNativeEnum<typeof SupportedTokenContracts>;
|
|
82
|
+
maxConsecutiveErrors: z.ZodNumber;
|
|
83
|
+
stopWhenUnhealthy: z.ZodBoolean;
|
|
84
|
+
}, "strip", z.ZodTypeAny, {
|
|
85
|
+
recipientEncryptionSecret: Fr;
|
|
86
|
+
tokenSalt: Fr;
|
|
87
|
+
txIntervalSeconds: number;
|
|
88
|
+
privateTransfersPerTx: number;
|
|
89
|
+
publicTransfersPerTx: number;
|
|
90
|
+
feePaymentMethod: "fee_juice";
|
|
91
|
+
noStart: boolean;
|
|
92
|
+
txMinedWaitSeconds: number;
|
|
93
|
+
followChain: "NONE" | "PENDING" | "PROVEN";
|
|
94
|
+
maxPendingTxs: number;
|
|
95
|
+
flushSetupTransactions: boolean;
|
|
96
|
+
skipPublicSimulation: boolean;
|
|
97
|
+
contract: SupportedTokenContracts;
|
|
98
|
+
maxConsecutiveErrors: number;
|
|
99
|
+
stopWhenUnhealthy: boolean;
|
|
100
|
+
nodeUrl?: string | undefined;
|
|
101
|
+
pxeUrl?: string | undefined;
|
|
102
|
+
l1RpcUrls?: string[] | undefined;
|
|
103
|
+
l1Mnemonic?: string | undefined;
|
|
104
|
+
l1PrivateKey?: string | undefined;
|
|
105
|
+
senderPrivateKey?: Fr | undefined;
|
|
106
|
+
l2GasLimit?: number | undefined;
|
|
107
|
+
daGasLimit?: number | undefined;
|
|
108
|
+
}, {
|
|
109
|
+
txIntervalSeconds: number;
|
|
110
|
+
privateTransfersPerTx: number;
|
|
111
|
+
publicTransfersPerTx: number;
|
|
112
|
+
feePaymentMethod: "fee_juice";
|
|
113
|
+
noStart: boolean;
|
|
114
|
+
txMinedWaitSeconds: number;
|
|
115
|
+
followChain: "NONE" | "PENDING" | "PROVEN";
|
|
116
|
+
maxPendingTxs: number;
|
|
117
|
+
flushSetupTransactions: boolean;
|
|
118
|
+
skipPublicSimulation: boolean;
|
|
119
|
+
contract: SupportedTokenContracts;
|
|
120
|
+
maxConsecutiveErrors: number;
|
|
121
|
+
stopWhenUnhealthy: boolean;
|
|
122
|
+
nodeUrl?: string | undefined;
|
|
123
|
+
pxeUrl?: string | undefined;
|
|
124
|
+
l1RpcUrls?: string[] | undefined;
|
|
125
|
+
l1Mnemonic?: string | undefined;
|
|
126
|
+
l1PrivateKey?: string | undefined;
|
|
127
|
+
senderPrivateKey?: any;
|
|
128
|
+
recipientEncryptionSecret?: any;
|
|
129
|
+
tokenSalt?: any;
|
|
130
|
+
l2GasLimit?: number | undefined;
|
|
131
|
+
daGasLimit?: number | undefined;
|
|
132
|
+
}>, {
|
|
133
|
+
recipientEncryptionSecret: Fr;
|
|
134
|
+
tokenSalt: Fr;
|
|
135
|
+
txIntervalSeconds: number;
|
|
136
|
+
privateTransfersPerTx: number;
|
|
137
|
+
publicTransfersPerTx: number;
|
|
138
|
+
feePaymentMethod: "fee_juice";
|
|
139
|
+
noStart: boolean;
|
|
140
|
+
txMinedWaitSeconds: number;
|
|
141
|
+
followChain: "NONE" | "PENDING" | "PROVEN";
|
|
142
|
+
maxPendingTxs: number;
|
|
143
|
+
flushSetupTransactions: boolean;
|
|
144
|
+
skipPublicSimulation: boolean;
|
|
145
|
+
contract: SupportedTokenContracts;
|
|
146
|
+
maxConsecutiveErrors: number;
|
|
147
|
+
stopWhenUnhealthy: boolean;
|
|
148
|
+
nodeUrl: string | undefined;
|
|
149
|
+
pxeUrl: string | undefined;
|
|
150
|
+
l1RpcUrls: string[] | undefined;
|
|
151
|
+
l1Mnemonic: string | undefined;
|
|
152
|
+
l1PrivateKey: string | undefined;
|
|
153
|
+
senderPrivateKey: Fr | undefined;
|
|
154
|
+
l2GasLimit: number | undefined;
|
|
155
|
+
daGasLimit: number | undefined;
|
|
156
|
+
}, {
|
|
157
|
+
txIntervalSeconds: number;
|
|
158
|
+
privateTransfersPerTx: number;
|
|
159
|
+
publicTransfersPerTx: number;
|
|
160
|
+
feePaymentMethod: "fee_juice";
|
|
161
|
+
noStart: boolean;
|
|
162
|
+
txMinedWaitSeconds: number;
|
|
163
|
+
followChain: "NONE" | "PENDING" | "PROVEN";
|
|
164
|
+
maxPendingTxs: number;
|
|
165
|
+
flushSetupTransactions: boolean;
|
|
166
|
+
skipPublicSimulation: boolean;
|
|
167
|
+
contract: SupportedTokenContracts;
|
|
168
|
+
maxConsecutiveErrors: number;
|
|
169
|
+
stopWhenUnhealthy: boolean;
|
|
170
|
+
nodeUrl?: string | undefined;
|
|
171
|
+
pxeUrl?: string | undefined;
|
|
172
|
+
l1RpcUrls?: string[] | undefined;
|
|
173
|
+
l1Mnemonic?: string | undefined;
|
|
174
|
+
l1PrivateKey?: string | undefined;
|
|
175
|
+
senderPrivateKey?: any;
|
|
176
|
+
recipientEncryptionSecret?: any;
|
|
177
|
+
tokenSalt?: any;
|
|
178
|
+
l2GasLimit?: number | undefined;
|
|
179
|
+
daGasLimit?: number | undefined;
|
|
180
|
+
}>;
|
|
181
|
+
export declare const botConfigMappings: ConfigMappingsType<BotConfig>;
|
|
182
|
+
export declare function getBotConfigFromEnv(): BotConfig;
|
|
183
|
+
export declare function getBotDefaultConfig(): BotConfig;
|
|
184
|
+
export declare function getVersions(): Partial<ComponentsVersions>;
|
|
185
|
+
export {};
|
|
186
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAMxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAG9C,OAAO,EAAE,KAAK,MAAM,EAAW,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,cAAc,wCAAyC,CAAC;AAC9D,KAAK,cAAc,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,oBAAY,uBAAuB;IACjC,aAAa,kBAAkB;IAC/B,wBAAwB,6BAA6B;CACtD;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,8EAA8E;IAC9E,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,gCAAgC;IAChC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAChC,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,mEAAmE;IACnE,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,kDAAkD;IAClD,gBAAgB,EAAE,EAAE,GAAG,SAAS,CAAC;IACjC,iDAAiD;IACjD,yBAAyB,EAAE,EAAE,CAAC;IAC9B,8CAA8C;IAC9C,SAAS,EAAE,EAAE,CAAC;IACd,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2DAA2D;IAC3D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kCAAkC;IAClC,gBAAgB,EAAE,WAAW,CAAC;IAC9B,0EAA0E;IAC1E,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,WAAW,EAAE,cAAc,CAAC;IAC5B,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,sBAAsB,EAAE,OAAO,CAAC;IAChC,oEAAoE;IACpE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,+EAA+E;IAC/E,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,+EAA+E;IAC/E,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4BAA4B;IAC5B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,yEAAyE;IACzE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCK,CAAC;AAElC,eAAO,MAAM,iBAAiB,EAAE,kBAAkB,CAAC,SAAS,CAmI3D,CAAC;AAEF,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED,wBAAgB,WAAW,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAKzD"}
|
package/dest/config.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { booleanConfigHelper, getConfigFromMappings, getDefaultConfig, numberConfigHelper, optionalNumberConfigHelper } from '@aztec/foundation/config';
|
|
2
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
4
|
+
import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
|
|
5
|
+
import { schemas } from '@aztec/stdlib/schemas';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
const BotFollowChain = [
|
|
8
|
+
'NONE',
|
|
9
|
+
'PENDING',
|
|
10
|
+
'PROVEN'
|
|
11
|
+
];
|
|
12
|
+
export var SupportedTokenContracts = /*#__PURE__*/ function(SupportedTokenContracts) {
|
|
13
|
+
SupportedTokenContracts["TokenContract"] = "TokenContract";
|
|
14
|
+
SupportedTokenContracts["EasyPrivateTokenContract"] = "EasyPrivateTokenContract";
|
|
15
|
+
return SupportedTokenContracts;
|
|
16
|
+
}({});
|
|
17
|
+
export const BotConfigSchema = z.object({
|
|
18
|
+
nodeUrl: z.string().optional(),
|
|
19
|
+
pxeUrl: z.string().optional(),
|
|
20
|
+
l1RpcUrls: z.array(z.string()).optional(),
|
|
21
|
+
l1Mnemonic: z.string().optional(),
|
|
22
|
+
l1PrivateKey: z.string().optional(),
|
|
23
|
+
senderPrivateKey: schemas.Fr.optional(),
|
|
24
|
+
recipientEncryptionSecret: schemas.Fr,
|
|
25
|
+
tokenSalt: schemas.Fr,
|
|
26
|
+
txIntervalSeconds: z.number(),
|
|
27
|
+
privateTransfersPerTx: z.number().int().nonnegative(),
|
|
28
|
+
publicTransfersPerTx: z.number().int().nonnegative(),
|
|
29
|
+
feePaymentMethod: z.literal('fee_juice'),
|
|
30
|
+
noStart: z.boolean(),
|
|
31
|
+
txMinedWaitSeconds: z.number(),
|
|
32
|
+
followChain: z.enum(BotFollowChain),
|
|
33
|
+
maxPendingTxs: z.number().int().nonnegative(),
|
|
34
|
+
flushSetupTransactions: z.boolean(),
|
|
35
|
+
skipPublicSimulation: z.boolean(),
|
|
36
|
+
l2GasLimit: z.number().int().nonnegative().optional(),
|
|
37
|
+
daGasLimit: z.number().int().nonnegative().optional(),
|
|
38
|
+
contract: z.nativeEnum(SupportedTokenContracts),
|
|
39
|
+
maxConsecutiveErrors: z.number().int().nonnegative(),
|
|
40
|
+
stopWhenUnhealthy: z.boolean()
|
|
41
|
+
}).transform((config)=>({
|
|
42
|
+
nodeUrl: undefined,
|
|
43
|
+
pxeUrl: undefined,
|
|
44
|
+
l1RpcUrls: undefined,
|
|
45
|
+
l1Mnemonic: undefined,
|
|
46
|
+
l1PrivateKey: undefined,
|
|
47
|
+
senderPrivateKey: undefined,
|
|
48
|
+
l2GasLimit: undefined,
|
|
49
|
+
daGasLimit: undefined,
|
|
50
|
+
...config
|
|
51
|
+
}));
|
|
52
|
+
export const botConfigMappings = {
|
|
53
|
+
nodeUrl: {
|
|
54
|
+
env: 'AZTEC_NODE_URL',
|
|
55
|
+
description: 'The URL to the Aztec node to check for tx pool status.'
|
|
56
|
+
},
|
|
57
|
+
pxeUrl: {
|
|
58
|
+
env: 'BOT_PXE_URL',
|
|
59
|
+
description: 'URL to the PXE for sending txs, or undefined if an in-proc PXE is used.'
|
|
60
|
+
},
|
|
61
|
+
l1RpcUrls: {
|
|
62
|
+
env: 'ETHEREUM_HOSTS',
|
|
63
|
+
description: 'URL of the ethereum host.',
|
|
64
|
+
parseEnv: (val)=>val.split(',').map((url)=>url.trim())
|
|
65
|
+
},
|
|
66
|
+
l1Mnemonic: {
|
|
67
|
+
env: 'BOT_L1_MNEMONIC',
|
|
68
|
+
description: 'The mnemonic for the account to bridge fee juice from L1.'
|
|
69
|
+
},
|
|
70
|
+
l1PrivateKey: {
|
|
71
|
+
env: 'BOT_L1_PRIVATE_KEY',
|
|
72
|
+
description: 'The private key for the account to bridge fee juice from L1.'
|
|
73
|
+
},
|
|
74
|
+
senderPrivateKey: {
|
|
75
|
+
env: 'BOT_PRIVATE_KEY',
|
|
76
|
+
description: 'Signing private key for the sender account.',
|
|
77
|
+
parseEnv: (val)=>val ? Fr.fromHexString(val) : undefined
|
|
78
|
+
},
|
|
79
|
+
recipientEncryptionSecret: {
|
|
80
|
+
env: 'BOT_RECIPIENT_ENCRYPTION_SECRET',
|
|
81
|
+
description: 'Encryption secret for a recipient account.',
|
|
82
|
+
parseEnv: (val)=>Fr.fromHexString(val),
|
|
83
|
+
defaultValue: Fr.fromHexString('0xcafecafe')
|
|
84
|
+
},
|
|
85
|
+
tokenSalt: {
|
|
86
|
+
env: 'BOT_TOKEN_SALT',
|
|
87
|
+
description: 'Salt for the token contract deployment.',
|
|
88
|
+
parseEnv: (val)=>Fr.fromHexString(val),
|
|
89
|
+
defaultValue: Fr.fromHexString('1')
|
|
90
|
+
},
|
|
91
|
+
txIntervalSeconds: {
|
|
92
|
+
env: 'BOT_TX_INTERVAL_SECONDS',
|
|
93
|
+
description: 'Every how many seconds should a new tx be sent.',
|
|
94
|
+
...numberConfigHelper(60)
|
|
95
|
+
},
|
|
96
|
+
privateTransfersPerTx: {
|
|
97
|
+
env: 'BOT_PRIVATE_TRANSFERS_PER_TX',
|
|
98
|
+
description: 'How many private token transfers are executed per tx.',
|
|
99
|
+
...numberConfigHelper(1)
|
|
100
|
+
},
|
|
101
|
+
publicTransfersPerTx: {
|
|
102
|
+
env: 'BOT_PUBLIC_TRANSFERS_PER_TX',
|
|
103
|
+
description: 'How many public token transfers are executed per tx.',
|
|
104
|
+
...numberConfigHelper(1)
|
|
105
|
+
},
|
|
106
|
+
feePaymentMethod: {
|
|
107
|
+
env: 'BOT_FEE_PAYMENT_METHOD',
|
|
108
|
+
description: 'How to handle fee payments. (Options: fee_juice)',
|
|
109
|
+
parseEnv: (val)=>val || undefined,
|
|
110
|
+
defaultValue: 'fee_juice'
|
|
111
|
+
},
|
|
112
|
+
noStart: {
|
|
113
|
+
env: 'BOT_NO_START',
|
|
114
|
+
description: 'True to not automatically setup or start the bot on initialization.',
|
|
115
|
+
...booleanConfigHelper()
|
|
116
|
+
},
|
|
117
|
+
txMinedWaitSeconds: {
|
|
118
|
+
env: 'BOT_TX_MINED_WAIT_SECONDS',
|
|
119
|
+
description: 'How long to wait for a tx to be mined before reporting an error.',
|
|
120
|
+
...numberConfigHelper(180)
|
|
121
|
+
},
|
|
122
|
+
followChain: {
|
|
123
|
+
env: 'BOT_FOLLOW_CHAIN',
|
|
124
|
+
description: 'Which chain the bot follows',
|
|
125
|
+
defaultValue: 'NONE',
|
|
126
|
+
parseEnv (val) {
|
|
127
|
+
if (!BotFollowChain.includes(val.toUpperCase())) {
|
|
128
|
+
throw new Error(`Invalid value for BOT_FOLLOW_CHAIN: ${val}`);
|
|
129
|
+
}
|
|
130
|
+
return val;
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
maxPendingTxs: {
|
|
134
|
+
env: 'BOT_MAX_PENDING_TXS',
|
|
135
|
+
description: "Do not send a tx if the node's tx pool already has this many pending txs.",
|
|
136
|
+
...numberConfigHelper(128)
|
|
137
|
+
},
|
|
138
|
+
flushSetupTransactions: {
|
|
139
|
+
env: 'BOT_FLUSH_SETUP_TRANSACTIONS',
|
|
140
|
+
description: 'Make a request for the sequencer to build a block after each setup transaction.',
|
|
141
|
+
...booleanConfigHelper(false)
|
|
142
|
+
},
|
|
143
|
+
skipPublicSimulation: {
|
|
144
|
+
env: 'BOT_SKIP_PUBLIC_SIMULATION',
|
|
145
|
+
description: 'Whether to skip public simulation of txs before sending them.',
|
|
146
|
+
...booleanConfigHelper(false)
|
|
147
|
+
},
|
|
148
|
+
l2GasLimit: {
|
|
149
|
+
env: 'BOT_L2_GAS_LIMIT',
|
|
150
|
+
description: 'L2 gas limit for the tx (empty to have the bot trigger an estimate gas).',
|
|
151
|
+
...optionalNumberConfigHelper()
|
|
152
|
+
},
|
|
153
|
+
daGasLimit: {
|
|
154
|
+
env: 'BOT_DA_GAS_LIMIT',
|
|
155
|
+
description: 'DA gas limit for the tx (empty to have the bot trigger an estimate gas).',
|
|
156
|
+
...optionalNumberConfigHelper()
|
|
157
|
+
},
|
|
158
|
+
contract: {
|
|
159
|
+
env: 'BOT_TOKEN_CONTRACT',
|
|
160
|
+
description: 'Token contract to use',
|
|
161
|
+
defaultValue: "TokenContract",
|
|
162
|
+
parseEnv (val) {
|
|
163
|
+
if (!Object.values(SupportedTokenContracts).includes(val)) {
|
|
164
|
+
throw new Error(`Invalid value for BOT_TOKEN_CONTRACT: ${val}. Valid values: ${Object.values(SupportedTokenContracts).join(', ')}`);
|
|
165
|
+
}
|
|
166
|
+
return val;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
maxConsecutiveErrors: {
|
|
170
|
+
env: 'BOT_MAX_CONSECUTIVE_ERRORS',
|
|
171
|
+
description: 'The maximum number of consecutive errors before the bot shuts down',
|
|
172
|
+
...numberConfigHelper(0)
|
|
173
|
+
},
|
|
174
|
+
stopWhenUnhealthy: {
|
|
175
|
+
env: 'BOT_STOP_WHEN_UNHEALTHY',
|
|
176
|
+
description: 'Stops the bot if service becomes unhealthy',
|
|
177
|
+
...booleanConfigHelper(false)
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
export function getBotConfigFromEnv() {
|
|
181
|
+
return getConfigFromMappings(botConfigMappings);
|
|
182
|
+
}
|
|
183
|
+
export function getBotDefaultConfig() {
|
|
184
|
+
return getDefaultConfig(botConfigMappings);
|
|
185
|
+
}
|
|
186
|
+
export function getVersions() {
|
|
187
|
+
return {
|
|
188
|
+
l2ProtocolContractsTreeRoot: protocolContractTreeRoot.toString(),
|
|
189
|
+
l2CircuitsVkTreeRoot: getVKTreeRoot().toString()
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AztecAddress, type AztecNode, type PXE } from '@aztec/aztec.js';
|
|
2
|
+
import { EasyPrivateTokenContract } from '@aztec/noir-contracts.js/EasyPrivateToken';
|
|
3
|
+
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
4
|
+
import { type BotConfig } from './config.js';
|
|
5
|
+
export declare class BotFactory {
|
|
6
|
+
private readonly config;
|
|
7
|
+
private pxe;
|
|
8
|
+
private node?;
|
|
9
|
+
private log;
|
|
10
|
+
constructor(config: BotConfig, dependencies?: {
|
|
11
|
+
pxe?: PXE;
|
|
12
|
+
node?: AztecNode;
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Initializes a new bot by setting up the sender account, registering the recipient,
|
|
16
|
+
* deploying the token contract, and minting tokens if necessary.
|
|
17
|
+
*/
|
|
18
|
+
setup(): Promise<{
|
|
19
|
+
wallet: import("@aztec/aztec.js").AccountWalletWithSecretKey;
|
|
20
|
+
token: TokenContract | EasyPrivateTokenContract;
|
|
21
|
+
pxe: PXE;
|
|
22
|
+
recipient: AztecAddress;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the sender account contract is initialized, and initializes it if necessary.
|
|
26
|
+
* @returns The sender wallet.
|
|
27
|
+
*/
|
|
28
|
+
private setupAccount;
|
|
29
|
+
private setupAccountWithPrivateKey;
|
|
30
|
+
private setupTestAccount;
|
|
31
|
+
/**
|
|
32
|
+
* Registers the recipient for txs in the pxe.
|
|
33
|
+
*/
|
|
34
|
+
private registerRecipient;
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the token contract is deployed and deploys it if necessary.
|
|
37
|
+
* @param wallet - Wallet to deploy the token contract from.
|
|
38
|
+
* @returns The TokenContract instance.
|
|
39
|
+
*/
|
|
40
|
+
private setupToken;
|
|
41
|
+
/**
|
|
42
|
+
* Mints private and public tokens for the sender if their balance is below the minimum.
|
|
43
|
+
* @param token - Token contract.
|
|
44
|
+
*/
|
|
45
|
+
private mintTokens;
|
|
46
|
+
private bridgeL1FeeJuice;
|
|
47
|
+
private advanceL2Block;
|
|
48
|
+
private tryFlushTxs;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,YAAY,EACZ,KAAK,SAAS,EAMd,KAAK,GAAG,EAIT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAK/D,OAAO,EAAE,KAAK,SAAS,EAAwC,MAAM,aAAa,CAAC;AAMnF,qBAAa,UAAU;IAKT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,IAAI,CAAC,CAAY;IACzB,OAAO,CAAC,GAAG,CAAuB;gBAEL,MAAM,EAAE,SAAS,EAAE,YAAY,GAAE;QAAE,GAAG,CAAC,EAAE,GAAG,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAO;IAwBlG;;;OAGG;IACU,KAAK;;;;;;IAQlB;;;OAGG;YACW,YAAY;YAQZ,0BAA0B;YA4B1B,gBAAgB;IAc9B;;OAEG;YACW,iBAAiB;IAK/B;;;;OAIG;YACW,UAAU;IA8BxB;;;OAGG;YACW,UAAU;YAuCV,gBAAgB;YA+BhB,cAAc;YAMd,WAAW;CAU1B"}
|