@stellar-expert/tx-meta-effects-parser 7.0.0-rc.19 → 7.0.0-rc.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +21 -21
- package/src/aggregation/events-analyzer.js +321 -321
- package/src/effect-types.js +104 -104
- package/src/effects-analyzer.js +1154 -1154
- package/src/index.js +232 -232
- package/src/parser/ledger-entry-changes-parser.js +331 -335
- package/src/parser/tx-xdr-parser-utils.js +323 -323
package/src/index.js
CHANGED
|
@@ -1,233 +1,233 @@
|
|
|
1
|
-
const {TransactionBuilder, xdr} = require('@stellar/stellar-base')
|
|
2
|
-
const {TxMetaEffectParserError, UnexpectedTxMetaChangeError} = require('./errors')
|
|
3
|
-
const {processFeeChargedEffect, analyzeOperationEffects, EffectsAnalyzer} = require('./effects-analyzer')
|
|
4
|
-
const {disposeSacCache} = require('./aggregation/sac-contract-mapper')
|
|
5
|
-
const {parseTxResult} = require('./parser/tx-result-parser')
|
|
6
|
-
const {parseLedgerEntryChanges} = require('./parser/ledger-entry-changes-parser')
|
|
7
|
-
const {parseTxMetaChanges} = require('./parser/tx-meta-changes-parser')
|
|
8
|
-
const {analyzeSignerChanges} = require('./aggregation/signer-changes-analyzer')
|
|
9
|
-
const contractPreimageEncoder = require('./parser/contract-preimage-encoder')
|
|
10
|
-
const xdrParserUtils = require('./parser/tx-xdr-parser-utils')
|
|
11
|
-
const effectTypes = require('./effect-types')
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Retrieve effects from transaction execution result metadata
|
|
15
|
-
* @param {String} network - Network passphrase
|
|
16
|
-
* @param {String|Buffer|xdr.TransactionEnvelope} tx - Base64-encoded tx envelope xdr
|
|
17
|
-
* @param {String|Buffer|xdr.TransactionResult} [result] - Base64-encoded tx envelope result
|
|
18
|
-
* @param {String|Buffer|xdr.TransactionMeta} [meta] - Base64-encoded tx envelope meta
|
|
19
|
-
* @param {Boolean} [mapSac] - Whether to create a map SAC->Asset
|
|
20
|
-
* @param {Boolean} [processSystemEvents] - Emit effects for contract errors and resource stats
|
|
21
|
-
* @param {Boolean} [processFailedOpEffects] - Whether to generate operation effects for failed/rejected transactions
|
|
22
|
-
* @param {Boolean} [processMetrics] - Process invocation metrics emitted by Soroban
|
|
23
|
-
* @param {Number} [protocol] - Specific Stellar protocol version for the executed transaction
|
|
24
|
-
* @return {ParsedTxOperationsMetadata}
|
|
25
|
-
*/
|
|
26
|
-
function parseTxOperationsMeta({
|
|
27
|
-
network,
|
|
28
|
-
tx,
|
|
29
|
-
result,
|
|
30
|
-
meta,
|
|
31
|
-
mapSac = false,
|
|
32
|
-
processSystemEvents = false,
|
|
33
|
-
processFailedOpEffects = false,
|
|
34
|
-
processMetrics,
|
|
35
|
-
protocol
|
|
36
|
-
}) {
|
|
37
|
-
if (!network)
|
|
38
|
-
throw new TypeError(`Network passphrase argument is required.`)
|
|
39
|
-
if (typeof network !== 'string')
|
|
40
|
-
throw new TypeError(`Invalid network passphrase: "${network}".`)
|
|
41
|
-
if (!tx)
|
|
42
|
-
throw new TypeError(`Transaction envelope argument is required.`)
|
|
43
|
-
if (processMetrics !== false)
|
|
44
|
-
processMetrics = true
|
|
45
|
-
const isEphemeral = !meta
|
|
46
|
-
//parse tx, result, and meta xdr
|
|
47
|
-
try {
|
|
48
|
-
tx = ensureXdrInputType(tx, xdr.TransactionEnvelope)
|
|
49
|
-
} catch (e) {
|
|
50
|
-
throw new TxMetaEffectParserError('Invalid transaction envelope XDR. ' + e.message)
|
|
51
|
-
}
|
|
52
|
-
if (!isEphemeral) {
|
|
53
|
-
try {
|
|
54
|
-
result = ensureXdrInputType(result, xdr.TransactionResult)
|
|
55
|
-
} catch (e) {
|
|
56
|
-
try {
|
|
57
|
-
const pair = ensureXdrInputType(result, xdr.TransactionResultPair)
|
|
58
|
-
result = pair.result()
|
|
59
|
-
} catch {
|
|
60
|
-
throw new TxMetaEffectParserError('Invalid transaction result XDR. ' + e.message)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
tx = TransactionBuilder.fromXDR(tx, network)
|
|
65
|
-
|
|
66
|
-
let parsedTx = tx
|
|
67
|
-
let parsedResult = result
|
|
68
|
-
|
|
69
|
-
const isFeeBump = !!parsedTx.innerTransaction
|
|
70
|
-
let feeBumpSuccess
|
|
71
|
-
|
|
72
|
-
const res = {
|
|
73
|
-
tx,
|
|
74
|
-
isEphemeral
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
//take inner transaction if parsed tx is a fee bump tx
|
|
78
|
-
if (isFeeBump) {
|
|
79
|
-
parsedTx = parsedTx.innerTransaction
|
|
80
|
-
if (parsedTx.innerTransaction)
|
|
81
|
-
throw new TxMetaEffectParserError('Failed to process FeeBumpTransaction wrapped with another FeeBumpTransaction')
|
|
82
|
-
if (!isEphemeral) {
|
|
83
|
-
parsedResult = result.result().innerResultPair().result()
|
|
84
|
-
feeBumpSuccess = parsedResult.result().switch().value >= 0
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
//normalize operation source and effects container
|
|
89
|
-
if (parsedTx.operations) {
|
|
90
|
-
res.operations = parsedTx.operations
|
|
91
|
-
|
|
92
|
-
for (const op of parsedTx.operations) {
|
|
93
|
-
if (!op.source) {
|
|
94
|
-
op.source = parsedTx.source
|
|
95
|
-
}
|
|
96
|
-
op.effects = []
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
res.effects = []
|
|
101
|
-
|
|
102
|
-
if (isEphemeral)
|
|
103
|
-
return res //do not parse meta for unsubmitted/rejected transactions
|
|
104
|
-
|
|
105
|
-
//process fee charge
|
|
106
|
-
const feeEffect = processFeeChargedEffect(tx, tx.feeSource || parsedTx.source, result.feeCharged().toString(), isFeeBump)
|
|
107
|
-
res.effects.push(feeEffect)
|
|
108
|
-
|
|
109
|
-
//check execution result
|
|
110
|
-
const {success, opResults} = parseTxResult(parsedResult)
|
|
111
|
-
if (!success || isFeeBump && !feeBumpSuccess) {
|
|
112
|
-
res.failed = true
|
|
113
|
-
if (!processFailedOpEffects)
|
|
114
|
-
return res
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
//retrieve operations result metadata
|
|
118
|
-
try {
|
|
119
|
-
meta = ensureXdrInputType(meta, xdr.TransactionMeta)
|
|
120
|
-
} catch (e) {
|
|
121
|
-
throw new TxMetaEffectParserError('Invalid transaction metadata XDR. ' + e.message)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
//add tx-level effects
|
|
125
|
-
for (const {before, after} of parseTxMetaChanges(meta)) {
|
|
126
|
-
if (before.entry !== 'account')
|
|
127
|
-
throw new UnexpectedTxMetaChangeError({type: before.entry, action: 'update'})
|
|
128
|
-
for (const effect of analyzeSignerChanges(before, after)) {
|
|
129
|
-
effect.source = (before || after).address
|
|
130
|
-
res.effects.push(effect)
|
|
131
|
-
}
|
|
132
|
-
if (isFeeBump && protocol === 20 && before.balance !== after.balance) { //bump fee calculation bug in protocol v20
|
|
133
|
-
const currentFee = BigInt(feeEffect.charged)
|
|
134
|
-
const diff = BigInt(after.balance) - BigInt(before.balance)
|
|
135
|
-
if (diff < currentFee) { // do not allow negative fee
|
|
136
|
-
feeEffect.charged = (currentFee - diff).toString()
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const metaValue = meta.value()
|
|
141
|
-
const opMeta = metaValue.operations()
|
|
142
|
-
const isV4Meta = meta.arm() === 'v4'
|
|
143
|
-
|
|
144
|
-
//analyze operation effects for each operation
|
|
145
|
-
for (let i = 0; i < parsedTx.operations.length; i++) {
|
|
146
|
-
const operation = parsedTx.operations[i]
|
|
147
|
-
if (success || processFailedOpEffects) {
|
|
148
|
-
const params = {
|
|
149
|
-
network,
|
|
150
|
-
operation,
|
|
151
|
-
meta: opMeta[i]?.changes() || [],
|
|
152
|
-
result: opResults[i],
|
|
153
|
-
processFailedOpEffects,
|
|
154
|
-
processMetrics
|
|
155
|
-
}
|
|
156
|
-
const isSorobanInvocation = operation.type === 'invokeHostFunction'
|
|
157
|
-
//only for Soroban contract invocation
|
|
158
|
-
if (isSorobanInvocation) {
|
|
159
|
-
const {sorobanMeta} = metaValue._attributes
|
|
160
|
-
if (sorobanMeta) {
|
|
161
|
-
if (sorobanMeta.events) {
|
|
162
|
-
params.events = sorobanMeta.events()
|
|
163
|
-
}
|
|
164
|
-
if (sorobanMeta.diagnosticEvents) {
|
|
165
|
-
params.diagnosticEvents = sorobanMeta.diagnosticEvents()
|
|
166
|
-
}
|
|
167
|
-
params.processSystemEvents = processSystemEvents
|
|
168
|
-
}
|
|
169
|
-
if (isV4Meta) {
|
|
170
|
-
params.diagnosticEvents = metaValue.diagnosticEvents()
|
|
171
|
-
const invocationOp = metaValue.operations()[0]
|
|
172
|
-
if (invocationOp) {
|
|
173
|
-
params.events = invocationOp.events()
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
params.mapSac = mapSac
|
|
177
|
-
}
|
|
178
|
-
const analyzer = new EffectsAnalyzer(params)
|
|
179
|
-
operation.effects = analyzer.analyze()
|
|
180
|
-
if (analyzer.sacMap && !isEmptyObject(analyzer.sacMap)) {
|
|
181
|
-
operation.sacMap = analyzer.sacMap
|
|
182
|
-
}
|
|
183
|
-
if (isSorobanInvocation) {
|
|
184
|
-
analyzer.addFeeMetric(metaValue)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return res
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Convert base64/raw XDR representation to XDR type
|
|
193
|
-
* @param {String|Buffer|Uint8Array|xdrType} value
|
|
194
|
-
* @param xdrType
|
|
195
|
-
* @return {xdrType|*}
|
|
196
|
-
* @internal
|
|
197
|
-
*/
|
|
198
|
-
function ensureXdrInputType(value, xdrType) {
|
|
199
|
-
if (value?.toXDR) // duck-typing check XDR types
|
|
200
|
-
return value
|
|
201
|
-
|
|
202
|
-
if (!value || (typeof value !== 'string' && !(value instanceof Uint8Array)))
|
|
203
|
-
throw new TypeError(`Invalid input format. Expected xdr.${xdrType.name} (raw, buffer, or bas64-encoded).`)
|
|
204
|
-
return xdrType.fromXDR(value, typeof value === 'string' ? 'base64' : 'raw')
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function isEmptyObject(obj) {
|
|
208
|
-
for (const key in obj)
|
|
209
|
-
return false
|
|
210
|
-
return true
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @typedef {{}} ParsedTxOperationsMetadata
|
|
215
|
-
* @property {Transaction|FeeBumpTransaction} tx - Parsed transaction object
|
|
216
|
-
* @property {BaseOperation[]} operations - Transaction operations
|
|
217
|
-
* @property {Boolean} isEphemeral - True for transactions without result metadata
|
|
218
|
-
* @property {Boolean} [failed] - True for transactions failed during on-chain execution
|
|
219
|
-
* @property {{}[]} [effects] - Top-level transaction effects (fee charges and )
|
|
220
|
-
* @property {Object<String,String>} [sacMap] - Optional map of SAC->Asset
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
module.exports = {
|
|
224
|
-
parseTxOperationsMeta,
|
|
225
|
-
parseTxResult,
|
|
226
|
-
analyzeOperationEffects,
|
|
227
|
-
parseLedgerEntryChanges,
|
|
228
|
-
parseTxMetaChanges,
|
|
229
|
-
effectTypes,
|
|
230
|
-
xdrParserUtils,
|
|
231
|
-
contractPreimageEncoder,
|
|
232
|
-
disposeSacCache
|
|
1
|
+
const {TransactionBuilder, xdr} = require('@stellar/stellar-base')
|
|
2
|
+
const {TxMetaEffectParserError, UnexpectedTxMetaChangeError} = require('./errors')
|
|
3
|
+
const {processFeeChargedEffect, analyzeOperationEffects, EffectsAnalyzer} = require('./effects-analyzer')
|
|
4
|
+
const {disposeSacCache} = require('./aggregation/sac-contract-mapper')
|
|
5
|
+
const {parseTxResult} = require('./parser/tx-result-parser')
|
|
6
|
+
const {parseLedgerEntryChanges} = require('./parser/ledger-entry-changes-parser')
|
|
7
|
+
const {parseTxMetaChanges} = require('./parser/tx-meta-changes-parser')
|
|
8
|
+
const {analyzeSignerChanges} = require('./aggregation/signer-changes-analyzer')
|
|
9
|
+
const contractPreimageEncoder = require('./parser/contract-preimage-encoder')
|
|
10
|
+
const xdrParserUtils = require('./parser/tx-xdr-parser-utils')
|
|
11
|
+
const effectTypes = require('./effect-types')
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Retrieve effects from transaction execution result metadata
|
|
15
|
+
* @param {String} network - Network passphrase
|
|
16
|
+
* @param {String|Buffer|xdr.TransactionEnvelope} tx - Base64-encoded tx envelope xdr
|
|
17
|
+
* @param {String|Buffer|xdr.TransactionResult} [result] - Base64-encoded tx envelope result
|
|
18
|
+
* @param {String|Buffer|xdr.TransactionMeta} [meta] - Base64-encoded tx envelope meta
|
|
19
|
+
* @param {Boolean} [mapSac] - Whether to create a map SAC->Asset
|
|
20
|
+
* @param {Boolean} [processSystemEvents] - Emit effects for contract errors and resource stats
|
|
21
|
+
* @param {Boolean} [processFailedOpEffects] - Whether to generate operation effects for failed/rejected transactions
|
|
22
|
+
* @param {Boolean} [processMetrics] - Process invocation metrics emitted by Soroban
|
|
23
|
+
* @param {Number} [protocol] - Specific Stellar protocol version for the executed transaction
|
|
24
|
+
* @return {ParsedTxOperationsMetadata}
|
|
25
|
+
*/
|
|
26
|
+
function parseTxOperationsMeta({
|
|
27
|
+
network,
|
|
28
|
+
tx,
|
|
29
|
+
result,
|
|
30
|
+
meta,
|
|
31
|
+
mapSac = false,
|
|
32
|
+
processSystemEvents = false,
|
|
33
|
+
processFailedOpEffects = false,
|
|
34
|
+
processMetrics,
|
|
35
|
+
protocol
|
|
36
|
+
}) {
|
|
37
|
+
if (!network)
|
|
38
|
+
throw new TypeError(`Network passphrase argument is required.`)
|
|
39
|
+
if (typeof network !== 'string')
|
|
40
|
+
throw new TypeError(`Invalid network passphrase: "${network}".`)
|
|
41
|
+
if (!tx)
|
|
42
|
+
throw new TypeError(`Transaction envelope argument is required.`)
|
|
43
|
+
if (processMetrics !== false)
|
|
44
|
+
processMetrics = true
|
|
45
|
+
const isEphemeral = !meta
|
|
46
|
+
//parse tx, result, and meta xdr
|
|
47
|
+
try {
|
|
48
|
+
tx = ensureXdrInputType(tx, xdr.TransactionEnvelope)
|
|
49
|
+
} catch (e) {
|
|
50
|
+
throw new TxMetaEffectParserError('Invalid transaction envelope XDR. ' + e.message)
|
|
51
|
+
}
|
|
52
|
+
if (!isEphemeral) {
|
|
53
|
+
try {
|
|
54
|
+
result = ensureXdrInputType(result, xdr.TransactionResult)
|
|
55
|
+
} catch (e) {
|
|
56
|
+
try {
|
|
57
|
+
const pair = ensureXdrInputType(result, xdr.TransactionResultPair)
|
|
58
|
+
result = pair.result()
|
|
59
|
+
} catch {
|
|
60
|
+
throw new TxMetaEffectParserError('Invalid transaction result XDR. ' + e.message)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
tx = TransactionBuilder.fromXDR(tx, network)
|
|
65
|
+
|
|
66
|
+
let parsedTx = tx
|
|
67
|
+
let parsedResult = result
|
|
68
|
+
|
|
69
|
+
const isFeeBump = !!parsedTx.innerTransaction
|
|
70
|
+
let feeBumpSuccess
|
|
71
|
+
|
|
72
|
+
const res = {
|
|
73
|
+
tx,
|
|
74
|
+
isEphemeral
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//take inner transaction if parsed tx is a fee bump tx
|
|
78
|
+
if (isFeeBump) {
|
|
79
|
+
parsedTx = parsedTx.innerTransaction
|
|
80
|
+
if (parsedTx.innerTransaction)
|
|
81
|
+
throw new TxMetaEffectParserError('Failed to process FeeBumpTransaction wrapped with another FeeBumpTransaction')
|
|
82
|
+
if (!isEphemeral) {
|
|
83
|
+
parsedResult = result.result().innerResultPair().result()
|
|
84
|
+
feeBumpSuccess = parsedResult.result().switch().value >= 0
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//normalize operation source and effects container
|
|
89
|
+
if (parsedTx.operations) {
|
|
90
|
+
res.operations = parsedTx.operations
|
|
91
|
+
|
|
92
|
+
for (const op of parsedTx.operations) {
|
|
93
|
+
if (!op.source) {
|
|
94
|
+
op.source = parsedTx.source
|
|
95
|
+
}
|
|
96
|
+
op.effects = []
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
res.effects = []
|
|
101
|
+
|
|
102
|
+
if (isEphemeral)
|
|
103
|
+
return res //do not parse meta for unsubmitted/rejected transactions
|
|
104
|
+
|
|
105
|
+
//process fee charge
|
|
106
|
+
const feeEffect = processFeeChargedEffect(tx, tx.feeSource || parsedTx.source, result.feeCharged().toString(), isFeeBump)
|
|
107
|
+
res.effects.push(feeEffect)
|
|
108
|
+
|
|
109
|
+
//check execution result
|
|
110
|
+
const {success, opResults} = parseTxResult(parsedResult)
|
|
111
|
+
if (!success || isFeeBump && !feeBumpSuccess) {
|
|
112
|
+
res.failed = true
|
|
113
|
+
if (!processFailedOpEffects)
|
|
114
|
+
return res
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//retrieve operations result metadata
|
|
118
|
+
try {
|
|
119
|
+
meta = ensureXdrInputType(meta, xdr.TransactionMeta)
|
|
120
|
+
} catch (e) {
|
|
121
|
+
throw new TxMetaEffectParserError('Invalid transaction metadata XDR. ' + e.message)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//add tx-level effects
|
|
125
|
+
for (const {before, after} of parseTxMetaChanges(meta)) {
|
|
126
|
+
if (before.entry !== 'account')
|
|
127
|
+
throw new UnexpectedTxMetaChangeError({type: before.entry, action: 'update'})
|
|
128
|
+
for (const effect of analyzeSignerChanges(before, after)) {
|
|
129
|
+
effect.source = (before || after).address
|
|
130
|
+
res.effects.push(effect)
|
|
131
|
+
}
|
|
132
|
+
if (isFeeBump && protocol === 20 && before.balance !== after.balance) { //bump fee calculation bug in protocol v20
|
|
133
|
+
const currentFee = BigInt(feeEffect.charged)
|
|
134
|
+
const diff = BigInt(after.balance) - BigInt(before.balance)
|
|
135
|
+
if (diff < currentFee) { // do not allow negative fee
|
|
136
|
+
feeEffect.charged = (currentFee - diff).toString()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const metaValue = meta.value()
|
|
141
|
+
const opMeta = metaValue.operations()
|
|
142
|
+
const isV4Meta = meta.arm() === 'v4'
|
|
143
|
+
|
|
144
|
+
//analyze operation effects for each operation
|
|
145
|
+
for (let i = 0; i < parsedTx.operations.length; i++) {
|
|
146
|
+
const operation = parsedTx.operations[i]
|
|
147
|
+
if (success || processFailedOpEffects) {
|
|
148
|
+
const params = {
|
|
149
|
+
network,
|
|
150
|
+
operation,
|
|
151
|
+
meta: opMeta[i]?.changes() || [],
|
|
152
|
+
result: opResults[i],
|
|
153
|
+
processFailedOpEffects,
|
|
154
|
+
processMetrics
|
|
155
|
+
}
|
|
156
|
+
const isSorobanInvocation = operation.type === 'invokeHostFunction'
|
|
157
|
+
//only for Soroban contract invocation
|
|
158
|
+
if (isSorobanInvocation) {
|
|
159
|
+
const {sorobanMeta} = metaValue._attributes
|
|
160
|
+
if (sorobanMeta) {
|
|
161
|
+
if (sorobanMeta.events) {
|
|
162
|
+
params.events = sorobanMeta.events()
|
|
163
|
+
}
|
|
164
|
+
if (sorobanMeta.diagnosticEvents) {
|
|
165
|
+
params.diagnosticEvents = sorobanMeta.diagnosticEvents()
|
|
166
|
+
}
|
|
167
|
+
params.processSystemEvents = processSystemEvents
|
|
168
|
+
}
|
|
169
|
+
if (isV4Meta) {
|
|
170
|
+
params.diagnosticEvents = metaValue.diagnosticEvents()
|
|
171
|
+
const invocationOp = metaValue.operations()[0]
|
|
172
|
+
if (invocationOp) {
|
|
173
|
+
params.events = invocationOp.events()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
params.mapSac = mapSac
|
|
177
|
+
}
|
|
178
|
+
const analyzer = new EffectsAnalyzer(params)
|
|
179
|
+
operation.effects = analyzer.analyze()
|
|
180
|
+
if (analyzer.sacMap && !isEmptyObject(analyzer.sacMap)) {
|
|
181
|
+
operation.sacMap = analyzer.sacMap
|
|
182
|
+
}
|
|
183
|
+
if (isSorobanInvocation) {
|
|
184
|
+
analyzer.addFeeMetric(metaValue)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return res
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Convert base64/raw XDR representation to XDR type
|
|
193
|
+
* @param {String|Buffer|Uint8Array|xdrType} value
|
|
194
|
+
* @param xdrType
|
|
195
|
+
* @return {xdrType|*}
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
function ensureXdrInputType(value, xdrType) {
|
|
199
|
+
if (value?.toXDR) // duck-typing check XDR types
|
|
200
|
+
return value
|
|
201
|
+
|
|
202
|
+
if (!value || (typeof value !== 'string' && !(value instanceof Uint8Array)))
|
|
203
|
+
throw new TypeError(`Invalid input format. Expected xdr.${xdrType.name} (raw, buffer, or bas64-encoded).`)
|
|
204
|
+
return xdrType.fromXDR(value, typeof value === 'string' ? 'base64' : 'raw')
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function isEmptyObject(obj) {
|
|
208
|
+
for (const key in obj)
|
|
209
|
+
return false
|
|
210
|
+
return true
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @typedef {{}} ParsedTxOperationsMetadata
|
|
215
|
+
* @property {Transaction|FeeBumpTransaction} tx - Parsed transaction object
|
|
216
|
+
* @property {BaseOperation[]} operations - Transaction operations
|
|
217
|
+
* @property {Boolean} isEphemeral - True for transactions without result metadata
|
|
218
|
+
* @property {Boolean} [failed] - True for transactions failed during on-chain execution
|
|
219
|
+
* @property {{}[]} [effects] - Top-level transaction effects (fee charges and )
|
|
220
|
+
* @property {Object<String,String>} [sacMap] - Optional map of SAC->Asset
|
|
221
|
+
*/
|
|
222
|
+
|
|
223
|
+
module.exports = {
|
|
224
|
+
parseTxOperationsMeta,
|
|
225
|
+
parseTxResult,
|
|
226
|
+
analyzeOperationEffects,
|
|
227
|
+
parseLedgerEntryChanges,
|
|
228
|
+
parseTxMetaChanges,
|
|
229
|
+
effectTypes,
|
|
230
|
+
xdrParserUtils,
|
|
231
|
+
contractPreimageEncoder,
|
|
232
|
+
disposeSacCache
|
|
233
233
|
}
|