@mapprotocol/common-contracts 0.3.0 → 0.3.2
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/package.json +8 -3
- package/utils/dist/addressCodec.d.ts +14 -0
- package/utils/dist/addressCodec.js +61 -0
- package/utils/dist/codeHash.d.ts +24 -0
- package/utils/dist/codeHash.js +60 -0
- package/utils/dist/deployRecord.d.ts +37 -0
- package/utils/dist/deployRecord.js +104 -0
- package/utils/dist/deployer.d.ts +36 -0
- package/utils/dist/deployer.js +80 -0
- package/utils/dist/evmHelper.d.ts +33 -0
- package/utils/dist/evmHelper.js +83 -0
- package/utils/dist/factory.d.ts +36 -0
- package/utils/dist/factory.js +187 -0
- package/utils/dist/index.d.ts +17 -0
- package/utils/dist/index.js +45 -0
- package/utils/dist/tronHelper.d.ts +127 -0
- package/utils/dist/tronHelper.js +291 -0
- package/utils/dist/verifier.d.ts +14 -0
- package/utils/dist/verifier.js +205 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface VerifyOptions {
|
|
2
|
+
address: string;
|
|
3
|
+
contractName: string;
|
|
4
|
+
contractPath?: string;
|
|
5
|
+
constructorArgs?: any[];
|
|
6
|
+
constructorParams?: string;
|
|
7
|
+
compiler?: string;
|
|
8
|
+
optimizer?: boolean;
|
|
9
|
+
optimizerRuns?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Unified contract verification — auto-routes to EVM (hardhat verify) or Tron (TronScan API)
|
|
13
|
+
*/
|
|
14
|
+
export declare function verify(hre: any, opts: VerifyOptions): Promise<void>;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verify = verify;
|
|
4
|
+
/**
|
|
5
|
+
* Contract verification — supports Etherscan, Blockscout (Mapo), and TronScan.
|
|
6
|
+
* Auto-routes based on network name.
|
|
7
|
+
*/
|
|
8
|
+
const tronHelper_1 = require("./tronHelper");
|
|
9
|
+
// TronScan API endpoints by chainId
|
|
10
|
+
const TRONSCAN_API = {
|
|
11
|
+
728126428: "https://apilist.tronscan.org/api/solidity/contract/verify", // mainnet
|
|
12
|
+
3448148188: "https://nile.tronscan.org/api/solidity/contract/verify", // nile testnet
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Unified contract verification — auto-routes to EVM (hardhat verify) or Tron (TronScan API)
|
|
16
|
+
*/
|
|
17
|
+
async function verify(hre, opts) {
|
|
18
|
+
const network = hre.network.name;
|
|
19
|
+
if ((0, tronHelper_1.isTronNetwork)(network)) {
|
|
20
|
+
await verifyTron(hre, opts);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await verifyEvm(hre, opts);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// ============================================================
|
|
27
|
+
// EVM verification via hardhat-verify
|
|
28
|
+
// ============================================================
|
|
29
|
+
async function verifyEvm(hre, opts) {
|
|
30
|
+
const contractPath = opts.contractPath || `contracts/${opts.contractName}.sol:${opts.contractName}`;
|
|
31
|
+
console.log(`verifying ${opts.contractName} at ${opts.address} ...`);
|
|
32
|
+
try {
|
|
33
|
+
await hre.run("verify:verify", {
|
|
34
|
+
contract: contractPath,
|
|
35
|
+
address: opts.address,
|
|
36
|
+
constructorArguments: opts.constructorArgs || [],
|
|
37
|
+
});
|
|
38
|
+
console.log(`${opts.contractName} verified`);
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
if (e.message?.includes("Already Verified")) {
|
|
42
|
+
console.log(`${opts.contractName} already verified`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(`verification failed: ${e.message || e}`);
|
|
46
|
+
// Print manual command as fallback
|
|
47
|
+
const args = (opts.constructorArgs || []).map((a) => typeof a === "string" ? `'${a}'` : a).join(" ");
|
|
48
|
+
console.log(`manual: npx hardhat verify --network ${hre.network.name} --contract ${contractPath} ${opts.address} ${args}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ============================================================
|
|
53
|
+
// Tron verification via TronScan API
|
|
54
|
+
// ============================================================
|
|
55
|
+
async function verifyTron(hre, opts) {
|
|
56
|
+
const chainId = hre.network.config.chainId;
|
|
57
|
+
const fs = require("fs");
|
|
58
|
+
const path = require("path");
|
|
59
|
+
// Auto-read compiler settings from hardhat config
|
|
60
|
+
const solcConfig = hre.config?.solidity?.compilers?.[0] || hre.config?.solidity || {};
|
|
61
|
+
const compiler = opts.compiler || solcConfig.version || "0.8.25";
|
|
62
|
+
const optimizer = opts.optimizer ?? solcConfig.settings?.optimizer?.enabled ?? true;
|
|
63
|
+
const optimizerRuns = opts.optimizerRuns ?? solcConfig.settings?.optimizer?.runs ?? 200;
|
|
64
|
+
const evmVersion = solcConfig.settings?.evmVersion || "london";
|
|
65
|
+
const viaIR = solcConfig.settings?.viaIR ? "1" : "0";
|
|
66
|
+
// Convert address to Tron format
|
|
67
|
+
let address = opts.address;
|
|
68
|
+
if (address.startsWith("0x")) {
|
|
69
|
+
address = (0, tronHelper_1.tronFromHex)(address);
|
|
70
|
+
}
|
|
71
|
+
// Generate flattened source
|
|
72
|
+
const outputDir = path.join(process.cwd(), "verify-output");
|
|
73
|
+
const flattenPath = path.join(outputDir, `${opts.contractName}_flatten.sol`);
|
|
74
|
+
console.log(`generating flatten for ${opts.contractName}...`);
|
|
75
|
+
try {
|
|
76
|
+
// Find actual source path from artifact
|
|
77
|
+
const artifact = await hre.artifacts.readArtifact(opts.contractName);
|
|
78
|
+
const sourcePath = artifact.sourceName; // e.g. "contracts/factory/Create2Factory.sol"
|
|
79
|
+
let flattenedSource = await hre.run("flatten:get-flattened-sources", {
|
|
80
|
+
files: [sourcePath],
|
|
81
|
+
});
|
|
82
|
+
flattenedSource = removeDuplicateSPDX(flattenedSource);
|
|
83
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
84
|
+
fs.writeFileSync(flattenPath, flattenedSource);
|
|
85
|
+
console.log(`flatten saved to: ${flattenPath}`);
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
if (fs.existsSync(flattenPath)) {
|
|
89
|
+
console.log(`using existing flatten: ${flattenPath}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(`flatten failed, generate manually: forge flatten contracts/${opts.contractName}.sol`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Submit to TronScan API
|
|
97
|
+
const apiUrl = TRONSCAN_API[chainId];
|
|
98
|
+
if (!apiUrl) {
|
|
99
|
+
console.log(`no TronScan API for chainId ${chainId}, printing manual instructions instead`);
|
|
100
|
+
printTronVerifyInfo(address, opts.contractName, compiler, optimizer, optimizerRuns, evmVersion, flattenPath, chainId);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
console.log(`submitting verification to TronScan for ${address}...`);
|
|
104
|
+
try {
|
|
105
|
+
const FormData = require("form-data");
|
|
106
|
+
const form = new FormData();
|
|
107
|
+
form.append("contractAddress", address);
|
|
108
|
+
form.append("contractName", opts.contractName);
|
|
109
|
+
// Read full compiler version from build-info (includes commit hash)
|
|
110
|
+
let fullCompiler = `v${compiler}`;
|
|
111
|
+
try {
|
|
112
|
+
const buildInfoDir = path.join(process.cwd(), "artifacts/build-info");
|
|
113
|
+
const buildInfoFiles = fs.readdirSync(buildInfoDir);
|
|
114
|
+
if (buildInfoFiles.length > 0) {
|
|
115
|
+
const buildInfo = JSON.parse(fs.readFileSync(path.join(buildInfoDir, buildInfoFiles[0]), "utf-8"));
|
|
116
|
+
if (buildInfo.solcLongVersion) {
|
|
117
|
+
fullCompiler = `v${buildInfo.solcLongVersion}`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
console.log(`[warn] could not read build-info: ${e.message}`);
|
|
123
|
+
}
|
|
124
|
+
form.append("compiler", fullCompiler);
|
|
125
|
+
form.append("license", "3"); // MIT
|
|
126
|
+
form.append("optimizer", optimizer ? "1" : "0");
|
|
127
|
+
form.append("runs", String(optimizerRuns));
|
|
128
|
+
form.append("viaIR", viaIR);
|
|
129
|
+
form.append("evmVersion", evmVersion);
|
|
130
|
+
// Encode constructor params from ABI if not pre-encoded
|
|
131
|
+
let constructorParams = opts.constructorParams || "";
|
|
132
|
+
if (!constructorParams && opts.constructorArgs && opts.constructorArgs.length > 0) {
|
|
133
|
+
const { Interface } = require("ethers");
|
|
134
|
+
const artifact = await hre.artifacts.readArtifact(opts.contractName);
|
|
135
|
+
const iface = new Interface(artifact.abi);
|
|
136
|
+
const encoded = iface.encodeDeploy(opts.constructorArgs);
|
|
137
|
+
constructorParams = encoded.slice(2); // remove 0x
|
|
138
|
+
}
|
|
139
|
+
form.append("constructorParams", constructorParams);
|
|
140
|
+
form.append("files", fs.createReadStream(flattenPath), {
|
|
141
|
+
filename: `${opts.contractName}.flat.tron.sol`,
|
|
142
|
+
contentType: "application/octet-stream",
|
|
143
|
+
});
|
|
144
|
+
const result = await new Promise((resolve, reject) => {
|
|
145
|
+
const url = new URL(apiUrl);
|
|
146
|
+
const https = require("https");
|
|
147
|
+
const req = https.request({
|
|
148
|
+
hostname: url.hostname,
|
|
149
|
+
path: url.pathname,
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: form.getHeaders(),
|
|
152
|
+
}, (res) => {
|
|
153
|
+
let data = "";
|
|
154
|
+
res.on("data", (chunk) => data += chunk);
|
|
155
|
+
res.on("end", () => {
|
|
156
|
+
try {
|
|
157
|
+
resolve(JSON.parse(data));
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
resolve({ code: -1, errmsg: data });
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
req.on("error", reject);
|
|
165
|
+
form.pipe(req);
|
|
166
|
+
});
|
|
167
|
+
if (result.code === 200 || result.success) {
|
|
168
|
+
console.log(`${opts.contractName} verified on TronScan: ${result.data?.message || "success"}`);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(`TronScan response:`, JSON.stringify(result, null, 2));
|
|
172
|
+
printTronVerifyInfo(address, opts.contractName, fullCompiler, optimizer, optimizerRuns, evmVersion, flattenPath, chainId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
console.log(`TronScan API error: ${e.message || e}`);
|
|
177
|
+
printTronVerifyInfo(address, opts.contractName, `v${compiler}`, optimizer, optimizerRuns, evmVersion, flattenPath, chainId);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function printTronVerifyInfo(address, contractName, compiler, optimizer, runs, evmVersion, flattenPath, chainId) {
|
|
181
|
+
const isMainnet = chainId === 728126428;
|
|
182
|
+
const tronscanUrl = isMainnet
|
|
183
|
+
? `https://tronscan.org/#/contract/${address}/code`
|
|
184
|
+
: `https://nile.tronscan.org/#/contract/${address}/code`;
|
|
185
|
+
console.log(`\n=== Verify manually on TronScan ===`);
|
|
186
|
+
console.log(`Address: ${address}`);
|
|
187
|
+
console.log(`Contract: ${contractName}`);
|
|
188
|
+
console.log(`Compiler: ${compiler}`);
|
|
189
|
+
console.log(`Optimizer: ${optimizer ? "enabled" : "disabled"}, runs: ${runs}`);
|
|
190
|
+
console.log(`EVM: ${evmVersion}`);
|
|
191
|
+
console.log(`Flatten: ${flattenPath}`);
|
|
192
|
+
console.log(`URL: ${tronscanUrl}`);
|
|
193
|
+
console.log(`=====================================\n`);
|
|
194
|
+
}
|
|
195
|
+
function removeDuplicateSPDX(source) {
|
|
196
|
+
let found = false;
|
|
197
|
+
return source.split("\n").filter(line => {
|
|
198
|
+
if (line.includes("SPDX-License-Identifier")) {
|
|
199
|
+
if (found)
|
|
200
|
+
return false;
|
|
201
|
+
found = true;
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}).join("\n");
|
|
205
|
+
}
|