@stellar-expert/tx-meta-effects-parser 7.0.0-rc.7 → 7.0.0-rc.9

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": "7.0.0-rc.7",
3
+ "version": "7.0.0-rc.9",
4
4
  "description": "Low-level effects parser for Stellar transaction results and meta XDR",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -1,4 +1,4 @@
1
- const {StrKey} = require('@stellar/stellar-base')
1
+ const {StrKey, encodeMuxedAccount, encodeMuxedAccountToAddress} = require('@stellar/stellar-base')
2
2
  const effectTypes = require('../effect-types')
3
3
  const {xdrParseScVal, xdrParseAsset, isContractAddress} = require('../parser/tx-xdr-parser-utils')
4
4
  const {mapSacContract} = require('./sac-contract-mapper')
@@ -146,15 +146,19 @@ class EventsAnalyzer {
146
146
  if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
147
147
  return
148
148
  const from = xdrParseScVal(topics[1])
149
- const to = xdrParseScVal(topics[2])
149
+ const receiver = xdrParseScVal(topics[2])
150
+ let to = receiver
151
+ let amount = processEventBodyValue(body.data())
152
+ if (amount?.amount !== undefined) {
153
+ if (amount.to_muxed_id && !to.startsWith('M')) {
154
+ to = encodeMuxedAccountToAddress(encodeMuxedAccount(to, amount.to_muxed_id))
155
+ amount = amount.amount
156
+ }
157
+ }
158
+ if (typeof amount!=='string')
159
+ return null
150
160
  if (to === from) //self transfer - nothing happens
151
161
  return // TODO: need additional checks
152
- const amount = processEventBodyValue(body.data())
153
- if (!this.matchInvocationEffect(e =>
154
- (e.function === 'transfer' && matchArrays([from, to, amount], e.args)) ||
155
- (e.function === 'transfer_from' && matchArrays([undefined, from, to, amount], e.args))
156
- ))
157
- return
158
162
  let classicAsset
159
163
  if (topics.length > 3) {
160
164
  classicAsset = xdrParseAsset(xdrParseScVal(topics[3]))
@@ -172,7 +176,7 @@ class EventsAnalyzer {
172
176
  if (isContractAddress(to)) {
173
177
  this.effectsAnalyzer.credit(amount, classicAsset, to)
174
178
  }
175
- if (classicAsset.includes(to)) { //SAC transfer by asset issuer
179
+ if (classicAsset.includes(receiver)) { //SAC transfer by asset issuer
176
180
  this.effectsAnalyzer.burn(classicAsset, amount)
177
181
  }
178
182
  } else { //other cases
@@ -182,14 +186,21 @@ class EventsAnalyzer {
182
186
  }
183
187
  break
184
188
  case 'mint': {
185
- if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
189
+ if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']) && !matchEventTopicsShape(topics, ['address', 'str?']))
186
190
  return //throw new Error('Non-standard event')
187
- const to = xdrParseScVal(topics[2])
188
- const amount = processEventBodyValue(body.data())
189
- if (!this.matchInvocationEffect(e => e.function === 'mint' && matchArrays([to, amount], e.args)))
190
- return
191
- if (topics.length > 3) {
192
- mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[3])))
191
+ let to = xdrParseScVal(topics[topics[2]?._arm === 'address' ? 2 : 1])
192
+ let amount = processEventBodyValue(body.data())
193
+ if (amount?.amount !== undefined) {
194
+ if (amount.to_muxed_id && !to.startsWith('M')) {
195
+ to = encodeMuxedAccountToAddress(encodeMuxedAccount(to, amount.to_muxed_id))
196
+ amount = amount.amount
197
+ }
198
+ }
199
+ if (typeof amount !== 'string')
200
+ return null
201
+ const last = topics[topics.length - 1]
202
+ if (last._arm === 'str') {
203
+ mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(last)))
193
204
  }
194
205
  const asset = this.effectsAnalyzer.resolveAsset(contract)
195
206
  this.effectsAnalyzer.mint(asset, amount)
@@ -203,13 +214,8 @@ class EventsAnalyzer {
203
214
  return //throw new Error('Non-standard event')
204
215
  const from = xdrParseScVal(topics[1])
205
216
  const amount = processEventBodyValue(body.data())
206
- if (!amount)
207
- return
208
- if (!this.matchInvocationEffect(e =>
209
- (e.function === 'burn' && matchArrays([from, amount], e.args)) ||
210
- (e.function === 'burn_from' && matchArrays([undefined, from, amount], e.args))
211
- ))
212
- return
217
+ if (typeof amount !== 'string')
218
+ return null
213
219
  if (topics.length > 2) {
214
220
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[2])))
215
221
  }
