ethershell 0.1.1-alpha.15 → 0.1.1-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 +177 -32
- 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/serialize.js +17 -0
- package/src/utils/typeGenerator.js +247 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TypeScript type generation from Solidity ABIs
|
|
3
|
+
* @description Generates type-safe TypeScript interfaces and classes
|
|
4
|
+
* from compiled Solidity contracts for use in TypeScript projects
|
|
5
|
+
* @module typeGenerator
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate TypeScript types from contract ABI
|
|
13
|
+
* @param {string} contractName - Name of the contract
|
|
14
|
+
* @param {Array} abi - Contract ABI array
|
|
15
|
+
* @param {string} outputPath - Output directory for types
|
|
16
|
+
* @returns {string} Path to generated type file
|
|
17
|
+
*/
|
|
18
|
+
export function generateContractTypes(contractName, abi, outputPath) {
|
|
19
|
+
try {
|
|
20
|
+
// Ensure output directory exists
|
|
21
|
+
if (!fs.existsSync(outputPath)) {
|
|
22
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Generate TypeScript interfaces
|
|
26
|
+
const interfaces = generateInterfaces(contractName, abi);
|
|
27
|
+
const typePath = path.join(outputPath, `${contractName}.ts`);
|
|
28
|
+
|
|
29
|
+
fs.writeFileSync(typePath, interfaces);
|
|
30
|
+
|
|
31
|
+
return typePath;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(`Error generating types for ${contractName}:`, error.message);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generate all TypeScript types from build artifacts
|
|
40
|
+
* @param {string} buildPath - Path to build directory with ABIs
|
|
41
|
+
* @param {string} typesOutputPath - Output directory for TypeScript types
|
|
42
|
+
* @returns {Array} Array of generated type file paths
|
|
43
|
+
*/
|
|
44
|
+
export function generateAllTypes(buildPath, typesOutputPath = './src/types') {
|
|
45
|
+
try {
|
|
46
|
+
const abisPath = path.join(buildPath, 'abis');
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(abisPath)) {
|
|
49
|
+
throw new Error(`ABIs directory not found at ${abisPath}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const abiFiles = fs.readdirSync(abisPath).filter(f => f.endsWith('.abi.json'));
|
|
53
|
+
const generatedFiles = [];
|
|
54
|
+
|
|
55
|
+
abiFiles.forEach(file => {
|
|
56
|
+
const contractName = file.replace('.abi.json', '');
|
|
57
|
+
const abiPath = path.join(abisPath, file);
|
|
58
|
+
const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
|
|
59
|
+
|
|
60
|
+
const typePath = generateContractTypes(contractName, abi, typesOutputPath);
|
|
61
|
+
generatedFiles.push(typePath);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Generate index.ts for barrel export
|
|
65
|
+
generateIndexFile(typesOutputPath, abiFiles);
|
|
66
|
+
|
|
67
|
+
return generatedFiles;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error generating types:', error.message);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate TypeScript interface from ABI
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
function generateInterfaces(contractName, abi) {
|
|
79
|
+
const functions = abi.filter(item => item.type === 'function');
|
|
80
|
+
const events = abi.filter(item => item.type === 'event');
|
|
81
|
+
const structs = extractStructTypes(abi);
|
|
82
|
+
|
|
83
|
+
let typescript = `/**
|
|
84
|
+
* Auto-generated types for ${contractName} contract
|
|
85
|
+
* Generated from ABI
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
// ============= TYPES =============
|
|
89
|
+
${generateStructTypes(structs)}
|
|
90
|
+
|
|
91
|
+
// ============= FUNCTION INPUTS =============
|
|
92
|
+
${generateFunctionTypes(functions, 'input')}
|
|
93
|
+
|
|
94
|
+
// ============= FUNCTION OUTPUTS =============
|
|
95
|
+
${generateFunctionTypes(functions, 'output')}
|
|
96
|
+
|
|
97
|
+
// ============= EVENT TYPES =============
|
|
98
|
+
${generateEventTypes(events)}
|
|
99
|
+
|
|
100
|
+
// ============= CONTRACT INTERFACE =============
|
|
101
|
+
export interface I${contractName} {
|
|
102
|
+
${generateContractMethods(functions)}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============= ABI EXPORT =============
|
|
106
|
+
export const ${contractName}ABI = ${JSON.stringify(abi, null, 2)} as const;
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
return typescript;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Generate TypeScript types for function inputs/outputs
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
function generateFunctionTypes(functions, direction) {
|
|
117
|
+
const lines = [];
|
|
118
|
+
|
|
119
|
+
functions.forEach(func => {
|
|
120
|
+
const params = direction === 'input' ? func.inputs : func.outputs;
|
|
121
|
+
if (!params || params.length === 0) return;
|
|
122
|
+
|
|
123
|
+
const funcName = func.name;
|
|
124
|
+
const typeName = `${funcName.charAt(0).toUpperCase() + funcName.slice(1)}${direction === 'input' ? 'Params' : 'Result'}`;
|
|
125
|
+
|
|
126
|
+
lines.push(`export interface ${typeName} {`);
|
|
127
|
+
params.forEach((param, idx) => {
|
|
128
|
+
const name = param.name || `param${idx}`;
|
|
129
|
+
const type = solToTsType(param.type);
|
|
130
|
+
lines.push(` ${name}: ${type};`);
|
|
131
|
+
});
|
|
132
|
+
lines.push('}\n');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate TypeScript types for events
|
|
140
|
+
* @private
|
|
141
|
+
*/
|
|
142
|
+
function generateEventTypes(events) {
|
|
143
|
+
const lines = [];
|
|
144
|
+
|
|
145
|
+
events.forEach(event => {
|
|
146
|
+
const typeName = `${event.name}Event`;
|
|
147
|
+
lines.push(`export interface ${typeName} {`);
|
|
148
|
+
|
|
149
|
+
event.inputs.forEach((input, idx) => {
|
|
150
|
+
const name = input.name || `param${idx}`;
|
|
151
|
+
const type = solToTsType(input.type);
|
|
152
|
+
const indexed = input.indexed ? ' // indexed' : '';
|
|
153
|
+
lines.push(` ${name}: ${type};${indexed}`);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
lines.push('}\n');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return lines.join('\n');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generate contract method signatures
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
function generateContractMethods(functions) {
|
|
167
|
+
const lines = [];
|
|
168
|
+
|
|
169
|
+
functions.forEach(func => {
|
|
170
|
+
const inputs = func.inputs.map(inp => {
|
|
171
|
+
const type = solToTsType(inp.type);
|
|
172
|
+
return `${inp.name || 'param'}: ${type}`;
|
|
173
|
+
}).join(', ');
|
|
174
|
+
|
|
175
|
+
let returnType = 'Promise<void>';
|
|
176
|
+
if (func.outputs && func.outputs.length > 0) {
|
|
177
|
+
if (func.outputs.length === 1) {
|
|
178
|
+
returnType = `Promise<${solToTsType(func.outputs[0].type)}>`;
|
|
179
|
+
} else {
|
|
180
|
+
returnType = `Promise<[${func.outputs.map(o => solToTsType(o.type)).join(', ')}]>`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const stateMutability = func.stateMutability || 'nonpayable';
|
|
185
|
+
lines.push(` ${func.name}(${inputs}): ${returnType}; // ${stateMutability}`);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return lines.join('\n');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Convert Solidity type to TypeScript type
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
function solToTsType(solidityType) {
|
|
196
|
+
// Handle arrays
|
|
197
|
+
if (solidityType.endsWith(']')) {
|
|
198
|
+
const baseType = solidityType.replace(/\[\d*\]/g, '');
|
|
199
|
+
return `${solToTsType(baseType)}[]`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Handle base types
|
|
203
|
+
if (solidityType.startsWith('uint')) return 'bigint';
|
|
204
|
+
if (solidityType.startsWith('int')) return 'bigint';
|
|
205
|
+
if (solidityType.startsWith('bytes')) return 'string | Uint8Array';
|
|
206
|
+
if (solidityType === 'bool') return 'boolean';
|
|
207
|
+
if (solidityType === 'address') return 'string'; // EVM address as checksum string
|
|
208
|
+
if (solidityType === 'string') return 'string';
|
|
209
|
+
|
|
210
|
+
// Fallback for custom types
|
|
211
|
+
return 'any';
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Extract struct types from ABI
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
function extractStructTypes(abi) {
|
|
219
|
+
// This would require more advanced parsing for tuple types
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Generate struct type definitions
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
function generateStructTypes(structs) {
|
|
228
|
+
if (structs.length === 0) return '// No custom structs\n';
|
|
229
|
+
|
|
230
|
+
return structs.map(struct => `export interface ${struct.name} {\n // struct fields\n}\n`).join('\n');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Generate barrel export index.ts
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
237
|
+
function generateIndexFile(typesPath, abiFiles) {
|
|
238
|
+
const exports = abiFiles
|
|
239
|
+
.map(file => {
|
|
240
|
+
const name = file.replace('.abi.json', '');
|
|
241
|
+
return `export * from './${name}';`;
|
|
242
|
+
})
|
|
243
|
+
.join('\n');
|
|
244
|
+
|
|
245
|
+
const indexPath = path.join(typesPath, 'index.ts');
|
|
246
|
+
fs.writeFileSync(indexPath, `// Auto-generated barrel export\n${exports}\n`);
|
|
247
|
+
}
|