@subsquid/evm-typegen 1.0.1 → 1.2.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/lib/main.js +133 -38
- package/lib/main.js.map +1 -1
- package/package.json +2 -2
- package/src/main.ts +168 -51
package/lib/main.js
CHANGED
|
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.run = void 0;
|
|
7
|
+
const abi_1 = require("@ethersproject/abi");
|
|
8
|
+
const util_internal_code_printer_1 = require("@subsquid/util-internal-code-printer");
|
|
7
9
|
const commander_1 = require("commander");
|
|
8
|
-
const process_1 = __importDefault(require("process"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const process_1 = __importDefault(require("process"));
|
|
13
13
|
function run() {
|
|
14
14
|
commander_1.program.description(`
|
|
15
15
|
Generates TypeScript definitions for evm log events
|
|
@@ -42,6 +42,7 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
42
42
|
const rawABI = JSON.parse(fs_1.default.readFileSync(inputPathRaw, { encoding: "utf-8" }));
|
|
43
43
|
const output = new util_internal_code_printer_1.Output();
|
|
44
44
|
output.line("import * as ethers from \"ethers\";");
|
|
45
|
+
output.line("import assert from \"assert\";");
|
|
45
46
|
output.line();
|
|
46
47
|
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
47
48
|
output.line();
|
|
@@ -49,7 +50,6 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
49
50
|
const abi = new abi_1.Interface(rawABI);
|
|
50
51
|
const typeNames = {};
|
|
51
52
|
const abiEvents = Object.values(abi.events).map((event) => {
|
|
52
|
-
let signature = `${event.name}(`;
|
|
53
53
|
let eventTypeName = `${event.name}`;
|
|
54
54
|
if (typeNames[event.name]) {
|
|
55
55
|
eventTypeName += typeNames[event.name].toString();
|
|
@@ -59,6 +59,8 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
59
59
|
eventTypeName += "0";
|
|
60
60
|
typeNames[event.name] = 1;
|
|
61
61
|
}
|
|
62
|
+
eventTypeName += 'Event';
|
|
63
|
+
let signature = `${event.name}(`;
|
|
62
64
|
if (event.inputs.length > 0) {
|
|
63
65
|
signature += event.inputs[0].type;
|
|
64
66
|
}
|
|
@@ -74,11 +76,7 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
74
76
|
};
|
|
75
77
|
});
|
|
76
78
|
for (const decl of abiEvents) {
|
|
77
|
-
output.
|
|
78
|
-
for (const input of decl.inputs) {
|
|
79
|
-
output.line(`${input.name}: ${getType(input)};`);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
79
|
+
output.line(`export type ${decl.eventTypeName} = ${getTupleType(decl.inputs)}`);
|
|
82
80
|
output.line("");
|
|
83
81
|
}
|
|
84
82
|
output.block("export interface EvmEvent", () => {
|
|
@@ -86,30 +84,116 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
86
84
|
output.line("topics: string[];");
|
|
87
85
|
});
|
|
88
86
|
output.line();
|
|
87
|
+
output.block(`function decodeEvent(signature: string, data: EvmEvent): any`, () => {
|
|
88
|
+
output.line(`return abi.decodeEventLog(`);
|
|
89
|
+
output.indentation(() => {
|
|
90
|
+
output.line(`abi.getEvent(signature),`);
|
|
91
|
+
output.line(`data.data || "",`);
|
|
92
|
+
output.line("data.topics");
|
|
93
|
+
});
|
|
94
|
+
output.line(");");
|
|
95
|
+
});
|
|
96
|
+
output.line();
|
|
89
97
|
output.block("export const events =", () => {
|
|
90
98
|
for (const decl of abiEvents) {
|
|
91
|
-
output.block(`"${decl.signature}"
|
|
99
|
+
output.block(`"${decl.signature}":`, () => {
|
|
92
100
|
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
93
|
-
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}
|
|
94
|
-
output.line(`
|
|
95
|
-
output.indentation(() => {
|
|
96
|
-
output.line(`abi.getEvent("${decl.signature}"),`);
|
|
97
|
-
output.line(`data.data || "",`);
|
|
98
|
-
output.line("data.topics");
|
|
99
|
-
});
|
|
100
|
-
output.line(");");
|
|
101
|
-
output.block("return ", () => {
|
|
102
|
-
for (let i = 0; i < decl.inputs.length; ++i) {
|
|
103
|
-
const input = decl.inputs[i];
|
|
104
|
-
output.line(`${input.name}: ${`result[${i}]`},`);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
101
|
+
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}`, () => {
|
|
102
|
+
output.line(`return decodeEvent("${decl.signature}", data)`);
|
|
107
103
|
});
|
|
108
104
|
});
|
|
109
105
|
output.line(",");
|
|
110
106
|
}
|
|
111
107
|
});
|
|
112
108
|
output.line();
|
|
109
|
+
let abiFunctions = new Map();
|
|
110
|
+
for (let func of Object.values(abi.functions)) {
|
|
111
|
+
if (!func.constant || func.outputs == null)
|
|
112
|
+
continue;
|
|
113
|
+
let abiFunction = abiFunctions.get(func.name);
|
|
114
|
+
if (abiFunction == null) {
|
|
115
|
+
abiFunction = {
|
|
116
|
+
name: func.name,
|
|
117
|
+
overloads: []
|
|
118
|
+
};
|
|
119
|
+
abiFunctions.set(func.name, abiFunction);
|
|
120
|
+
}
|
|
121
|
+
let returnTypeName = func.outputs.length == 1 ? getType(func.outputs[0]) : getTupleType(func.outputs);
|
|
122
|
+
abiFunction.overloads.push({
|
|
123
|
+
inputs: func.inputs,
|
|
124
|
+
outputs: func.outputs || [],
|
|
125
|
+
returnTypeName
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
output.block("interface ChainContext ", () => {
|
|
129
|
+
output.line(`_chain: Chain`);
|
|
130
|
+
});
|
|
131
|
+
output.line();
|
|
132
|
+
output.block("interface BlockContext ", () => {
|
|
133
|
+
output.line(`_chain: Chain`);
|
|
134
|
+
output.line(`block: Block`);
|
|
135
|
+
});
|
|
136
|
+
output.line();
|
|
137
|
+
output.block("interface Block ", () => {
|
|
138
|
+
output.line(`height: number`);
|
|
139
|
+
});
|
|
140
|
+
output.line();
|
|
141
|
+
output.block("interface Chain ", () => {
|
|
142
|
+
output.block("client: ", () => {
|
|
143
|
+
output.line(`call: <T=any>(method: string, params?: unknown[]) => Promise<T>`);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
output.line();
|
|
147
|
+
output.block("export class Contract ", () => {
|
|
148
|
+
output.line(`private readonly _chain: Chain`);
|
|
149
|
+
output.line(`private readonly blockHeight: number`);
|
|
150
|
+
output.line(`readonly address: string`);
|
|
151
|
+
output.line();
|
|
152
|
+
output.line(`constructor(ctx: BlockContext, address: string)`);
|
|
153
|
+
output.line(`constructor(ctx: ChainContext, block: Block, address: string)`);
|
|
154
|
+
output.block(`constructor(ctx: BlockContext, blockOrAddress: Block | string, address?: string)`, () => {
|
|
155
|
+
output.line(`this._chain = ctx._chain`);
|
|
156
|
+
output.block(`if (typeof blockOrAddress === 'string') `, () => {
|
|
157
|
+
output.line(`this.blockHeight = ctx.block.height`);
|
|
158
|
+
output.line(`this.address = ethers.utils.getAddress(blockOrAddress)`);
|
|
159
|
+
});
|
|
160
|
+
output.block(`else `, () => {
|
|
161
|
+
output.line(`assert(address != null)`);
|
|
162
|
+
output.line(`this.blockHeight = blockOrAddress.height`);
|
|
163
|
+
output.line(`this.address = ethers.utils.getAddress(address)`);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
output.line();
|
|
167
|
+
for (const decl of abiFunctions.values()) {
|
|
168
|
+
if (decl.overloads.length > 1) {
|
|
169
|
+
for (let overload of decl.overloads) {
|
|
170
|
+
const args = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`);
|
|
171
|
+
const returnType = overload.returnTypeName;
|
|
172
|
+
output.line(`async ${decl.name}(${args}): Promise<${returnType}>`);
|
|
173
|
+
}
|
|
174
|
+
output.block(`async ${decl.name}(...args: any[])`, () => {
|
|
175
|
+
output.line(`return this.call("${decl.name}", args)`);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const overload = decl.overloads[0];
|
|
180
|
+
const params = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`);
|
|
181
|
+
const returnType = overload.returnTypeName;
|
|
182
|
+
output.block(`async ${decl.name}(${params.join(`, `)}): Promise<${returnType}>`, () => {
|
|
183
|
+
output.line(`return this.call("${decl.name}", [${overload.inputs.map((i, n) => `${i.name || `arg${n}`}`).join(`, `)}])`);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
output.line();
|
|
187
|
+
}
|
|
188
|
+
output.block(`private async call(name: string, args: any[]) : Promise<any>`, () => {
|
|
189
|
+
output.line(`const fragment = abi.getFunction(name)`);
|
|
190
|
+
output.line(`const data = abi.encodeFunctionData(fragment, args)`);
|
|
191
|
+
output.line(`const result = await this._chain.client.call('eth_call', [{to: this.address, data}, this.blockHeight])`);
|
|
192
|
+
output.line(`const decoded = abi.decodeFunctionResult(fragment, result)`);
|
|
193
|
+
output.line(`return decoded.length > 1 ? decoded : decoded[0]`);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
output.line();
|
|
113
197
|
output.block("function getJsonAbi(): any", () => {
|
|
114
198
|
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
115
199
|
output.line(line);
|
|
@@ -118,7 +202,7 @@ function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
|
118
202
|
fs_1.default.writeFileSync(outputPathRaw, output.toString());
|
|
119
203
|
}
|
|
120
204
|
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
121
|
-
function getType(param
|
|
205
|
+
function getType(param) {
|
|
122
206
|
if (param.type === "address" || param.type === "string") {
|
|
123
207
|
return "string";
|
|
124
208
|
}
|
|
@@ -126,28 +210,39 @@ function getType(param, flexible) {
|
|
|
126
210
|
return "boolean";
|
|
127
211
|
}
|
|
128
212
|
if (param.type.substring(0, 5) === "bytes") {
|
|
129
|
-
if (flexible) {
|
|
130
|
-
return "string | ethers.utils.BytesLike";
|
|
131
|
-
}
|
|
132
213
|
return "string";
|
|
133
214
|
}
|
|
134
215
|
let match = param.type.match(/^(u?int)([0-9]+)$/);
|
|
135
216
|
if (match) {
|
|
136
|
-
|
|
137
|
-
return "ethers.BigNumberish";
|
|
138
|
-
}
|
|
139
|
-
if (parseInt(match[2]) < 53) {
|
|
140
|
-
return 'number';
|
|
141
|
-
}
|
|
142
|
-
return 'ethers.BigNumber';
|
|
217
|
+
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber';
|
|
143
218
|
}
|
|
144
219
|
if (param.baseType === "array") {
|
|
145
220
|
return "Array<" + getType(param.arrayChildren) + ">";
|
|
146
221
|
}
|
|
147
222
|
if (param.baseType === "tuple") {
|
|
148
|
-
|
|
149
|
-
return "{ " + struct.join(", ") + " }";
|
|
223
|
+
return getTupleType(param.components);
|
|
150
224
|
}
|
|
151
225
|
throw new Error("unknown type");
|
|
152
226
|
}
|
|
227
|
+
function getTupleType(params) {
|
|
228
|
+
let tuple = '[' + params.map(p => {
|
|
229
|
+
return p.name ? `${p.name}: ${getType(p)}` : getType(p);
|
|
230
|
+
}).join(', ') + ']';
|
|
231
|
+
let fields = getStructFields(params);
|
|
232
|
+
if (fields.length == 0)
|
|
233
|
+
return tuple;
|
|
234
|
+
let struct = '{' + fields.map(f => `${f.name}: ${getType(f)}`).join(', ') + '}';
|
|
235
|
+
return `(${tuple} & ${struct})`;
|
|
236
|
+
}
|
|
237
|
+
// https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/abi/src.ts/coders/tuple.ts#L29
|
|
238
|
+
function getStructFields(params) {
|
|
239
|
+
let array = [];
|
|
240
|
+
let counts = {};
|
|
241
|
+
for (let p of params) {
|
|
242
|
+
if (p.name && array[p.name] == null) {
|
|
243
|
+
counts[p.name] = (counts[p.name] || 0) + 1;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return params.filter(p => counts[p.name] == 1);
|
|
247
|
+
}
|
|
153
248
|
//# sourceMappingURL=main.js.map
|
package/lib/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subsquid/evm-typegen",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CLI for generating typescript types and decode implementations for evm logs",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"repository": "git@github.com:subsquid/squid.git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"commander": "^9.3.0",
|
|
20
20
|
"@ethersproject/abi": "^5.6.4",
|
|
21
|
-
"@subsquid/util-internal-code-printer": "^0.0.
|
|
21
|
+
"@subsquid/util-internal-code-printer": "^0.0.2"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^16.11.41",
|
package/src/main.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import fs from "fs"
|
|
5
|
-
import
|
|
6
|
-
import
|
|
1
|
+
import {EventFragment, Interface, ParamType} from "@ethersproject/abi"
|
|
2
|
+
import {Output} from "@subsquid/util-internal-code-printer"
|
|
3
|
+
import {program} from "commander"
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import process from "process"
|
|
7
7
|
|
|
8
8
|
export function run(): void {
|
|
9
9
|
program.description(`
|
|
@@ -21,7 +21,7 @@ for use within substrate-processor mapping handlers.
|
|
|
21
21
|
|
|
22
22
|
try {
|
|
23
23
|
generateTsFromAbi(inputPath, outputPath);
|
|
24
|
-
} catch(err: any) {
|
|
24
|
+
} catch (err: any) {
|
|
25
25
|
console.error(`evm-typegen error: ${err.toString()}`);
|
|
26
26
|
process.exit(1);
|
|
27
27
|
}
|
|
@@ -39,11 +39,12 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
39
39
|
throw new Error("invalid output file extension");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const rawABI = JSON.parse(fs.readFileSync(inputPathRaw, {
|
|
42
|
+
const rawABI = JSON.parse(fs.readFileSync(inputPathRaw, {encoding: "utf-8"}));
|
|
43
43
|
|
|
44
44
|
const output = new Output();
|
|
45
45
|
|
|
46
46
|
output.line("import * as ethers from \"ethers\";");
|
|
47
|
+
output.line("import assert from \"assert\";");
|
|
47
48
|
output.line();
|
|
48
49
|
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
49
50
|
output.line();
|
|
@@ -51,29 +52,27 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
51
52
|
// validate the abi
|
|
52
53
|
const abi = new Interface(rawABI);
|
|
53
54
|
|
|
54
|
-
const typeNames: {
|
|
55
|
+
const typeNames: {[key: string]: number} = {};
|
|
55
56
|
|
|
56
57
|
const abiEvents: Array<AbiEvent> = Object.values(abi.events).map((event: EventFragment): AbiEvent => {
|
|
57
|
-
let signature = `${event.name}(`;
|
|
58
58
|
let eventTypeName = `${event.name}`;
|
|
59
|
-
|
|
60
|
-
if(typeNames[event.name]) {
|
|
59
|
+
if (typeNames[event.name]) {
|
|
61
60
|
eventTypeName += typeNames[event.name].toString();
|
|
62
61
|
typeNames[event.name]++;
|
|
63
62
|
} else {
|
|
64
63
|
eventTypeName += "0";
|
|
65
64
|
typeNames[event.name] = 1;
|
|
66
65
|
}
|
|
66
|
+
eventTypeName += 'Event'
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
let signature = `${event.name}(`;
|
|
69
|
+
if (event.inputs.length > 0) {
|
|
69
70
|
signature += event.inputs[0].type;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
-
for (let i=1; i<event.inputs.length; ++i) {
|
|
72
|
+
for (let i = 1; i < event.inputs.length; ++i) {
|
|
73
73
|
const input = event.inputs[i];
|
|
74
74
|
signature += `,${input.type}`;
|
|
75
75
|
}
|
|
76
|
-
|
|
77
76
|
signature += ")";
|
|
78
77
|
|
|
79
78
|
return {
|
|
@@ -83,12 +82,8 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
83
82
|
};
|
|
84
83
|
});
|
|
85
84
|
|
|
86
|
-
for(const decl of abiEvents) {
|
|
87
|
-
output.
|
|
88
|
-
for (const input of decl.inputs) {
|
|
89
|
-
output.line(`${input.name}: ${getType(input)};`);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
85
|
+
for (const decl of abiEvents) {
|
|
86
|
+
output.line(`export type ${decl.eventTypeName} = ${getTupleType(decl.inputs)}`)
|
|
92
87
|
output.line("");
|
|
93
88
|
}
|
|
94
89
|
|
|
@@ -99,24 +94,24 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
99
94
|
|
|
100
95
|
output.line();
|
|
101
96
|
|
|
97
|
+
output.block(`function decodeEvent(signature: string, data: EvmEvent): any`, () => {
|
|
98
|
+
output.line(`return abi.decodeEventLog(`);
|
|
99
|
+
output.indentation(() => {
|
|
100
|
+
output.line(`abi.getEvent(signature),`);
|
|
101
|
+
output.line(`data.data || "",`);
|
|
102
|
+
output.line("data.topics");
|
|
103
|
+
});
|
|
104
|
+
output.line(");");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
output.line();
|
|
108
|
+
|
|
102
109
|
output.block("export const events =", () => {
|
|
103
|
-
for(const decl of abiEvents) {
|
|
104
|
-
output.block(`"${decl.signature}"
|
|
110
|
+
for (const decl of abiEvents) {
|
|
111
|
+
output.block(`"${decl.signature}":`, () => {
|
|
105
112
|
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
106
|
-
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}
|
|
107
|
-
output.line(`
|
|
108
|
-
output.indentation(() => {
|
|
109
|
-
output.line(`abi.getEvent("${decl.signature}"),`);
|
|
110
|
-
output.line(`data.data || "",`);
|
|
111
|
-
output.line("data.topics");
|
|
112
|
-
});
|
|
113
|
-
output.line(");");
|
|
114
|
-
output.block("return ", () => {
|
|
115
|
-
for (let i=0; i<decl.inputs.length; ++i) {
|
|
116
|
-
const input = decl.inputs[i];
|
|
117
|
-
output.line(`${input.name}: ${`result[${i}]`},`);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
113
|
+
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}`, () => {
|
|
114
|
+
output.line(`return decodeEvent("${decl.signature}", data)`);
|
|
120
115
|
});
|
|
121
116
|
});
|
|
122
117
|
output.line(",");
|
|
@@ -125,6 +120,98 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
125
120
|
|
|
126
121
|
output.line();
|
|
127
122
|
|
|
123
|
+
let abiFunctions: Map<string, AbiFunction> = new Map()
|
|
124
|
+
for (let func of Object.values(abi.functions)) {
|
|
125
|
+
if (!func.constant || func.outputs == null) continue
|
|
126
|
+
|
|
127
|
+
let abiFunction = abiFunctions.get(func.name)
|
|
128
|
+
if (abiFunction == null) {
|
|
129
|
+
abiFunction = {
|
|
130
|
+
name: func.name,
|
|
131
|
+
overloads: []
|
|
132
|
+
}
|
|
133
|
+
abiFunctions.set(func.name, abiFunction)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let returnTypeName = func.outputs.length == 1 ? getType(func.outputs[0]) : getTupleType(func.outputs)
|
|
137
|
+
|
|
138
|
+
abiFunction.overloads.push({
|
|
139
|
+
inputs: func.inputs,
|
|
140
|
+
outputs: func.outputs || [],
|
|
141
|
+
returnTypeName
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
output.block("interface ChainContext ", () => {
|
|
146
|
+
output.line(`_chain: Chain`);
|
|
147
|
+
})
|
|
148
|
+
output.line();
|
|
149
|
+
output.block("interface BlockContext ", () => {
|
|
150
|
+
output.line(`_chain: Chain`);
|
|
151
|
+
output.line(`block: Block`);
|
|
152
|
+
})
|
|
153
|
+
output.line();
|
|
154
|
+
output.block("interface Block ", () => {
|
|
155
|
+
output.line(`height: number`);
|
|
156
|
+
})
|
|
157
|
+
output.line();
|
|
158
|
+
output.block("interface Chain ", () => {
|
|
159
|
+
output.block("client: ", () => {
|
|
160
|
+
output.line(`call: <T=any>(method: string, params?: unknown[]) => Promise<T>`);
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
output.line();
|
|
164
|
+
output.block("export class Contract ", () => {
|
|
165
|
+
output.line(`private readonly _chain: Chain`);
|
|
166
|
+
output.line(`private readonly blockHeight: number`);
|
|
167
|
+
output.line(`readonly address: string`);
|
|
168
|
+
output.line();
|
|
169
|
+
output.line(`constructor(ctx: BlockContext, address: string)`);
|
|
170
|
+
output.line(`constructor(ctx: ChainContext, block: Block, address: string)`);
|
|
171
|
+
output.block(`constructor(ctx: BlockContext, blockOrAddress: Block | string, address?: string)`, () => {
|
|
172
|
+
output.line(`this._chain = ctx._chain`);
|
|
173
|
+
output.block(`if (typeof blockOrAddress === 'string') `, () => {
|
|
174
|
+
output.line(`this.blockHeight = ctx.block.height`)
|
|
175
|
+
output.line(`this.address = ethers.utils.getAddress(blockOrAddress)`)
|
|
176
|
+
})
|
|
177
|
+
output.block(`else `, () => {
|
|
178
|
+
output.line(`assert(address != null)`)
|
|
179
|
+
output.line(`this.blockHeight = blockOrAddress.height`)
|
|
180
|
+
output.line(`this.address = ethers.utils.getAddress(address)`)
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
output.line();
|
|
184
|
+
for (const decl of abiFunctions.values()) {
|
|
185
|
+
if (decl.overloads.length > 1) {
|
|
186
|
+
for (let overload of decl.overloads) {
|
|
187
|
+
const args = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`)
|
|
188
|
+
const returnType = overload.returnTypeName
|
|
189
|
+
output.line(`async ${decl.name}(${args}): Promise<${returnType}>`)
|
|
190
|
+
}
|
|
191
|
+
output.block(`async ${decl.name}(...args: any[])`, () => {
|
|
192
|
+
output.line(`return this.call("${decl.name}", args)`);
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
const overload = decl.overloads[0]
|
|
196
|
+
const params = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`)
|
|
197
|
+
const returnType = overload.returnTypeName
|
|
198
|
+
output.block(`async ${decl.name}(${params.join(`, `)}): Promise<${returnType}>`, () => {
|
|
199
|
+
output.line(`return this.call("${decl.name}", [${overload.inputs.map((i, n) => `${i.name || `arg${n}`}`).join(`, `)}])`);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
output.line();
|
|
203
|
+
}
|
|
204
|
+
output.block(`private async call(name: string, args: any[]) : Promise<any>`, () => {
|
|
205
|
+
output.line(`const fragment = abi.getFunction(name)`);
|
|
206
|
+
output.line(`const data = abi.encodeFunctionData(fragment, args)`);
|
|
207
|
+
output.line(`const result = await this._chain.client.call('eth_call', [{to: this.address, data}, this.blockHeight])`);
|
|
208
|
+
output.line(`const decoded = abi.decodeFunctionResult(fragment, result)`);
|
|
209
|
+
output.line(`return decoded.length > 1 ? decoded : decoded[0]`);
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
output.line();
|
|
214
|
+
|
|
128
215
|
output.block("function getJsonAbi(): any", () => {
|
|
129
216
|
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
130
217
|
output.line(line)
|
|
@@ -135,25 +222,22 @@ function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
|
135
222
|
}
|
|
136
223
|
|
|
137
224
|
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
138
|
-
function getType(param: ParamType
|
|
139
|
-
if (param.type === "address" || param.type === "string") {
|
|
225
|
+
function getType(param: ParamType): string {
|
|
226
|
+
if (param.type === "address" || param.type === "string") {
|
|
227
|
+
return "string"
|
|
228
|
+
}
|
|
140
229
|
|
|
141
|
-
if (param.type === "bool") {
|
|
230
|
+
if (param.type === "bool") {
|
|
231
|
+
return "boolean"
|
|
232
|
+
}
|
|
142
233
|
|
|
143
234
|
if (param.type.substring(0, 5) === "bytes") {
|
|
144
|
-
if (flexible) {
|
|
145
|
-
return "string | ethers.utils.BytesLike";
|
|
146
|
-
}
|
|
147
235
|
return "string"
|
|
148
236
|
}
|
|
149
237
|
|
|
150
238
|
let match = param.type.match(/^(u?int)([0-9]+)$/)
|
|
151
239
|
if (match) {
|
|
152
|
-
|
|
153
|
-
return "ethers.BigNumberish";
|
|
154
|
-
}
|
|
155
|
-
if (parseInt(match[2]) < 53) { return 'number'; }
|
|
156
|
-
return 'ethers.BigNumber';
|
|
240
|
+
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber'
|
|
157
241
|
}
|
|
158
242
|
|
|
159
243
|
if (param.baseType === "array") {
|
|
@@ -161,15 +245,48 @@ function getType(param: ParamType, flexible?: boolean): string {
|
|
|
161
245
|
}
|
|
162
246
|
|
|
163
247
|
if (param.baseType === "tuple") {
|
|
164
|
-
|
|
165
|
-
return "{ " + struct.join(", ") + " }";
|
|
248
|
+
return getTupleType(param.components);
|
|
166
249
|
}
|
|
167
250
|
|
|
168
251
|
throw new Error("unknown type");
|
|
169
252
|
}
|
|
170
253
|
|
|
254
|
+
function getTupleType(params: ParamType[]) {
|
|
255
|
+
let tuple = '[' + params.map(p => {
|
|
256
|
+
return p.name ? `${p.name}: ${getType(p)}` : getType(p)
|
|
257
|
+
}).join(', ') + ']'
|
|
258
|
+
|
|
259
|
+
let fields = getStructFields(params)
|
|
260
|
+
if (fields.length == 0) return tuple
|
|
261
|
+
|
|
262
|
+
let struct = '{' + fields.map(f => `${f.name}: ${getType(f)}`).join(', ') + '}'
|
|
263
|
+
|
|
264
|
+
return `(${tuple} & ${struct})`
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/abi/src.ts/coders/tuple.ts#L29
|
|
268
|
+
function getStructFields(params: ParamType[]): ParamType[] {
|
|
269
|
+
let array: any = []
|
|
270
|
+
let counts: Record<string, number> = {}
|
|
271
|
+
for (let p of params) {
|
|
272
|
+
if (p.name && array[p.name] == null) {
|
|
273
|
+
counts[p.name] = (counts[p.name] || 0) + 1
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return params.filter(p => counts[p.name] == 1)
|
|
277
|
+
}
|
|
278
|
+
|
|
171
279
|
interface AbiEvent {
|
|
172
280
|
signature: string;
|
|
173
281
|
eventTypeName: string;
|
|
174
282
|
inputs: ParamType[];
|
|
175
283
|
}
|
|
284
|
+
|
|
285
|
+
interface AbiFunction {
|
|
286
|
+
name: string;
|
|
287
|
+
overloads: {
|
|
288
|
+
inputs: ParamType[];
|
|
289
|
+
outputs: ParamType[];
|
|
290
|
+
returnTypeName?: string;
|
|
291
|
+
}[]
|
|
292
|
+
}
|