UNPKG

@matterlabs/hardhat-zksync-verify

Version:
78 lines (64 loc) 3.02 kB
import type cbor from 'cbor'; import debug from 'debug'; import util from 'util'; interface MetadataDescription { solcVersion: string; metadataSectionSizeInBytes: number; } export const METADATA_LENGTH_SIZE = 2; export const METADATA_PRESENT_SOLC_NOT_FOUND_VERSION_RANGE = '0.4.7 - 0.5.8'; export const METADATA_ABSENT_VERSION_RANGE = '<0.4.7'; const log = debug('hardhat:hardhat-etherscan:metadata'); export function inferSolcVersion(bytecode: Buffer): MetadataDescription { let solcMetadata; let metadataSectionSizeInBytes; try { const metadata = decodeSolcMetadata(bytecode); log(`Metadata decoded: ${util.inspect(metadata.decoded)}`); metadataSectionSizeInBytes = metadata.metadataSectionSizeInBytes; solcMetadata = metadata.decoded.solc; } catch { // The decoding failed. Unfortunately, our only option is to assume that this bytecode was emitted by an old version. // This could also mean that contract has keccak metadata instead of ipfs. log('Could not decode metadata.'); return { metadataSectionSizeInBytes: 0, solcVersion: METADATA_ABSENT_VERSION_RANGE, }; } if (solcMetadata instanceof Buffer) { if (solcMetadata.length === 3) { const [major, minor, patch] = solcMetadata; const solcVersion = `${major}.${minor}.${patch}`; log(`Solc version detected in bytecode: ${solcVersion}`); return { metadataSectionSizeInBytes, solcVersion }; } log(`Found solc version field with ${solcMetadata.length} elements instead of three!`); } // The embedded metadata was successfully decoded but there was no solc version in it. log(`Could not detect solidity version in metadata.`); return { metadataSectionSizeInBytes, solcVersion: METADATA_PRESENT_SOLC_NOT_FOUND_VERSION_RANGE, }; } export function decodeSolcMetadata(bytecode: Buffer) { const metadataSectionLength = getSolcMetadataSectionLength(bytecode); // The metadata and its length are in the last few bytes. const metadataPayload = bytecode.slice(-metadataSectionLength, -METADATA_LENGTH_SIZE); log(`Read metadata length ${metadataSectionLength}`); const lastMetadataBytes = metadataPayload.slice(-100); log(`Last ${lastMetadataBytes.length} bytes of metadata: ${lastMetadataBytes.toString('hex')}`); const { decodeFirstSync }: typeof cbor = require('cbor'); // The documentation for decodeFirst mentions the `required` option even though // the type information is missing it. // See http://hildjj.github.io/node-cbor/Decoder.html#.decodeFirst const decoded = decodeFirstSync(metadataPayload, { required: true }); return { decoded, metadataSectionSizeInBytes: metadataSectionLength, }; } export function getSolcMetadataSectionLength(bytecode: Buffer) { return bytecode.slice(-METADATA_LENGTH_SIZE).readUInt16BE(0) + METADATA_LENGTH_SIZE; }