UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

93 lines (79 loc) 2.34 kB
import { CompilerOutputBytecode } from "../../../types"; import { Opcode } from "./opcodes"; export function getLibraryAddressPositions( bytecodeOutput: CompilerOutputBytecode ): number[] { const positions = []; for (const libs of Object.values(bytecodeOutput.linkReferences)) { for (const references of Object.values(libs)) { for (const ref of references) { positions.push(ref.start); } } } return positions; } export function normalizeCompilerOutputBytecode( compilerOutputBytecodeObject: string, addressesPositions: number[] ): Buffer { const ZERO_ADDRESS = "0000000000000000000000000000000000000000"; for (const position of addressesPositions) { compilerOutputBytecodeObject = linkHexStringBytecode( compilerOutputBytecodeObject, ZERO_ADDRESS, position ); } return Buffer.from(compilerOutputBytecodeObject, "hex"); } export function linkHexStringBytecode( code: string, address: string, position: number ) { if (address.startsWith("0x")) { address = address.substring(2); } return ( code.substring(0, position * 2) + address + code.slice(position * 2 + address.length) ); } export function zeroOutAddresses( code: Uint8Array, addressesPositions: number[] ): Uint8Array { const addressesSlices = addressesPositions.map((start) => ({ start, length: 20, })); return zeroOutSlices(code, addressesSlices); } export function zeroOutSlices( code: Uint8Array, slices: Array<{ start: number; length: number }> ): Uint8Array { for (const { start, length } of slices) { code = Buffer.concat([ code.slice(0, start), Buffer.alloc(length, 0), code.slice(start + length), ]); } return code; } export function normalizeLibraryRuntimeBytecodeIfNecessary( code: Uint8Array ): Uint8Array { // Libraries' protection normalization: // Solidity 0.4.20 introduced a protection to prevent libraries from being called directly. // This is done by modifying the code on deployment, and hard-coding the contract address. // The first instruction is a PUSH20 of the address, which we zero-out as a way of normalizing // it. Note that it's also zeroed-out in the compiler output. if (code[0] === Opcode.PUSH20) { return zeroOutAddresses(code, [1]); } return code; }