import { utils as ethersUtils } from 'ethers' ; import { ErrorInvalid } from '../errors' ; import { CallScriptAction } from '../types' ; export const CALLSCRIPT_ID = '0x00000001' ; interface Segment { segment : CallScriptAction ; scriptLeft : string ; } function decodeSegment ( script ) { const to = `0x${ script . substring ( 0 , 40 ) }` ; script = script . substring ( 40 ) ; const dataLength = parseInt ( `0x${ script . substring ( 0 , 8 ) }` , 16 ) * 2 ; script = script . substring ( 8 ) ; const data = `0x${ script . substring ( 0 , dataLength ) }` ; script = script . substring ( dataLength ) ; return { segment : { to , data , } , scriptLeft : script , } ; } /**
 * Checks whether a EVMScript bytes string is a call script.
 */ export function isCallScript ( script ) { const scriptId = script . substring ( 0 , 10 ) ; return scriptId === CALLSCRIPT_ID ; } /**
 * Decode a call script bytes string into its actions.
 *
 * Will return an array containing objects with:
 *
 *  - `to`: to address
 *  - `data`: call data
 *
 */ export function decodeCallScript ( script ) { if ( ! isCallScript ( script ) ) { throw new ErrorInvalid ( `Not a call script: ${ script }` ) ; } let scriptData = script . substring ( 10 ) ; const segments = [ ] ; while ( scriptData . length > 0 ) { const { segment , scriptLeft } = decodeSegment ( scriptData ) ; segments . push ( segment ) ; scriptData = scriptLeft ; } return segments ; } param { Array < CallScriptAction > } actions returns { string } export function encodeCallScript ( actions ) { return actions . reduce ( ( script , { to , data } ) => { const address = ethersUtils . defaultAbiCoder . encode ( [ 'address' ] , [ to ] ) ; const dataLength = ethersUtils . defaultAbiCoder . encode ( [ 'uint256' ] , [ ( data . length - 2 ) / 2 ] ) ; return script + address . slice ( 26 ) + dataLength . slice ( 58 ) + data . slice ( 2 ) ; } , CALLSCRIPT_ID ) ; }