"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.assembleTransaction = assembleTransaction;
var _stellarBase = require("@stellar/stellar-base");
var _api = require("./api");
var _parsers = require("./parsers");
function isSorobanTransaction(tx) {
if (tx.operations.length !== 1) {
return false;
}
switch (tx.operations[0].type) {
case 'invokeHostFunction':
case 'extendFootprintTtl':
case 'restoreFootprint':
return true;
default:
return false;
}
}
/**
* Combines the given raw transaction alongside the simulation results.
* If the given transaction already has authorization entries in a host
* function invocation (see {@link Operation.invokeHostFunction}), **the
* simulation entries are ignored**.
*
* If the given transaction already has authorization entries in a host function
* invocation (see {@link Operation.invokeHostFunction}), **the simulation
* entries are ignored**.
*
* @param {Transaction|FeeBumpTransaction} raw the initial transaction, w/o simulation applied
* @param {Api.SimulateTransactionResponse|Api.RawSimulateTransactionResponse} simulation the Soroban RPC simulation result (see {@link module:rpc.Server#simulateTransaction})
* @returns {TransactionBuilder} a new, cloned transaction with the proper auth and resource (fee, footprint) simulation data applied
*
* @memberof module:rpc
* @see {@link module:rpc.Server#simulateTransaction}
* @see {@link module:rpc.Server#prepareTransaction}
*/
function assembleTransaction(raw, simulation) {
if ('innerTransaction' in raw) {
// TODO: Handle feebump transactions
return assembleTransaction(raw.innerTransaction, simulation);
}
if (!isSorobanTransaction(raw)) {
throw new TypeError('unsupported transaction: must contain exactly one ' + 'invokeHostFunction, extendFootprintTtl, or restoreFootprint ' + 'operation');
}
const success = (0, _parsers.parseRawSimulation)(simulation);
if (!_api.Api.isSimulationSuccess(success)) {
throw new Error(`simulation incorrect: ${JSON.stringify(success)}`);
}
/* eslint-disable radix */
const classicFeeNum = parseInt(raw.fee) || 0;
const minResourceFeeNum = parseInt(success.minResourceFee) || 0;
const txnBuilder = _stellarBase.TransactionBuilder.cloneFrom(raw, {
// automatically update the tx fee that will be set on the resulting tx to
// the sum of 'classic' fee provided from incoming tx.fee and minResourceFee
// provided by simulation.
//
// 'classic' tx fees are measured as the product of tx.fee * 'number of
// operations', In soroban contract tx, there can only be single operation
// in the tx, so can make simplification of total classic fees for the
// soroban transaction will be equal to incoming tx.fee + minResourceFee.
fee: (classicFeeNum + minResourceFeeNum).toString(),
// apply the pre-built Soroban Tx Data from simulation onto the Tx
sorobanData: success.transactionData.build(),
networkPassphrase: raw.networkPassphrase
});
if (raw.operations[0].type === 'invokeHostFunction') {
// In this case, we don't want to clone the operation, so we drop it.
txnBuilder.clearOperations();
const invokeOp = raw.operations[0];
const existingAuth = invokeOp.auth ?? [];
txnBuilder.addOperation(_stellarBase.Operation.invokeHostFunction({
source: invokeOp.source,
func: invokeOp.func,
// if auth entries are already present, we consider this "advanced
// usage" and disregard ALL auth entries from the simulation
//
// the intuition is "if auth exists, this tx has probably been
// simulated before"
auth: existingAuth.length > 0 ? existingAuth : success.result.auth
}));
}
return txnBuilder;
}
Source