@stellar-expert/tx-meta-effects-parser 7.0.0-rc.8 → 7.0.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/README.MD +92 -14
- package/package.json +21 -21
- package/src/aggregation/events-analyzer.js +323 -301
- package/src/aggregation/sac-contract-mapper.js +3 -3
- package/src/effect-types.js +104 -101
- package/src/effects-analyzer.js +1142 -1123
- package/src/index.js +226 -233
- package/src/parser/ledger-entry-changes-parser.js +331 -312
- package/src/parser/normalization.js +73 -0
- package/src/parser/tx-xdr-parser-utils.js +299 -322
- package/tmp +0 -100
|
@@ -1,302 +1,324 @@
|
|
|
1
|
-
const {StrKey, encodeMuxedAccount, encodeMuxedAccountToAddress} = require('@stellar/stellar-base')
|
|
2
|
-
const effectTypes = require('../effect-types')
|
|
3
|
-
const {xdrParseScVal, xdrParseAsset
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* @
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
* @param {
|
|
85
|
-
* @param {
|
|
86
|
-
* @param {
|
|
87
|
-
* @
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
let
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
this.effectsAnalyzer.
|
|
170
|
-
}
|
|
171
|
-
if (isContractAddress(
|
|
172
|
-
this.effectsAnalyzer.
|
|
173
|
-
}
|
|
174
|
-
if (
|
|
175
|
-
this.effectsAnalyzer.
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (
|
|
210
|
-
return
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
1
|
+
const {StrKey, encodeMuxedAccount, encodeMuxedAccountToAddress} = require('@stellar/stellar-base')
|
|
2
|
+
const effectTypes = require('../effect-types')
|
|
3
|
+
const {xdrParseScVal, xdrParseAsset} = require('../parser/tx-xdr-parser-utils')
|
|
4
|
+
const {isContractAddress, validateAmount} = require('../parser/normalization')
|
|
5
|
+
const {mapSacContract} = require('./sac-contract-mapper')
|
|
6
|
+
|
|
7
|
+
const EVENT_TYPES = {
|
|
8
|
+
SYSTEM: 0,
|
|
9
|
+
CONTRACT: 1,
|
|
10
|
+
DIAGNOSTIC: 2
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class EventsAnalyzer {
|
|
14
|
+
/**
|
|
15
|
+
* @param {EffectsAnalyzer} effectsAnalyzer
|
|
16
|
+
*/
|
|
17
|
+
constructor(effectsAnalyzer) {
|
|
18
|
+
this.effectsAnalyzer = effectsAnalyzer
|
|
19
|
+
this.callStack = []
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @type {[]}
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
callStack
|
|
27
|
+
|
|
28
|
+
analyze() {
|
|
29
|
+
this.analyzeDiagnosticEvents()
|
|
30
|
+
this.analyzeEvents()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
analyzeEvents() {
|
|
37
|
+
const {events} = this.effectsAnalyzer
|
|
38
|
+
if (!events)
|
|
39
|
+
return
|
|
40
|
+
//contract-generated events
|
|
41
|
+
for (const evt of events) {
|
|
42
|
+
const body = evt.body().value()
|
|
43
|
+
const rawTopics = body.topics()
|
|
44
|
+
const topics = rawTopics.map(xdrParseScVal)
|
|
45
|
+
if (topics[0] === 'DATA' && topics[1] === 'set')
|
|
46
|
+
continue //skip data entries modifications
|
|
47
|
+
const rawData = body.data()
|
|
48
|
+
//add event to the pipeline
|
|
49
|
+
this.effectsAnalyzer.addEffect({
|
|
50
|
+
type: effectTypes.contractEvent,
|
|
51
|
+
contract: StrKey.encodeContract(evt.contractId()),
|
|
52
|
+
topics,
|
|
53
|
+
rawTopics: rawTopics.map(v => v.toXDR('base64')),
|
|
54
|
+
data: processEventBodyValue(rawData),
|
|
55
|
+
rawData: rawData.toXDR('base64')
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
analyzeDiagnosticEvents() {
|
|
65
|
+
const {diagnosticEvents, processSystemEvents, processMetrics, processFailedOpEffects} = this.effectsAnalyzer
|
|
66
|
+
if (!diagnosticEvents)
|
|
67
|
+
return
|
|
68
|
+
const opContractId = this.effectsAnalyzer.retrieveOpContractId()
|
|
69
|
+
//diagnostic events
|
|
70
|
+
for (const evt of diagnosticEvents) {
|
|
71
|
+
if (!processSystemEvents && !(processFailedOpEffects || evt.inSuccessfulContractCall()))
|
|
72
|
+
continue //throw new UnexpectedTxMetaChangeError({type: 'diagnostic_event', action: 'failed'})
|
|
73
|
+
//parse event
|
|
74
|
+
const event = evt.event()
|
|
75
|
+
let contractId = event.contractId() || opContractId //contract id may be attached to the event itself, otherwise use contract from operation
|
|
76
|
+
if (contractId && typeof contractId !== 'string') {
|
|
77
|
+
contractId = StrKey.encodeContract(contractId)
|
|
78
|
+
}
|
|
79
|
+
this.processDiagnosticEvent(event._attributes.body._value, event._attributes.type.value, contractId, processMetrics)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {xdr.ContractEventV0} body
|
|
85
|
+
* @param {Number} type
|
|
86
|
+
* @param {String} contract
|
|
87
|
+
* @param {Boolean} processMetrics
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
processDiagnosticEvent(body, type, contract, processMetrics) {
|
|
91
|
+
const topics = body.topics()
|
|
92
|
+
if (!topics?.length)
|
|
93
|
+
return
|
|
94
|
+
switch (xdrParseScVal(topics[0])) {
|
|
95
|
+
case 'fn_call': // contract call
|
|
96
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
97
|
+
return // skip non-diagnostic events
|
|
98
|
+
const rawArgs = body.data()
|
|
99
|
+
const funcCall = {
|
|
100
|
+
type: effectTypes.contractInvoked,
|
|
101
|
+
contract: xdrParseScVal(topics[1], true),
|
|
102
|
+
function: xdrParseScVal(topics[2]),
|
|
103
|
+
args: processEventBodyValue(rawArgs),
|
|
104
|
+
rawArgs: rawArgs.toXDR('base64')
|
|
105
|
+
}
|
|
106
|
+
//add the invocation to the call stack
|
|
107
|
+
if (this.callStack.length) {
|
|
108
|
+
funcCall.depth = this.callStack.length
|
|
109
|
+
}
|
|
110
|
+
this.callStack.push(funcCall)
|
|
111
|
+
this.effectsAnalyzer.addEffect(funcCall)
|
|
112
|
+
break
|
|
113
|
+
case 'fn_return':
|
|
114
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
115
|
+
return // skip non-diagnostic events
|
|
116
|
+
//attach execution result to the contract invocation event
|
|
117
|
+
const lastFuncCall = this.callStack.pop()
|
|
118
|
+
const result = body.data()
|
|
119
|
+
if (result.switch().name !== 'scvVoid') {
|
|
120
|
+
lastFuncCall.result = result.toXDR('base64')
|
|
121
|
+
}
|
|
122
|
+
break
|
|
123
|
+
case 'error':
|
|
124
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
125
|
+
return // skip non-diagnostic events
|
|
126
|
+
let code = topics[1].value().value()
|
|
127
|
+
if (code.name) {
|
|
128
|
+
code = code.name
|
|
129
|
+
}
|
|
130
|
+
this.effectsAnalyzer.addEffect({
|
|
131
|
+
type: effectTypes.contractError,
|
|
132
|
+
contract,
|
|
133
|
+
code,
|
|
134
|
+
details: processEventBodyValue(body.data())
|
|
135
|
+
})
|
|
136
|
+
break
|
|
137
|
+
case 'core_metrics':
|
|
138
|
+
if (type !== EVENT_TYPES.DIAGNOSTIC)
|
|
139
|
+
return // skip non-diagnostic events
|
|
140
|
+
if (!processMetrics)
|
|
141
|
+
return
|
|
142
|
+
this.effectsAnalyzer.addMetric(contract, xdrParseScVal(topics[1]), parseInt(processEventBodyValue(body.data())))
|
|
143
|
+
break
|
|
144
|
+
//handle standard token contract events
|
|
145
|
+
//see https://github.com/stellar/rs-soroban-sdk/blob/main/soroban-sdk/src/token.rs
|
|
146
|
+
case 'transfer': {
|
|
147
|
+
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
|
|
148
|
+
return
|
|
149
|
+
const from = xdrParseScVal(topics[1])
|
|
150
|
+
const receiver = xdrParseScVal(topics[2])
|
|
151
|
+
let to = receiver
|
|
152
|
+
let amount = processEventBodyValue(body.data())
|
|
153
|
+
if (amount?.amount !== undefined) {
|
|
154
|
+
if (amount.to_muxed_id && !to.startsWith('M')) {
|
|
155
|
+
to = encodeMuxedAccountToAddress(encodeMuxedAccount(to, amount.to_muxed_id))
|
|
156
|
+
amount = amount.amount
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (validateAmount(amount, false) === null)
|
|
160
|
+
return null
|
|
161
|
+
if (to === from) //self transfer - nothing happens
|
|
162
|
+
return // TODO: need additional checks
|
|
163
|
+
const asset = this.getAssetFromEventTopics(topics, contract)
|
|
164
|
+
if (!StrKey.isValidContract(asset)) {
|
|
165
|
+
if (asset.includes(from)) { //SAC transfer by asset issuer
|
|
166
|
+
this.effectsAnalyzer.mint(asset, amount)
|
|
167
|
+
}
|
|
168
|
+
if (isContractAddress(from)) {
|
|
169
|
+
this.effectsAnalyzer.debit(amount, asset, from)
|
|
170
|
+
}
|
|
171
|
+
if (isContractAddress(to)) {
|
|
172
|
+
this.effectsAnalyzer.credit(amount, asset, to)
|
|
173
|
+
}
|
|
174
|
+
if (asset.includes(receiver)) { //SAC transfer by asset issuer
|
|
175
|
+
this.effectsAnalyzer.burn(asset, amount)
|
|
176
|
+
}
|
|
177
|
+
} else { //other cases
|
|
178
|
+
this.effectsAnalyzer.debit(amount, asset, from)
|
|
179
|
+
this.effectsAnalyzer.credit(amount, asset, to)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
break
|
|
183
|
+
case 'mint': {
|
|
184
|
+
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']) && !matchEventTopicsShape(topics, ['address', 'str?']))
|
|
185
|
+
return //throw new Error('Non-standard event')
|
|
186
|
+
let to = xdrParseScVal(topics[topics[2]?._arm === 'address' ? 2 : 1])
|
|
187
|
+
let amount = processEventBodyValue(body.data())
|
|
188
|
+
if (amount?.amount !== undefined) {
|
|
189
|
+
if (amount.to_muxed_id && !to.startsWith('M')) {
|
|
190
|
+
to = encodeMuxedAccountToAddress(encodeMuxedAccount(to, amount.to_muxed_id))
|
|
191
|
+
amount = amount.amount
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (validateAmount(amount, false) === null)
|
|
195
|
+
return null
|
|
196
|
+
validateAmount(amount)
|
|
197
|
+
const asset = this.getAssetFromEventTopics(topics, contract)
|
|
198
|
+
this.effectsAnalyzer.mint(asset, amount)
|
|
199
|
+
if (isContractAddress(asset) || isContractAddress(to)) {
|
|
200
|
+
this.effectsAnalyzer.credit(amount, asset, to)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
break
|
|
204
|
+
case 'burn': {
|
|
205
|
+
if (!matchEventTopicsShape(topics, ['address', 'str?']))
|
|
206
|
+
return //throw new Error('Non-standard event')
|
|
207
|
+
const from = xdrParseScVal(topics[1])
|
|
208
|
+
const amount = processEventBodyValue(body.data())
|
|
209
|
+
if (validateAmount(amount, false) === null)
|
|
210
|
+
return null
|
|
211
|
+
const asset = this.getAssetFromEventTopics(topics, contract)
|
|
212
|
+
if (isContractAddress(asset) || isContractAddress(from)) {
|
|
213
|
+
this.effectsAnalyzer.debit(amount, asset, from)
|
|
214
|
+
}
|
|
215
|
+
this.effectsAnalyzer.burn(asset, amount)
|
|
216
|
+
}
|
|
217
|
+
break
|
|
218
|
+
case 'clawback': {
|
|
219
|
+
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']) && !matchEventTopicsShape(topics, ['address', 'str?']))
|
|
220
|
+
return //throw new Error('Non-standard event')
|
|
221
|
+
const from = xdrParseScVal(topics[topics[2]?._arm === 'address' ? 2 : 1])
|
|
222
|
+
const amount = processEventBodyValue(body.data())
|
|
223
|
+
if (validateAmount(amount, false) === null)
|
|
224
|
+
return null
|
|
225
|
+
const asset = this.getAssetFromEventTopics(topics, contract)
|
|
226
|
+
if (StrKey.isValidContract(from)) { //transfer tokens from account only in case of contract assets to avoid double debits
|
|
227
|
+
this.effectsAnalyzer.debit(amount, asset, from)
|
|
228
|
+
this.effectsAnalyzer.burn(asset, amount)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
break
|
|
232
|
+
case 'set_admin': {
|
|
233
|
+
if (!matchEventTopicsShape(topics, ['address', 'str?']))
|
|
234
|
+
return //throw new Error('Non-standard event')
|
|
235
|
+
const currentAdmin = xdrParseScVal(topics[1])
|
|
236
|
+
const newAdmin = processEventBodyValue(body.data())
|
|
237
|
+
this.getAssetFromEventTopics(topics, contract)
|
|
238
|
+
this.effectsAnalyzer.setAdmin(contract, newAdmin)
|
|
239
|
+
}
|
|
240
|
+
break
|
|
241
|
+
case 'set_authorized': {
|
|
242
|
+
if (!matchEventTopicsShape(topics, ['address', 'str?']))
|
|
243
|
+
return //throw new Error('Non-standard event')
|
|
244
|
+
const trustor = xdrParseScVal(topics[1])
|
|
245
|
+
const asset = this.getAssetFromEventTopics(topics, contract)
|
|
246
|
+
const isAuthorized = processEventBodyValue(body.data())
|
|
247
|
+
this.effectsAnalyzer.addEffect({
|
|
248
|
+
type: effectTypes.trustlineAuthorizationUpdated,
|
|
249
|
+
trustor,
|
|
250
|
+
asset,
|
|
251
|
+
flags: isAuthorized ? 1 : 0,
|
|
252
|
+
prevFlags: isAuthorized ? 0 : 1
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
break
|
|
256
|
+
//TODO: think about processing these effects
|
|
257
|
+
/*case 'approve': {
|
|
258
|
+
if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
|
|
259
|
+
throw new Error('Non-standard event')
|
|
260
|
+
const from = xdrParseScVal(topics[1])
|
|
261
|
+
const spender = xdrParseScVal(topics[2])
|
|
262
|
+
if (topics.length > 3) {
|
|
263
|
+
mapSacContract(this.effectsAnalyzer, contractId, xdrParseAsset(xdrParseScVal(topics[3])))
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
break*/
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {ScVal[]} topics
|
|
272
|
+
* @param {string} contract
|
|
273
|
+
* @return {string|null}
|
|
274
|
+
* @private
|
|
275
|
+
*/
|
|
276
|
+
getAssetFromEventTopics(topics, contract) {
|
|
277
|
+
const last = topics[topics.length - 1]
|
|
278
|
+
if (last._arm === 'str') {
|
|
279
|
+
const classicAsset = xdrParseAsset(xdrParseScVal(last))
|
|
280
|
+
mapSacContract(this.effectsAnalyzer, contract, classicAsset)
|
|
281
|
+
}
|
|
282
|
+
return this.effectsAnalyzer.resolveAsset(contract)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Compare types in the topics array with expected values
|
|
288
|
+
* @param {ScVal[]} topics
|
|
289
|
+
* @param {string[]} shape
|
|
290
|
+
* @return {boolean}
|
|
291
|
+
*/
|
|
292
|
+
function matchEventTopicsShape(topics, shape) {
|
|
293
|
+
if (topics.length > shape.length + 1)
|
|
294
|
+
return false
|
|
295
|
+
//we ignore the first topic because it's an event name
|
|
296
|
+
for (let i = 0; i < shape.length; i++) {
|
|
297
|
+
let match = shape[i]
|
|
298
|
+
let optional = false
|
|
299
|
+
if (match.endsWith('?')) {
|
|
300
|
+
match = match.substring(0, match.length - 1)
|
|
301
|
+
optional = true
|
|
302
|
+
}
|
|
303
|
+
const topic = topics[i + 1]
|
|
304
|
+
if (topic) {
|
|
305
|
+
if (topic._arm !== match)
|
|
306
|
+
return false
|
|
307
|
+
} else if (!optional)
|
|
308
|
+
return false
|
|
309
|
+
}
|
|
310
|
+
return true
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Retrieve event body value
|
|
315
|
+
* @param value
|
|
316
|
+
*/
|
|
317
|
+
function processEventBodyValue(value) {
|
|
318
|
+
const innerValue = value.value()
|
|
319
|
+
if (innerValue === undefined) //scVoid
|
|
320
|
+
return null
|
|
321
|
+
return xdrParseScVal(value) //other scValue
|
|
322
|
+
}
|
|
323
|
+
|
|
302
324
|
module.exports = EventsAnalyzer
|