UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

117 lines 6.04 kB
import { buildArtifact as zksyncBuildArtifact } from '@hyperlane-xyz/core/buildArtifact-zksync.js'; import { assert, retryAsync, rootLogger, strip0x, } from '@hyperlane-xyz/utils'; import { checkContractVerificationStatus, getContractSourceCode, verifyContractSourceCodeViaStandardJsonInput, verifyProxyContract, } from '../../block-explorer/etherscan.js'; import { ContractVerificationStatus } from '../../token/types.js'; import { BaseContractVerifier } from './BaseContractVerifier.js'; export class ContractVerifier extends BaseContractVerifier { multiProvider; apiKeys; logger = rootLogger.child({ module: 'ContractVerifier' }); compilerOptions; constructor(multiProvider, apiKeys, buildArtifact, licenseType) { super(multiProvider, buildArtifact); this.multiProvider = multiProvider; this.apiKeys = apiKeys; const compilerversion = `v${buildArtifact.solcLongVersion}`; const versionRegex = /v(\d.\d.\d+)\+commit.\w+/; const matches = versionRegex.exec(compilerversion); if (!matches) { throw new Error(`Invalid compiler version ${compilerversion}`); } this.compilerOptions = { codeformat: 'solidity-standard-json-input', compilerversion, licenseType, }; if (zksyncBuildArtifact?.zk_version) this.compilerOptions.zksolcversion = `v${zksyncBuildArtifact.zk_version}`; } async verify(chain, input, verificationLogger) { const contractType = input.isProxy ? 'proxy' : 'implementation'; try { const verificationStatus = await this.getContractVerificationStatus(chain, input.address, verificationLogger); if (verificationStatus === ContractVerificationStatus.Verified || verificationStatus === ContractVerificationStatus.Skipped) { verificationLogger.debug(`Contract ${contractType} at address "${input.address}" on chain "${chain}" is already verified. Skipping...`); return; } let verificationId; if (input.isProxy) { verificationId = await this.verifyProxy(chain, input); } else { verificationId = await this.verifyImplementation(chain, input, verificationLogger); } verificationLogger.debug(`Verification request for ${contractType} contract at address "${input.address}" on chain "${chain}" sent. GUID ${verificationId}`); await this.checkStatus(chain, verificationId, !!input.isProxy, verificationLogger); verificationLogger.debug(`Contract ${contractType} at address "${input.address}" on chain "${chain}" successfully verified`); } catch (err) { verificationLogger.error(`Failed to verify ${contractType} contract at address "${input.address}" on chain "${chain}"`, err); } } async verifyImplementation(chain, input, verificationLogger) { const { apiUrl, apiKey } = this.multiProvider.getEvmExplorerMetadata(chain); const data = this.getImplementationData(chain, input, verificationLogger); return verifyContractSourceCodeViaStandardJsonInput({ apiUrl, apiKey, }, { compilerVersion: this.compilerOptions.compilerversion, constructorArguments: input.constructorArguments, contractAddress: input.address, contractName: data.contractname, sourceCode: data.sourceCode, licenseType: this.compilerOptions.licenseType, zkCompilerVersion: this.compilerOptions.zksolcversion, }); } async verifyProxy(chain, input) { assert(input.expectedimplementation, `Implementation address not provided for proxied contract at address "${input.address}" on chain "${chain}". Skipping verification`); const { apiUrl, apiKey } = this.multiProvider.getEvmExplorerMetadata(chain); return verifyProxyContract({ apiUrl, apiKey, }, { implementationAddress: input.expectedimplementation, contractAddress: input.address, }); } async checkStatus(chain, verificationId, isProxy, verificationLogger) { const contractType = isProxy ? 'proxy' : 'implementation'; verificationLogger.trace({ verificationId }, `Checking ${contractType} verification status on chain "${chain}"...`); const { apiUrl, apiKey } = this.multiProvider.getEvmExplorerMetadata(chain); await retryAsync(() => checkContractVerificationStatus({ apiUrl, apiKey, }, { isProxy, verificationId }), undefined, 1000); } prepareImplementationData(sourceName, input, filteredStandardInputJson) { return { sourceCode: filteredStandardInputJson, contractname: `${sourceName}:${input.name}`, contractaddress: input.address, constructorArguements: strip0x(input.constructorArguments ?? ''), ...this.compilerOptions, }; } async getContractVerificationStatus(chain, address, verificationLogger = this.logger) { try { const { apiUrl, apiKey } = this.multiProvider.getEvmExplorerMetadata(chain); verificationLogger.trace(`Fetching contract ABI for ${chain} address ${address}`); const sourceCodeResults = await getContractSourceCode({ apiUrl, apiKey, }, { contractAddress: address }); // Explorer won't return ContractName if unverified return sourceCodeResults.ContractName ? ContractVerificationStatus.Verified : ContractVerificationStatus.Unverified; } catch (e) { this.logger.error(`Error fetching contract verification status for ${address} on chain ${chain}: ${e}`); return ContractVerificationStatus.Error; } } } //# sourceMappingURL=ContractVerifier.js.map