import * as blakejs from 'blakejs' ; import { KeyStore , Signer } from '../../types/ExternalInterfaces' ; import * as TezosTypes from '../../types/tezos/TezosChainTypes' ; import { TezosConstants } from '../../types/tezos/TezosConstants' ; import { ServiceResponseError } from '../../types/ErrorTypes' ; import * as TezosP2PMessageTypes from '../../types/tezos/TezosP2PMessageTypes' ; import { TezosNodeReader } from './TezosNodeReader' ; import { TezosMessageCodec } from './TezosMessageCodec' ; import { TezosMessageUtils } from './TezosMessageUtil' ; import { TezosLanguageUtil } from './TezosLanguageUtil' ; import { TezosOperationQueue } from './TezosOperationQueue' ; import FetchSelector from '../../utils/FetchSelector' ; const fetch = FetchSelector . fetch ; import LogSelector from '../../utils/LoggerSelector' ; const log = LogSelector . log ; const counterMatcher = new RegExp ( /.*Counter [0-9]{1,} already used for contract.*/ , 'gm' ) ; let operationQueues = { } ; /**
 *  Functions for sending operations on the Tezos network.
 */ export namespace TezosNodeWriter { param { string } server param { string } command param { object } payload returns { Promise < object > } function performPostRequest ( server , command , payload = { } ) { const url = `${ server }/${ command }` ; const payloadStr = JSON . stringify ( payload ) ; log . debug ( `TezosNodeWriter.performPostRequest sending ${ payloadStr }\n->\n${ url }` ) ; return fetch ( url , { method : 'post' , body : payloadStr , headers : { 'Content-Type' : 'application/json' } } ) ; } param { string } branch param { TezosP2PMessageTypes . Operation [ ] } operations returns { string } export function forgeOperations ( branch , operations ) { log . debug ( `TezosNodeWriter.forgeOperations: ${ JSON . stringify ( operations ) }` ) ; let encoded = TezosMessageUtils . writeBranch ( branch ) ; operations . forEach ( m => encoded += TezosMessageCodec . encodeOperation ( m ) ) ; log . debug ( `TezosNodeWriter.forgeOperations: ${ encoded }` ) ; return encoded ; } deprecated param { string } server param { TezosRPCTypes . TezosBlock } blockHead param { TezosP2PMessageTypes . Operation [ ] } operations returns { Promise < string > } export async function forgeOperationsRemotely ( server , branch , operations , chainid = 'main' ) { log . debug ( 'TezosNodeWriter.forgeOperations:' ) ; log . debug ( JSON . stringify ( operations ) ) ; log . warn ( 'forgeOperationsRemotely() is not intrinsically trustless' ) ; const response = await performPostRequest ( server , `chains/${ chainid }/blocks/head/helpers/forge/operations` , { branch : branch , contents : operations } ) ; const forgedOperation = await response . text ( ) ; const ops = forgedOperation . replace ( /\n/g , '' ) . replace ( /['"]+/g , '' ) ; let optypes = Array . from ( operations . map ( o => o [ "kind" ] ) ) ; let validate = false ; for ( let t of optypes ) { validate = [ 'reveal' , 'transaction' , 'delegation' , 'origination' ] . includes ( t ) ; if ( validate ) { break ; } } if ( validate ) { const decoded = TezosMessageCodec . parseOperationGroup ( ops ) ; for ( let i = 0 ; i < operations . length ; i ++ ) { const clientop = operations [ i ] ; const serverop = decoded [ i ] ; if ( clientop [ 'kind' ] === 'transaction' ) { if ( serverop . kind !== clientop [ 'kind' ] || serverop . fee !== clientop [ 'fee' ] || serverop . amount !== clientop [ 'amount' ] || serverop . destination !== clientop [ 'destination' ] ) { throw new Error ( 'Forged transaction failed validation.' ) ; } } else if ( clientop [ 'kind' ] === 'delegation' ) { if ( serverop . kind !== clientop [ 'kind' ] || serverop . fee !== clientop [ 'fee' ] || serverop . delegate !== clientop [ 'delegate' ] ) { throw new Error ( 'Forged delegation failed validation.' ) ; } } else if ( clientop [ 'kind' ] === 'origination' ) { if ( serverop . kind !== clientop [ 'kind' ] || serverop . fee !== clientop [ 'fee' ] || serverop . balance !== clientop [ 'balance' ] || serverop . spendable !== clientop [ 'spendable' ] || serverop . delegatable !== clientop [ 'delegatable' ] || serverop . delegate !== clientop [ 'delegate' ] || serverop . script !== undefined ) { throw new Error ( 'Forged origination failed validation.' ) ; } } } } return ops ; } deprecated export async function packDataRemotely ( server , data , type , gas = TezosConstants . OperationGasCap , chainid = 'main' ) { log . debug ( 'TezosNodeWriter.packDataRemotely:' ) ; log . debug ( JSON . stringify ( data ) ) ; log . warn ( 'packDataRemotely() is not intrinsically trustless' ) ; const response = await performPostRequest ( server , `chains/${ chainid }/blocks/head/helpers/scripts/pack_data` , { data , type , gas : `${ gas }` } ) ; const jsonResponse = await response . json ( ) ; try { return jsonResponse . packed ; } catch ( e ) { throw new Error ( `Could not pack ${ data } as ${ type }; error ${ e }` ) ; } } param { string } server param { string } branch param { string } protocol param { Operation [ ] } operations param { SignedOperationGroup } signedOpGroup returns { Promise < AppliedOperation > } export async function preapplyOperation ( server , branch , protocol , operations , signedOpGroup , chainid = 'main' ) { const payload = [ { protocol : protocol , branch : branch , contents : operations , signature : signedOpGroup . signature } ] ; const response = await performPostRequest ( server , `chains/${ chainid }/blocks/head/helpers/preapply/operations` , payload ) ; const text = await response . text ( ) ; let json ; try { log . debug ( `TezosNodeWriter.preapplyOperation received ${ text }` ) ; json = JSON . parse ( text ) ; } catch ( err ) { log . error ( `TezosNodeWriter.preapplyOperation failed to parse response` ) ; throw new Error ( `Could not parse JSON from response of chains/${ chainid }/blocks/head/helpers/preapply/operation: '${ text }' for ${ payload }` ) ; } parseRPCError ( text ) ; return json as TezosTypes . AlphaOperationsWithMetadata [ ] ; } param { string } server param { SignedOperationGroup } signedOpGroup returns { Promise < InjectedOperation > } export async function injectOperation ( server , signedOpGroup , chainid = 'main' ) { const response = await performPostRequest ( server , `injection/operation?chain=${ chainid }` , signedOpGroup . bytes . toString ( 'hex' ) ) ; const text = await response . text ( ) ; parseRPCError ( text ) ; return text ; } param { string } server param { Operation [ ] } operations param { Signer } signer param { number } offset returns { Promise < OperationResult > } export async function sendOperation ( server , operations , signer , offset = TezosConstants . HeadBranchOffset ) { const blockHead = await TezosNodeReader . getBlockAtOffset ( server , offset ) ; const blockHash = blockHead . hash . slice ( 0 , 51 ) ; const forgedOperationGroup = forgeOperations ( blockHash , operations ) ; const opSignature = await signer . signOperation ( Buffer . from ( TezosConstants . OperationGroupWatermark + forgedOperationGroup , 'hex' ) ) ; const signedOpGroup = Buffer . concat ( [ Buffer . from ( forgedOperationGroup , 'hex' ) , opSignature ] ) ; const base58signature = TezosMessageUtils . readSignatureWithHint ( opSignature , signer . getSignerCurve ( ) ) ; const opPair = { bytes : signedOpGroup , signature : base58signature } ; const appliedOp = await preapplyOperation ( server , blockHash , blockHead . protocol , operations , opPair ) ; const injectedOperation = await injectOperation ( server , opPair ) ; return { results : appliedOp [ 0 ] , operationGroupID : injectedOperation } ; } param server param operations param keyStore param { number } batchDelay export function queueOperation ( server , operations , signer , keyStore , batchDelay = 25 ) { const k = blakejs . blake2s ( `${ server }${ keyStore . publicKeyHash }` , null , 16 ) ; if ( ! ! ! operationQueues [ k ] ) { operationQueues [ k ] = TezosOperationQueue . createQueue ( server , signer , keyStore , batchDelay ) ; } operationQueues [ k ] . addOperations ( ... operations ) ; } export function getQueueStatus ( server , keyStore ) { const k = blakejs . blake2s ( `${ server }${ keyStore . publicKeyHash }` , null , 16 ) ; if ( operationQueues [ k ] ) { return operationQueues [ k ] . getStatus ( ) ; } return - 1 ; } param { string } server param { string } publicKey param { string } accountHash param { number } accountOperationIndex param { StackableOperation [ ] } operations export async function appendRevealOperation ( server , publicKey , accountHash , accountOperationIndex , operations ) { const isKeyRevealed = await TezosNodeReader . isManagerKeyRevealedForAccount ( server , accountHash ) ; const counter = accountOperationIndex + 1 ; if ( ! isKeyRevealed ) { const revealOp = { kind : 'reveal' , source : accountHash , fee : TezosConstants . DefaultKeyRevealFee . toString ( ) , counter : counter . toString ( ) , gas_limit : TezosConstants . DefaultKeyRevealGasLimit . toString ( ) , storage_limit : TezosConstants . DefaultKeyRevealStorageLimit . toString ( ) , public_key : publicKey } ; operations . forEach ( ( operation , index ) => { const c = accountOperationIndex + 2 + index ; operation . counter = c . toString ( ) ; } ) ; return [ revealOp , ... operations ] ; } else { return operations . map ( ( o , i ) => { return { ... o , counter : `${ counter + i }` } ; } ) ; } } param { string } server param { KeyStore } keyStore param { String } to param { number } amount param { number } fee param { number } offset returns { Promise < OperationResult > } export async function sendTransactionOperation ( server , signer , keyStore , to , amount , fee = TezosConstants . DefaultSimpleTransactionFee , offset = TezosConstants . HeadBranchOffset , optimizeFee = false ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const transaction = { destination : to , amount : amount . toString ( ) , storage_limit : TezosConstants . DefaultTransactionStorageLimit + '' , gas_limit : TezosConstants . DefaultTransactionGasLimit + '' , counter : counter . toString ( ) , fee : fee . toString ( ) , source : keyStore . publicKeyHash , kind : 'transaction' } ; const operations = await prepareOperation ( server , keyStore , counter , transaction , optimizeFee ) ; return sendOperation ( server , operations , signer , offset ) ; } param { string } server param { KeyStore } keyStore param { string } delegate param { number } fee param { number } offset returns { Promise < OperationResult > } export async function sendDelegationOperation ( server , signer , keyStore , delegate , fee = TezosConstants . DefaultDelegationFee , offset = TezosConstants . HeadBranchOffset , optimizeFee = false ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const delegation = { kind : 'delegation' , source : keyStore . publicKeyHash , fee : fee . toString ( ) , counter : counter . toString ( ) , storage_limit : TezosConstants . DefaultDelegationStorageLimit . toString ( ) , gas_limit : TezosConstants . DefaultDelegationGasLimit . toString ( ) , delegate : delegate } ; const operations = await prepareOperation ( server , keyStore , counter , delegation , optimizeFee ) ; return sendOperation ( server , operations , signer , offset ) ; } param { string } server param { KeyStore } keyStore param { string } delegator param { number } fee param { number } offset returns { Promise < OperationResult > } export async function sendUndelegationOperation ( server , signer , keyStore , fee = TezosConstants . DefaultDelegationFee , offset = TezosConstants . HeadBranchOffset , optimizeFee = false ) { return sendDelegationOperation ( server , signer , keyStore , undefined , fee , offset , optimizeFee ) ; } param { string } server param { KeyStore } keyStore param { number } amount param { string | undefined } delegate param { number } fee param { number } storageLimit param { number } gasLimit param { string } code param { string } storage param { TezosParameterFormat } codeFormat param { number } offset export async function sendContractOriginationOperation ( server , signer , keyStore , amount , delegate , fee , storageLimit , gasLimit , code , storage , codeFormat = TezosTypes . TezosParameterFormat . Micheline , offset = TezosConstants . HeadBranchOffset , optimizeFee = false ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const origination = constructContractOriginationOperation ( keyStore , amount , delegate , fee , storageLimit , gasLimit , code , storage , codeFormat , counter ) ; const operations = await prepareOperation ( server , keyStore , counter , origination , optimizeFee ) ; return sendOperation ( server , operations , signer , offset ) ; } param { KeyStore } keyStore param { number } amount param { string | undefined } delegate param { number } fee param { number } storageLimit param { number } gasLimit param { string } code param { string } storage param { TezosParameterFormat } codeFormat export function constructContractOriginationOperation ( keyStore , amount , delegate , fee , storageLimit , gasLimit , code , storage , codeFormat , counter ) { let parsedCode = undefined ; let parsedStorage = undefined ; if ( codeFormat === TezosTypes . TezosParameterFormat . Michelson ) { parsedCode = JSON . parse ( TezosLanguageUtil . translateMichelsonToMicheline ( code ) ) ; log . debug ( `TezosNodeWriter.constructContractOriginationOperation code translation:\n${ code }\n->\n${ JSON . stringify ( parsedCode ) }` ) ; parsedStorage = JSON . parse ( TezosLanguageUtil . translateMichelsonToMicheline ( storage ) ) ; log . debug ( `TezosNodeWriter.constructContractOriginationOperation storage translation:\n${ storage }\n->\n${ JSON . stringify ( parsedStorage ) }` ) ; } else if ( codeFormat === TezosTypes . TezosParameterFormat . Micheline ) { parsedCode = JSON . parse ( code ) ; parsedStorage = JSON . parse ( storage ) ; } return { kind : 'origination' , source : keyStore . publicKeyHash , fee : fee . toString ( ) , counter : counter . toString ( ) , gas_limit : gasLimit . toString ( ) , storage_limit : storageLimit . toString ( ) , balance : amount . toString ( ) , delegate : delegate , script : { code : parsedCode , storage : parsedStorage } } ; } param { string } server param { KeyStore } keyStore param { string } to param { number } amount param { number } fee param { string } storage_limit param { string } gas_limit param { string } entrypoint param { string } parameters param { TezosParameterFormat } parameterFormat param { number } offset export async function sendContractInvocationOperation ( server , signer , keyStore , contract , amount , fee , storageLimit , gasLimit , entrypoint , parameters , parameterFormat = TezosTypes . TezosParameterFormat . Micheline , offset = TezosConstants . HeadBranchOffset , optimizeFee = false ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const transaction = constructContractInvocationOperation ( keyStore . publicKeyHash , counter , contract , amount , fee , storageLimit , gasLimit , entrypoint , parameters , parameterFormat ) ; const operations = await prepareOperation ( server , keyStore , counter , transaction , optimizeFee ) ; return sendOperation ( server , operations , signer , offset ) ; } /**
     * Creates a transaction object for contract invocation.
     *
     */ export function constructContractInvocationOperation ( publicKeyHash , counter , to , amount , fee , storageLimit , gasLimit , entrypoint , parameters , parameterFormat = TezosTypes . TezosParameterFormat . Micheline ) { let transaction = { destination : to , amount : amount . toString ( ) , storage_limit : storageLimit . toString ( ) , gas_limit : gasLimit . toString ( ) , counter : counter . toString ( ) , fee : fee . toString ( ) , source : publicKeyHash , kind : 'transaction' } ; if ( parameters !== undefined ) { if ( parameterFormat === TezosTypes . TezosParameterFormat . Michelson ) { const michelineParams = TezosLanguageUtil . translateParameterMichelsonToMicheline ( parameters ) ; transaction . parameters = { entrypoint : entrypoint || 'default' , value : JSON . parse ( michelineParams ) } ; } else if ( parameterFormat === TezosTypes . TezosParameterFormat . Micheline ) { transaction . parameters = { entrypoint : entrypoint || 'default' , value : JSON . parse ( parameters ) } ; } else if ( parameterFormat === TezosTypes . TezosParameterFormat . MichelsonLambda ) { const michelineLambda = TezosLanguageUtil . translateMichelsonToMicheline ( `code ${ parameters }` ) ; transaction . parameters = { entrypoint : entrypoint || 'default' , value : JSON . parse ( michelineLambda ) } ; } } else if ( entrypoint !== undefined ) { transaction . parameters = { entrypoint : entrypoint , value : [ ] } ; } return transaction ; } param { string } server param { KeyStore } keyStore param { string } to param { number } fee param { string } storage_limit param { string } gas_limit param { string } entrypoint export async function sendContractPing ( server , signer , keyStore , to , fee , storageLimit , gasLimit , entrypoint ) { return sendContractInvocationOperation ( server , signer , keyStore , to , 0 , fee , storageLimit , gasLimit , entrypoint , undefined ) ; } param { string } server param { KeyStore } keyStore param { number } fee param { number } offset returns { Promise < OperationResult > } export async function sendKeyRevealOperation ( server , signer , keyStore , fee = TezosConstants . DefaultKeyRevealFee , offset = TezosConstants . HeadBranchOffset ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const revealOp = { kind : 'reveal' , source : keyStore . publicKeyHash , fee : fee + '' , counter : counter . toString ( ) , gas_limit : '10000' , storage_limit : '0' , public_key : keyStore . publicKey } ; const operations = [ revealOp ] ; return sendOperation ( server , operations , signer , offset ) ; } param { string } server param { KeyStore } keyStore param { string } activationCode returns { Promise < OperationResult > } export function sendIdentityActivationOperation ( server , signer , keyStore , activationCode ) { const activation = { kind : 'activate_account' , pkh : keyStore . publicKeyHash , secret : activationCode } ; return sendOperation ( server , [ activation ] , signer ) ; } param { string } server param { string } chainid param { KeyStore } keyStore param { string } contract param { number } amount param { number } fee param { string } storage_limit param { string } gas_limit param { string | undefined } entrypoint param { string | undefined } parameters param { TezosParameterFormat } parameterFormat returns export async function testContractInvocationOperation ( server , chainid , keyStore , contract , amount , fee , storageLimit , gasLimit , entrypoint , parameters , parameterFormat = TezosTypes . TezosParameterFormat . Micheline ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const transaction = constructContractInvocationOperation ( keyStore . publicKeyHash , counter , contract , amount , fee , storageLimit , gasLimit , entrypoint , parameters , parameterFormat ) ; return estimateOperation ( server , chainid , transaction ) ; } param { string } server param { string } chainid param { KeyStore } keyStore param { number } amount param { string | undefined } delegate param { number } fee param { number } storageLimit param { number } gasLimit param { string } code param { string } storage param { TezosParameterFormat } codeFormat returns export async function testContractDeployOperation ( server , chainid , keyStore , amount , delegate , fee , storageLimit , gasLimit , code , storage , codeFormat = TezosTypes . TezosParameterFormat . Micheline ) { const counter = await TezosNodeReader . getCounterForAccount ( server , keyStore . publicKeyHash ) + 1 ; const transaction = constructContractOriginationOperation ( keyStore , amount , delegate , fee , storageLimit , gasLimit , code , storage , codeFormat , counter ) ; return estimateOperation ( server , chainid , transaction ) ; } see https param { string } server param { string } chainid param operations returns { [ gas : number , storageCost : number ] export async function estimateOperationGroup ( server , chainid , operations ) { let operationResources = [ ] ; for ( let i = 0 ; i < operations . length ; i ++ ) { let priorConsumedResources = { gas : 0 , storageCost : 0 } ; if ( i > 0 ) { const priorTransactions = operations . slice ( 0 , i ) ; priorConsumedResources = await estimateOperation ( server , chainid , ... priorTransactions ) ; } const currentTransactions = operations . slice ( 0 , i + 1 ) ; const currentConsumedResources = await estimateOperation ( server , chainid , ... currentTransactions ) ; const gasLimitDelta = currentConsumedResources . gas - priorConsumedResources . gas ; const storageLimitDelta = currentConsumedResources . storageCost - priorConsumedResources . storageCost ; operationResources . push ( { gas : gasLimitDelta + TezosConstants . GasLimitPadding , storageCost : storageLimitDelta + TezosConstants . StorageLimitPadding } ) ; } const staticFee = ( operations . filter ( o => o . kind === 'reveal' ) . length === 1 ) ? 1270 : 0 ; const validBranch = 'BMLxA4tQjiu1PT2x3dMiijgvMTQo8AVxkPBPpdtM8hCfiyiC1jz' ; const gasLimitTotal = operationResources . map ( r => r . gas ) . reduce ( ( a , c ) => a + c , 0 ) ; const storageLimitTotal = operationResources . map ( r => r . storageCost ) . reduce ( ( a , c ) => a + c , 0 ) ; const forgedOperationGroup = forgeOperations ( validBranch , operations ) ; const groupSize = forgedOperationGroup . length / 2 + 64 ; let estimatedFee = staticFee + Math . ceil ( gasLimitTotal / 10 ) + TezosConstants . BaseOperationFee + groupSize + TezosConstants . DefaultBakerVig ; const estimatedStorageBurn = Math . ceil ( storageLimitTotal * TezosConstants . StorageRate ) ; if ( Number ( operations [ 0 ] . fee ) < estimatedFee ) { estimatedFee += 16 ; } log . debug ( 'group estimate' , operationResources , estimatedFee , estimatedStorageBurn ) ; return { operationResources , estimatedFee , estimatedStorageBurn } ; } param { string } server param { string } chainid param { TezosP2PMessageTypes . Operation } operations returns export async function estimateOperation ( server , chainid , ... operations ) { const naiveOperationGasCap = Math . min ( Math . floor ( TezosConstants . BlockGasCap / operations . length ) , TezosConstants . OperationGasCap ) . toString ( ) ; const localOperations = [ ... operations ] . map ( o => { return { ... o , gas_limit : naiveOperationGasCap , storage_limit : TezosConstants . OperationStorageCap . toString ( ) } ; } ) ; const responseJSON = await dryRunOperation ( server , chainid , ... localOperations ) ; let gas = 0 ; let storageCost = 0 ; let staticFee = 0 ; for ( let c of responseJSON [ 'contents' ] ) { try { gas += parseInt ( c [ 'metadata' ] [ 'operation_result' ] [ 'consumed_gas' ] ) || 0 ; storageCost += parseInt ( c [ 'metadata' ] [ 'operation_result' ] [ 'paid_storage_size_diff' ] ) || 0 ; if ( c . kind === 'origination' || c [ 'metadata' ] [ 'operation_result' ] [ 'allocated_destination_contract' ] ) { storageCost += TezosConstants . EmptyAccountStorageBurn ; } else if ( c . kind === 'reveal' ) { staticFee += 1270 ; } } catch { } const internalOperations = c [ 'metadata' ] [ 'internal_operation_results' ] ; if ( internalOperations === undefined ) { continue ; } for ( const internalOperation of internalOperations ) { const result = internalOperation [ 'result' ] ; gas += parseInt ( result [ 'consumed_gas' ] ) || 0 ; storageCost += parseInt ( result [ 'paid_storage_size_diff' ] ) || 0 ; if ( internalOperation . kind === 'origination' ) { storageCost += TezosConstants . EmptyAccountStorageBurn ; } } } const validBranch = 'BMLxA4tQjiu1PT2x3dMiijgvMTQo8AVxkPBPpdtM8hCfiyiC1jz' ; const forgedOperationGroup = forgeOperations ( validBranch , operations ) ; const operationSize = forgedOperationGroup . length / 2 + 64 ; const estimatedFee = staticFee + Math . ceil ( gas / 10 ) + TezosConstants . BaseOperationFee + operationSize + TezosConstants . DefaultBakerVig ; const estimatedStorageBurn = Math . ceil ( storageCost * TezosConstants . StorageRate ) ; log . debug ( `TezosNodeWriter.estimateOperation; gas: ${ gas }, storage: ${ storageCost }, fee estimate: ${ estimatedFee }, burn estimate: ${ estimatedStorageBurn }` ) ; return { gas , storageCost , estimatedFee , estimatedStorageBurn } ; } param { string } server param { string } chainid param { TezosP2PMessageTypes . Operation } operations returns { Promise < any > } export async function dryRunOperation ( server , chainid , ... operations ) { const fake_signature = 'edsigu6xFLH2NpJ1VcYshpjW99Yc1TAL1m2XBqJyXrxcZQgBMo8sszw2zm626yjpA3pWMhjpsahLrWdmvX9cqhd4ZEUchuBuFYy' ; const fake_chainid = 'NetXdQprcVkpaWU' ; const fake_branch = 'BL94i2ShahPx3BoNs6tJdXDdGeoJ9ukwujUA2P8WJwULYNdimmq' ; const response = await performPostRequest ( server , `chains/${ chainid }/blocks/head/helpers/scripts/run_operation` , { chain_id : fake_chainid , operation : { branch : fake_branch , contents : operations , signature : fake_signature } } ) ; const responseText = await response . text ( ) ; parseRPCError ( responseText ) ; const responseJSON = JSON . parse ( responseText ) ; return responseJSON ; } param server param keyStore param counter param operation param optimizeFee async function prepareOperation ( server , keyStore , counter , operation , optimizeFee = false ) { const operationGroup = await appendRevealOperation ( server , keyStore . publicKey , keyStore . publicKeyHash , counter - 1 , [ operation ] ) ; if ( optimizeFee ) { const estimate = await estimateOperationGroup ( server , 'main' , operationGroup ) ; operationGroup [ 0 ] . fee = estimate . estimatedFee . toString ( ) ; for ( let i = 0 ; i < operationGroup . length ; i ++ ) { operationGroup [ i ] . gas_limit = estimate . operationResources [ i ] . gas . toString ( ) ; operationGroup [ i ] . storage_limit = estimate . operationResources [ i ] . storageCost . toString ( ) ; } } return operationGroup ; } export async function prepareOperationGroup ( server , keyStore , counter , operations , optimizeFee = false ) { const operationGroup = await appendRevealOperation ( server , keyStore . publicKey , keyStore . publicKeyHash , counter , operations ) ; if ( optimizeFee ) { const estimate = await estimateOperationGroup ( server , 'main' , operationGroup ) ; operationGroup [ 0 ] . fee = estimate . estimatedFee . toString ( ) ; for ( let i = 0 ; i < operationGroup . length ; i ++ ) { operationGroup [ i ] . gas_limit = estimate . operationResources [ i ] . gas . toString ( ) ; operationGroup [ i ] . storage_limit = estimate . operationResources [ i ] . storageCost . toString ( ) ; } } return operationGroup ; } param { string } response returns export function parseRPCError ( response ) { let errors = '' ; try { const json = JSON . parse ( response ) ; const arr = Array . isArray ( json ) ? json : [ json ] ; if ( 'kind' in arr [ 0 ] ) { errors = arr . map ( e => { if ( e . msg ) { if ( counterMatcher . test ( e . msg ) ) { return `(${ e . kind }: ${ e . id }, counter already used)` ; } return `(${ e . kind }: ${ e . id }, ${ e . msg })` ; } return `(${ e . kind }: ${ e . id })` ; } ) . join ( ', ' ) ; } else if ( arr . length === 1 && arr [ 0 ] . contents . length === 1 && arr [ 0 ] . contents [ 0 ] . kind === 'activate_account' ) { } else { errors = arr . map ( r => r . contents ) . map ( o => o . map ( c => c . metadata . operation_result ) . concat ( o . flatMap ( c => c . metadata . internal_operation_results ) . filter ( c => ! ! c ) . map ( c => c . result ) ) . map ( r => parseRPCOperationResult ( r ) ) . filter ( i => i . length > 0 ) . join ( ', ' ) ) . join ( ', ' ) ; } } catch ( err ) { if ( response . startsWith ( 'Failed to parse the request body: ' ) ) { errors = response . slice ( 34 ) ; } else { const hash = response . replace ( /\"/g , '' ) . replace ( /\n/ , '' ) ; if ( hash . length === 51 && hash . charAt ( 0 ) === 'o' ) { } else { log . error ( `failed to parse errors: '${ err }' from '${ response }'\n, PLEASE report this to the maintainers` ) ; } } } if ( errors . length > 0 ) { log . debug ( `errors found in response:\n${ response }` ) ; let e = new ServiceResponseError ( 200 , '' , '' , '' , response ) ; e . message = errors ; throw e ; } } /**
     * Processes `operation_result` and `internal_operation_results` objects from the RPC responses into an error string.
     */ function parseRPCOperationResult ( result ) { if ( result . status !== 'applied' ) { let error = result . status ; if ( result . errors && result . errors . length > 0 ) { try { error += result . errors . map ( e => `(${ e . kind }: ${ e . id })` ) . join ( ', ' ) ; } catch { log . error ( `failed to parse errors from '${ result }'\n, PLEASE report this to the maintainers` ) ; } } return error ; } return '' ; } }