@enjinstarter/hardhat-oklink-verify
Version:
Hardhat plugin for verifying contracts on OKLink
244 lines (243 loc) • 9.94 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OklinkResponse = exports.verifyContract = exports.delay = void 0;
const buffer_1 = require("buffer");
const path_1 = __importDefault(require("path"));
const plugins_1 = require("hardhat/plugins");
const undici_1 = require("undici");
const constants_1 = require("../constants");
async function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
exports.delay = delay;
async function verifyContract(url, req) {
const { request } = await Promise.resolve().then(() => __importStar(require("undici")));
const method = "POST";
let licenseType = "UNLICENSED";
if (req.sources[req.sourceName] !== undefined) {
const matches = req.sources[req.sourceName].content.match(/^\/\/\s+SPDX-License-Identifier:\s+([A-Za-z0-9.-]+)$/im);
/*
if (matches !== null) {
console.log(`matches.length: ${matches.length}`);
for (let i = 0; i < matches.length; i++) {
console.log(`matches[${i}]: ${matches[i]}`);
}
}
*/
if (matches !== null && matches.length > 1) {
licenseType = matches[1];
/*
console.log(
`matches.length=${matches.length}, licenseType=${licenseType}`
);
*/
}
}
// console.log(`req.licenseType=${req.licenseType}, licenseType=${licenseType}`);
const body = new undici_1.FormData();
for (const [sourceName, _source] of Object.entries(req.sources)) {
/*
console.log(
`files: sourceName=${sourceName}, basename=${path.posix.basename(
sourceName
)}, content=${req.sources[sourceName].content}`
);
*/
const contentImportAddCurrentDirectory = req.sources[sourceName].content
.replace(/^import\s+"\//gm, 'import "./')
.replace(/^import\s+"(?!\.\/)/gm, 'import "./');
/*
console.log(
`files: contentImportAddCurrentDirectory=${contentImportAddCurrentDirectory}`
);
*/
body.append("files", new buffer_1.Blob([contentImportAddCurrentDirectory]), path_1.default.posix.basename(sourceName));
}
/*
console.log(`url: ${url}`);
console.log(`apkKey: ${req.apiKey}`);
console.log(`sourceName: ${req.sourceName}`);
console.log(`contractAddress: ${req.contractAddress}`);
console.log(`compilerVersion: ${req.compilerVersion}`);
console.log(`evmVersion: ${req.evmVersion}`);
console.log(
`optimization: ${
req.optimization === undefined ? "N.A." : req.optimization.toString()
}`
);
console.log(
`optimizationRuns: ${
req.optimizationRuns === undefined
? "N.A."
: req.optimizationRuns.toString()
}`
);
console.log(
`licenseType: ${
req.licenseType === null || req.licenseType.trim() === ""
? licenseType
: req.licenseType
}`
);
console.log(`contractAbi: ${req.contractAbi}`);
console.log(`compilerType: ${req.compilerType}`);
*/
body.set("contractAddress", req.contractAddress);
body.set("compilerVersion", req.compilerVersion);
body.set("evmVersion", req.evmVersion);
if (req.optimization !== undefined) {
body.set("optimization", req.optimization);
}
if (req.optimizationRuns !== undefined) {
body.set("optimizationRuns", req.optimizationRuns);
}
body.set("licenseType", req.licenseType === null || req.licenseType.trim() === ""
? licenseType
: req.licenseType);
body.set("contractAbi", req.contractAbi);
if (req.libraryList !== undefined) {
// console.log(`req.libraryList: ${JSON.stringify(req.libraryList)}`);
const libraryList = [];
for (const [_libraryFileName, libraryInfo] of Object.entries(req.libraryList)) {
for (const [libraryName, libraryAddress] of Object.entries(libraryInfo)) {
/*
console.log(
`libraryList[]: libraryName=${libraryName}, libraryAddress=${libraryAddress}`
);
*/
libraryList.push({ address: libraryAddress, name: libraryName });
}
}
if (libraryList.length > 0) {
// console.log(`libraryList: ${JSON.stringify(libraryList)}`);
body.set("libraryList", JSON.stringify(libraryList));
}
}
body.set("compilerType", req.compilerType);
const requestDetails = {
method,
headers: { "x-apiKey": req.apiKey },
body,
};
let response;
try {
response = await request(url, requestDetails);
}
catch (error) {
throw new plugins_1.NomicLabsHardhatPluginError(constants_1.pluginName, `Failed to send contract verification request.
Endpoint URL: ${url}
Reason: ${error.message}`, error);
}
if (!(response.statusCode >= 200 && response.statusCode <= 299)) {
// This could be always interpreted as JSON if there were any such guarantee in the OKLink API.
const responseText = await response.body.text();
throw new plugins_1.NomicLabsHardhatPluginError(constants_1.pluginName, `Failed to send contract verification request.
Endpoint URL: ${url}
The HTTP server response is not ok. Status code: ${response.statusCode} Response text: ${responseText}`);
}
const responseBody = await response.body.json();
// console.log(`response: ${JSON.stringify(responseBody)}`);
const oklinkResponse = new OklinkResponse(responseBody);
if (oklinkResponse.isBytecodeMissingInNetworkError()) {
throw new plugins_1.NomicLabsHardhatPluginError(constants_1.pluginName, `Failed to send contract verification request.
Endpoint URL: ${url}
Reason: The OKLink API responded that the address ${req.contractAddress} does not have bytecode.
This can happen if the contract was recently deployed and this fact hasn't propagated to the backend yet.
Try waiting for a minute before verifying your contract. If you are invoking this from a script,
try to wait for five confirmations of your contract deployment transaction before running the verification subtask.`);
}
if (!oklinkResponse.isOk()) {
throw new plugins_1.NomicLabsHardhatPluginError(constants_1.pluginName, `The OKLink API responded with a failure status.
The verification may still succeed but should be checked manually.
Reason: ${oklinkResponse.errorType}`);
}
return oklinkResponse;
}
exports.verifyContract = verifyContract;
class OklinkResponse {
// public readonly contractErrorCodeList?: string;
// public readonly errorLibrary?: string;
constructor(response) {
this.code = response.code;
this.msg = response.msg;
this.detailMsg = response.detailMsg;
this.isSuccess = response.data.isSuccess;
if (response.data.contractAddress !== undefined) {
this.contractAddress = response.data.contractAddress;
}
if (response.data.contractCreateTxHash !== undefined) {
this.contractCreateTxHash = response.data.contractCreateTxHash;
}
if (response.data.compilerVersion !== undefined) {
this.compilerVersion = response.data.compilerVersion;
}
if (response.data.optimization !== undefined) {
this.optimization = response.data.optimization;
}
if (response.data.optimizationRuns !== undefined) {
this.optimizationRuns = response.data.optimizationRuns;
}
this.errorType =
response.data.errorType === undefined
? response.data.isSuccess === true
? ""
: "OKLINK_UNKNOWN_ERROR"
: response.data.errorType;
if (response.data.statusCode !== undefined) {
this.statusCode = response.data.statusCode;
}
if (response.data.compileErrorMessage !== undefined) {
this.compileErrorMessage = response.data.compileErrorMessage;
}
if (response.data.contractCreationCode !== undefined) {
this.contractCreationCode = response.data.contractCreationCode;
}
/*
if (response.data.contractErrorCodeList !== undefined) {
this.contractErrorCodeList = response.data.contractErrorCodeList;
}
if (response.data.errorLibrary !== undefined) {
this.errorLibrary = response.data.errorLibrary;
}
*/
}
isPending() {
return false;
}
isVerificationFailure() {
return this.isSuccess !== true;
}
isVerificationSuccess() {
return this.isSuccess === true;
}
isBytecodeMissingInNetworkError() {
return false;
}
isOk() {
return true;
}
}
exports.OklinkResponse = OklinkResponse;
//# sourceMappingURL=OklinkService.js.map