@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
189 lines • 9.47 kB
JavaScript
import { isNullish, pick, strip0x, } from '@hyperlane-xyz/utils';
export var EtherscanLikeExplorerApiModule;
(function (EtherscanLikeExplorerApiModule) {
EtherscanLikeExplorerApiModule["LOGS"] = "logs";
EtherscanLikeExplorerApiModule["CONTRACT"] = "contract";
})(EtherscanLikeExplorerApiModule || (EtherscanLikeExplorerApiModule = {}));
export var EtherscanLikeExplorerApiAction;
(function (EtherscanLikeExplorerApiAction) {
EtherscanLikeExplorerApiAction["GETSOURCECODE"] = "getsourcecode";
EtherscanLikeExplorerApiAction["VERIFY_IMPLEMENTATION"] = "verifysourcecode";
EtherscanLikeExplorerApiAction["VERIFY_PROXY"] = "verifyproxycontract";
EtherscanLikeExplorerApiAction["CHECK_IMPLEMENTATION_STATUS"] = "checkverifystatus";
EtherscanLikeExplorerApiAction["CHECK_PROXY_STATUS"] = "checkproxyverification";
EtherscanLikeExplorerApiAction["GET_CONTRACT_CREATION_CODE"] = "getcontractcreation";
EtherscanLikeExplorerApiAction["GET_LOGS"] = "getLogs";
})(EtherscanLikeExplorerApiAction || (EtherscanLikeExplorerApiAction = {}));
export var EtherscanLikeExplorerApiErrors;
(function (EtherscanLikeExplorerApiErrors) {
EtherscanLikeExplorerApiErrors["ALREADY_VERIFIED"] = "Contract source code already verified";
EtherscanLikeExplorerApiErrors["ALREADY_VERIFIED_ALT"] = "Already Verified";
EtherscanLikeExplorerApiErrors["NOT_VERIFIED"] = "Contract source code not verified";
EtherscanLikeExplorerApiErrors["VERIFICATION_PENDING"] = "Pending in queue";
EtherscanLikeExplorerApiErrors["PROXY_FAILED"] = "A corresponding implementation contract was unfortunately not detected for the proxy address.";
EtherscanLikeExplorerApiErrors["BYTECODE_MISMATCH"] = "Fail - Unable to verify. Compiled contract deployment bytecode does NOT match the transaction deployment bytecode.";
EtherscanLikeExplorerApiErrors["UNABLE_TO_VERIFY"] = "Fail - Unable to verify";
EtherscanLikeExplorerApiErrors["UNKNOWN_UID"] = "Unknown UID";
EtherscanLikeExplorerApiErrors["NO_RECORD"] = "No records found";
EtherscanLikeExplorerApiErrors["NO_LOGS_FOUND"] = "No logs found";
})(EtherscanLikeExplorerApiErrors || (EtherscanLikeExplorerApiErrors = {}));
// see https://etherscan.io/contract-license-types
export var ExplorerLicenseType;
(function (ExplorerLicenseType) {
ExplorerLicenseType["NO_LICENSE"] = "1";
ExplorerLicenseType["UNLICENSED"] = "2";
ExplorerLicenseType["MIT"] = "3";
ExplorerLicenseType["GPL2"] = "4";
ExplorerLicenseType["GPL3"] = "5";
ExplorerLicenseType["LGPL2"] = "6";
ExplorerLicenseType["LGPL3"] = "7";
ExplorerLicenseType["BSD2"] = "8";
ExplorerLicenseType["BSD3"] = "9";
ExplorerLicenseType["MPL2"] = "10";
ExplorerLicenseType["OSL3"] = "11";
ExplorerLicenseType["APACHE2"] = "12";
ExplorerLicenseType["AGPL3"] = "13";
ExplorerLicenseType["BSL"] = "14";
})(ExplorerLicenseType || (ExplorerLicenseType = {}));
function formatExplorerUrl({ apiUrl, apiKey }, params) {
// hack for Blockscout API urls that in the explorer have the `eth-rpc` path set
// as it will cause requests to fail with a not found error
const urlObject = new URL(apiUrl.replace('eth-rpc', ''));
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
urlObject.searchParams.append(key, value.toString());
}
}
if (apiKey) {
urlObject.searchParams.append('apikey', apiKey);
}
return urlObject.toString();
}
async function handleEtherscanResponse(response) {
const body = await response.json();
const explorerUrl = new URL(response.url);
// Avoid throwing if no logs are found for the current address
if (body.status === '0' &&
body.message !== EtherscanLikeExplorerApiErrors.NO_RECORD &&
body.message !== EtherscanLikeExplorerApiErrors.NO_LOGS_FOUND) {
throw new Error(`Error while performing request to Etherscan like API at ${explorerUrl.host}: ${body.message} ${body.result}`);
}
return body.result;
}
function getFormPostRequestBody(input) {
const formParams = new URLSearchParams(Object.entries(input).filter(([_key, value]) => !isNullish(value)));
return {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formParams,
};
}
export async function tryGetContractDeploymentTransaction(explorerOptions, { contractAddress }) {
const options = {
module: EtherscanLikeExplorerApiModule.CONTRACT,
action: EtherscanLikeExplorerApiAction.GET_CONTRACT_CREATION_CODE,
contractaddresses: contractAddress,
};
const requestUrl = formatExplorerUrl(explorerOptions, options);
const response = await fetch(requestUrl);
const [deploymentTx] = await handleEtherscanResponse(response);
return deploymentTx;
}
export async function getContractDeploymentTransaction(explorerOptions, requestOptions) {
const deploymentTx = await tryGetContractDeploymentTransaction(explorerOptions, requestOptions);
if (!deploymentTx) {
throw new Error(`No deployment transaction found for contract ${requestOptions.contractAddress}`);
}
return deploymentTx;
}
export async function getLogsFromEtherscanLikeExplorerAPI({ apiUrl, apiKey: apikey }, options) {
const data = {
module: EtherscanLikeExplorerApiModule.LOGS,
action: EtherscanLikeExplorerApiAction.GET_LOGS,
address: options.address,
fromBlock: options.fromBlock,
toBlock: options.toBlock,
topic0: options.topic0,
};
const requestUrl = formatExplorerUrl({ apiUrl, apiKey: apikey }, data);
const response = await fetch(requestUrl);
const rawLogs = await handleEtherscanResponse(response);
return rawLogs.map((rawLogs) => ({
address: rawLogs.address,
blockNumber: Number(rawLogs.blockNumber),
data: rawLogs.data,
logIndex: Number(rawLogs.logIndex),
topics: rawLogs.topics,
transactionHash: rawLogs.transactionHash,
transactionIndex: Number(rawLogs.transactionIndex),
}));
}
export async function getContractSourceCode(explorerOptions, { contractAddress }) {
const options = {
action: EtherscanLikeExplorerApiAction.GETSOURCECODE,
address: contractAddress,
module: EtherscanLikeExplorerApiModule.CONTRACT,
};
const requestUrl = formatExplorerUrl(explorerOptions, options);
const response = await fetch(requestUrl);
const [sourceCodeResults] = await handleEtherscanResponse(response);
return sourceCodeResults;
}
/**
* Wrapper function for the `https://api.etherscan.io/v2/api?chainid=1&module=contract&action=verifysourcecode&apikey=...`
* endpoint request with the `codeformat` option set to `solidity-standard-json-input`
*/
export async function verifyContractSourceCodeViaStandardJsonInput(explorerOptions, verificationOptions) {
const input = {
module: EtherscanLikeExplorerApiModule.CONTRACT,
action: EtherscanLikeExplorerApiAction.VERIFY_IMPLEMENTATION,
codeformat: 'solidity-standard-json-input',
compilerversion: verificationOptions.compilerVersion,
contractaddress: verificationOptions.contractAddress,
contractname: verificationOptions.contractName,
sourceCode: JSON.stringify(verificationOptions.sourceCode),
constructorArguements: strip0x(verificationOptions.constructorArguments ?? ''),
licenseType: verificationOptions.licenseType,
};
if (!isNullish(verificationOptions.zkCompilerVersion)) {
input.zksolcversion = verificationOptions.zkCompilerVersion;
}
const params = pick(input, ['action', 'module']);
const requestUrl = formatExplorerUrl(explorerOptions, params);
const response = await fetch(requestUrl, getFormPostRequestBody(input));
return handleEtherscanResponse(response);
}
/**
* Wrapper function for the `https://api.etherscan.io/v2/api?chainid=...&module=contract&action=verifyproxycontract&apikey=...`
*/
export async function verifyProxyContract(explorerOptions, { contractAddress, implementationAddress }) {
const input = {
action: EtherscanLikeExplorerApiAction.VERIFY_PROXY,
module: EtherscanLikeExplorerApiModule.CONTRACT,
address: contractAddress,
expectedimplementation: implementationAddress,
};
const params = pick(input, ['action', 'module']);
const requestUrl = formatExplorerUrl(explorerOptions, params);
const response = await fetch(requestUrl, getFormPostRequestBody(input));
return handleEtherscanResponse(response);
}
/**
* Wrapper function for the
* `https://api.etherscan.io/v2/api?chainid=...&module=contract&action=...&guid=...&apikey=...`
* endpoint request with the `action` option set to `checkverifystatus` if `isProxy` is false
* or set to `checkproxyverification` if set to true.
*/
export async function checkContractVerificationStatus(explorerOptions, { isProxy, verificationId }) {
const input = {
action: isProxy
? EtherscanLikeExplorerApiAction.CHECK_PROXY_STATUS
: EtherscanLikeExplorerApiAction.CHECK_IMPLEMENTATION_STATUS,
guid: verificationId,
module: EtherscanLikeExplorerApiModule.CONTRACT,
};
const requestUrl = formatExplorerUrl(explorerOptions, input);
const response = await fetch(requestUrl);
await handleEtherscanResponse(response);
}
//# sourceMappingURL=etherscan.js.map