@ -5,450 +5,448 @@ import { eachOfSeries } from 'async'
import { linkBytecode } from 'solc/linker'
import { isValidAddress , addHexPrefix } from 'ethereumjs-util'
module .exports = {
/ * *
* build the transaction data
*
* @param { Object } function abi
* @param { Object } values to encode
* @param { String } contractbyteCode
* /
export function encodeData ( funABI , values , contractbyteCode ) {
let encoded
let encodedHex
try {
encoded = helper . encodeParams ( funABI , values )
encodedHex = encoded . toString ( 'hex' )
} catch ( e ) {
return { error : 'cannot encode arguments' }
}
if ( contractbyteCode ) {
return { data : '0x' + contractbyteCode + encodedHex . replace ( '0x' , '' ) }
} else {
return { data : helper.encodeFunctionId ( funABI ) + encodedHex . replace ( '0x' , '' ) }
}
}
/ * *
* build the transaction data
*
* @param { Object } function abi
* @param { Object } values to encode
* @param { String } contractbyteCode
* /
encodeData : function ( funABI , values , contractbyteCode ) {
let encoded
let encodedHex
/ * *
* encode function / c o n s t r u c t o r p a r a m e t e r s
*
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* /
export function encodeParams ( params , funAbi , callback ) {
let data : any = ''
let dataHex = ''
let funArgs
if ( params . indexOf ( 'raw:0x' ) === 0 ) {
// in that case we consider that the input is already encoded and *does not* contain the method signature
dataHex = params . replace ( 'raw:0x' , '' )
data = Buffer . from ( dataHex , 'hex' )
} else {
try {
encoded = helper . encodeParams ( funABI , values )
encodedHex = encoded . toString ( 'hex' )
params = params . replace ( /(^|,\s+|,)(\d+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted number by quoted number
params = params . replace ( /(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted hex string by quoted hex string
funArgs = JSON . parse ( '[' + params + ']' )
} catch ( e ) {
return { error : 'cannot encode arguments' }
return callback ( 'Error encoding arguments: ' + e )
}
if ( contractbyteCode ) {
return { data : '0x' + contractbyteCode + encodedHex . replace ( '0x' , '' ) }
} else {
return { data : helper.encodeFunctionId ( funABI ) + encodedHex . replace ( '0x' , '' ) }
}
} ,
/ * *
* encode function / c o n s t r u c t o r p a r a m e t e r s
*
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* /
encodeParams : function ( params , funAbi , callback ) {
let data : any = ''
let dataHex = ''
let funArgs
if ( params . indexOf ( 'raw:0x' ) === 0 ) {
// in that case we consider that the input is already encoded and *does not* contain the method signature
dataHex = params . replace ( 'raw:0x' , '' )
data = Buffer . from ( dataHex , 'hex' )
} else {
if ( funArgs . length > 0 ) {
try {
params = params . replace ( /(^|,\s+|,)(\d+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted number by quoted number
params = params . replace ( /(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted hex string by quoted hex string
funArgs = JSON . parse ( '[' + params + ']' )
data = helper . encodeParams ( funAbi , funArgs )
dataHex = data . toString ( 'hex' )
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
if ( funArgs . length > 0 ) {
try {
data = helper . encodeParams ( funAbi , funArgs )
dataHex = data . toString ( 'hex' )
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
}
if ( data . slice ( 0 , 9 ) === 'undefined' ) {
dataHex = data . slice ( 9 )
}
if ( data . slice ( 0 , 2 ) === '0x' ) {
dataHex = data . slice ( 2 )
}
}
callback ( null , { data : data , dataHex : dataHex , funArgs : funArgs } )
} ,
if ( data . slice ( 0 , 9 ) === 'undefined' ) {
dataHex = data . slice ( 9 )
}
if ( data . slice ( 0 , 2 ) === '0x' ) {
dataHex = data . slice ( 2 )
}
}
callback ( null , { data : data , dataHex : dataHex , funArgs : funArgs } )
}
/ * *
* encode function call ( function id + encoded parameters )
*
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* /
encodeFunctionCall : function ( params , funAbi , callback ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
callback ( null , { dataHex : helper.encodeFunctionId ( funAbi ) + encodedParam . dataHex , funAbi , funArgs : encodedParam.funArgs } )
} )
} ,
/ * *
* encode function call ( function id + encoded parameters )
*
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* /
export function encodeFunctionCall ( params , funAbi , callback ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
callback ( null , { dataHex : helper.encodeFunctionId ( funAbi ) + encodedParam . dataHex , funAbi , funArgs : encodedParam.funArgs } )
} )
}
/ * *
* encode constructor creation and link with provided libraries if needed
*
* @param { Object } contract - input paramater of the function to call
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Object } linkLibraries - contains { linkReferences } object which list all the addresses to be linked
* @param { Object } linkReferences - given by the compiler , contains the proper linkReferences
* @param { Function } callback - callback
* /
encodeConstructorCallAndLinkLibraries : function ( contract , params , funAbi , linkLibraries , linkReferences , callback ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
if ( linkLibraries && linkReferences ) {
for ( let libFile in linkLibraries ) {
for ( let lib in linkLibraries [ libFile ] ) {
const address = linkLibraries [ libFile ] [ lib ]
if ( ! isValidAddress ( address ) ) return callback ( address + ' is not a valid address. Please check the provided address is valid.' )
bytecodeToDeploy = this . linkLibraryStandardFromlinkReferences ( lib , address . replace ( '0x' , '' ) , bytecodeToDeploy , linkReferences )
}
/ * *
* encode constructor creation and link with provided libraries if needed
*
* @param { Object } contract - input paramater of the function to call
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Object } linkLibraries - contains { linkReferences } object which list all the addresses to be linked
* @param { Object } linkReferences - given by the compiler , contains the proper linkReferences
* @param { Function } callback - callback
* /
export function encodeConstructorCallAndLinkLibraries ( contract , params , funAbi , linkLibraries , linkReferences , callback ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
if ( linkLibraries && linkReferences ) {
for ( let libFile in linkLibraries ) {
for ( let lib in linkLibraries [ libFile ] ) {
const address = linkLibraries [ libFile ] [ lib ]
if ( ! isValidAddress ( address ) ) return callback ( address + ' is not a valid address. Please check the provided address is valid.' )
bytecodeToDeploy = this . linkLibraryStandardFromlinkReferences ( lib , address . replace ( '0x' , '' ) , bytecodeToDeploy , linkReferences )
}
}
}
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
return callback ( 'Failed to link some libraries' )
}
return callback ( null , { dataHex : bytecodeToDeploy + encodedParam . dataHex , funAbi , funArgs : encodedParam.funArgs , contractBytecode : contract.evm.bytecode.object } )
} )
} ,
/ * *
* encode constructor creation and deploy librairies if needed
*
* @param { String } contractName - current contract name
* @param { Object } contract - input paramater of the function to call
* @param { Object } contracts - map of all compiled contracts .
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* @param { Function } callbackStep - callbackStep
* @param { Function } callbackDeployLibrary - callbackDeployLibrary
* @param { Function } callback - callback
* /
encodeConstructorCallAndDeployLibraries : function ( contractName , contract , contracts , params , funAbi , callback , callbackStep , callbackDeployLibrary ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
let dataHex = ''
const contractBytecode = contract . evm . bytecode . object
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( contract , contracts , ( err , bytecode ) = > {
if ( err ) {
callback ( 'Error deploying required libraries: ' + err )
} else {
bytecodeToDeploy = bytecode + dataHex
return callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs : encodedParam.funArgs , contractBytecode , contractName : contractName } )
}
} , callbackStep , callbackDeployLibrary )
return
} else {
dataHex = bytecodeToDeploy + encodedParam . dataHex
}
callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs : encodedParam.funArgs , contractBytecode , contractName : contractName } )
} )
} ,
}
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
return callback ( 'Failed to link some libraries' )
}
return callback ( null , { dataHex : bytecodeToDeploy + encodedParam . dataHex , funAbi , funArgs : encodedParam.funArgs , contractBytecode : contract.evm.bytecode.object } )
} )
}
/ * *
* ( DEPRECATED ) build the transaction data
*
* @param { String } contractName
* @param { Object } contract - abi definition of the current contract .
* @param { Object } contracts - map of all compiled contracts .
* @param { Bool } isConstructor - isConstructor .
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Object } params - input paramater of the function to call
* @param { Function } callback - callback
* @param { Function } callbackStep - callbackStep
* @param { Function } callbackDeployLibrary - callbackDeployLibrary
* /
buildData : function ( contractName , contract , contracts , isConstructor , funAbi , params , callback , callbackStep , callbackDeployLibrary ) {
let funArgs = [ ]
let data : any = ''
/ * *
* encode constructor creation and deploy librairies if needed
*
* @param { String } contractName - current contract name
* @param { Object } contract - input paramater of the function to call
* @param { Object } contracts - map of all compiled contracts .
* @param { Object } params - input paramater of the function to call
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Function } callback - callback
* @param { Function } callbackStep - callbackStep
* @param { Function } callbackDeployLibrary - callbackDeployLibrary
* @param { Function } callback - callback
* /
export function encodeConstructorCallAndDeployLibraries ( contractName , contract , contracts , params , funAbi , callback , callbackStep , callbackDeployLibrary ) {
this . encodeParams ( params , funAbi , ( error , encodedParam ) = > {
if ( error ) return callback ( error )
let dataHex = ''
if ( params . indexOf ( 'raw:0x' ) === 0 ) {
// in that case we consider that the input is already encoded and *does not* contain the method signature
dataHex = params . replace ( 'raw:0x' , '' )
data = Buffer . from ( dataHex , 'hex' )
} else {
try {
if ( params . length > 0 ) {
funArgs = this . parseFunctionParams ( params )
const contractBytecode = contract . evm . bytecode . object
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( contract , contracts , ( err , bytecode ) = > {
if ( err ) {
callback ( 'Error deploying required libraries: ' + err )
} else {
bytecodeToDeploy = bytecode + dataHex
return callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs : encodedParam.funArgs , contractBytecode , contractName : contractName } )
}
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
try {
data = helper . encodeParams ( funAbi , funArgs )
dataHex = data . toString ( 'hex' )
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
if ( data . slice ( 0 , 9 ) === 'undefined' ) {
dataHex = data . slice ( 9 )
}
if ( data . slice ( 0 , 2 ) === '0x' ) {
dataHex = data . slice ( 2 )
}
}
let contractBytecode
if ( isConstructor ) {
contractBytecode = contract . evm . bytecode . object
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( contract , contracts , ( err , bytecode ) = > {
if ( err ) {
callback ( 'Error deploying required libraries: ' + err )
} else {
bytecodeToDeploy = bytecode + dataHex
return callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs , contractBytecode , contractName : contractName } )
}
} , callbackStep , callbackDeployLibrary )
return
} else {
dataHex = bytecodeToDeploy + dataHex
}
} , callbackStep , callbackDeployLibrary )
return
} else {
dataHex = helper . encodeFunctionId ( funAbi ) + dataHex
dataHex = bytecodeToDeploy + encodedParam . dataHex
}
callback ( null , { dataHex , funAbi , funArgs , contractBytecode , contractName : contractName } )
} ,
callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs : encodedParam.funArgs , contractBytecode , contractName : contractName } )
} )
}
atAddress : function ( ) { } ,
/ * *
* ( DEPRECATED ) build the transaction data
*
* @param { String } contractName
* @param { Object } contract - abi definition of the current contract .
* @param { Object } contracts - map of all compiled contracts .
* @param { Bool } isConstructor - isConstructor .
* @param { Object } funAbi - abi definition of the function to call . null if building data for the ctor .
* @param { Object } params - input paramater of the function to call
* @param { Function } callback - callback
* @param { Function } callbackStep - callbackStep
* @param { Function } callbackDeployLibrary - callbackDeployLibrary
* /
export function buildData ( contractName , contract , contracts , isConstructor , funAbi , params , callback , callbackStep , callbackDeployLibrary ) {
let funArgs = [ ]
let data : any = ''
let dataHex = ''
linkBytecodeStandard : function ( contract , contracts , callback , callbackStep , callbackDeployLibrary ) {
let contractBytecode = contract . evm . bytecode . object
eachOfSeries ( contract . evm . bytecode . linkReferences , ( libs , file , cbFile ) = > {
eachOfSeries ( contract . evm . bytecode . linkReferences [ file ] , ( libRef , libName , cbLibDeployed ) = > {
const library = contracts [ file ] [ libName ]
if ( library ) {
this . deployLibrary ( file + ':' + libName , libName , library , contracts , ( error , address ) = > {
if ( error ) {
return cbLibDeployed ( error )
}
let hexAddress = address . toString ( 'hex' )
if ( hexAddress . slice ( 0 , 2 ) === '0x' ) {
hexAddress = hexAddress . slice ( 2 )
}
contractBytecode = this . linkLibraryStandard ( libName , hexAddress , contractBytecode , contract )
cbLibDeployed ( )
} , callbackStep , callbackDeployLibrary )
} else {
cbLibDeployed ( 'Cannot find compilation data of library ' + libName )
}
} , ( error ) = > {
cbFile ( error )
} )
} , ( error ) = > {
if ( error ) {
callbackStep ( error )
if ( params . indexOf ( 'raw:0x' ) === 0 ) {
// in that case we consider that the input is already encoded and *does not* contain the method signature
dataHex = params . replace ( 'raw:0x' , '' )
data = Buffer . from ( dataHex , 'hex' )
} else {
try {
if ( params . length > 0 ) {
funArgs = this . parseFunctionParams ( params )
}
callback ( error , contractBytecode )
} )
} ,
linkBytecodeLegacy : function ( contract , contracts , callback , callbackStep , callbackDeployLibrary ) {
const libraryRefMatch = contract . evm . bytecode . object . match ( /__([^_]{1,36})__/ )
if ( ! libraryRefMatch ) {
return callback ( 'Invalid bytecode format.' )
}
const libraryName = libraryRefMatch [ 1 ]
// file_name:library_name
const libRef = libraryName . match ( /(.*):(.*)/ )
if ( ! libRef ) {
return callback ( 'Cannot extract library reference ' + libraryName )
}
if ( ! contracts [ libRef [ 1 ] ] || ! contracts [ libRef [ 1 ] ] [ libRef [ 2 ] ] ) {
return callback ( 'Cannot find library reference ' + libraryName )
}
const libraryShortName = libRef [ 2 ]
const library = contracts [ libRef [ 1 ] ] [ libraryShortName ]
if ( ! library ) {
return callback ( 'Library ' + libraryName + ' not found.' )
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
this . deployLibrary ( libraryName , libraryShortName , library , contracts , ( err , address ) = > {
if ( err ) {
return callback ( err )
}
let hexAddress = address . toString ( 'hex' )
if ( hexAddress . slice ( 0 , 2 ) === '0x' ) {
hexAddress = hexAddress . slice ( 2 )
}
contract . evm . bytecode . object = this . linkLibrary ( libraryName , hexAddress , contract . evm . bytecode . object )
this . linkBytecode ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
} , callbackStep , callbackDeployLibrary )
} ,
linkBytecode : function ( contract , contracts , callback , callbackStep , callbackDeployLibrary ) {
if ( contract . evm . bytecode . object . indexOf ( '_' ) < 0 ) {
return callback ( null , contract . evm . bytecode . object )
try {
data = helper . encodeParams ( funAbi , funArgs )
dataHex = data . toString ( 'hex' )
} catch ( e ) {
return callback ( 'Error encoding arguments: ' + e )
}
if ( contract . evm . bytecode . linkReferences && Object . keys ( contract . evm . bytecode . linkReferences ) . length ) {
this . linkBytecodeStandard ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
} else {
this . linkBytecodeLegacy ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
if ( data . slice ( 0 , 9 ) === 'undefined' ) {
dataHex = data . slice ( 9 )
}
} ,
deployLibrary : function ( libraryName , libraryShortName , library , contracts , callback , callbackStep , callbackDeployLibrary ) {
const address = library . address
if ( address ) {
return callback ( null , address )
if ( data . slice ( 0 , 2 ) === '0x' ) {
dataHex = data . slice ( 2 )
}
const bytecode = library . evm . bytecode . object
if ( bytecode . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( library , contracts , ( err , bytecode ) = > {
if ( err ) callback ( err )
else {
library . evm . bytecode . object = bytecode
this . deployLibrary ( libraryName , libraryShortName , library , contracts , callback , callbackStep , callbackDeployLibrary )
}
let contractBytecode
if ( isConstructor ) {
contractBytecode = contract . evm . bytecode . object
let bytecodeToDeploy = contract . evm . bytecode . object
if ( bytecodeToDeploy . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( contract , contracts , ( err , bytecode ) = > {
if ( err ) {
callback ( 'Error deploying required libraries: ' + err )
} else {
bytecodeToDeploy = bytecode + dataHex
return callback ( null , { dataHex : bytecodeToDeploy , funAbi , funArgs , contractBytecode , contractName : contractName } )
}
} , callbackStep , callbackDeployLibrary )
return
} else {
callbackStep ( ` creation of library ${ libraryName } pending... ` )
const data = { dataHex : bytecode , funAbi : { type : 'constructor' } , funArgs : [ ] , contractBytecode : bytecode , contractName : libraryShortName }
callbackDeployLibrary ( { data : data , useCall : false } , ( err , txResult ) = > {
if ( err ) {
return callback ( err )
}
const address = txResult . result . createdAddress || txResult . result . contractAddress
library . address = address
callback ( err , address )
} )
dataHex = bytecodeToDeploy + dataHex
}
} ,
} else {
dataHex = helper . encodeFunctionId ( funAbi ) + dataHex
}
callback ( null , { dataHex , funAbi , funArgs , contractBytecode , contractName : contractName } )
}
linkLibraryStandardFromlinkReferences : function ( libraryName , address , bytecode , linkReferences ) {
for ( let file in linkReferences ) {
for ( let libName in linkReferences [ file ] ) {
if ( libraryName === libName ) {
bytecode = this . setLibraryAddress ( address , bytecode , linkReferences [ file ] [ libName ] )
}
export function atAddress ( ) { }
export function linkBytecodeStandard ( contract , contracts , callback , callbackStep , callbackDeployLibrary ) {
let contractBytecode = contract . evm . bytecode . object
eachOfSeries ( contract . evm . bytecode . linkReferences , ( libs , file , cbFile ) = > {
eachOfSeries ( contract . evm . bytecode . linkReferences [ file ] , ( libRef , libName , cbLibDeployed ) = > {
const library = contracts [ file ] [ libName ]
if ( library ) {
this . deployLibrary ( file + ':' + libName , libName , library , contracts , ( error , address ) = > {
if ( error ) {
return cbLibDeployed ( error )
}
let hexAddress = address . toString ( 'hex' )
if ( hexAddress . slice ( 0 , 2 ) === '0x' ) {
hexAddress = hexAddress . slice ( 2 )
}
contractBytecode = this . linkLibraryStandard ( libName , hexAddress , contractBytecode , contract )
cbLibDeployed ( )
} , callbackStep , callbackDeployLibrary )
} else {
cbLibDeployed ( 'Cannot find compilation data of library ' + libName )
}
} , ( error ) = > {
cbFile ( error )
} )
} , ( error ) = > {
if ( error ) {
callbackStep ( error )
}
return bytecode
} ,
callback ( error , contractBytecode )
} )
}
linkLibraryStandard : function ( libraryName , address , bytecode , contract ) {
return this . linkLibraryStandardFromlinkReferences ( libraryName , address , bytecode , contract . evm . bytecode . linkReferences )
} ,
export function linkBytecodeLegacy ( contract , contracts , callback , callbackStep , callbackDeployLibrary ) {
const libraryRefMatch = contract . evm . bytecode . object . match ( /__([^_]{1,36})__/ )
if ( ! libraryRefMatch ) {
return callback ( 'Invalid bytecode format.' )
}
const libraryName = libraryRefMatch [ 1 ]
// file_name:library_name
const libRef = libraryName . match ( /(.*):(.*)/ )
if ( ! libRef ) {
return callback ( 'Cannot extract library reference ' + libraryName )
}
if ( ! contracts [ libRef [ 1 ] ] || ! contracts [ libRef [ 1 ] ] [ libRef [ 2 ] ] ) {
return callback ( 'Cannot find library reference ' + libraryName )
}
const libraryShortName = libRef [ 2 ]
const library = contracts [ libRef [ 1 ] ] [ libraryShortName ]
if ( ! library ) {
return callback ( 'Library ' + libraryName + ' not found.' )
}
this . deployLibrary ( libraryName , libraryShortName , library , contracts , ( err , address ) = > {
if ( err ) {
return callback ( err )
}
let hexAddress = address . toString ( 'hex' )
if ( hexAddress . slice ( 0 , 2 ) === '0x' ) {
hexAddress = hexAddress . slice ( 2 )
}
contract . evm . bytecode . object = this . linkLibrary ( libraryName , hexAddress , contract . evm . bytecode . object )
this . linkBytecode ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
} , callbackStep , callbackDeployLibrary )
}
setLibraryAddress : function ( address , bytecodeToLink , positions ) {
if ( positions ) {
for ( let pos of positions ) {
const regpos = bytecodeToLink . match ( new RegExp ( ` (.{ ${ 2 * pos . start } })(.{ ${ 2 * pos . length } })(.*) ` ) )
if ( regpos ) {
bytecodeToLink = regpos [ 1 ] + address + regpos [ 3 ]
}
export function linkBytecode ( contract , contracts , callback ? , callbackStep ? , callbackDeployLibrary ? ) {
if ( contract . evm . bytecode . object . indexOf ( '_' ) < 0 ) {
return callback ( null , contract . evm . bytecode . object )
}
if ( contract . evm . bytecode . linkReferences && Object . keys ( contract . evm . bytecode . linkReferences ) . length ) {
this . linkBytecodeStandard ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
} else {
this . linkBytecodeLegacy ( contract , contracts , callback , callbackStep , callbackDeployLibrary )
}
}
export function deployLibrary ( libraryName , libraryShortName , library , contracts , callback , callbackStep , callbackDeployLibrary ) {
const address = library . address
if ( address ) {
return callback ( null , address )
}
const bytecode = library . evm . bytecode . object
if ( bytecode . indexOf ( '_' ) >= 0 ) {
this . linkBytecode ( library , contracts , ( err , bytecode ) = > {
if ( err ) callback ( err )
else {
library . evm . bytecode . object = bytecode
this . deployLibrary ( libraryName , libraryShortName , library , contracts , callback , callbackStep , callbackDeployLibrary )
}
} , callbackStep , callbackDeployLibrary )
} else {
callbackStep ( ` creation of library ${ libraryName } pending... ` )
const data = { dataHex : bytecode , funAbi : { type : 'constructor' } , funArgs : [ ] , contractBytecode : bytecode , contractName : libraryShortName }
callbackDeployLibrary ( { data : data , useCall : false } , ( err , txResult ) = > {
if ( err ) {
return callback ( err )
}
const address = txResult . result . createdAddress || txResult . result . contractAddress
library . address = address
callback ( err , address )
} )
}
}
export function linkLibraryStandardFromlinkReferences ( libraryName , address , bytecode , linkReferences ) {
for ( let file in linkReferences ) {
for ( let libName in linkReferences [ file ] ) {
if ( libraryName === libName ) {
bytecode = this . setLibraryAddress ( address , bytecode , linkReferences [ file ] [ libName ] )
}
}
return bytecodeToLink
} ,
}
return bytecode
}
linkLibrary : function ( libraryName , address , bytecodeToLink ) {
return linkBytecode ( bytecodeToLink , { [ libraryName ] : addHexPrefix ( address ) } )
} ,
export function linkLibraryStandard ( libraryName , address , bytecode , contract ) {
return this . linkLibraryStandardFromlinkReferences ( libraryName , address , bytecode , contract . evm . bytecode . linkReferences )
}
decodeResponse : function ( response , fnabi ) {
// Only decode if there supposed to be fields
if ( fnabi . outputs && fnabi . outputs . length > 0 ) {
try {
let i
export function setLibraryAddress ( address , bytecodeToLink , positions ) {
if ( positions ) {
for ( let pos of positions ) {
const regpos = bytecodeToLink . match ( new RegExp ( ` (.{ ${ 2 * pos . start } })(.{ ${ 2 * pos . length } })(.*) ` ) )
if ( regpos ) {
bytecodeToLink = regpos [ 1 ] + address + regpos [ 3 ]
}
}
}
return bytecodeToLink
}
const outputTypes = [ ]
for ( i = 0 ; i < fnabi . outputs . length ; i ++ ) {
const type = fnabi . outputs [ i ] . type
outputTypes . push ( type . indexOf ( 'tuple' ) === 0 ? helper . makeFullTypeDefinition ( fnabi . outputs [ i ] ) : type )
}
export function linkLibrary ( libraryName , address , bytecodeToLink ) {
return linkBytecode ( bytecodeToLink , { [ libraryName ] : addHexPrefix ( address ) } )
}
export function decodeResponse ( response , fnabi ) {
// Only decode if there supposed to be fields
if ( fnabi . outputs && fnabi . outputs . length > 0 ) {
try {
let i
if ( ! response . length ) response = new Uint8Array ( 32 * fnabi . outputs . length ) // ensuring the data is at least filled by 0 cause `AbiCoder` throws if there's not engouh data
// decode data
const abiCoder = new ethers . utils . AbiCoder ( )
const decodedObj = abiCoder . decode ( outputTypes , response )
const outputTypes = [ ]
for ( i = 0 ; i < fnabi . outputs . length ; i ++ ) {
const type = fnabi . outputs [ i ] . type
outputTypes . push ( type . indexOf ( 'tuple' ) === 0 ? helper . makeFullTypeDefinition ( fnabi . outputs [ i ] ) : type )
}
const json = { }
for ( i = 0 ; i < outputTypes . length ; i ++ ) {
const name = fnabi . outputs [ i ] . name
json [ i ] = outputTypes [ i ] + ': ' + ( name ? name + ' ' + decodedObj [ i ] : decodedObj [ i ] )
}
if ( ! response . length ) response = new Uint8Array ( 32 * fnabi . outputs . length ) // ensuring the data is at least filled by 0 cause `AbiCoder` throws if there's not engouh data
// decode data
const abiCoder = new ethers . utils . AbiCoder ( )
const decodedObj = abiCoder . decode ( outputTypes , response )
return json
} catch ( e ) {
return { error : 'Failed to decode output: ' + e }
const json = { }
for ( i = 0 ; i < outputTypes . length ; i ++ ) {
const name = fnabi . outputs [ i ] . name
json [ i ] = outputTypes [ i ] + ': ' + ( name ? name + ' ' + decodedObj [ i ] : decodedObj [ i ] )
}
return json
} catch ( e ) {
return { error : 'Failed to decode output: ' + e }
}
return { }
} ,
}
return { }
}
parseFunctionParams : function ( params ) {
let args = [ ]
// Check if parameter string starts with array or string
let startIndex = this . isArrayOrStringStart ( params , 0 ) ? - 1 : 0
for ( let i = 0 ; i < params . length ; i ++ ) {
// If a quote is received
if ( params . charAt ( i ) === '"' ) {
startIndex = - 1
let endQuoteIndex = false
// look for closing quote. On success, push the complete string in arguments list
for ( let j = i + 1 ; ! endQuoteIndex ; j ++ ) {
if ( params . charAt ( j ) === '"' ) {
args . push ( params . substring ( i + 1 , j ) )
endQuoteIndex = true
i = j
}
// Throw error if end of params string is arrived but couldn't get end quote
if ( ! endQuoteIndex && j === params . length - 1 ) {
throw new Error ( 'invalid params' )
}
export function parseFunctionParams ( params ) {
let args = [ ]
// Check if parameter string starts with array or string
let startIndex = this . isArrayOrStringStart ( params , 0 ) ? - 1 : 0
for ( let i = 0 ; i < params . length ; i ++ ) {
// If a quote is received
if ( params . charAt ( i ) === '"' ) {
startIndex = - 1
let endQuoteIndex = false
// look for closing quote. On success, push the complete string in arguments list
for ( let j = i + 1 ; ! endQuoteIndex ; j ++ ) {
if ( params . charAt ( j ) === '"' ) {
args . push ( params . substring ( i + 1 , j ) )
endQuoteIndex = true
i = j
}
} else if ( params . charAt ( i ) === '[' ) { // If an array/struct opening bracket is received
startIndex = - 1
let bracketCount = 1
let j
for ( j = i + 1 ; bracketCount !== 0 ; j ++ ) {
// Increase count if another array opening bracket is received (To handle nested array)
if ( params . charAt ( j ) === '[' ) {
bracketCount ++
} else if ( params . charAt ( j ) === ']' ) { // // Decrease count if an array closing bracket is received (To handle nested array)
bracketCount --
}
// Throw error if end of params string is arrived but couldn't get end of tuple
if ( bracketCount !== 0 && j === params . length - 1 ) {
throw new Error ( 'invalid tuple params' )
}
// Throw error if end of params string is arrived but couldn't get end quote
if ( ! endQuoteIndex && j === params . length - 1 ) {
throw new Error ( 'invalid params' )
}
// If bracketCount = 0, it means complete array/nested array parsed, push it to the arguments list
args . push ( JSON . parse ( params . substring ( i , j ) ) )
i = j - 1
} else if ( params . charAt ( i ) === ',' ) {
// if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter
if ( startIndex >= 0 ) {
args . push ( params . substring ( startIndex , i ) )
}
} else if ( params . charAt ( i ) === '[' ) { // If an array/struct opening bracket is received
startIndex = - 1
let bracketCount = 1
let j
for ( j = i + 1 ; bracketCount !== 0 ; j ++ ) {
// Increase count if another array opening bracket is received (To handle nested array)
if ( params . charAt ( j ) === '[' ) {
bracketCount ++
} else if ( params . charAt ( j ) === ']' ) { // // Decrease count if an array closing bracket is received (To handle nested array)
bracketCount --
}
// Throw error if end of params string is arrived but couldn't get end of tuple
if ( bracketCount !== 0 && j === params . length - 1 ) {
throw new Error ( 'invalid tuple params' )
}
// Register start index of a parameter to parse
startIndex = this . isArrayOrStringStart ( params , i + 1 ) ? - 1 : i + 1
} else if ( startIndex >= 0 && i === params . length - 1 ) {
// If start index is registered and string is completed (To handle last parameter)
args . push ( params . substring ( startIndex , params . length ) )
}
}
args = args . map ( e = > {
if ( ! Array . isArray ( e ) ) {
return e . trim ( )
} else {
return e
// If bracketCount = 0, it means complete array/nested array parsed, push it to the arguments list
args . push ( JSON . parse ( params . substring ( i , j ) ) )
i = j - 1
} else if ( params . charAt ( i ) === ',' ) {
// if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter
if ( startIndex >= 0 ) {
args . push ( params . substring ( startIndex , i ) )
}
} )
return args
} ,
isArrayOrStringStart : function ( str , index ) {
return str . charAt ( index ) === '"' || str . charAt ( index ) === '['
// Register start index of a parameter to parse
startIndex = this . isArrayOrStringStart ( params , i + 1 ) ? - 1 : i + 1
} else if ( startIndex >= 0 && i === params . length - 1 ) {
// If start index is registered and string is completed (To handle last parameter)
args . push ( params . substring ( startIndex , params . length ) )
}
}
args = args . map ( e = > {
if ( ! Array . isArray ( e ) ) {
return e . trim ( )
} else {
return e
}
} )
return args
}
export function isArrayOrStringStart ( str , index ) {
return str . charAt ( index ) === '"' || str . charAt ( index ) === '['
}