@@ -221,12 +227,12 @@ class EventsAnalyzer {
221
227
  }
222
228
  break
223
229
  case 'clawback': {
224
- if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
230
+ if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']) && !matchEventTopicsShape(topics, ['address', 'str?']))
225
231
  return //throw new Error('Non-standard event')
226
- const from = xdrParseScVal(topics[2])
232
+ const from = xdrParseScVal(topics[topics[2]?._arm === 'address' ? 2 : 1])
227
233
  const amount = processEventBodyValue(body.data())
228
- if (!this.matchInvocationEffect(e => e.function === 'clawback' && matchArrays([from, amount], e.args)))
229
- return
234
+ if (typeof amount !== 'string')
235
+ return null
230
236
  if (topics.length > 3) {
231
237
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[3])))
232
238
  }
@@ -240,15 +246,14 @@ class EventsAnalyzer {
240
246
  return //throw new Error('Non-standard event')
241
247
  const currentAdmin = xdrParseScVal(topics[1])
242
248
  const newAdmin = processEventBodyValue(body.data())
243
- if (!this.matchInvocationEffect(e => e.function === 'set_admin' && matchArrays([currentAdmin, newAdmin], [this.effectsAnalyzer.source, e.args])))
244
- return
245
249
  if (topics.length > 2) {
246
250
  mapSacContract(this.effectsAnalyzer, contract, xdrParseAsset(xdrParseScVal(topics[2])))
247
251
  }
248
252
  this.effectsAnalyzer.setAdmin(contract, newAdmin)
249
253
  }
250
254
  break
251
- /*case 'approve': { //TODO: think about processing this effect
255
+ /*case 'set_authorized':*/ //TODO: think about processing this effects
256
+ /*case 'approve': {
252
257
  if (!matchEventTopicsShape(topics, ['address', 'address', 'str?']))
253
258
  throw new Error('Non-standard event')
254
259
  const from = xdrParseScVal(topics[1])
@@ -260,12 +265,14 @@ class EventsAnalyzer {
260
265
  break*/
261
266
  }
262
267
  }
263
-
264
- matchInvocationEffect(cb) {
265
- return this.effectsAnalyzer.effects.find(e => e.type === effectTypes.contractInvoked && cb(e))
266
- }
267
268
  }
268
269
 
270
+ /**
271
+ * Compare types in the topics array with expected values
272
+ * @param {ScVal[]} topics
273
+ * @param {string[]} shape
274
+ * @return {boolean}
275
+ */
269
276
  function matchEventTopicsShape(topics, shape) {
270
277
  if (topics.length > shape.length + 1)
271
278
  return false
@@ -287,22 +294,12 @@ function matchEventTopicsShape(topics, shape) {
287
294
  return true
288
295
  }
289
296
 
290
- function matchArrays(a, b) {
291
- if (!a || !b)
292
- return false
293
- if (a.length !== b.length)
294
- return false
295
- for (let i = a.length; i--;) {
296
- if (a[i] !== undefined && a[i] !== b[i]) //undefined serves as * substitution
297
- return false
298
- }
299
- return true
300
- }
301
-
297
+ /**
298
+ * Retrieve event body value
299
+ * @param value
300
+ */
302
301
  function processEventBodyValue(value) {
303
302
  const innerValue = value.value()
304
- /*if (innerValue instanceof Array) //handle simple JS arrays
305
- return innerValue.map(xdrParseScVal)*/
306
303
  if (!innerValue) //scVoid
307
304
  return null
308
305
  return xdrParseScVal(value) //other scValue
@@ -24,12 +24,16 @@ function mapSacContract(effectsAnalyzer, contractAddress, classicAsset) {
24
24
  //try to load from cache first
25
25
  const fromCache = sacCache.get(classicAsset + network)
26
26
  if (!fromCache) {
27
- const encodedContract = contractIdFromAsset(toStellarAsset(classicAsset), network)
28
- sacCache.set(classicAsset + network, contractAddress)
29
- if (contractAddress === undefined) {
30
- contractAddress = encodedContract
31
- } else if (encodedContract !== contractAddress)
27
+ try {
28
+ const encodedContract = contractIdFromAsset(toStellarAsset(classicAsset), network)
29
+ sacCache.set(classicAsset + network, contractAddress)
30
+ if (contractAddress === undefined) {
31
+ contractAddress = encodedContract
32
+ } else if (encodedContract !== contractAddress)
33
+ return false
34
+ } catch (e) {
32
35
  return false
36
+ }
33
37
  } else if (contractAddress !== fromCache)
34
38
  return false //check whether validated contract from cache matches the asset
35
39
  if (sacMap) {