@stellar-expert/tx-meta-effects-parser 5.2.0 → 5.4.0
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 +1 -1
- package/src/aggregation/events-analyzer.js +37 -10
- package/src/effect-types.js +3 -1
- package/src/effects-analyzer.js +35 -2
- package/src/index.js +3 -1
package/package.json
CHANGED
|
@@ -61,13 +61,13 @@ class EventsAnalyzer {
|
|
|
61
61
|
* @private
|
|
62
62
|
*/
|
|
63
63
|
analyzeDiagnosticEvents() {
|
|
64
|
-
const {diagnosticEvents} = this.effectsAnalyzer
|
|
64
|
+
const {diagnosticEvents, processSystemEvents} = this.effectsAnalyzer
|
|
65
65
|
if (!diagnosticEvents)
|
|
66
66
|
return
|
|
67
67
|
//diagnostic events
|
|
68
68
|
for (const evt of diagnosticEvents) {
|
|
69
|
-
if (!evt.inSuccessfulContractCall())
|
|
70
|
-
|
|
69
|
+
if (!processSystemEvents && !evt.inSuccessfulContractCall())
|
|
70
|
+
continue //throw new UnexpectedTxMetaChangeError({type: 'diagnostic_event', action: 'failed'})
|
|
71
71
|
//parse event
|
|
72
72
|
const event = evt.event()
|
|
73
73
|
const contractId = event.contractId()
|
|
@@ -90,7 +90,7 @@ class EventsAnalyzer {
|
|
|
90
90
|
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
91
91
|
return // skip non-diagnostic events
|
|
92
92
|
const rawArgs = body.data()
|
|
93
|
-
const
|
|
93
|
+
const funcCall = {
|
|
94
94
|
type: effectTypes.contractInvoked,
|
|
95
95
|
contract: xdrParseScVal(topics[1], true),
|
|
96
96
|
function: xdrParseScVal(topics[2]),
|
|
@@ -99,23 +99,37 @@ class EventsAnalyzer {
|
|
|
99
99
|
}
|
|
100
100
|
//add the invocation to the call stack
|
|
101
101
|
if (this.callStack.length) {
|
|
102
|
-
|
|
102
|
+
funcCall.depth = this.callStack.length
|
|
103
103
|
}
|
|
104
|
-
this.callStack.push(
|
|
105
|
-
this.effectsAnalyzer.addEffect(
|
|
104
|
+
this.callStack.push(funcCall)
|
|
105
|
+
this.effectsAnalyzer.addEffect(funcCall)
|
|
106
106
|
break
|
|
107
107
|
case 'fn_return':
|
|
108
108
|
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
109
109
|
return // skip non-diagnostic events
|
|
110
110
|
//attach execution result to the contract invocation event
|
|
111
|
-
const
|
|
111
|
+
const lastFuncCall = this.callStack.pop()
|
|
112
112
|
const result = body.data()
|
|
113
113
|
if (result.switch().name !== 'scvVoid') {
|
|
114
|
-
|
|
114
|
+
lastFuncCall.result = result.toXDR('base64')
|
|
115
115
|
}
|
|
116
116
|
break
|
|
117
|
+
case 'error':
|
|
118
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
119
|
+
return // skip non-diagnostic events
|
|
120
|
+
this.effectsAnalyzer.addEffect({
|
|
121
|
+
type: effectTypes.contractError,
|
|
122
|
+
code: topics[1].value().value(),
|
|
123
|
+
details: processEventBodyValue(body.data())
|
|
124
|
+
})
|
|
125
|
+
break
|
|
126
|
+
case 'core_metrics':
|
|
127
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
128
|
+
return // skip non-diagnostic events
|
|
129
|
+
this.effectsAnalyzer.addMetric(xdrParseScVal(topics[1]), parseInt(processEventBodyValue(body.data())))
|
|
130
|
+
break
|
|
117
131
|
//handle standard token contract events
|
|
118
|
-
//see https://github.com/stellar/rs-soroban-sdk/blob/
|
|
132
|
+
//see https://github.com/stellar/rs-soroban-sdk/blob/main/soroban-sdk/src/token.rs
|
|
119
133
|
case 'transfer': {
|
|
120
134
|
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
|
|
121
135
|
return
|
|
@@ -212,6 +226,19 @@ class EventsAnalyzer {
|
|
|
212
226
|
}
|
|
213
227
|
}
|
|
214
228
|
break
|
|
229
|
+
case 'set_admin': {
|
|
230
|
+
if (!matchEventTopicsShape(topics, ['address', 'str?']))
|
|
231
|
+
return //throw new Error('Non-standard event')
|
|
232
|
+
const currentAdmin = xdrParseScVal(topics[1])
|
|
233
|
+
const newAdmin = processEventBodyValue(body.data())
|
|
234
|
+
if (!this.matchInvocationEffect(e => e.function === 'set_admin' && matchArrays([currentAdmin, newAdmin], [this.effectsAnalyzer.source, e.args])))
|
|
235
|
+
return
|
|
236
|
+
this.effectsAnalyzer.setAdmin(contractId, newAdmin)
|
|
237
|
+
if (topics.length > 2) {
|
|
238
|
+
mapSacContract(this.effectsAnalyzer, contractId, xdrParseAsset(xdrParseScVal(topics[2])))
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
break
|
|
215
242
|
/*case 'approve': { //TODO: think about processing this effect
|
|
216
243
|
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
|
|
217
244
|
throw new Error('Non-standard event')
|
package/src/effect-types.js
CHANGED
|
@@ -86,12 +86,14 @@ const effectTypes = {
|
|
|
86
86
|
contractUpdated: 'contractUpdated',
|
|
87
87
|
|
|
88
88
|
contractInvoked: 'contractInvoked',
|
|
89
|
+
contractError: 'contractError',
|
|
89
90
|
|
|
90
91
|
contractDataCreated: 'contractDataCreated',
|
|
91
92
|
contractDataUpdated: 'contractDataUpdated',
|
|
92
93
|
contractDataRemoved: 'contractDataRemoved',
|
|
93
94
|
|
|
94
|
-
contractEvent: 'contractEvent'
|
|
95
|
+
contractEvent: 'contractEvent',
|
|
96
|
+
contractMetrics: 'contractMetrics'
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
module.exports = effectTypes
|
package/src/effects-analyzer.js
CHANGED
|
@@ -9,7 +9,7 @@ const AssetSupplyAnalyzer = require('./aggregation/asset-supply-analyzer')
|
|
|
9
9
|
const {UnexpectedTxMetaChangeError, TxMetaEffectParserError} = require('./errors')
|
|
10
10
|
|
|
11
11
|
class EffectsAnalyzer {
|
|
12
|
-
constructor({operation, meta, result, network, events, diagnosticEvents, mapSac}) {
|
|
12
|
+
constructor({operation, meta, result, network, events, diagnosticEvents, mapSac, processSystemEvents}) {
|
|
13
13
|
//set execution context
|
|
14
14
|
if (!operation.source)
|
|
15
15
|
throw new TxMetaEffectParserError('Operation source is not explicitly defined')
|
|
@@ -21,6 +21,9 @@ class EffectsAnalyzer {
|
|
|
21
21
|
this.events = events
|
|
22
22
|
if (diagnosticEvents?.length) {
|
|
23
23
|
this.diagnosticEvents = diagnosticEvents
|
|
24
|
+
if (processSystemEvents) {
|
|
25
|
+
this.processSystemEvents = true
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
this.network = network
|
|
26
29
|
if (mapSac) {
|
|
@@ -69,10 +72,20 @@ class EffectsAnalyzer {
|
|
|
69
72
|
*/
|
|
70
73
|
source = ''
|
|
71
74
|
/**
|
|
72
|
-
* @type {
|
|
75
|
+
* @type {Boolean}
|
|
73
76
|
* @private
|
|
74
77
|
*/
|
|
75
78
|
isContractCall = false
|
|
79
|
+
/**
|
|
80
|
+
* @type {Boolean}
|
|
81
|
+
* @readonly
|
|
82
|
+
*/
|
|
83
|
+
processSystemEvents = false
|
|
84
|
+
/**
|
|
85
|
+
* @type {{}}
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
metrics
|
|
76
89
|
|
|
77
90
|
analyze() {
|
|
78
91
|
//find appropriate parser method
|
|
@@ -160,6 +173,17 @@ class EffectsAnalyzer {
|
|
|
160
173
|
}, position)
|
|
161
174
|
}
|
|
162
175
|
|
|
176
|
+
addMetric(metric, value) {
|
|
177
|
+
let {metrics} = this
|
|
178
|
+
if (!metrics) {
|
|
179
|
+
metrics = this.metrics = {
|
|
180
|
+
type: effectTypes.contractMetrics
|
|
181
|
+
}
|
|
182
|
+
this.addEffect(metrics)
|
|
183
|
+
}
|
|
184
|
+
metrics[metric] = value
|
|
185
|
+
}
|
|
186
|
+
|
|
163
187
|
setOptions() {
|
|
164
188
|
const sourceAccount = normalizeAddress(this.source)
|
|
165
189
|
const {before, after} = this.changes.find(ch => ch.type === 'account' && ch.before.address === sourceAccount)
|
|
@@ -375,6 +399,15 @@ class EffectsAnalyzer {
|
|
|
375
399
|
restoreFootprint() {
|
|
376
400
|
}
|
|
377
401
|
|
|
402
|
+
setAdmin(contractId, newAdmin) {
|
|
403
|
+
const effect = {
|
|
404
|
+
type: effectTypes.contractUpdated,
|
|
405
|
+
contract: contractId,
|
|
406
|
+
admin: newAdmin
|
|
407
|
+
}
|
|
408
|
+
this.addEffect(effect)
|
|
409
|
+
}
|
|
410
|
+
|
|
378
411
|
processDexOperationEffects() {
|
|
379
412
|
//process trades first
|
|
380
413
|
for (const claimedOffer of this.result.claimedOffers) {
|
package/src/index.js
CHANGED
|
@@ -17,9 +17,10 @@ const effectTypes = require('./effect-types')
|
|
|
17
17
|
* @param {String|Buffer|xdr.TransactionResult} [result] - Base64-encoded tx envelope result
|
|
18
18
|
* @param {String|Buffer|xdr.TransactionMeta} [meta] - Base64-encoded tx envelope meta
|
|
19
19
|
* @param {Boolean} [mapSac] - Whether to create a map SAC->Asset
|
|
20
|
+
* @param {Boolean} [processSystemEvents] - Emit effects for contract errors and resource stats
|
|
20
21
|
* @return {ParsedTxOperationsMetadata}
|
|
21
22
|
*/
|
|
22
|
-
function parseTxOperationsMeta({network, tx, result, meta, mapSac = false}) {
|
|
23
|
+
function parseTxOperationsMeta({network, tx, result, meta, mapSac = false, processSystemEvents = false}) {
|
|
23
24
|
if (!network)
|
|
24
25
|
throw new TypeError(`Network passphrase argument is required.`)
|
|
25
26
|
if (typeof network !== 'string')
|
|
@@ -138,6 +139,7 @@ function parseTxOperationsMeta({network, tx, result, meta, mapSac = false}) {
|
|
|
138
139
|
params.events = sorobanMeta.events()
|
|
139
140
|
params.diagnosticEvents = sorobanMeta.diagnosticEvents()
|
|
140
141
|
params.mapSac = mapSac
|
|
142
|
+
params.processSystemEvents = processSystemEvents
|
|
141
143
|
}
|
|
142
144
|
const analyzer = new EffectsAnalyzer(params)
|
|
143
145
|
operation.effects = analyzer.analyze()
|