import { keccak256 } from 'ethereumjs-util' ; import cbor from 'cbor' ; export interface Version { withMetadata : string ; withoutMetadata : string ; linkedWithoutMetadata : string ; } export function getVersion ( bytecode , linkedBytecode ? , constructorArgs = '' ) { if ( bytecode !== '' ) { return { withMetadata : hashBytecode ( bytecode ) , withoutMetadata : hashBytecodeWithoutMetadata ( bytecode ) , linkedWithoutMetadata : hashBytecodeWithoutMetadata ( linkedBytecode ?? bytecode , constructorArgs ) , } ; } else { throw new Error ( 'Abstract contract not allowed here' ) ; } } export function hashBytecode ( bytecode , constructorArgs = '' ) { bytecode = bytecode . replace ( /__\$([0-9a-fA-F]{34})\$__/g , ( _ , placeholder ) => `000${ placeholder }000` ) . replace ( /__\w{36}__/g , placeholder => keccak256 ( Buffer . from ( placeholder ) ) . toString ( 'hex' , 0 , 20 ) ) ; if ( ! /^(0x)?[0-9a-fA-F]*$/ . test ( bytecode ) ) { throw new Error ( 'Bytecode is not a valid hex string' ) ; } if ( ! /^(0x)?[0-9a-fA-F]*$/ . test ( constructorArgs ) ) { throw new Error ( 'Constructor arguments are not a valid hex string' ) ; } const buf = Buffer . concat ( [ Buffer . from ( bytecode . replace ( /^0x/ , '' ) , 'hex' ) , Buffer . from ( constructorArgs . replace ( /^0x/ , '' ) , 'hex' ) , ] ) ; return keccak256 ( buf ) . toString ( 'hex' ) ; } export function hashBytecodeWithoutMetadata ( bytecode , constructorArgs = '' ) { return hashBytecode ( trimBytecodeMetadata ( bytecode ) , constructorArgs ) ; } function trimBytecodeMetadata ( bytecode ) { if ( bytecode . length <= 4 ) { return bytecode ; } const rawLength = bytecode . slice ( bytecode . length - 4 ) ; const metadataLength = parseInt ( rawLength , 16 ) * 2 ; if ( metadataLength > bytecode . length - 4 ) { return bytecode ; } const metadataStart = bytecode . length - metadataLength - 4 ; const metadata = bytecode . slice ( metadataStart , bytecode . length - 4 ) ; try { cbor . decode ( Buffer . from ( metadata , 'hex' ) ) ; } catch ( err ) { return bytecode ; } return bytecode . slice ( 0 , metadataStart ) ; }