@subsquid/evm-typegen 1.2.0 → 1.3.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.d.ts.map +1 -1
- package/lib/main.js +8 -219
- package/lib/main.js.map +1 -1
- package/lib/typegen.d.ts +14 -0
- package/lib/typegen.d.ts.map +1 -0
- package/lib/typegen.js +315 -0
- package/lib/typegen.js.map +1 -0
- package/package.json +3 -2
- package/src/main.ts +8 -266
- package/src/typegen.ts +342 -0
package/lib/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAKA,wBAAgB,GAAG,IAAI,IAAI,CA4B1B"}
|
package/lib/main.js
CHANGED
|
@@ -4,12 +4,10 @@ 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");
|
|
9
7
|
const commander_1 = require("commander");
|
|
10
|
-
const fs_1 = __importDefault(require("fs"));
|
|
11
8
|
const path_1 = __importDefault(require("path"));
|
|
12
9
|
const process_1 = __importDefault(require("process"));
|
|
10
|
+
const typegen_1 = require("./typegen");
|
|
13
11
|
function run() {
|
|
14
12
|
commander_1.program.description(`
|
|
15
13
|
Generates TypeScript definitions for evm log events
|
|
@@ -21,8 +19,14 @@ for use within substrate-processor mapping handlers.
|
|
|
21
19
|
const options = commander_1.program.opts();
|
|
22
20
|
const inputPath = options.abi;
|
|
23
21
|
const outputPath = options.output;
|
|
22
|
+
if (path_1.default.parse(inputPath).ext !== ".json") {
|
|
23
|
+
throw new Error("invalid abi file extension");
|
|
24
|
+
}
|
|
25
|
+
if (path_1.default.parse(outputPath).ext !== ".ts") {
|
|
26
|
+
throw new Error("invalid output file extension");
|
|
27
|
+
}
|
|
24
28
|
try {
|
|
25
|
-
|
|
29
|
+
new typegen_1.Typegen(inputPath, outputPath).generate();
|
|
26
30
|
}
|
|
27
31
|
catch (err) {
|
|
28
32
|
console.error(`evm-typegen error: ${err.toString()}`);
|
|
@@ -30,219 +34,4 @@ for use within substrate-processor mapping handlers.
|
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
exports.run = run;
|
|
33
|
-
function generateTsFromAbi(inputPathRaw, outputPathRaw) {
|
|
34
|
-
const inputPath = path_1.default.parse(inputPathRaw);
|
|
35
|
-
const outputPath = path_1.default.parse(outputPathRaw);
|
|
36
|
-
if (inputPath.ext !== ".json") {
|
|
37
|
-
throw new Error("invalid abi file extension");
|
|
38
|
-
}
|
|
39
|
-
if (outputPath.ext !== ".ts") {
|
|
40
|
-
throw new Error("invalid output file extension");
|
|
41
|
-
}
|
|
42
|
-
const rawABI = JSON.parse(fs_1.default.readFileSync(inputPathRaw, { encoding: "utf-8" }));
|
|
43
|
-
const output = new util_internal_code_printer_1.Output();
|
|
44
|
-
output.line("import * as ethers from \"ethers\";");
|
|
45
|
-
output.line("import assert from \"assert\";");
|
|
46
|
-
output.line();
|
|
47
|
-
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
48
|
-
output.line();
|
|
49
|
-
// validate the abi
|
|
50
|
-
const abi = new abi_1.Interface(rawABI);
|
|
51
|
-
const typeNames = {};
|
|
52
|
-
const abiEvents = Object.values(abi.events).map((event) => {
|
|
53
|
-
let eventTypeName = `${event.name}`;
|
|
54
|
-
if (typeNames[event.name]) {
|
|
55
|
-
eventTypeName += typeNames[event.name].toString();
|
|
56
|
-
typeNames[event.name]++;
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
eventTypeName += "0";
|
|
60
|
-
typeNames[event.name] = 1;
|
|
61
|
-
}
|
|
62
|
-
eventTypeName += 'Event';
|
|
63
|
-
let signature = `${event.name}(`;
|
|
64
|
-
if (event.inputs.length > 0) {
|
|
65
|
-
signature += event.inputs[0].type;
|
|
66
|
-
}
|
|
67
|
-
for (let i = 1; i < event.inputs.length; ++i) {
|
|
68
|
-
const input = event.inputs[i];
|
|
69
|
-
signature += `,${input.type}`;
|
|
70
|
-
}
|
|
71
|
-
signature += ")";
|
|
72
|
-
return {
|
|
73
|
-
signature,
|
|
74
|
-
eventTypeName,
|
|
75
|
-
inputs: event.inputs,
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
for (const decl of abiEvents) {
|
|
79
|
-
output.line(`export type ${decl.eventTypeName} = ${getTupleType(decl.inputs)}`);
|
|
80
|
-
output.line("");
|
|
81
|
-
}
|
|
82
|
-
output.block("export interface EvmEvent", () => {
|
|
83
|
-
output.line("data: string;");
|
|
84
|
-
output.line("topics: string[];");
|
|
85
|
-
});
|
|
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();
|
|
97
|
-
output.block("export const events =", () => {
|
|
98
|
-
for (const decl of abiEvents) {
|
|
99
|
-
output.block(`"${decl.signature}":`, () => {
|
|
100
|
-
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
101
|
-
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}`, () => {
|
|
102
|
-
output.line(`return decodeEvent("${decl.signature}", data)`);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
output.line(",");
|
|
106
|
-
}
|
|
107
|
-
});
|
|
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();
|
|
197
|
-
output.block("function getJsonAbi(): any", () => {
|
|
198
|
-
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
199
|
-
output.line(line);
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
fs_1.default.writeFileSync(outputPathRaw, output.toString());
|
|
203
|
-
}
|
|
204
|
-
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
205
|
-
function getType(param) {
|
|
206
|
-
if (param.type === "address" || param.type === "string") {
|
|
207
|
-
return "string";
|
|
208
|
-
}
|
|
209
|
-
if (param.type === "bool") {
|
|
210
|
-
return "boolean";
|
|
211
|
-
}
|
|
212
|
-
if (param.type.substring(0, 5) === "bytes") {
|
|
213
|
-
return "string";
|
|
214
|
-
}
|
|
215
|
-
let match = param.type.match(/^(u?int)([0-9]+)$/);
|
|
216
|
-
if (match) {
|
|
217
|
-
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber';
|
|
218
|
-
}
|
|
219
|
-
if (param.baseType === "array") {
|
|
220
|
-
return "Array<" + getType(param.arrayChildren) + ">";
|
|
221
|
-
}
|
|
222
|
-
if (param.baseType === "tuple") {
|
|
223
|
-
return getTupleType(param.components);
|
|
224
|
-
}
|
|
225
|
-
throw new Error("unknown type");
|
|
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
|
-
}
|
|
248
37
|
//# 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":";;;;;;AAAA,yCAAiC;AACjC,gDAAuB;AACvB,sDAA6B;AAC7B,uCAAiC;AAEjC,SAAgB,GAAG;IACf,mBAAO,CAAC,WAAW,CAAC;;;KAGnB,CAAC,IAAI,EAAE,CAAC;SACJ,cAAc,CAAC,cAAc,EAAE,yBAAyB,CAAC;SACzD,cAAc,CAAC,iBAAiB,EAAE,iCAAiC,CAAC,CAAC;IAE1E,mBAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,MAAM,OAAO,GAAG,mBAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;IAC9B,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAElC,IAAI,cAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,OAAO,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;KACjD;IAED,IAAI,cAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE;QACtC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;KACpD;IAED,IAAI;QACA,IAAI,iBAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;KACjD;IAAC,OAAO,GAAQ,EAAE;QACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACtD,iBAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACnB;AACL,CAAC;AA5BD,kBA4BC"}
|
package/lib/typegen.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class Typegen {
|
|
2
|
+
private rawAbi;
|
|
3
|
+
private abi;
|
|
4
|
+
private out;
|
|
5
|
+
constructor(abiFile: string, outPath: string);
|
|
6
|
+
generate(): void;
|
|
7
|
+
private generateEvents;
|
|
8
|
+
private generateFunctions;
|
|
9
|
+
private generateContract;
|
|
10
|
+
private getEvents;
|
|
11
|
+
private getFunctions;
|
|
12
|
+
private getCalls;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=typegen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.d.ts","sourceRoot":"","sources":["../src/typegen.ts"],"names":[],"mappings":"AAKA,qBAAa,OAAO;IAChB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,GAAG,CAAY;gBAEX,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM5C,QAAQ,IAAI,IAAI;IAoBhB,OAAO,CAAC,cAAc;IA0CtB,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,gBAAgB;IAyExB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,QAAQ;CAsBnB"}
|
package/lib/typegen.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.Typegen = void 0;
|
|
16
|
+
const abi_1 = require("@ethersproject/abi");
|
|
17
|
+
const util_internal_code_printer_1 = require("@subsquid/util-internal-code-printer");
|
|
18
|
+
const util_internal_1 = require("@subsquid/util-internal");
|
|
19
|
+
const fs_1 = __importDefault(require("fs"));
|
|
20
|
+
class Typegen {
|
|
21
|
+
constructor(abiFile, outPath) {
|
|
22
|
+
this.rawAbi = JSON.parse(fs_1.default.readFileSync(abiFile, { encoding: "utf-8" }));
|
|
23
|
+
this.abi = new abi_1.Interface(this.rawAbi);
|
|
24
|
+
this.out = new util_internal_code_printer_1.FileOutput(outPath);
|
|
25
|
+
}
|
|
26
|
+
generate() {
|
|
27
|
+
this.out.line("import * as ethers from \"ethers\";");
|
|
28
|
+
this.out.line("import assert from \"assert\";");
|
|
29
|
+
this.out.line();
|
|
30
|
+
this.out.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
31
|
+
this.out.line();
|
|
32
|
+
this.generateEvents();
|
|
33
|
+
this.out.line();
|
|
34
|
+
this.generateFunctions();
|
|
35
|
+
this.out.line();
|
|
36
|
+
this.generateContract();
|
|
37
|
+
this.out.line();
|
|
38
|
+
this.out.block("function getJsonAbi(): any", () => {
|
|
39
|
+
`return ${JSON.stringify(this.rawAbi, null, 2)}`.split('\n').forEach(line => {
|
|
40
|
+
this.out.line(line);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
this.out.write();
|
|
44
|
+
}
|
|
45
|
+
generateEvents() {
|
|
46
|
+
for (const decl of this.getEvents()) {
|
|
47
|
+
for (let i = 0; i < decl.overloads.length; i++) {
|
|
48
|
+
if (decl.overloads[i].inputs.length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
this.out.line(`export type ${decl.name}${i}Event = ${getTupleType(decl.overloads[i].inputs)}`);
|
|
51
|
+
this.out.line();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.out.block("export interface EvmLog", () => {
|
|
55
|
+
this.out.line("data: string;");
|
|
56
|
+
this.out.line("topics: string[];");
|
|
57
|
+
});
|
|
58
|
+
this.out.line();
|
|
59
|
+
this.out.block(`function decodeEvent(signature: string, data: EvmLog): any`, () => {
|
|
60
|
+
this.out.line(`return abi.decodeEventLog(`);
|
|
61
|
+
this.out.indentation(() => {
|
|
62
|
+
this.out.line(`abi.getEvent(signature),`);
|
|
63
|
+
this.out.line(`data.data || "",`);
|
|
64
|
+
this.out.line("data.topics");
|
|
65
|
+
});
|
|
66
|
+
this.out.line(");");
|
|
67
|
+
});
|
|
68
|
+
this.out.line();
|
|
69
|
+
this.out.block(`export const events =`, () => {
|
|
70
|
+
for (const event of this.getEvents()) {
|
|
71
|
+
for (let i = 0; i < event.overloads.length; i++) {
|
|
72
|
+
const overload = event.overloads[i];
|
|
73
|
+
const signature = createSignature(event.name, overload.inputs);
|
|
74
|
+
this.out.block(`"${signature}":`, () => {
|
|
75
|
+
this.out.line(`topic: abi.getEventTopic("${signature}"),`);
|
|
76
|
+
if (event.overloads[i].inputs.length > 0) {
|
|
77
|
+
this.out.block(`decode(data: EvmLog): ${event.name}${i}Event`, () => {
|
|
78
|
+
this.out.line(`return decodeEvent("${signature}", data)`);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
this.out.line(",");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
generateFunctions() {
|
|
88
|
+
for (const func of this.getFunctions()) {
|
|
89
|
+
for (let i = 0; i < func.overloads.length; i++) {
|
|
90
|
+
if (func.overloads[i].inputs.length === 0)
|
|
91
|
+
continue;
|
|
92
|
+
this.out.line(`export type ${upperCaseFirst(func.name)}${i}Function = ${getTupleType(func.overloads[i].inputs)}`);
|
|
93
|
+
this.out.line();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
this.out.line();
|
|
97
|
+
this.out.block(`function decodeFunction(data: string): any`, () => {
|
|
98
|
+
this.out.line(`return abi.decodeFunctionData(data.slice(0, 10), data)`);
|
|
99
|
+
});
|
|
100
|
+
this.out.line();
|
|
101
|
+
this.out.block(`export const functions =`, () => {
|
|
102
|
+
for (const func of this.getFunctions()) {
|
|
103
|
+
for (let i = 0; i < func.overloads.length; i++) {
|
|
104
|
+
const overload = func.overloads[i];
|
|
105
|
+
const signature = createSignature(func.name, overload.inputs);
|
|
106
|
+
this.out.block(`"${signature}":`, () => {
|
|
107
|
+
this.out.line(`sighash: abi.getSighash("${signature}"),`);
|
|
108
|
+
if (func.overloads[i].inputs.length > 0)
|
|
109
|
+
this.out.block(`decode(input: string): ${upperCaseFirst(func.name)}${i}Function`, () => {
|
|
110
|
+
this.out.line(`return decodeFunction(input)`);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
this.out.line(",");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
generateContract() {
|
|
119
|
+
let abiCalls = this.getCalls();
|
|
120
|
+
this.out.block("interface ChainContext ", () => {
|
|
121
|
+
this.out.line(`_chain: Chain`);
|
|
122
|
+
});
|
|
123
|
+
this.out.line();
|
|
124
|
+
this.out.block("interface BlockContext ", () => {
|
|
125
|
+
this.out.line(`_chain: Chain`);
|
|
126
|
+
this.out.line(`block: Block`);
|
|
127
|
+
});
|
|
128
|
+
this.out.line();
|
|
129
|
+
this.out.block("interface Block ", () => {
|
|
130
|
+
this.out.line(`height: number`);
|
|
131
|
+
});
|
|
132
|
+
this.out.line();
|
|
133
|
+
this.out.block("interface Chain ", () => {
|
|
134
|
+
this.out.block("client: ", () => {
|
|
135
|
+
this.out.line(`call: <T=any>(method: string, params?: unknown[]) => Promise<T>`);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
this.out.line();
|
|
139
|
+
this.out.block("export class Contract ", () => {
|
|
140
|
+
this.out.line(`private readonly _chain: Chain`);
|
|
141
|
+
this.out.line(`private readonly blockHeight: number`);
|
|
142
|
+
this.out.line(`readonly address: string`);
|
|
143
|
+
this.out.line();
|
|
144
|
+
this.out.line(`constructor(ctx: BlockContext, address: string)`);
|
|
145
|
+
this.out.line(`constructor(ctx: ChainContext, block: Block, address: string)`);
|
|
146
|
+
this.out.block(`constructor(ctx: BlockContext, blockOrAddress: Block | string, address?: string)`, () => {
|
|
147
|
+
this.out.line(`this._chain = ctx._chain`);
|
|
148
|
+
this.out.block(`if (typeof blockOrAddress === 'string') `, () => {
|
|
149
|
+
this.out.line(`this.blockHeight = ctx.block.height`);
|
|
150
|
+
this.out.line(`this.address = ethers.utils.getAddress(blockOrAddress)`);
|
|
151
|
+
});
|
|
152
|
+
this.out.block(`else `, () => {
|
|
153
|
+
this.out.line(`assert(address != null)`);
|
|
154
|
+
this.out.line(`this.blockHeight = blockOrAddress.height`);
|
|
155
|
+
this.out.line(`this.address = ethers.utils.getAddress(address)`);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
this.out.line();
|
|
159
|
+
for (const decl of abiCalls) {
|
|
160
|
+
if (decl.overloads.length > 1) {
|
|
161
|
+
for (let overload of decl.overloads) {
|
|
162
|
+
const args = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`);
|
|
163
|
+
const returnType = overload.outputs.length == 1 ? getType(overload.outputs[0]) : getTupleType(overload.outputs);
|
|
164
|
+
this.out.line(`async ${decl.name}(${args}): Promise<${returnType}>`);
|
|
165
|
+
}
|
|
166
|
+
this.out.block(`async ${decl.name}(...args: any[])`, () => {
|
|
167
|
+
this.out.line(`return this.call("${decl.name}", args)`);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const overload = decl.overloads[0];
|
|
172
|
+
const params = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`);
|
|
173
|
+
const returnType = overload.outputs.length == 1 ? getType(overload.outputs[0]) : getTupleType(overload.outputs);
|
|
174
|
+
this.out.block(`async ${decl.name}(${params.join(`, `)}): Promise<${returnType}>`, () => {
|
|
175
|
+
this.out.line(`return this.call("${decl.name}", [${overload.inputs.map((i, n) => `${i.name || `arg${n}`}`).join(`, `)}])`);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
this.out.line();
|
|
179
|
+
}
|
|
180
|
+
this.out.block(`private async call(name: string, args: any[]) : Promise<any>`, () => {
|
|
181
|
+
this.out.line(`const fragment = abi.getFunction(name)`);
|
|
182
|
+
this.out.line(`const data = abi.encodeFunctionData(fragment, args)`);
|
|
183
|
+
this.out.line(`const result = await this._chain.client.call('eth_call', [{to: this.address, data}, this.blockHeight])`);
|
|
184
|
+
this.out.line(`const decoded = abi.decodeFunctionResult(fragment, result)`);
|
|
185
|
+
this.out.line(`return decoded.length > 1 ? decoded : decoded[0]`);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
getEvents() {
|
|
190
|
+
let res = new Map();
|
|
191
|
+
for (let event of Object.values(this.abi.events)) {
|
|
192
|
+
let abiEvent = res.get(event.name);
|
|
193
|
+
if (abiEvent == null) {
|
|
194
|
+
abiEvent = {
|
|
195
|
+
name: event.name,
|
|
196
|
+
overloads: []
|
|
197
|
+
};
|
|
198
|
+
res.set(event.name, abiEvent);
|
|
199
|
+
}
|
|
200
|
+
abiEvent.overloads.push({
|
|
201
|
+
inputs: event.inputs || [],
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return [...res.values()];
|
|
205
|
+
}
|
|
206
|
+
getFunctions() {
|
|
207
|
+
let res = new Map();
|
|
208
|
+
for (let func of Object.values(this.abi.functions)) {
|
|
209
|
+
if (func.constant)
|
|
210
|
+
continue;
|
|
211
|
+
let abiFunc = res.get(func.name);
|
|
212
|
+
if (abiFunc == null) {
|
|
213
|
+
abiFunc = {
|
|
214
|
+
name: func.name,
|
|
215
|
+
overloads: []
|
|
216
|
+
};
|
|
217
|
+
res.set(func.name, abiFunc);
|
|
218
|
+
}
|
|
219
|
+
abiFunc.overloads.push({
|
|
220
|
+
inputs: func.inputs || [],
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return [...res.values()];
|
|
224
|
+
}
|
|
225
|
+
getCalls() {
|
|
226
|
+
let res = new Map();
|
|
227
|
+
for (let func of Object.values(this.abi.functions)) {
|
|
228
|
+
if (!func.constant || func.outputs == null)
|
|
229
|
+
continue;
|
|
230
|
+
let abiCall = res.get(func.name);
|
|
231
|
+
if (abiCall == null) {
|
|
232
|
+
abiCall = {
|
|
233
|
+
name: func.name,
|
|
234
|
+
overloads: []
|
|
235
|
+
};
|
|
236
|
+
res.set(func.name, abiCall);
|
|
237
|
+
}
|
|
238
|
+
abiCall.overloads.push({
|
|
239
|
+
inputs: func.inputs,
|
|
240
|
+
outputs: func.outputs || [],
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return [...res.values()];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
__decorate([
|
|
247
|
+
util_internal_1.def,
|
|
248
|
+
__metadata("design:type", Function),
|
|
249
|
+
__metadata("design:paramtypes", []),
|
|
250
|
+
__metadata("design:returntype", Array)
|
|
251
|
+
], Typegen.prototype, "getEvents", null);
|
|
252
|
+
__decorate([
|
|
253
|
+
util_internal_1.def,
|
|
254
|
+
__metadata("design:type", Function),
|
|
255
|
+
__metadata("design:paramtypes", []),
|
|
256
|
+
__metadata("design:returntype", Array)
|
|
257
|
+
], Typegen.prototype, "getFunctions", null);
|
|
258
|
+
__decorate([
|
|
259
|
+
util_internal_1.def,
|
|
260
|
+
__metadata("design:type", Function),
|
|
261
|
+
__metadata("design:paramtypes", []),
|
|
262
|
+
__metadata("design:returntype", Array)
|
|
263
|
+
], Typegen.prototype, "getCalls", null);
|
|
264
|
+
exports.Typegen = Typegen;
|
|
265
|
+
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
266
|
+
function getType(param) {
|
|
267
|
+
if (param.type === "address" || param.type === "string") {
|
|
268
|
+
return "string";
|
|
269
|
+
}
|
|
270
|
+
if (param.type === "bool") {
|
|
271
|
+
return "boolean";
|
|
272
|
+
}
|
|
273
|
+
if (param.type.substring(0, 5) === "bytes") {
|
|
274
|
+
return "string";
|
|
275
|
+
}
|
|
276
|
+
let match = param.type.match(/^(u?int)([0-9]+)$/);
|
|
277
|
+
if (match) {
|
|
278
|
+
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber';
|
|
279
|
+
}
|
|
280
|
+
if (param.baseType === "array") {
|
|
281
|
+
return "Array<" + getType(param.arrayChildren) + ">";
|
|
282
|
+
}
|
|
283
|
+
if (param.baseType === "tuple") {
|
|
284
|
+
return getTupleType(param.components);
|
|
285
|
+
}
|
|
286
|
+
throw new Error("unknown type");
|
|
287
|
+
}
|
|
288
|
+
function getTupleType(params) {
|
|
289
|
+
let tuple = '[' + params.map(p => {
|
|
290
|
+
return p.name ? `${p.name}: ${getType(p)}` : getType(p);
|
|
291
|
+
}).join(', ') + ']';
|
|
292
|
+
let fields = getStructFields(params);
|
|
293
|
+
if (fields.length == 0)
|
|
294
|
+
return tuple;
|
|
295
|
+
let struct = '{' + fields.map(f => `${f.name}: ${getType(f)}`).join(', ') + '}';
|
|
296
|
+
return `(${tuple} & ${struct})`;
|
|
297
|
+
}
|
|
298
|
+
// https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/abi/src.ts/coders/tuple.ts#L29
|
|
299
|
+
function getStructFields(params) {
|
|
300
|
+
let array = [];
|
|
301
|
+
let counts = {};
|
|
302
|
+
for (let p of params) {
|
|
303
|
+
if (p.name && array[p.name] == null) {
|
|
304
|
+
counts[p.name] = (counts[p.name] || 0) + 1;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return params.filter(p => counts[p.name] == 1);
|
|
308
|
+
}
|
|
309
|
+
function createSignature(name, inputs) {
|
|
310
|
+
return `${name}(${inputs.map((i) => i.type).join(`,`)})`;
|
|
311
|
+
}
|
|
312
|
+
function upperCaseFirst(s) {
|
|
313
|
+
return s[0].toUpperCase() + s.slice(1);
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=typegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.js","sourceRoot":"","sources":["../src/typegen.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.
|
|
3
|
+
"version": "1.3.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,8 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"commander": "^9.3.0",
|
|
20
20
|
"@ethersproject/abi": "^5.6.4",
|
|
21
|
-
"@subsquid/util-internal-code-printer": "^0.0.2"
|
|
21
|
+
"@subsquid/util-internal-code-printer": "^0.0.2",
|
|
22
|
+
"@subsquid/util-internal": "^0.0.1"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@types/node": "^16.11.41",
|
package/src/main.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {EventFragment, Interface, ParamType} from "@ethersproject/abi"
|
|
2
|
-
import {Output} from "@subsquid/util-internal-code-printer"
|
|
3
1
|
import {program} from "commander"
|
|
4
|
-
import fs from "fs"
|
|
5
2
|
import path from "path"
|
|
6
3
|
import process from "process"
|
|
4
|
+
import {Typegen} from "./typegen"
|
|
7
5
|
|
|
8
6
|
export function run(): void {
|
|
9
7
|
program.description(`
|
|
@@ -19,274 +17,18 @@ for use within substrate-processor mapping handlers.
|
|
|
19
17
|
const inputPath = options.abi;
|
|
20
18
|
const outputPath = options.output;
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
generateTsFromAbi(inputPath, outputPath);
|
|
24
|
-
} catch (err: any) {
|
|
25
|
-
console.error(`evm-typegen error: ${err.toString()}`);
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function generateTsFromAbi(inputPathRaw: string, outputPathRaw: string): void {
|
|
31
|
-
const inputPath = path.parse(inputPathRaw);
|
|
32
|
-
const outputPath = path.parse(outputPathRaw);
|
|
33
|
-
|
|
34
|
-
if (inputPath.ext !== ".json") {
|
|
20
|
+
if (path.parse(inputPath).ext !== ".json") {
|
|
35
21
|
throw new Error("invalid abi file extension");
|
|
36
22
|
}
|
|
37
23
|
|
|
38
|
-
if (outputPath.ext !== ".ts") {
|
|
24
|
+
if (path.parse(outputPath).ext !== ".ts") {
|
|
39
25
|
throw new Error("invalid output file extension");
|
|
40
26
|
}
|
|
41
27
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
output.line("import assert from \"assert\";");
|
|
48
|
-
output.line();
|
|
49
|
-
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
50
|
-
output.line();
|
|
51
|
-
|
|
52
|
-
// validate the abi
|
|
53
|
-
const abi = new Interface(rawABI);
|
|
54
|
-
|
|
55
|
-
const typeNames: {[key: string]: number} = {};
|
|
56
|
-
|
|
57
|
-
const abiEvents: Array<AbiEvent> = Object.values(abi.events).map((event: EventFragment): AbiEvent => {
|
|
58
|
-
let eventTypeName = `${event.name}`;
|
|
59
|
-
if (typeNames[event.name]) {
|
|
60
|
-
eventTypeName += typeNames[event.name].toString();
|
|
61
|
-
typeNames[event.name]++;
|
|
62
|
-
} else {
|
|
63
|
-
eventTypeName += "0";
|
|
64
|
-
typeNames[event.name] = 1;
|
|
65
|
-
}
|
|
66
|
-
eventTypeName += 'Event'
|
|
67
|
-
|
|
68
|
-
let signature = `${event.name}(`;
|
|
69
|
-
if (event.inputs.length > 0) {
|
|
70
|
-
signature += event.inputs[0].type;
|
|
71
|
-
}
|
|
72
|
-
for (let i = 1; i < event.inputs.length; ++i) {
|
|
73
|
-
const input = event.inputs[i];
|
|
74
|
-
signature += `,${input.type}`;
|
|
75
|
-
}
|
|
76
|
-
signature += ")";
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
signature,
|
|
80
|
-
eventTypeName,
|
|
81
|
-
inputs: event.inputs,
|
|
82
|
-
};
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
for (const decl of abiEvents) {
|
|
86
|
-
output.line(`export type ${decl.eventTypeName} = ${getTupleType(decl.inputs)}`)
|
|
87
|
-
output.line("");
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
output.block("export interface EvmEvent", () => {
|
|
91
|
-
output.line("data: string;");
|
|
92
|
-
output.line("topics: string[];");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
output.line();
|
|
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
|
-
|
|
109
|
-
output.block("export const events =", () => {
|
|
110
|
-
for (const decl of abiEvents) {
|
|
111
|
-
output.block(`"${decl.signature}":`, () => {
|
|
112
|
-
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
113
|
-
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}`, () => {
|
|
114
|
-
output.line(`return decodeEvent("${decl.signature}", data)`);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
output.line(",");
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
output.line();
|
|
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
|
-
|
|
215
|
-
output.block("function getJsonAbi(): any", () => {
|
|
216
|
-
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
217
|
-
output.line(line)
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
fs.writeFileSync(outputPathRaw, output.toString());
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
225
|
-
function getType(param: ParamType): string {
|
|
226
|
-
if (param.type === "address" || param.type === "string") {
|
|
227
|
-
return "string"
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (param.type === "bool") {
|
|
231
|
-
return "boolean"
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (param.type.substring(0, 5) === "bytes") {
|
|
235
|
-
return "string"
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
let match = param.type.match(/^(u?int)([0-9]+)$/)
|
|
239
|
-
if (match) {
|
|
240
|
-
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber'
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (param.baseType === "array") {
|
|
244
|
-
return "Array<" + getType(param.arrayChildren) + ">";
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (param.baseType === "tuple") {
|
|
248
|
-
return getTupleType(param.components);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
throw new Error("unknown type");
|
|
252
|
-
}
|
|
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
|
-
}
|
|
28
|
+
try {
|
|
29
|
+
new Typegen(inputPath, outputPath).generate();
|
|
30
|
+
} catch (err: any) {
|
|
31
|
+
console.error(`evm-typegen error: ${err.toString()}`);
|
|
32
|
+
process.exit(1);
|
|
275
33
|
}
|
|
276
|
-
return params.filter(p => counts[p.name] == 1)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
interface AbiEvent {
|
|
280
|
-
signature: string;
|
|
281
|
-
eventTypeName: string;
|
|
282
|
-
inputs: ParamType[];
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
interface AbiFunction {
|
|
286
|
-
name: string;
|
|
287
|
-
overloads: {
|
|
288
|
-
inputs: ParamType[];
|
|
289
|
-
outputs: ParamType[];
|
|
290
|
-
returnTypeName?: string;
|
|
291
|
-
}[]
|
|
292
34
|
}
|
package/src/typegen.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import {Interface, ParamType} from "@ethersproject/abi"
|
|
2
|
+
import {FileOutput, Output} from "@subsquid/util-internal-code-printer"
|
|
3
|
+
import {def} from "@subsquid/util-internal"
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
|
|
6
|
+
export class Typegen {
|
|
7
|
+
private rawAbi: any
|
|
8
|
+
private abi: Interface
|
|
9
|
+
private out: FileOutput
|
|
10
|
+
|
|
11
|
+
constructor(abiFile: string, outPath: string) {
|
|
12
|
+
this.rawAbi = JSON.parse(fs.readFileSync(abiFile, {encoding: "utf-8"}))
|
|
13
|
+
this.abi = new Interface(this.rawAbi)
|
|
14
|
+
this.out = new FileOutput(outPath)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
generate(): void {
|
|
18
|
+
this.out.line("import * as ethers from \"ethers\";")
|
|
19
|
+
this.out.line("import assert from \"assert\";")
|
|
20
|
+
this.out.line()
|
|
21
|
+
this.out.line("export const abi = new ethers.utils.Interface(getJsonAbi());")
|
|
22
|
+
this.out.line()
|
|
23
|
+
this.generateEvents()
|
|
24
|
+
this.out.line()
|
|
25
|
+
this.generateFunctions()
|
|
26
|
+
this.out.line()
|
|
27
|
+
this.generateContract()
|
|
28
|
+
this.out.line()
|
|
29
|
+
this.out.block("function getJsonAbi(): any", () => {
|
|
30
|
+
`return ${JSON.stringify(this.rawAbi, null, 2)}`.split('\n').forEach(line => {
|
|
31
|
+
this.out.line(line)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
this.out.write()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private generateEvents() {
|
|
38
|
+
for (const decl of this.getEvents()) {
|
|
39
|
+
for (let i = 0; i < decl.overloads.length; i++) {
|
|
40
|
+
if (decl.overloads[i].inputs.length === 0) continue
|
|
41
|
+
this.out.line(`export type ${decl.name}${i}Event = ${getTupleType(decl.overloads[i].inputs)}`)
|
|
42
|
+
this.out.line()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.out.block("export interface EvmLog", () => {
|
|
46
|
+
this.out.line("data: string;")
|
|
47
|
+
this.out.line("topics: string[];")
|
|
48
|
+
})
|
|
49
|
+
this.out.line()
|
|
50
|
+
this.out.block(`function decodeEvent(signature: string, data: EvmLog): any`, () => {
|
|
51
|
+
this.out.line(`return abi.decodeEventLog(`)
|
|
52
|
+
this.out.indentation(() => {
|
|
53
|
+
this.out.line(`abi.getEvent(signature),`)
|
|
54
|
+
this.out.line(`data.data || "",`)
|
|
55
|
+
this.out.line("data.topics")
|
|
56
|
+
})
|
|
57
|
+
this.out.line(");")
|
|
58
|
+
})
|
|
59
|
+
this.out.line()
|
|
60
|
+
this.out.block(`export const events =`, () => {
|
|
61
|
+
for (const event of this.getEvents()) {
|
|
62
|
+
for (let i = 0; i < event.overloads.length; i++) {
|
|
63
|
+
const overload = event.overloads[i]
|
|
64
|
+
const signature = createSignature(event.name, overload.inputs)
|
|
65
|
+
this.out.block(`"${signature}":`, () => {
|
|
66
|
+
this.out.line(`topic: abi.getEventTopic("${signature}"),`)
|
|
67
|
+
if (event.overloads[i].inputs.length > 0) {
|
|
68
|
+
this.out.block(`decode(data: EvmLog): ${event.name}${i}Event`, () => {
|
|
69
|
+
this.out.line(`return decodeEvent("${signature}", data)`)
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
this.out.line(",")
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private generateFunctions() {
|
|
80
|
+
for (const func of this.getFunctions()) {
|
|
81
|
+
for (let i = 0; i < func.overloads.length; i++) {
|
|
82
|
+
if (func.overloads[i].inputs.length === 0) continue
|
|
83
|
+
this.out.line(`export type ${upperCaseFirst(func.name)}${i}Function = ${getTupleType(func.overloads[i].inputs)}`)
|
|
84
|
+
this.out.line()
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.out.line()
|
|
88
|
+
this.out.block(`function decodeFunction(data: string): any`, () => {
|
|
89
|
+
this.out.line(`return abi.decodeFunctionData(data.slice(0, 10), data)`)
|
|
90
|
+
})
|
|
91
|
+
this.out.line()
|
|
92
|
+
this.out.block(`export const functions =`, () => {
|
|
93
|
+
for (const func of this.getFunctions()) {
|
|
94
|
+
for (let i = 0; i < func.overloads.length; i++) {
|
|
95
|
+
const overload = func.overloads[i]
|
|
96
|
+
const signature = createSignature(func.name, overload.inputs)
|
|
97
|
+
this.out.block(`"${signature}":`, () => {
|
|
98
|
+
this.out.line(`sighash: abi.getSighash("${signature}"),`)
|
|
99
|
+
if (func.overloads[i].inputs.length > 0)
|
|
100
|
+
this.out.block(`decode(input: string): ${upperCaseFirst(func.name)}${i}Function`, () => {
|
|
101
|
+
this.out.line(`return decodeFunction(input)`)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
this.out.line(",")
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private generateContract() {
|
|
111
|
+
let abiCalls = this.getCalls()
|
|
112
|
+
|
|
113
|
+
this.out.block("interface ChainContext ", () => {
|
|
114
|
+
this.out.line(`_chain: Chain`)
|
|
115
|
+
})
|
|
116
|
+
this.out.line()
|
|
117
|
+
this.out.block("interface BlockContext ", () => {
|
|
118
|
+
this.out.line(`_chain: Chain`)
|
|
119
|
+
this.out.line(`block: Block`)
|
|
120
|
+
})
|
|
121
|
+
this.out.line()
|
|
122
|
+
this.out.block("interface Block ", () => {
|
|
123
|
+
this.out.line(`height: number`)
|
|
124
|
+
})
|
|
125
|
+
this.out.line()
|
|
126
|
+
this.out.block("interface Chain ", () => {
|
|
127
|
+
this.out.block("client: ", () => {
|
|
128
|
+
this.out.line(`call: <T=any>(method: string, params?: unknown[]) => Promise<T>`)
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
this.out.line()
|
|
132
|
+
this.out.block("export class Contract ", () => {
|
|
133
|
+
this.out.line(`private readonly _chain: Chain`)
|
|
134
|
+
this.out.line(`private readonly blockHeight: number`)
|
|
135
|
+
this.out.line(`readonly address: string`)
|
|
136
|
+
this.out.line()
|
|
137
|
+
this.out.line(`constructor(ctx: BlockContext, address: string)`)
|
|
138
|
+
this.out.line(`constructor(ctx: ChainContext, block: Block, address: string)`)
|
|
139
|
+
this.out.block(`constructor(ctx: BlockContext, blockOrAddress: Block | string, address?: string)`, () => {
|
|
140
|
+
this.out.line(`this._chain = ctx._chain`)
|
|
141
|
+
this.out.block(`if (typeof blockOrAddress === 'string') `, () => {
|
|
142
|
+
this.out.line(`this.blockHeight = ctx.block.height`)
|
|
143
|
+
this.out.line(`this.address = ethers.utils.getAddress(blockOrAddress)`)
|
|
144
|
+
})
|
|
145
|
+
this.out.block(`else `, () => {
|
|
146
|
+
this.out.line(`assert(address != null)`)
|
|
147
|
+
this.out.line(`this.blockHeight = blockOrAddress.height`)
|
|
148
|
+
this.out.line(`this.address = ethers.utils.getAddress(address)`)
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
this.out.line()
|
|
152
|
+
for (const decl of abiCalls) {
|
|
153
|
+
if (decl.overloads.length > 1) {
|
|
154
|
+
for (let overload of decl.overloads) {
|
|
155
|
+
const args = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`)
|
|
156
|
+
const returnType = overload.outputs.length == 1 ? getType(overload.outputs[0]) : getTupleType(overload.outputs)
|
|
157
|
+
this.out.line(`async ${decl.name}(${args}): Promise<${returnType}>`)
|
|
158
|
+
}
|
|
159
|
+
this.out.block(`async ${decl.name}(...args: any[])`, () => {
|
|
160
|
+
this.out.line(`return this.call("${decl.name}", args)`)
|
|
161
|
+
})
|
|
162
|
+
} else {
|
|
163
|
+
const overload = decl.overloads[0]
|
|
164
|
+
const params = overload.inputs.map((i, n) => `${i.name || `arg${n}`}: ${getType(i)}`)
|
|
165
|
+
const returnType = overload.outputs.length == 1 ? getType(overload.outputs[0]) : getTupleType(overload.outputs)
|
|
166
|
+
this.out.block(`async ${decl.name}(${params.join(`, `)}): Promise<${returnType}>`, () => {
|
|
167
|
+
this.out.line(`return this.call("${decl.name}", [${overload.inputs.map((i, n) => `${i.name || `arg${n}`}`).join(`, `)}])`)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
this.out.line()
|
|
171
|
+
}
|
|
172
|
+
this.out.block(`private async call(name: string, args: any[]) : Promise<any>`, () => {
|
|
173
|
+
this.out.line(`const fragment = abi.getFunction(name)`)
|
|
174
|
+
this.out.line(`const data = abi.encodeFunctionData(fragment, args)`)
|
|
175
|
+
this.out.line(`const result = await this._chain.client.call('eth_call', [{to: this.address, data}, this.blockHeight])`)
|
|
176
|
+
this.out.line(`const decoded = abi.decodeFunctionResult(fragment, result)`)
|
|
177
|
+
this.out.line(`return decoded.length > 1 ? decoded : decoded[0]`)
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@def
|
|
183
|
+
private getEvents(): AbiEvent[] {
|
|
184
|
+
let res: Map<string, AbiEvent> = new Map()
|
|
185
|
+
for (let event of Object.values(this.abi.events)) {
|
|
186
|
+
let abiEvent = res.get(event.name)
|
|
187
|
+
if (abiEvent == null) {
|
|
188
|
+
abiEvent = {
|
|
189
|
+
name: event.name,
|
|
190
|
+
overloads: []
|
|
191
|
+
}
|
|
192
|
+
res.set(event.name, abiEvent)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
abiEvent.overloads.push({
|
|
196
|
+
inputs: event.inputs || [],
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return [...res.values()]
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@def
|
|
204
|
+
private getFunctions(): AbiFunction[] {
|
|
205
|
+
let res: Map<string, AbiFunction> = new Map()
|
|
206
|
+
for (let func of Object.values(this.abi.functions)) {
|
|
207
|
+
if (func.constant) continue
|
|
208
|
+
|
|
209
|
+
let abiFunc = res.get(func.name)
|
|
210
|
+
if (abiFunc == null) {
|
|
211
|
+
abiFunc = {
|
|
212
|
+
name: func.name,
|
|
213
|
+
overloads: []
|
|
214
|
+
}
|
|
215
|
+
res.set(func.name, abiFunc)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
abiFunc.overloads.push({
|
|
219
|
+
inputs: func.inputs || [],
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return [...res.values()]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@def
|
|
227
|
+
private getCalls(): AbiCall[] {
|
|
228
|
+
let res: Map<string, AbiCall> = new Map()
|
|
229
|
+
for (let func of Object.values(this.abi.functions)) {
|
|
230
|
+
if (!func.constant || func.outputs == null) continue
|
|
231
|
+
|
|
232
|
+
let abiCall = res.get(func.name)
|
|
233
|
+
if (abiCall == null) {
|
|
234
|
+
abiCall = {
|
|
235
|
+
name: func.name,
|
|
236
|
+
overloads: []
|
|
237
|
+
}
|
|
238
|
+
res.set(func.name, abiCall)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
abiCall.overloads.push({
|
|
242
|
+
inputs: func.inputs,
|
|
243
|
+
outputs: func.outputs || [],
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return [...res.values()]
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
253
|
+
function getType(param: ParamType): string {
|
|
254
|
+
if (param.type === "address" || param.type === "string") {
|
|
255
|
+
return "string"
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (param.type === "bool") {
|
|
259
|
+
return "boolean"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (param.type.substring(0, 5) === "bytes") {
|
|
263
|
+
return "string"
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
let match = param.type.match(/^(u?int)([0-9]+)$/)
|
|
267
|
+
if (match) {
|
|
268
|
+
return parseInt(match[2]) < 53 ? 'number' : 'ethers.BigNumber'
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (param.baseType === "array") {
|
|
272
|
+
return "Array<" + getType(param.arrayChildren) + ">"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (param.baseType === "tuple") {
|
|
276
|
+
return getTupleType(param.components)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
throw new Error("unknown type")
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
function getTupleType(params: ParamType[]) {
|
|
284
|
+
let tuple = '[' + params.map(p => {
|
|
285
|
+
return p.name ? `${p.name}: ${getType(p)}` : getType(p)
|
|
286
|
+
}).join(', ') + ']'
|
|
287
|
+
|
|
288
|
+
let fields = getStructFields(params)
|
|
289
|
+
if (fields.length == 0) return tuple
|
|
290
|
+
|
|
291
|
+
let struct = '{' + fields.map(f => `${f.name}: ${getType(f)}`).join(', ') + '}'
|
|
292
|
+
|
|
293
|
+
return `(${tuple} & ${struct})`
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
// https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/abi/src.ts/coders/tuple.ts#L29
|
|
298
|
+
function getStructFields(params: ParamType[]): ParamType[] {
|
|
299
|
+
let array: any = []
|
|
300
|
+
let counts: Record<string, number> = {}
|
|
301
|
+
for (let p of params) {
|
|
302
|
+
if (p.name && array[p.name] == null) {
|
|
303
|
+
counts[p.name] = (counts[p.name] || 0) + 1
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return params.filter(p => counts[p.name] == 1)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
function createSignature(name: string, inputs: ParamType[]) {
|
|
311
|
+
return `${name}(${inputs.map((i) => i.type).join(`,`)})`
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
interface AbiEvent {
|
|
316
|
+
name: string
|
|
317
|
+
overloads: {
|
|
318
|
+
inputs: ParamType[]
|
|
319
|
+
}[]
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
interface AbiFunction {
|
|
324
|
+
name: string
|
|
325
|
+
overloads: {
|
|
326
|
+
inputs: ParamType[]
|
|
327
|
+
}[]
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
interface AbiCall {
|
|
332
|
+
name: string
|
|
333
|
+
overloads: {
|
|
334
|
+
inputs: ParamType[]
|
|
335
|
+
outputs: ParamType[]
|
|
336
|
+
}[]
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
function upperCaseFirst(s: string): string {
|
|
341
|
+
return s[0].toUpperCase() + s.slice(1)
|
|
342
|
+
}
|