@stellar-expert/tx-meta-effects-parser 5.5.3 → 5.6.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellar-expert/tx-meta-effects-parser",
3
- "version": "5.5.3",
3
+ "version": "5.6.0",
4
4
  "description": "Low-level effects parser for Stellar transaction results and meta XDR",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -1,7 +1,6 @@
1
1
  const {StrKey} = require('@stellar/stellar-base')
2
2
  const effectTypes = require('../effect-types')
3
3
  const {xdrParseScVal, xdrParseAsset, isContractAddress} = require('../parser/tx-xdr-parser-utils')
4
- const {contractIdFromPreimage} = require('../parser/contract-preimage-encoder')
5
4
  const {mapSacContract} = require('./sac-contract-mapper')
6
5
 
7
6
  const EVENT_TYPES = {
@@ -65,7 +64,7 @@ class EventsAnalyzer {
65
64
  const {diagnosticEvents, processSystemEvents} = this.effectsAnalyzer
66
65
  if (!diagnosticEvents)
67
66
  return
68
- const opContractId = retrieveOpContractId(this.effectsAnalyzer.operation, this.effectsAnalyzer.network)
67
+ const opContractId = this.effectsAnalyzer.retrieveOpContractId()
69
68
  //diagnostic events
70
69
  for (const evt of diagnosticEvents) {
71
70
  if (!processSystemEvents && !evt.inSuccessfulContractCall())
@@ -156,30 +155,27 @@ class EventsAnalyzer {
156
155
  classicAsset = null //not an SAC event
157
156
  }
158
157
  }
159
- if (classicAsset && (classicAsset.includes(from) || classicAsset.includes(to))) { //SAC transfer by asset issuer
160
- if (classicAsset.includes(from)) {
161
- this.effectsAnalyzer.mint(contract, amount)
162
- this.effectsAnalyzer.credit(amount, isContractAddress(to) ? contract : classicAsset, to)
163
- }
164
- if (classicAsset.includes(to)) {
165
- this.effectsAnalyzer.debit(amount, isContractAddress(from) ? contract : classicAsset, from)
166
- this.effectsAnalyzer.burn(contract, amount)
158
+ if (classicAsset) {
159
+ if (classicAsset.includes(from)) { //SAC transfer by asset issuer
160
+ this.effectsAnalyzer.mint(classicAsset, amount)
161
+ this.effectsAnalyzer.credit(amount, classicAsset, to)
162
+ return
167
163
  }
168
- } else { //other cases
169
- if (classicAsset && !isContractAddress(from)) { //classic asset bridged to Soroban
164
+ if (classicAsset.includes(to)) { //SAC transfer by asset issuer
165
+ this.effectsAnalyzer.debit(amount, classicAsset, from)
170
166
  this.effectsAnalyzer.burn(classicAsset, amount)
171
- this.effectsAnalyzer.mint(contract, amount)
172
- } else {
173
- this.effectsAnalyzer.debit(amount, contract, from)
167
+ return
174
168
  }
175
- if (classicAsset && !isContractAddress(to)) { //classic asset bridged from Soroban
176
- this.effectsAnalyzer.burn(contract, amount)
177
- this.effectsAnalyzer.mint(classicAsset, amount)
178
- } else {
179
- this.effectsAnalyzer.credit(amount, contract, to)
169
+ if (isContractAddress(from)) {
170
+ this.effectsAnalyzer.debit(amount, classicAsset, from)
171
+ }
172
+ if (isContractAddress(to)) {
173
+ this.effectsAnalyzer.credit(amount, classicAsset, to)
180
174
  }
175
+ } else { //other cases
176
+ this.effectsAnalyzer.debit(amount, this.effectsAnalyzer.resolveAsset(contract), from)
177
+ this.effectsAnalyzer.credit(amount, this.effectsAnalyzer.resolveAsset(contract), to)
181
178
  }
182
-
183
179
  }
184
180
  break
185
181
  case 'mint': {
@@ -189,15 +185,14 @@ class EventsAnalyzer {
189
185
  const amount = processEventBodyValue(body.data())
190
186
  if (!this.matchInvocationEffect(e => e.function === 'mint' && matchArrays([to, amount], e.args)))
191
187
  return
192
- this.effectsAnalyzer.addEffect({
193
- type: effectTypes.assetMinted,
194
- asset: contract,
195
- amount
196
- })
197
- this.effectsAnalyzer.credit(amount, contract, to)
198
188
  if (topics.length > 3) {
199
189
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[3])))
200
190
  }
191
+ const asset = this.effectsAnalyzer.resolveAsset(contract)
192
+ this.effectsAnalyzer.mint(asset, amount)
193
+ if (isContractAddress(asset)) {
194
+ this.effectsAnalyzer.credit(amount, asset, to)
195
+ }
201
196
  }
202
197
  break
203
198
  case 'burn': {
@@ -210,12 +205,14 @@ class EventsAnalyzer {
210
205
  (e.function === 'burn_from' && matchArrays([undefined, from, amount], e.args))
211
206
  ))
212
207
  return
213
-
214
- this.effectsAnalyzer.debit(amount, contract, from)
215
- this.effectsAnalyzer.burn(contract, amount)
216
208
  if (topics.length > 2) {
217
209
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[2])))
218
210
  }
