ethershell 0.1.1-alpha.15 → 0.1.2-beta.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/LICENSE +21 -55
- package/README.md +179 -34
- package/bin/cli.js +8 -3
- package/package.json +9 -3
- package/src/services/addContracts.js +39 -26
- package/src/services/build.js +53 -26
- package/src/services/config.js +12 -2
- package/src/services/files.js +3 -2
- package/src/services/network.js +8 -11
- package/src/services/wallet.js +60 -3
- package/src/utils/accounter.js +29 -4
- package/src/utils/builder.js +1 -1
- package/src/utils/configFileUpdate.js +7 -0
- package/src/utils/contractProxy.js +162 -0
- package/src/utils/dir.js +10 -0
- package/src/utils/serialize.js +17 -0
- package/src/utils/typeGenerator.js +247 -0
package/src/services/build.js
CHANGED
|
@@ -15,12 +15,15 @@ import {
|
|
|
15
15
|
extractLoadableVersion
|
|
16
16
|
} from '../utils/builder.js';
|
|
17
17
|
import fs from 'fs';
|
|
18
|
+
import {
|
|
19
|
+
generateAllTypes,
|
|
20
|
+
} from '../utils/typeGenerator.js';
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
|
-
* Stored
|
|
23
|
+
* Stored config path
|
|
21
24
|
* @type {string}
|
|
22
25
|
*/
|
|
23
|
-
const
|
|
26
|
+
export const configPath = './ethershell/config.json';
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
29
|
* Global compiler configuration state
|
|
@@ -40,7 +43,11 @@ let compConfig = {};
|
|
|
40
43
|
* @property {number} optimizerRuns - Number of optimizer runs
|
|
41
44
|
* @property {boolean} viaIR - Whether to use IR-based code generation
|
|
42
45
|
*/
|
|
43
|
-
export let
|
|
46
|
+
export let configFile = {
|
|
47
|
+
providerEndpoint: '',
|
|
48
|
+
defaultWallet: {},
|
|
49
|
+
compiler: {}
|
|
50
|
+
};
|
|
44
51
|
|
|
45
52
|
/**
|
|
46
53
|
* Global compiler configuration state
|
|
@@ -52,33 +59,38 @@ export let compConfigFile = {};
|
|
|
52
59
|
let storedCompConfig;
|
|
53
60
|
|
|
54
61
|
// Load config file
|
|
55
|
-
if(fs.existsSync(
|
|
56
|
-
storedCompConfig = JSON.parse(fs.readFileSync(
|
|
62
|
+
if(fs.existsSync(configPath)){
|
|
63
|
+
storedCompConfig = JSON.parse(fs.readFileSync(configPath));
|
|
57
64
|
} else {
|
|
58
65
|
storedCompConfig = null;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
// Initialize global configuration of compiler
|
|
62
69
|
if(storedCompConfig){
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
compConfig.
|
|
66
|
-
|
|
67
|
-
compConfig.
|
|
70
|
+
configFile.compiler = storedCompConfig.compiler;
|
|
71
|
+
console.info(`Compiler is loading ...`);
|
|
72
|
+
compConfig.currentSolcInstance = await loadSolcVersion(configFile.compiler.version);
|
|
73
|
+
console.info(`Loading done!`);
|
|
74
|
+
compConfig.optimizer = configFile.compiler.optimizer;
|
|
75
|
+
compConfig.viaIR = configFile.compiler.viaIR;
|
|
76
|
+
compConfig.optimizerRuns = configFile.compiler.optimizerRuns;
|
|
77
|
+
compConfig.compilePath = configFile.compiler.compilePath;
|
|
68
78
|
} else {
|
|
69
79
|
compConfig = {
|
|
70
80
|
currentSolcInstance: solc, // default local compiler
|
|
71
81
|
optimizer: false,
|
|
72
82
|
viaIR: false,
|
|
73
|
-
optimizerRuns: 200
|
|
83
|
+
optimizerRuns: 200,
|
|
84
|
+
compilePath: './build'
|
|
74
85
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
configFile.compiler.version = extractLoadableVersion(compConfig.currentSolcInstance.version());
|
|
87
|
+
configFile.compiler.optimizer = compConfig.optimizer;
|
|
88
|
+
configFile.compiler.viaIR = compConfig.viaIR;
|
|
89
|
+
configFile.compiler.optimizerRuns = compConfig.optimizerRuns;
|
|
90
|
+
configFile.compiler.compilePath = compConfig.compilePath;
|
|
79
91
|
|
|
80
92
|
// Update config file
|
|
81
|
-
fs.writeFileSync(
|
|
93
|
+
fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
/**
|
|
@@ -96,8 +108,8 @@ export async function updateCompiler(version){
|
|
|
96
108
|
compConfig.currentSolcInstance = await setVersion(version, compConfig.currentSolcInstance);
|
|
97
109
|
|
|
98
110
|
// Update config file
|
|
99
|
-
|
|
100
|
-
fs.writeFileSync(
|
|
111
|
+
configFile.compiler.version = extractLoadableVersion(compConfig.currentSolcInstance.version());
|
|
112
|
+
fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
|
|
101
113
|
} catch(err) {
|
|
102
114
|
console.error(err);
|
|
103
115
|
}
|
|
@@ -141,20 +153,20 @@ export function compilerOptions(gasOptimizer, viaIR, optimizerRuns = 200) {
|
|
|
141
153
|
compConfig.viaIR = viaIR;
|
|
142
154
|
compConfig.optimizerRuns = optimizerRuns;
|
|
143
155
|
|
|
144
|
-
compConfigFile.optimizer = compConfig.optimizer;
|
|
145
|
-
compConfigFile.viaIR = compConfig.viaIR;
|
|
146
|
-
compConfigFile.optimizerRuns = compConfig.optimizerRuns;
|
|
147
|
-
|
|
148
156
|
// Update config file
|
|
149
|
-
|
|
157
|
+
configFile.compiler.optimizer = compConfig.optimizer;
|
|
158
|
+
configFile.compiler.viaIR = compConfig.viaIR;
|
|
159
|
+
configFile.compiler.optimizerRuns = compConfig.optimizerRuns;
|
|
160
|
+
fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
|
|
150
161
|
|
|
151
162
|
// Provide user feedback
|
|
152
163
|
console.log('✓ Compiler options updated:');
|
|
153
164
|
console.log(` Gas Optimizer: ${compConfig.optimizer ? 'Enabled' : 'Disabled'}`);
|
|
165
|
+
console.log(` ViaIR: ${compConfig.viaIR ? 'Enabled' : 'Disabled'}`);
|
|
154
166
|
if (compConfig.optimizer) {
|
|
155
167
|
console.log(` Optimizer Runs: ${compConfig.optimizerRuns}`);
|
|
156
168
|
}
|
|
157
|
-
|
|
169
|
+
|
|
158
170
|
} catch (error) {
|
|
159
171
|
console.error('Error setting compiler options:', error.message);
|
|
160
172
|
return null;
|
|
@@ -168,7 +180,7 @@ export function compilerOptions(gasOptimizer, viaIR, optimizerRuns = 200) {
|
|
|
168
180
|
* const opts = getCompilerOptions();
|
|
169
181
|
*/
|
|
170
182
|
export function getCompilerOptions() {
|
|
171
|
-
return { ...
|
|
183
|
+
return { ...configFile.compiler };
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
/**
|
|
@@ -187,7 +199,7 @@ export function compile(fullPath, selectedContracts, buildPath){
|
|
|
187
199
|
try{
|
|
188
200
|
// Set default path if buildPath is undefined
|
|
189
201
|
if(!buildPath){
|
|
190
|
-
buildPath =
|
|
202
|
+
buildPath = compConfig.compilePath;
|
|
191
203
|
[buildPath].forEach(check);
|
|
192
204
|
}
|
|
193
205
|
|
|
@@ -213,7 +225,22 @@ export function compile(fullPath, selectedContracts, buildPath){
|
|
|
213
225
|
build(fullPath, selectedContracts, buildPath);
|
|
214
226
|
console.log(`Contract compiled into ${path.resolve(buildPath)}`);
|
|
215
227
|
}
|
|
228
|
+
|
|
229
|
+
// Generate TypeScript types
|
|
230
|
+
const typesOutputPath = path.join(buildPath, 'types');
|
|
231
|
+
generateAllTypes(buildPath, typesOutputPath);
|
|
232
|
+
console.log(`TypeScript types generated in ${path.resolve(typesOutputPath)}`);
|
|
216
233
|
} catch(err){
|
|
217
234
|
console.error(err);
|
|
218
235
|
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Changes the default path to generate build files there
|
|
240
|
+
* @param {string} newPath - The new path to build
|
|
241
|
+
*/
|
|
242
|
+
export function changeCompPath(newPath) {
|
|
243
|
+
compConfig.compilePath = newPath;
|
|
244
|
+
configFile.compiler.compilePath = compConfig.compilePath;
|
|
245
|
+
fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
|
|
219
246
|
}
|
package/src/services/config.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { configFile } from './build.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Gets all fields of config file
|
|
5
|
+
*/
|
|
3
6
|
export function getConfigInfo() {
|
|
4
|
-
console.log(
|
|
7
|
+
console.log(configFile);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Gets just default account of config file
|
|
12
|
+
*/
|
|
13
|
+
export function getDefaultAccount() {
|
|
14
|
+
console.log(configFile.defaultWallet);
|
|
5
15
|
}
|
package/src/services/files.js
CHANGED
|
@@ -19,12 +19,13 @@ import path from 'path';
|
|
|
19
19
|
export function deleteDirectory(dirPath){
|
|
20
20
|
try {
|
|
21
21
|
if(!dirPath){
|
|
22
|
-
dirPath = path.resolve('
|
|
22
|
+
dirPath = path.resolve('.', 'build');
|
|
23
23
|
}
|
|
24
24
|
// Check if the directory exists
|
|
25
25
|
if(!fs.existsSync(dirPath)){
|
|
26
26
|
console.log('Path is not a directory');
|
|
27
|
-
return;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
28
29
|
|
|
29
30
|
// For Node.js 14.14.0+ (recommended)
|
|
30
31
|
fs.rmSync(dirPath, { recursive: true, force: true });
|
package/src/services/network.js
CHANGED
|
@@ -6,13 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { ethers } from 'ethers';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Local storage instance for persisting compiler artifacts paths
|
|
13
|
-
* @type {LocalStorage}
|
|
14
|
-
*/
|
|
15
|
-
const localStorage = new LocalStorage('./localStorage');
|
|
9
|
+
import { configPath } from './build.js';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import { changeProvider } from '../utils/configFileUpdate.js';
|
|
16
12
|
|
|
17
13
|
/**
|
|
18
14
|
* Default JSON-RPC URL for local Ethereum node
|
|
@@ -37,13 +33,14 @@ export let provider
|
|
|
37
33
|
* The specific RPC endpoint URL saved on storage before.
|
|
38
34
|
* @type {string}
|
|
39
35
|
*/
|
|
40
|
-
const storedUrl =
|
|
36
|
+
const storedUrl = JSON.parse(fs.readFileSync(configPath)).providerEndpoint;
|
|
41
37
|
if(storedUrl) {
|
|
42
|
-
provider = new ethers.JsonRpcProvider(storedUrl)
|
|
43
|
-
currentUrl = storedUrl
|
|
38
|
+
provider = new ethers.JsonRpcProvider(storedUrl);
|
|
39
|
+
currentUrl = storedUrl;
|
|
44
40
|
} else {
|
|
45
41
|
provider = new ethers.JsonRpcProvider(defaultUrl);
|
|
46
42
|
currentUrl = defaultUrl;
|
|
43
|
+
changeProvider(currentUrl);
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
|
|
@@ -66,7 +63,7 @@ export async function set(url){
|
|
|
66
63
|
name: result.name,
|
|
67
64
|
chainId: result.chainId
|
|
68
65
|
}
|
|
69
|
-
|
|
66
|
+
changeProvider(currentUrl);
|
|
70
67
|
console.log(network);
|
|
71
68
|
}catch(err){
|
|
72
69
|
console.error(err);
|
package/src/services/wallet.js
CHANGED
|
@@ -15,15 +15,28 @@ import {
|
|
|
15
15
|
detectDupWallet,
|
|
16
16
|
updateWalletJSON,
|
|
17
17
|
getWalletJSON,
|
|
18
|
-
updateAccountMemory
|
|
18
|
+
updateAccountMemory,
|
|
19
|
+
setDefaultAccount
|
|
19
20
|
} from '../utils/accounter.js';
|
|
21
|
+
import { configPath } from './build.js';
|
|
22
|
+
import fs from 'fs';
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Array containing all accounts (imported, generated, HD, and node-managed)
|
|
23
26
|
* @type {Array<Object>}
|
|
24
27
|
*/
|
|
25
|
-
export let allAccounts =
|
|
26
|
-
|
|
28
|
+
export let allAccounts = getWalletJSON();
|
|
29
|
+
|
|
30
|
+
// Set the default account from stored wallets
|
|
31
|
+
const defWallet = JSON.parse(fs.readFileSync(configPath)).defaultWallet;
|
|
32
|
+
if(defWallet.address) {
|
|
33
|
+
setDefaultAccount(defWallet);
|
|
34
|
+
} else {
|
|
35
|
+
if(allAccounts && allAccounts.length > 0) {
|
|
36
|
+
setDefaultAccount(allAccounts[0]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
|
|
28
41
|
/**
|
|
29
42
|
* Array containing only regular accounts (imported and generated)
|
|
@@ -101,6 +114,7 @@ export function addAccounts(privKeyArr) {
|
|
|
101
114
|
|
|
102
115
|
console.log(allAccounts.slice(newFrom));
|
|
103
116
|
}
|
|
117
|
+
setDefaultAccount(allAccounts[0]);
|
|
104
118
|
}
|
|
105
119
|
|
|
106
120
|
/**
|
|
@@ -142,6 +156,7 @@ export function addHD(phrase, count = 10) {
|
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
updateWalletJSON(allAccounts);
|
|
159
|
+
setDefaultAccount(allAccounts[0]);
|
|
145
160
|
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
146
161
|
console.log(allAccounts.slice(newFrom));
|
|
147
162
|
}
|
|
@@ -171,6 +186,7 @@ export function createAccounts(count = 1) {
|
|
|
171
186
|
|
|
172
187
|
}
|
|
173
188
|
updateWalletJSON(allAccounts);
|
|
189
|
+
setDefaultAccount(allAccounts[0]);
|
|
174
190
|
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
175
191
|
console.log(allAccounts.slice(newFrom));
|
|
176
192
|
}
|
|
@@ -205,6 +221,7 @@ export function createHD(count = 10) {
|
|
|
205
221
|
hdAccounts.push(newAccObj);
|
|
206
222
|
}
|
|
207
223
|
updateWalletJSON(allAccounts);
|
|
224
|
+
setDefaultAccount(allAccounts[0]);
|
|
208
225
|
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
209
226
|
console.log(allAccounts.slice(newFrom));
|
|
210
227
|
}
|
|
@@ -362,3 +379,43 @@ export async function getWalletInfo(accPointer) {
|
|
|
362
379
|
console.error(err);
|
|
363
380
|
}
|
|
364
381
|
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Changes the default account in config file by user
|
|
385
|
+
* @param {number | string} accPointer
|
|
386
|
+
* @throws {Error} If input is empty or invalid
|
|
387
|
+
*/
|
|
388
|
+
export function changeDefaultAccount(accPointer) {
|
|
389
|
+
try {
|
|
390
|
+
if(!accPointer && accPointer != 0) {
|
|
391
|
+
throw new Error('Error: Empty input is NOT valid!');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if(typeof accPointer === 'number') {
|
|
395
|
+
const index = allAccounts.findIndex(wallet => wallet.index == accPointer);
|
|
396
|
+
setDefaultAccount(allAccounts[index]);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if(ethers.isAddress(accPointer)) {
|
|
400
|
+
const index = allAccounts.findIndex(wallet => wallet.address == accPointer);
|
|
401
|
+
setDefaultAccount(allAccounts[index]);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if(ethers.isHexString(accPointer, 32)) {
|
|
405
|
+
const newAccount = new ethers.Wallet(accPointer, provider);
|
|
406
|
+
const newAccObj = {
|
|
407
|
+
index: allAccounts.length,
|
|
408
|
+
address: newAccount.address,
|
|
409
|
+
privateKey: accPointer,
|
|
410
|
+
type: 'user-imported',
|
|
411
|
+
contracts: []
|
|
412
|
+
}
|
|
413
|
+
allAccounts.push(newAccObj);
|
|
414
|
+
accounts.push(newAccObj);
|
|
415
|
+
setDefaultAccount(newAccObj);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
} catch(err) {
|
|
419
|
+
console.error(err);
|
|
420
|
+
}
|
|
421
|
+
}
|
package/src/utils/accounter.js
CHANGED
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
import { allAccounts, accounts, hdAccounts } from '../services/wallet.js';
|
|
9
9
|
import { provider } from '../services/network.js';
|
|
10
10
|
import fs from 'fs';
|
|
11
|
+
import { configFile, configPath } from '../services/build.js';
|
|
12
|
+
import { serializeBigInts } from './serialize.js';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* The path which in wallets json file will be saved.
|
|
14
16
|
* @type {String}
|
|
15
17
|
*/
|
|
16
|
-
const walletJSONPath = './
|
|
18
|
+
const walletJSONPath = './ethershell/wallets.json';
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Delete account(s) by index
|
|
@@ -104,7 +106,8 @@ export function detectDupWallet(privKeyArr) {
|
|
|
104
106
|
}]);
|
|
105
107
|
*/
|
|
106
108
|
export function updateWalletJSON(walletArr) {
|
|
107
|
-
|
|
109
|
+
const walletObj = serializeBigInts(walletArr);
|
|
110
|
+
fs.writeFileSync(walletJSONPath, JSON.stringify(walletObj, null, 2));
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
/**
|
|
@@ -112,7 +115,20 @@ export function updateWalletJSON(walletArr) {
|
|
|
112
115
|
* @returns {Object}
|
|
113
116
|
*/
|
|
114
117
|
export function getWalletJSON() {
|
|
115
|
-
|
|
118
|
+
if(fs.existsSync(walletJSONPath)){
|
|
119
|
+
const walletJSON = fs.readFileSync(walletJSONPath, 'utf8');
|
|
120
|
+
// Return empry array if wallet is empty
|
|
121
|
+
if(walletJSON.length === 0) {
|
|
122
|
+
return [];
|
|
123
|
+
} else {
|
|
124
|
+
return JSON.parse(fs.readFileSync(walletJSONPath));
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
// Generate empty wallet.json if it doesn't exist
|
|
128
|
+
const fd = fs.openSync(walletJSONPath, 'w');
|
|
129
|
+
fs.closeSync(fd);
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
export function updateAccountMemory(allAccArr) {
|
|
@@ -268,4 +284,13 @@ function _deleteAll() {
|
|
|
268
284
|
hdAccounts.splice(0);
|
|
269
285
|
fs.writeFileSync(walletJSONPath, JSON.stringify([], null, 2));
|
|
270
286
|
return;
|
|
271
|
-
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Updates default account in config file
|
|
291
|
+
* @param {Object} account - // The given account to set as default account
|
|
292
|
+
*/
|
|
293
|
+
export function setDefaultAccount(account) {
|
|
294
|
+
configFile.defaultWallet = serializeBigInts(account);
|
|
295
|
+
fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
|
|
296
|
+
}
|
package/src/utils/builder.js
CHANGED
|
@@ -16,7 +16,7 @@ import { LocalStorage } from 'node-localstorage';
|
|
|
16
16
|
* Local storage instance for persisting compiler artifacts paths
|
|
17
17
|
* @type {LocalStorage}
|
|
18
18
|
*/
|
|
19
|
-
const localStorage = new LocalStorage('./
|
|
19
|
+
const localStorage = new LocalStorage('./ethershell');
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Load a specific version of the Solidity compiler
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/utils/contractProxy.js
|
|
2
|
+
import { ethers } from 'ethers';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a proxy wrapper for ethers.js Contract objects
|
|
6
|
+
* Allows dynamic sender changes and comprehensive transaction options
|
|
7
|
+
*
|
|
8
|
+
* @param {ethers.Contract} contract - The ethers.js contract instance
|
|
9
|
+
* @param {ethers.JsonRpcProvider} provider - The blockchain provider
|
|
10
|
+
* @param {Array} allAccounts - Array of available accounts with privateKey property
|
|
11
|
+
* @returns {Proxy} Proxied contract object
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Call with comprehensive options
|
|
15
|
+
* await Payment.spend(amount, {
|
|
16
|
+
* from: '0x...',
|
|
17
|
+
* value: ethers.parseEther('1'),
|
|
18
|
+
* gasLimit: 500000,
|
|
19
|
+
* maxFeePerGas: ethers.parseUnits('100', 'gwei'),
|
|
20
|
+
* maxPriorityFeePerGas: ethers.parseUnits('2', 'gwei'),
|
|
21
|
+
* nonce: 42,
|
|
22
|
+
* chainId: 1
|
|
23
|
+
* })
|
|
24
|
+
*/
|
|
25
|
+
export function createContractProxy(contract, provider, allAccounts) {
|
|
26
|
+
return new Proxy(contract, {
|
|
27
|
+
get(target, prop) {
|
|
28
|
+
// Pass through non-function properties
|
|
29
|
+
if (typeof target[prop] !== 'function') {
|
|
30
|
+
return target[prop];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Return a wrapper for contract methods
|
|
34
|
+
return async function(...args) {
|
|
35
|
+
// Extract options from last argument if it's an object with custom properties
|
|
36
|
+
const lastArg = args[args.length - 1];
|
|
37
|
+
|
|
38
|
+
// List of all valid transaction option keys (except 'data', 'to', 'from' which are handled internally)
|
|
39
|
+
const validTxOptions = [
|
|
40
|
+
'value',
|
|
41
|
+
'nonce',
|
|
42
|
+
'gasLimit',
|
|
43
|
+
'gas', // Maps to gasLimit
|
|
44
|
+
'gasPrice',
|
|
45
|
+
'maxFeePerGas',
|
|
46
|
+
'maxPriorityFeePerGas',
|
|
47
|
+
'chainId',
|
|
48
|
+
'accessList',
|
|
49
|
+
'type',
|
|
50
|
+
'customData',
|
|
51
|
+
'from' // Special handling for signer switching
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const hasOptions =
|
|
55
|
+
lastArg &&
|
|
56
|
+
typeof lastArg === 'object' &&
|
|
57
|
+
!Array.isArray(lastArg) &&
|
|
58
|
+
Object.keys(lastArg).some(key => validTxOptions.includes(key));
|
|
59
|
+
|
|
60
|
+
// Warn if user tries to pass 'data'
|
|
61
|
+
if (lastArg && typeof lastArg === 'object' && lastArg.data) {
|
|
62
|
+
console.warn(
|
|
63
|
+
"Warning: 'data' option is ignored. " +
|
|
64
|
+
"Function calldata is automatically encoded by ethers.js. " +
|
|
65
|
+
"Use .connect() to change the signer if needed."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const options = hasOptions ? args.pop() : null;
|
|
70
|
+
|
|
71
|
+
let method = target[prop];
|
|
72
|
+
let txOptions = {};
|
|
73
|
+
|
|
74
|
+
// Handle 'from' option - switch signer if specified
|
|
75
|
+
if (options && options.from) {
|
|
76
|
+
const account = allAccounts.find(
|
|
77
|
+
acc => acc.address?.toLowerCase() === options.from.toLowerCase()
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (!account) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Account ${options.from} not found in registered accounts`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!account.privateKey) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Account ${options.from} is a node-managed account and cannot be used with {from}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Create new signer with the specified account
|
|
93
|
+
const newSigner = new ethers.Wallet(account.privateKey, provider);
|
|
94
|
+
const connectedContract = target.connect(newSigner);
|
|
95
|
+
method = connectedContract[prop];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build transaction options object with all supported ethers.js v6 options
|
|
99
|
+
if (options) {
|
|
100
|
+
// Value (for payable functions)
|
|
101
|
+
if (options.value !== undefined) {
|
|
102
|
+
txOptions.value = options.value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Gas limit (handle both 'gas' and 'gasLimit')
|
|
106
|
+
if (options.gasLimit !== undefined) {
|
|
107
|
+
txOptions.gasLimit = options.gasLimit;
|
|
108
|
+
} else if (options.gas !== undefined) {
|
|
109
|
+
txOptions.gasLimit = options.gas; // Map 'gas' to 'gasLimit'
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Legacy gas price
|
|
113
|
+
if (options.gasPrice !== undefined) {
|
|
114
|
+
txOptions.gasPrice = options.gasPrice;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// EIP-1559 options
|
|
118
|
+
if (options.maxFeePerGas !== undefined) {
|
|
119
|
+
txOptions.maxFeePerGas = options.maxFeePerGas;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (options.maxPriorityFeePerGas !== undefined) {
|
|
123
|
+
txOptions.maxPriorityFeePerGas = options.maxPriorityFeePerGas;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Nonce for transaction ordering
|
|
127
|
+
if (options.nonce !== undefined) {
|
|
128
|
+
txOptions.nonce = options.nonce;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Chain ID
|
|
132
|
+
if (options.chainId !== undefined) {
|
|
133
|
+
txOptions.chainId = options.chainId;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// EIP-2930 access list
|
|
137
|
+
if (options.accessList !== undefined) {
|
|
138
|
+
txOptions.accessList = options.accessList;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Transaction type
|
|
142
|
+
if (options.type !== undefined) {
|
|
143
|
+
txOptions.type = options.type;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Custom data (for special networks like zkSync)
|
|
147
|
+
if (options.customData !== undefined) {
|
|
148
|
+
txOptions.customData = options.customData;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// If there are transaction options, pass them as the last argument
|
|
153
|
+
if (Object.keys(txOptions).length > 0) {
|
|
154
|
+
args.push(txOptions);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Call the method with remaining args and tx options
|
|
158
|
+
return method.apply(method, args);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
package/src/utils/dir.js
CHANGED
|
@@ -57,6 +57,16 @@ export function collectSolFiles(dirPath) {
|
|
|
57
57
|
*/
|
|
58
58
|
export function findImports(importPath, basePath) {
|
|
59
59
|
try {
|
|
60
|
+
// Handle node_modules imports (e.g., @openzeppelin/contracts/...)
|
|
61
|
+
if (importPath.startsWith('@')) {
|
|
62
|
+
const nodeModulesPath = path.resolve(process.cwd(), 'node_modules', importPath);
|
|
63
|
+
|
|
64
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
65
|
+
const content = fs.readFileSync(nodeModulesPath, 'utf8');
|
|
66
|
+
return { contents: content };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
// Resolve relative to the current file's directory
|
|
61
71
|
const resolvedPath = path.resolve(basePath, importPath);
|
|
62
72
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function serializeBigInts(obj) {
|
|
2
|
+
try{
|
|
3
|
+
if (Array.isArray(obj)) {
|
|
4
|
+
return obj.map(serializeBigInts);
|
|
5
|
+
} else if (obj && typeof obj === 'object') {
|
|
6
|
+
return Object.fromEntries(
|
|
7
|
+
Object.entries(obj).map(([key, value]) => [
|
|
8
|
+
key,
|
|
9
|
+
typeof value === 'bigint' ? value.toString() : serializeBigInts(value)
|
|
10
|
+
])
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return obj;
|
|
14
|
+
}catch(err){
|
|
15
|
+
console.error(err);
|
|
16
|
+
}
|
|
17
|
+
}
|