@subsquid/evm-typegen 0.0.1
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/README.md +5 -0
- package/bin/run.js +3 -0
- package/lib/main.d.ts +2 -0
- package/lib/main.d.ts.map +1 -0
- package/lib/main.js +149 -0
- package/lib/main.js.map +1 -0
- package/package.json +31 -0
- package/src/main.ts +171 -0
package/README.md
ADDED
package/bin/run.js
ADDED
package/lib/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAOA,wBAAgB,GAAG,IAAI,IAAI,CAoB1B"}
|
package/lib/main.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const process_1 = __importDefault(require("process"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const util_1 = require("@subsquid/util");
|
|
12
|
+
const abi_1 = require("@ethersproject/abi");
|
|
13
|
+
function run() {
|
|
14
|
+
commander_1.program.description(`
|
|
15
|
+
Generates TypeScript definitions for evm log events
|
|
16
|
+
for use within substrate-processor mapping handlers.
|
|
17
|
+
`.trim())
|
|
18
|
+
.requiredOption('--abi <path>', 'path to a JSON abi file')
|
|
19
|
+
.requiredOption('--output <path>', 'path for output typescript file');
|
|
20
|
+
commander_1.program.parse();
|
|
21
|
+
const options = commander_1.program.opts();
|
|
22
|
+
const inputPath = options.abi;
|
|
23
|
+
const outputPath = options.output;
|
|
24
|
+
try {
|
|
25
|
+
generateTsFromAbi(inputPath, outputPath);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
console.error(`evm-typegen error: ${err.toString()}`);
|
|
29
|
+
process_1.default.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
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_1.Output();
|
|
44
|
+
output.line("import * as ethers from \"ethers\";");
|
|
45
|
+
output.line();
|
|
46
|
+
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
47
|
+
output.line();
|
|
48
|
+
// validate the abi
|
|
49
|
+
const abi = new abi_1.Interface(rawABI);
|
|
50
|
+
const abiEvents = Object.values(abi.events).map((event) => {
|
|
51
|
+
let signature = `${event.name}(`;
|
|
52
|
+
let eventTypeName = `${event.name}`;
|
|
53
|
+
if (event.inputs.length > 0) {
|
|
54
|
+
signature += event.inputs[0].type;
|
|
55
|
+
eventTypeName += capitalize(event.inputs[0].type);
|
|
56
|
+
}
|
|
57
|
+
for (let i = 1; i < event.inputs.length; ++i) {
|
|
58
|
+
const input = event.inputs[i];
|
|
59
|
+
signature += `,${input.type}`;
|
|
60
|
+
eventTypeName += capitalize(input.type);
|
|
61
|
+
}
|
|
62
|
+
signature += ")";
|
|
63
|
+
return {
|
|
64
|
+
signature,
|
|
65
|
+
eventTypeName,
|
|
66
|
+
inputs: event.inputs,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
for (const decl of abiEvents) {
|
|
70
|
+
output.block(`export interface ${decl.eventTypeName}Event`, () => {
|
|
71
|
+
for (const input of decl.inputs) {
|
|
72
|
+
output.line(`${input.name}: ${getType(input)};`);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
output.line("");
|
|
76
|
+
}
|
|
77
|
+
output.block("export interface EvmEvent", () => {
|
|
78
|
+
output.line("data: string;");
|
|
79
|
+
output.line("topics: string[];");
|
|
80
|
+
});
|
|
81
|
+
output.line();
|
|
82
|
+
output.block("export const events =", () => {
|
|
83
|
+
for (const decl of abiEvents) {
|
|
84
|
+
output.block(`"${decl.signature}": `, () => {
|
|
85
|
+
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
86
|
+
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}Event`, () => {
|
|
87
|
+
output.line(`const result = abi.decodeEventLog(`);
|
|
88
|
+
output.indentation(() => {
|
|
89
|
+
output.line(`abi.getEvent("${decl.signature}"),`);
|
|
90
|
+
output.line(`data.data || "",`);
|
|
91
|
+
output.line("data.topics");
|
|
92
|
+
});
|
|
93
|
+
output.line(");");
|
|
94
|
+
output.block("return ", () => {
|
|
95
|
+
for (let i = 0; i < decl.inputs.length; ++i) {
|
|
96
|
+
const input = decl.inputs[i];
|
|
97
|
+
output.line(`${input.name}: ${`result[${i}]`},`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
output.line(",");
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
output.line();
|
|
106
|
+
output.block("function getJsonAbi(): any", () => {
|
|
107
|
+
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
108
|
+
output.line(line);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
fs_1.default.writeFileSync(outputPathRaw, output.toString());
|
|
112
|
+
}
|
|
113
|
+
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
114
|
+
function getType(param, flexible) {
|
|
115
|
+
if (param.type === "address" || param.type === "string") {
|
|
116
|
+
return "string";
|
|
117
|
+
}
|
|
118
|
+
if (param.type === "bool") {
|
|
119
|
+
return "boolean";
|
|
120
|
+
}
|
|
121
|
+
if (param.type.substring(0, 5) === "bytes") {
|
|
122
|
+
if (flexible) {
|
|
123
|
+
return "string | ethers.utils.BytesLike";
|
|
124
|
+
}
|
|
125
|
+
return "string";
|
|
126
|
+
}
|
|
127
|
+
let match = param.type.match(/^(u?int)([0-9]+)$/);
|
|
128
|
+
if (match) {
|
|
129
|
+
if (flexible) {
|
|
130
|
+
return "ethers.BigNumberish";
|
|
131
|
+
}
|
|
132
|
+
if (parseInt(match[2]) < 53) {
|
|
133
|
+
return 'number';
|
|
134
|
+
}
|
|
135
|
+
return 'ethers.BigNumber';
|
|
136
|
+
}
|
|
137
|
+
if (param.type === "array") {
|
|
138
|
+
return "Array<" + getType(param.arrayChildren) + ">";
|
|
139
|
+
}
|
|
140
|
+
if (param.type === "tuple") {
|
|
141
|
+
let struct = param.components.map((p, i) => `${p.name || "p_" + i}: ${getType(p, flexible)}`);
|
|
142
|
+
return "{ " + struct.join(", ") + " }";
|
|
143
|
+
}
|
|
144
|
+
throw new Error("unknown type");
|
|
145
|
+
}
|
|
146
|
+
function capitalize(input) {
|
|
147
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=main.js.map
|
package/lib/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@subsquid/evm-typegen",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI for generating typescript types and decode implementations for evm logs",
|
|
5
|
+
"license": "GPL-3.0-or-later",
|
|
6
|
+
"repository": "git@github.com:subsquid/squid.git",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"lib",
|
|
12
|
+
"src"
|
|
13
|
+
],
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"bin": {
|
|
16
|
+
"squid-evm-typegen": "bin/run.js"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"commander": "^9.0.0",
|
|
20
|
+
"@ethersproject/abi": "^5.5.0",
|
|
21
|
+
"@subsquid/util": "^0.0.5"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^16.11.22",
|
|
25
|
+
"typescript": "~4.5.5"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rm -rf lib && tsc"
|
|
29
|
+
},
|
|
30
|
+
"readme": "# @subsquid/evm-typegen\n\nThis package provides `squid-evm-typegen(1)` command \nwhich can generate TypeScript definitions for evm logs\nto be used within [substrate-processor](../substrate-processor) mapping handlers.\n"
|
|
31
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { program } from "commander";
|
|
2
|
+
import process from "process";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { Output } from "@subsquid/util";
|
|
6
|
+
import { EventFragment, Interface, ParamType } from "@ethersproject/abi";
|
|
7
|
+
|
|
8
|
+
export function run(): void {
|
|
9
|
+
program.description(`
|
|
10
|
+
Generates TypeScript definitions for evm log events
|
|
11
|
+
for use within substrate-processor mapping handlers.
|
|
12
|
+
`.trim())
|
|
13
|
+
.requiredOption('--abi <path>', 'path to a JSON abi file')
|
|
14
|
+
.requiredOption('--output <path>', 'path for output typescript file');
|
|
15
|
+
|
|
16
|
+
program.parse();
|
|
17
|
+
|
|
18
|
+
const options = program.opts();
|
|
19
|
+
const inputPath = options.abi;
|
|
20
|
+
const outputPath = options.output;
|
|
21
|
+
|
|
22
|
+
try {
|
|
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") {
|
|
35
|
+
throw new Error("invalid abi file extension");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (outputPath.ext !== ".ts") {
|
|
39
|
+
throw new Error("invalid output file extension");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const rawABI = JSON.parse(fs.readFileSync(inputPathRaw, { encoding: "utf-8" }));
|
|
43
|
+
|
|
44
|
+
const output = new Output();
|
|
45
|
+
|
|
46
|
+
output.line("import * as ethers from \"ethers\";");
|
|
47
|
+
output.line();
|
|
48
|
+
output.line("export const abi = new ethers.utils.Interface(getJsonAbi());");
|
|
49
|
+
output.line();
|
|
50
|
+
|
|
51
|
+
// validate the abi
|
|
52
|
+
const abi = new Interface(rawABI);
|
|
53
|
+
|
|
54
|
+
const abiEvents: Array<AbiEvent> = Object.values(abi.events).map((event: EventFragment): AbiEvent => {
|
|
55
|
+
let signature = `${event.name}(`;
|
|
56
|
+
let eventTypeName = `${event.name}`;
|
|
57
|
+
|
|
58
|
+
if(event.inputs.length > 0) {
|
|
59
|
+
signature += event.inputs[0].type;
|
|
60
|
+
eventTypeName += capitalize(event.inputs[0].type);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (let i=1; i<event.inputs.length; ++i) {
|
|
64
|
+
const input = event.inputs[i];
|
|
65
|
+
signature += `,${input.type}`;
|
|
66
|
+
eventTypeName += capitalize(input.type);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
signature += ")";
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
signature,
|
|
73
|
+
eventTypeName,
|
|
74
|
+
inputs: event.inputs,
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
for(const decl of abiEvents) {
|
|
79
|
+
output.block(`export interface ${decl.eventTypeName}Event`, () => {
|
|
80
|
+
for (const input of decl.inputs) {
|
|
81
|
+
output.line(`${input.name}: ${getType(input)};`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
output.line("");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
output.block("export interface EvmEvent", () => {
|
|
88
|
+
output.line("data: string;");
|
|
89
|
+
output.line("topics: string[];");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
output.line();
|
|
93
|
+
|
|
94
|
+
output.block("export const events =", () => {
|
|
95
|
+
for(const decl of abiEvents) {
|
|
96
|
+
output.block(`"${decl.signature}": `, () => {
|
|
97
|
+
output.line(`topic: abi.getEventTopic("${decl.signature}"),`);
|
|
98
|
+
output.block(`decode(data: EvmEvent): ${decl.eventTypeName}Event`, () => {
|
|
99
|
+
output.line(`const result = abi.decodeEventLog(`);
|
|
100
|
+
output.indentation(() => {
|
|
101
|
+
output.line(`abi.getEvent("${decl.signature}"),`);
|
|
102
|
+
output.line(`data.data || "",`);
|
|
103
|
+
output.line("data.topics");
|
|
104
|
+
});
|
|
105
|
+
output.line(");");
|
|
106
|
+
output.block("return ", () => {
|
|
107
|
+
for (let i=0; i<decl.inputs.length; ++i) {
|
|
108
|
+
const input = decl.inputs[i];
|
|
109
|
+
output.line(`${input.name}: ${`result[${i}]`},`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
output.line(",");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
output.line();
|
|
119
|
+
|
|
120
|
+
output.block("function getJsonAbi(): any", () => {
|
|
121
|
+
`return ${JSON.stringify(rawABI, null, 2)}`.split('\n').forEach(line => {
|
|
122
|
+
output.line(line)
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
fs.writeFileSync(outputPathRaw, output.toString());
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// taken from: https://github.com/ethers-io/ethers.js/blob/948f77050dae884fe88932fd88af75560aac9d78/packages/cli/src.ts/typescript.ts#L10
|
|
130
|
+
function getType(param: ParamType, flexible?: boolean): string {
|
|
131
|
+
if (param.type === "address" || param.type === "string") { return "string"; }
|
|
132
|
+
|
|
133
|
+
if (param.type === "bool") { return "boolean" }
|
|
134
|
+
|
|
135
|
+
if (param.type.substring(0, 5) === "bytes") {
|
|
136
|
+
if (flexible) {
|
|
137
|
+
return "string | ethers.utils.BytesLike";
|
|
138
|
+
}
|
|
139
|
+
return "string"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let match = param.type.match(/^(u?int)([0-9]+)$/)
|
|
143
|
+
if (match) {
|
|
144
|
+
if (flexible) {
|
|
145
|
+
return "ethers.BigNumberish";
|
|
146
|
+
}
|
|
147
|
+
if (parseInt(match[2]) < 53) { return 'number'; }
|
|
148
|
+
return 'ethers.BigNumber';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (param.type === "array") {
|
|
152
|
+
return "Array<" + getType(param.arrayChildren) + ">";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (param.type === "tuple") {
|
|
156
|
+
let struct = param.components.map((p, i) => `${p.name || "p_" + i}: ${getType(p, flexible)}`);
|
|
157
|
+
return "{ " + struct.join(", ") + " }";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
throw new Error("unknown type");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
interface AbiEvent {
|
|
164
|
+
signature: string;
|
|
165
|
+
eventTypeName: string;
|
|
166
|
+
inputs: ParamType[];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function capitalize(input: string): string {
|
|
170
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
171
|
+
}
|