211
+ const asset = this.effectsAnalyzer.resolveAsset(contract)
212
+ if (isContractAddress(asset)) {
213
+ this.effectsAnalyzer.debit(amount, asset, from)
214
+ }
215
+ this.effectsAnalyzer.burn(asset, amount)
219
216
  }
220
217
  break
221
218
  case 'clawback': {
@@ -225,11 +222,14 @@ class EventsAnalyzer {
225
222
  const amount = processEventBodyValue(body.data())
226
223
  if (!this.matchInvocationEffect(e => e.function === 'clawback' && matchArrays([from, amount], e.args)))
227
224
  return
228
- this.effectsAnalyzer.debit(amount, contract, from)
229
- this.effectsAnalyzer.burn(contract, amount)
230
225
  if (topics.length > 3) {
231
226
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[3])))
232
227
  }
228
+ const asset = this.effectsAnalyzer.resolveAsset(contract)
229
+ if (isContractAddress(asset)) {
230
+ this.effectsAnalyzer.debit(amount, asset, from)
231
+ }
232
+ this.effectsAnalyzer.burn(asset, amount)
233
233
  }
234
234
  break
235
235
  case 'set_admin': {
@@ -239,10 +239,10 @@ class EventsAnalyzer {
239
239
  const newAdmin = processEventBodyValue(body.data())
240
240
  if (!this.matchInvocationEffect(e => e.function === 'set_admin' && matchArrays([currentAdmin, newAdmin], [this.effectsAnalyzer.source, e.args])))
241
241
  return
242
- this.effectsAnalyzer.setAdmin(contract, newAdmin)
243
242
  if (topics.length > 2) {
244
243
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[2])))
245
244
  }
245
+ this.effectsAnalyzer.setAdmin(contract, newAdmin)
246
246
  }
247
247
  break
