ethershell 0.1.0-alpha.0 → 0.1.0-alpha.10

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.
@@ -1,221 +1,221 @@
1
- /**
2
- * @fileoverview Smart contract deployment and management
3
- * @description Provides functions to deploy new smart contracts and add existing
4
- * contracts to the EtherShell environment. Manages contract instances and integrates
5
- * them with the REPL context.
6
- * @module addContracts
7
- */
8
-
9
- import { ethers } from 'ethers';
10
- import fs from 'fs';
11
- import { provider } from './network.js';
12
- import { allAccounts, accounts, hdAccounts } from './wallet.js';
13
- import { LocalStorage } from 'node-localstorage';
14
- import { r } from '../../bin/cli.js';
15
-
16
- /**
17
- * Local storage instance for persisting contract metadata
18
- * @type {LocalStorage}
19
- */
20
- const localStorage = new LocalStorage('./localStorage');
21
-
22
- /**
23
- * Map of all deployed and added contracts
24
- * @type {Map<string, ethers.Contract>}
25
- */
26
- export const contracts = new Map();
27
-
28
- /**
29
- * Deploy a new smart contract to the blockchain
30
- * @async
31
- * @param {string} contractName - Name of the contract to deploy
32
- * @param {Array} [args=[]] - Constructor arguments for the contract
33
- * @param {number} [accIndex=0] - Index of the account to deploy from
34
- * @param {string} [chain] - Optional custom chain URL
35
- * @param {string} [abiLoc] - Optional custom ABI file location
36
- * @param {string} [bytecodeLoc] - Optional custom bytecode file location
37
- * @returns {Promise<void>}
38
- * @throws {Error} If contract name is empty, account index is out of range, or deployment fails
39
- * @example
40
- * deploy('MyToken', [1000000], 0);
41
- */
42
- export async function deploy(contractName, args, accIndex, chain, abiLoc, bytecodeLoc) {
43
- try {
44
- let currentProvider;
45
- let connectedChain;
46
-
47
- if(!contractName) {
48
- throw new Error('Contract name is empty');
49
- }
50
-
51
- const contractArgs = args || [];
52
-
53
- if(accIndex > allAccounts.length - 1) {
54
- throw new Error('Wallet index is out of range');
55
- }
56
-
57
- if(!accIndex) {
58
- accIndex = 0;
59
- }
60
-
61
- if(chain) {
62
- currentProvider = new ethers.JsonRpcProvider(chain);
63
- } else {
64
- currentProvider = provider;
65
- }
66
-
67
- let wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
68
- connectedChain = await currentProvider.getNetwork();
69
-
70
- const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
71
- const bytecodePath = bytecodeLoc || localStorage.getItem(`${contractName}_bytecode`);
72
-
73
- const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
74
- const bytecode = JSON.parse(fs.readFileSync(bytecodePath, 'utf8'));
75
-
76
- const factory = new ethers.ContractFactory(abi, bytecode, wallet);
77
- const deployTx = await factory.deploy(...contractArgs);
78
- await deployTx.waitForDeployment();
79
-
80
- // Update deployer contract list
81
- const contSpec = {
82
- address: deployTx.target,
83
- deployedOn: connectedChain.name,
84
- chainId: connectedChain.chainId
85
- }
86
-
87
- allAccounts[accIndex].contracts.push(contSpec);
88
-
89
- const accountsIndex = accounts.findIndex(wallet => wallet.index == accIndex);
90
- if(accountsIndex >= 0) {
91
- accounts[accountsIndex].contracts.push(contSpec);
92
- }
93
-
94
- const hdIndex = hdAccounts.findIndex(wallet => wallet.index == accIndex);
95
- if(hdIndex >= 0) {
96
- hdAccounts[hdIndex].contracts.push(contSpec);
97
- }
98
-
99
- // Extend contract object
100
- deployTx.index = Array.from(contracts.values()).length;
101
- deployTx.name = contractName;
102
- deployTx.chain = connectedChain.name;
103
- deployTx.chainId = connectedChain.chainId;
104
- deployTx.deployType = 'ethershell-deployed',
105
- deployTx.provider = currentProvider;
106
-
107
- // Add to contract list
108
- contracts.set(contractName, deployTx);
109
-
110
- // Add to REPL context
111
- r.context[contractName] = deployTx;
112
-
113
- const deployHash = deployTx.deploymentTransaction().hash;
114
- const tx = await provider.getTransaction(deployHash);
115
- delete tx.data;
116
-
117
- // Extend transaction object
118
- tx.ethershellIndex = deployTx.index;
119
- tx.address = deployTx.target;
120
- tx.name = deployTx.name;
121
- tx.chain = deployTx.chain;
122
- tx.deployType = deployTx.deployType;
123
-
124
- console.log(tx);
125
- } catch(err) {
126
- console.error(err);
127
- }
128
- }
129
-
130
- /**
131
- * Add an existing deployed contract to EtherShell
132
- * @async
133
- * @param {string} contractName - Name to assign to the contract
134
- * @param {string} contractAddr - Address of the deployed contract
135
- * @param {number} [accIndex=0] - Index of the account to interact with the contract
136
- * @param {string} abiLoc - Path to the contract ABI file
137
- * @param {string} [chain] - Optional custom chain URL
138
- * @returns {Promise<void>}
139
- * @throws {Error} If contract address or ABI location is null/undefined
140
- * @example
141
- * add('USDT', '0xdac17f958d2ee523a2206206994597c13d831ec7', 0, './abis/USDT.json');
142
- */
143
- export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
144
- try {
145
- let currentProvider;
146
- let connectedChain;
147
-
148
- if(!contractAddr) {
149
- throw new Error('Contract address may not be null or undefined!');
150
- }
151
-
152
- if(!accIndex) {
153
- accIndex = 0;
154
- }
155
-
156
- if(chain) {
157
- currentProvider = new ethers.JsonRpcProvider(chain);
158
- } else {
159
- currentProvider = provider;
160
- }
161
-
162
- let wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
163
- connectedChain = await currentProvider.getNetwork();
164
-
165
- if(!abiLoc) {
166
- throw new Error('ABI path may not be null or undefined!');
167
- }
168
-
169
- const abi = JSON.parse(fs.readFileSync(abiLoc, 'utf8'));
170
-
171
- const newContract = new ethers.Contract(contractAddr, abi, wallet);
172
-
173
- // Update deployer contract list
174
- const contSpec = {
175
- address: newContract.target,
176
- deployedOn: connectedChain.name,
177
- chainId: connectedChain.chainId
178
- }
179
-
180
- allAccounts[accIndex].contracts.push(contSpec);
181
-
182
- const accountsIndex = accounts.findIndex(wallet => wallet.index == accIndex);
183
- if(accountsIndex >= 0) {
184
- accounts[accountsIndex].contracts.push(contSpec);
185
- }
186
-
187
- const hdIndex = hdAccounts.findIndex(wallet => wallet.index == accIndex);
188
- if(hdIndex >= 0) {
189
- hdAccounts[hdIndex].contracts.push(contSpec);
190
- }
191
-
192
- // Extend contract object
193
- newContract.index = Array.from(contracts.values()).length;
194
- newContract.name = contractName;
195
- newContract.chain = connectedChain.name;
196
- newContract.chainId = connectedChain.chainId;
197
- newContract.deployType = 'pre-deployed',
198
- newContract.provider = currentProvider;
199
-
200
- // Add to contract list
201
- contracts.set(contractName, newContract);
202
-
203
- // Add to REPL context
204
- r.context[contractName] = newContract;
205
-
206
- // Add result
207
- const result = {
208
- index: newContract.index,
209
- name: newContract.name,
210
- address: newContract.target,
211
- chain: newContract.chain,
212
- chainId: newContract.chainId,
213
- deployType: newContract.deployType,
214
- provider: newContract.provider
215
- }
216
-
217
- console.log(result);
218
- } catch(err) {
219
- console.error(err);
220
- }
221
- }
1
+ /**
2
+ * @fileoverview Smart contract deployment and management
3
+ * @description Provides functions to deploy new smart contracts and add existing
4
+ * contracts to the EtherShell environment. Manages contract instances and integrates
5
+ * them with the REPL context.
6
+ * @module addContracts
7
+ */
8
+
9
+ import { ethers } from 'ethers';
10
+ import fs from 'fs';
11
+ import { provider } from './network.js';
12
+ import { allAccounts, accounts, hdAccounts } from './wallet.js';
13
+ import { LocalStorage } from 'node-localstorage';
14
+ import { r } from '../../bin/cli.js';
15
+
16
+ /**
17
+ * Local storage instance for persisting contract metadata
18
+ * @type {LocalStorage}
19
+ */
20
+ const localStorage = new LocalStorage('./localStorage');
21
+
22
+ /**
23
+ * Map of all deployed and added contracts
24
+ * @type {Map<string, ethers.Contract>}
25
+ */
26
+ export const contracts = new Map();
27
+
28
+ /**
29
+ * Deploy a new smart contract to the blockchain
30
+ * @async
31
+ * @param {string} contractName - Name of the contract to deploy
32
+ * @param {Array} [args=[]] - Constructor arguments for the contract
33
+ * @param {number} [accIndex=0] - Index of the account to deploy from
34
+ * @param {string} [chain] - Optional custom chain URL
35
+ * @param {string} [abiLoc] - Optional custom ABI file location
36
+ * @param {string} [bytecodeLoc] - Optional custom bytecode file location
37
+ * @returns {Promise<void>}
38
+ * @throws {Error} If contract name is empty, account index is out of range, or deployment fails
39
+ * @example
40
+ * deploy('MyToken', [1000000], 0);
41
+ */
42
+ export async function deploy(contractName, args, accIndex, chain, abiLoc, bytecodeLoc) {
43
+ try {
44
+ let currentProvider;
45
+ let connectedChain;
46
+
47
+ if(!contractName) {
48
+ throw new Error('Contract name is empty');
49
+ }
50
+
51
+ const contractArgs = args || [];
52
+
53
+ if(accIndex > allAccounts.length - 1) {
54
+ throw new Error('Wallet index is out of range');
55
+ }
56
+
57
+ if(!accIndex) {
58
+ accIndex = 0;
59
+ }
60
+
61
+ if(chain) {
62
+ currentProvider = new ethers.JsonRpcProvider(chain);
63
+ } else {
64
+ currentProvider = provider;
65
+ }
66
+
67
+ let wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
68
+ connectedChain = await currentProvider.getNetwork();
69
+
70
+ const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
71
+ const bytecodePath = bytecodeLoc || localStorage.getItem(`${contractName}_bytecode`);
72
+
73
+ const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
74
+ const bytecode = JSON.parse(fs.readFileSync(bytecodePath, 'utf8'));
75
+
76
+ const factory = new ethers.ContractFactory(abi, bytecode, wallet);
77
+ const deployTx = await factory.deploy(...contractArgs);
78
+ await deployTx.waitForDeployment();
79
+
80
+ // Update deployer contract list
81
+ const contSpec = {
82
+ address: deployTx.target,
83
+ deployedOn: connectedChain.name,
84
+ chainId: connectedChain.chainId
85
+ }
86
+
87
+ allAccounts[accIndex].contracts.push(contSpec);
88
+
89
+ const accountsIndex = accounts.findIndex(wallet => wallet.index == accIndex);
90
+ if(accountsIndex >= 0) {
91
+ accounts[accountsIndex].contracts.push(contSpec);
92
+ }
93
+
94
+ const hdIndex = hdAccounts.findIndex(wallet => wallet.index == accIndex);
95
+ if(hdIndex >= 0) {
96
+ hdAccounts[hdIndex].contracts.push(contSpec);
97
+ }
98
+
99
+ // Extend contract object
100
+ deployTx.index = Array.from(contracts.values()).length;
101
+ deployTx.name = contractName;
102
+ deployTx.chain = connectedChain.name;
103
+ deployTx.chainId = connectedChain.chainId;
104
+ deployTx.deployType = 'ethershell-deployed',
105
+ deployTx.provider = currentProvider;
106
+
107
+ // Add to contract list
108
+ contracts.set(contractName, deployTx);
109
+
110
+ // Add to REPL context
111
+ r.context[contractName] = deployTx;
112
+
113
+ const deployHash = deployTx.deploymentTransaction().hash;
114
+ const tx = await provider.getTransaction(deployHash);
115
+ delete tx.data;
116
+
117
+ // Extend transaction object
118
+ tx.ethershellIndex = deployTx.index;
119
+ tx.address = deployTx.target;
120
+ tx.name = deployTx.name;
121
+ tx.chain = deployTx.chain;
122
+ tx.deployType = deployTx.deployType;
123
+
124
+ console.log(tx);
125
+ } catch(err) {
126
+ console.error(err);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Add an existing deployed contract to EtherShell
132
+ * @async
133
+ * @param {string} contractName - Name to assign to the contract
134
+ * @param {string} contractAddr - Address of the deployed contract
135
+ * @param {number} [accIndex=0] - Index of the account to interact with the contract
136
+ * @param {string} abiLoc - Path to the contract ABI file
137
+ * @param {string} [chain] - Optional custom chain URL
138
+ * @returns {Promise<void>}
139
+ * @throws {Error} If contract address or ABI location is null/undefined
140
+ * @example
141
+ * add('USDT', '0xdac17f958d2ee523a2206206994597c13d831ec7', 0, './abis/USDT.json');
142
+ */
143
+ export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
144
+ try {
145
+ let currentProvider;
146
+ let connectedChain;
147
+
148
+ if(!contractAddr) {
149
+ throw new Error('Contract address may not be null or undefined!');
150
+ }
151
+
152
+ if(!accIndex) {
153
+ accIndex = 0;
154
+ }
155
+
156
+ if(chain) {
157
+ currentProvider = new ethers.JsonRpcProvider(chain);
158
+ } else {
159
+ currentProvider = provider;
160
+ }
161
+
162
+ let wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
163
+ connectedChain = await currentProvider.getNetwork();
164
+
165
+ if(!abiLoc) {
166
+ throw new Error('ABI path may not be null or undefined!');
167
+ }
168
+
169
+ const abi = JSON.parse(fs.readFileSync(abiLoc, 'utf8'));
170
+
171
+ const newContract = new ethers.Contract(contractAddr, abi, wallet);
172
+
173
+ // Update deployer contract list
174
+ const contSpec = {
175
+ address: newContract.target,
176
+ deployedOn: connectedChain.name,
177
+ chainId: connectedChain.chainId
178
+ }
179
+
180
+ allAccounts[accIndex].contracts.push(contSpec);
181
+
182
+ const accountsIndex = accounts.findIndex(wallet => wallet.index == accIndex);
183
+ if(accountsIndex >= 0) {
184
+ accounts[accountsIndex].contracts.push(contSpec);
185
+ }
186
+
187
+ const hdIndex = hdAccounts.findIndex(wallet => wallet.index == accIndex);
188
+ if(hdIndex >= 0) {
189
+ hdAccounts[hdIndex].contracts.push(contSpec);
190
+ }
191
+
192
+ // Extend contract object
193
+ newContract.index = Array.from(contracts.values()).length;
194
+ newContract.name = contractName;
195
+ newContract.chain = connectedChain.name;
196
+ newContract.chainId = connectedChain.chainId;
197
+ newContract.deployType = 'pre-deployed',
198
+ newContract.provider = currentProvider;
199
+
200
+ // Add to contract list
201
+ contracts.set(contractName, newContract);
202
+
203
+ // Add to REPL context
204
+ r.context[contractName] = newContract;
205
+
206
+ // Add result
207
+ const result = {
208
+ index: newContract.index,
209
+ name: newContract.name,
210
+ address: newContract.target,
211
+ chain: newContract.chain,
212
+ chainId: newContract.chainId,
213
+ deployType: newContract.deployType,
214
+ provider: newContract.provider
215
+ }
216
+
217
+ console.log(result);
218
+ } catch(err) {
219
+ console.error(err);
220
+ }
221
+ }