248
248
  /*case 'approve': { //TODO: think about processing this effect
@@ -305,18 +305,4 @@ function processEventBodyValue(value) {
305
305
  return xdrParseScVal(value) //other scValue
306
306
  }
307
307
 
308
- function retrieveOpContractId(operation, network) {
309
- const funcValue = operation.func._value._attributes
310
- if (!funcValue)
311
- return null //WASM upload
312
- let address = funcValue.contractAddress?._value
313
- if (!address) {
314
- const preimage = funcValue.contractIdPreimage
315
- if (preimage) {
316
- address = contractIdFromPreimage(preimage, network)
317
- }
318
- }
319
- return address
320
- }
321
-
322
308
  module.exports = EventsAnalyzer
@@ -15,14 +15,22 @@ function mapSacContract(effectsAnalyzer, contractAddress, classicAsset) {
15
15
  if (!classicAsset)
16
16
  return false
17
17
  const {network, sacMap} = effectsAnalyzer
18
+ if (!sacMap)
19
+ return false
20
+ const prevMapping = sacMap[contractAddress]
21
+ if (prevMapping) {
22
+ return prevMapping === classicAsset
23
+ }
18
24
  //try to load from cache first
19
- const fromCache = sacCache.get(contractAddress + network)
25
+ const fromCache = sacCache.get(classicAsset + network)
20
26
  if (!fromCache) {
21
27
  const encodedContract = contractIdFromAsset(toStellarAsset(classicAsset), network)
22
- sacCache.set(encodedContract + network, classicAsset)
23
- if (encodedContract !== contractAddress)
28
+ sacCache.set(classicAsset + network, contractAddress)
29
+ if (contractAddress === undefined) {
30
+ contractAddress = encodedContract
31
+ } else if (encodedContract !== contractAddress)
24
32
  return false
25
- } else if (classicAsset !== fromCache)
33
+ } else if (contractAddress !== fromCache)
26
34
  return false //check whether validated contract from cache matches the asset
27
35
  if (sacMap) {
28
36
  sacMap[contractAddress] = classicAsset
@@ -7,6 +7,7 @@ const {contractIdFromPreimage} = require('./parser/contract-preimage-encoder')
7
7
  const EventsAnalyzer = require('./aggregation/events-analyzer')
8
8
  const AssetSupplyAnalyzer = require('./aggregation/asset-supply-analyzer')
9
9
  const {UnexpectedTxMetaChangeError, TxMetaEffectParserError} = require('./errors')
10
+ const {mapSacContract} = require('./aggregation/sac-contract-mapper')
10
11
 
11
12
  class EffectsAnalyzer {
12
13
  constructor({operation, meta, result, network, events, diagnosticEvents, mapSac, processSystemEvents}) {
@@ -194,8 +195,7 @@ class EffectsAnalyzer {
194
195
  refundable: parseLargeInt(attrs.totalRefundableResourceFeeCharged),
195
196
  rent: parseLargeInt(attrs.rentFeeCharged)
196
197
  }
197
- const contract = StrKey.encodeContract(this.operation.func._value.contractAddress()._value)
198
- this.addMetric(contract, 'fee', fee)
198
+ this.addMetric(this.retrieveOpContractId(), 'fee', fee)
199
199
  }
200
200
  }
201
201
 
@@ -572,6 +572,9 @@ class EffectsAnalyzer {
572
572
  }
573
573
 
574
574
  processBalanceChange(account, asset, beforeBalance, afterBalance) {
575
+ if (this.isContractCall) { //map contract=>asset proactively
576
+ mapSacContract(this, undefined, asset)
577
+ }
575
578
  const balanceChange = BigInt(afterBalance) - BigInt(beforeBalance)
576
579
  if (balanceChange < 0n) {
577
580
  this.debit((-balanceChange).toString(), asset, account, afterBalance)
@@ -911,6 +914,25 @@ class EffectsAnalyzer {
911
914
  throw new UnexpectedTxMetaChangeError(change)
912
915
  }
913
916
  }
917
+
918
+ retrieveOpContractId() {
919
+ const funcValue = this.operation.func._value._attributes
920
+ if (funcValue) {
921
+ if (funcValue.contractAddress)
922
+ return StrKey.encodeContract(funcValue.contractAddress._value)
923
+ const preimage = funcValue.contractIdPreimage
924
+ if (preimage)
925
+ return contractIdFromPreimage(preimage, this.network)
926
+ }
927
+ return null
928
+ }
929
+
930
+ resolveAsset(assetOrContract) {
931
+ if (!assetOrContract.startsWith('C') || !this.sacMap)
932
+ return assetOrContract
933
+ //try to resolve using SAC map
934
+ return this.sacMap[assetOrContract] || assetOrContract
935
+ }
914
936
  }
915
937
 
916
938
  /**