@stellar-expert/tx-meta-effects-parser 6.4.0 → 7.0.0-rc.10
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 +2 -2
- package/src/aggregation/events-analyzer.js +46 -49
- package/src/aggregation/sac-contract-mapper.js +9 -5
- package/src/effect-types.js +3 -0
- package/src/effects-analyzer.js +50 -24
- package/src/index.js +16 -3
- package/src/parser/ledger-entry-changes-parser.js +16 -2
- package/src/parser/tx-meta-changes-parser.js +1 -0
- package/src/parser/tx-xdr-parser-utils.js +24 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stellar-expert/tx-meta-effects-parser",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-rc.10",
|
|
4
4
|
"description": "Low-level effects parser for Stellar transaction results and meta XDR",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"author": "team@stellar.expert",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"peerDependencies": {
|
|
12
|
-
"@stellar/stellar-base": "^
|
|
12
|
+
"@stellar/stellar-base": "^14.0.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@babel/core": "^7.22.9",
|
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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 (
|
|
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 (
|
|
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 '
|
|
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,24 +294,14 @@ function matchEventTopicsShape(topics, shape) {
|
|
|
287
294
|
return true
|
|
288
295
|
}
|
|
289
296
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
return
|
|
304
|
+
return null
|
|
308
305
|
return xdrParseScVal(value) //other scValue
|
|
309
306
|
}
|
|
310
307
|
|
|
@@ -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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
contractAddress
|
|
31
|
-
|
|
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) {
|
package/src/effect-types.js
CHANGED
|
@@ -82,9 +82,11 @@ const effectTypes = {
|
|
|
82
82
|
|
|
83
83
|
contractCodeUploaded: 'contractCodeUploaded',
|
|
84
84
|
contractCodeRemoved: 'contractCodeRemoved',
|
|
85
|
+
contractCodeRestored: 'contractCodeRestored',
|
|
85
86
|
|
|
86
87
|
contractCreated: 'contractCreated',
|
|
87
88
|
contractUpdated: 'contractUpdated',
|
|
89
|
+
contractRestored: 'contractRestored',
|
|
88
90
|
|
|
89
91
|
contractInvoked: 'contractInvoked',
|
|
90
92
|
contractError: 'contractError',
|
|
@@ -92,6 +94,7 @@ const effectTypes = {
|
|
|
92
94
|
contractDataCreated: 'contractDataCreated',
|
|
93
95
|
contractDataUpdated: 'contractDataUpdated',
|
|
94
96
|
contractDataRemoved: 'contractDataRemoved',
|
|
97
|
+
contractDataRestored: 'contractDataRestored',
|
|
95
98
|
|
|
96
99
|
contractEvent: 'contractEvent',
|
|
97
100
|
contractMetrics: 'contractMetrics',
|
package/src/effects-analyzer.js
CHANGED
|
@@ -2,13 +2,13 @@ const {StrKey, hash, xdr, nativeToScVal} = require('@stellar/stellar-base')
|
|
|
2
2
|
const effectTypes = require('./effect-types')
|
|
3
3
|
const {parseLedgerEntryChanges} = require('./parser/ledger-entry-changes-parser')
|
|
4
4
|
const {xdrParseAsset, xdrParseAccountAddress, xdrParseScVal} = require('./parser/tx-xdr-parser-utils')
|
|
5
|
-
const {analyzeSignerChanges} = require('./aggregation/signer-changes-analyzer')
|
|
6
5
|
const {contractIdFromPreimage} = require('./parser/contract-preimage-encoder')
|
|
6
|
+
const {generateContractCodeEntryHash} = require('./parser/ledger-key')
|
|
7
|
+
const {analyzeSignerChanges} = require('./aggregation/signer-changes-analyzer')
|
|
7
8
|
const EventsAnalyzer = require('./aggregation/events-analyzer')
|
|
8
9
|
const AssetSupplyAnalyzer = require('./aggregation/asset-supply-analyzer')
|
|
9
10
|
const {mapSacContract} = require('./aggregation/sac-contract-mapper')
|
|
10
11
|
const {UnexpectedTxMetaChangeError, TxMetaEffectParserError} = require('./errors')
|
|
11
|
-
const {generateContractCodeEntryHash} = require('./parser/ledger-key')
|
|
12
12
|
|
|
13
13
|
class EffectsAnalyzer {
|
|
14
14
|
constructor({
|
|
@@ -491,6 +491,7 @@ class EffectsAnalyzer {
|
|
|
491
491
|
const effect = {}
|
|
492
492
|
switch (action) {
|
|
493
493
|
case 'created':
|
|
494
|
+
case 'restored':
|
|
494
495
|
if (!after.sponsor)
|
|
495
496
|
continue
|
|
496
497
|
effect.sponsor = after.sponsor
|
|
@@ -823,13 +824,12 @@ class EffectsAnalyzer {
|
|
|
823
824
|
}
|
|
824
825
|
|
|
825
826
|
processContractChanges({action, before, after}) {
|
|
826
|
-
if (action !== 'created' && action !== 'updated')
|
|
827
|
-
throw new UnexpectedTxMetaChangeError({type: 'contract', action})
|
|
828
827
|
const {kind, owner: contract, keyHash} = after
|
|
829
828
|
let effect = {
|
|
830
829
|
type: effectTypes.contractCreated,
|
|
831
830
|
contract,
|
|
832
|
-
kind
|
|
831
|
+
kind,
|
|
832
|
+
keyHash
|
|
833
833
|
}
|
|
834
834
|
switch (kind) {
|
|
835
835
|
case 'fromAsset':
|
|
@@ -841,22 +841,30 @@ class EffectsAnalyzer {
|
|
|
841
841
|
default:
|
|
842
842
|
throw new TxMetaEffectParserError('Unexpected contract type: ' + kind)
|
|
843
843
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
effect =
|
|
853
|
-
|
|
844
|
+
switch (action) {
|
|
845
|
+
case 'created':
|
|
846
|
+
if (this.effects.some(e => e.type === effectTypes.contractCreated && e.contract === contract)) {
|
|
847
|
+
effect = undefined //skip contract creation effects processed by top-level createContract operation call
|
|
848
|
+
}
|
|
849
|
+
break
|
|
850
|
+
case 'updated':
|
|
851
|
+
effect.type = effectTypes.contractUpdated
|
|
852
|
+
effect.prevWasmHash = before.wasmHash
|
|
853
|
+
if (before.wasmHash === after.wasmHash) {//skip if hash unchanged
|
|
854
|
+
effect = undefined
|
|
855
|
+
}
|
|
856
|
+
break
|
|
857
|
+
case 'restored':
|
|
858
|
+
effect.type = effectTypes.contractRestored
|
|
859
|
+
break
|
|
860
|
+
default:
|
|
861
|
+
throw new UnexpectedTxMetaChangeError({type: 'contract', action})
|
|
854
862
|
}
|
|
855
863
|
if (effect) {
|
|
856
864
|
this.addEffect(effect, effect.type === effectTypes.contractCreated ? 0 : undefined)
|
|
857
865
|
}
|
|
858
866
|
if (before?.storage?.length || after?.storage?.length) {
|
|
859
|
-
this.processInstanceDataChanges(before, after)
|
|
867
|
+
this.processInstanceDataChanges(before, after, action === 'restored')
|
|
860
868
|
}
|
|
861
869
|
}
|
|
862
870
|
|
|
@@ -885,6 +893,10 @@ class EffectsAnalyzer {
|
|
|
885
893
|
effect.type = effectTypes.contractDataRemoved
|
|
886
894
|
effect.prevValue = before.value
|
|
887
895
|
break
|
|
896
|
+
case 'restored':
|
|
897
|
+
effect.type = effectTypes.contractDataRestored
|
|
898
|
+
effect.value = after.value
|
|
899
|
+
break
|
|
888
900
|
}
|
|
889
901
|
this.addEffect(effect)
|
|
890
902
|
this.processContractBalance(effect)
|
|
@@ -898,17 +910,23 @@ class EffectsAnalyzer {
|
|
|
898
910
|
case 'updated':
|
|
899
911
|
break //it doesn't change the state
|
|
900
912
|
case 'removed':
|
|
901
|
-
|
|
913
|
+
this.addEffect({
|
|
902
914
|
type: effectTypes.contractCodeRemoved,
|
|
903
915
|
wasmHash: hash,
|
|
904
916
|
keyHash
|
|
905
|
-
}
|
|
906
|
-
|
|
917
|
+
})
|
|
918
|
+
break
|
|
919
|
+
case 'restored':
|
|
920
|
+
this.addEffect({
|
|
921
|
+
type: effectTypes.contractCodeRestored,
|
|
922
|
+
wasmHash: hash,
|
|
923
|
+
keyHash
|
|
924
|
+
})
|
|
907
925
|
break
|
|
908
926
|
}
|
|
909
927
|
}
|
|
910
928
|
|
|
911
|
-
processInstanceDataChanges(before, after) {
|
|
929
|
+
processInstanceDataChanges(before, after, restored) {
|
|
912
930
|
const storageBefore = before?.storage || []
|
|
913
931
|
const storageAfter = [...(after?.storage || [])]
|
|
914
932
|
for (const {key, val} of storageBefore) {
|
|
@@ -948,7 +966,7 @@ class EffectsAnalyzer {
|
|
|
948
966
|
//iterate all storage items left
|
|
949
967
|
for (const {key, val} of storageAfter) {
|
|
950
968
|
const effect = {
|
|
951
|
-
type: effectTypes.contractDataCreated,
|
|
969
|
+
type: restored ? effectTypes.contractDataRestored : effectTypes.contractDataCreated,
|
|
952
970
|
owner: after?.owner || before.owner,
|
|
953
971
|
key,
|
|
954
972
|
value: val,
|
|
@@ -969,12 +987,17 @@ class EffectsAnalyzer {
|
|
|
969
987
|
ttl
|
|
970
988
|
}
|
|
971
989
|
if (stateEffect) {
|
|
972
|
-
if (stateEffect.type.
|
|
990
|
+
if (stateEffect.type.startsWith('contractCode')) {
|
|
973
991
|
effect.kind = 'contractCode'
|
|
974
|
-
} else if (stateEffect.type.
|
|
992
|
+
} else if (stateEffect.type.startsWith('contractData')) {
|
|
975
993
|
effect.kind = 'contractData'
|
|
976
994
|
effect.owner = stateEffect.owner
|
|
977
|
-
}
|
|
995
|
+
} else if (stateEffect.type.startsWith('contract')) {
|
|
996
|
+
effect.kind = 'contractData'
|
|
997
|
+
effect.owner = stateEffect.contract
|
|
998
|
+
} else
|
|
999
|
+
throw new UnexpectedTxMetaChangeError({type: 'ttl', action: stateEffect.type})
|
|
1000
|
+
stateEffect.ttl = ttl
|
|
978
1001
|
}
|
|
979
1002
|
this.addEffect(effect)
|
|
980
1003
|
}
|
|
@@ -1100,6 +1123,9 @@ function encodeSponsorshipEffectName(action, type) {
|
|
|
1100
1123
|
case 'removed':
|
|
1101
1124
|
actionKey = 'Removed'
|
|
1102
1125
|
break
|
|
1126
|
+
case 'restored':
|
|
1127
|
+
actionKey = 'Restored'
|
|
1128
|
+
break
|
|
1103
1129
|
default:
|
|
1104
1130
|
throw new UnexpectedTxMetaChangeError({action, type})
|
|
1105
1131
|
}
|
package/src/index.js
CHANGED
|
@@ -139,6 +139,8 @@ function parseTxOperationsMeta({
|
|
|
139
139
|
}
|
|
140
140
|
const metaValue = meta.value()
|
|
141
141
|
const opMeta = metaValue.operations()
|
|
142
|
+
const isV4Meta = meta.arm() === 'v4'
|
|
143
|
+
let txEvents = isV4Meta ? metaValue.events() : undefined
|
|
142
144
|
|
|
143
145
|
//analyze operation effects for each operation
|
|
144
146
|
for (let i = 0; i < parsedTx.operations.length; i++) {
|
|
@@ -155,12 +157,23 @@ function parseTxOperationsMeta({
|
|
|
155
157
|
const isSorobanInvocation = operation.type === 'invokeHostFunction'
|
|
156
158
|
//only for Soroban contract invocation
|
|
157
159
|
if (isSorobanInvocation) {
|
|
158
|
-
const sorobanMeta = metaValue._attributes
|
|
160
|
+
const {sorobanMeta} = metaValue._attributes
|
|
159
161
|
if (sorobanMeta) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
+
if (sorobanMeta.events) {
|
|
163
|
+
params.events = sorobanMeta.events()
|
|
164
|
+
}
|
|
165
|
+
if (sorobanMeta.diagnosticEvents) {
|
|
166
|
+
params.diagnosticEvents = sorobanMeta.diagnosticEvents()
|
|
167
|
+
}
|
|
162
168
|
params.processSystemEvents = processSystemEvents
|
|
163
169
|
}
|
|
170
|
+
if (isV4Meta) {
|
|
171
|
+
params.diagnosticEvents = metaValue.diagnosticEvents()
|
|
172
|
+
const invocationOp = metaValue.operations()[0]
|
|
173
|
+
if (invocationOp) {
|
|
174
|
+
params.events = invocationOp.events()
|
|
175
|
+
}
|
|
176
|
+
}
|
|
164
177
|
params.mapSac = mapSac
|
|
165
178
|
}
|
|
166
179
|
const analyzer = new EffectsAnalyzer(params)
|
|
@@ -6,7 +6,7 @@ const {generateContractStateEntryHash, generateContractCodeEntryHash} = require(
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {{}} ParsedLedgerEntryMeta
|
|
8
8
|
* @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'|'ttl'} type - Ledger entry type
|
|
9
|
-
* @property {'created'|'updated'|'removed'} action - Ledger modification action
|
|
9
|
+
* @property {'created'|'updated'|'removed'|'restored'} action - Ledger modification action
|
|
10
10
|
* @property {{}} before - Ledger entry state before changes applied
|
|
11
11
|
* @property {{}} after - Ledger entry state after changes application
|
|
12
12
|
*/
|
|
@@ -18,14 +18,15 @@ const {generateContractStateEntryHash, generateContractCodeEntryHash} = require(
|
|
|
18
18
|
function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
19
19
|
const changes = []
|
|
20
20
|
let state
|
|
21
|
+
let containsTtl = false
|
|
21
22
|
for (let i = 0; i < ledgerEntryChanges.length; i++) {
|
|
22
23
|
const entry = ledgerEntryChanges[i]
|
|
23
24
|
const action = entry._arm
|
|
24
25
|
const stateData = parseEntry(entry, action)
|
|
25
26
|
if (stateData === undefined)
|
|
26
27
|
continue
|
|
27
|
-
const change = {action}
|
|
28
28
|
const type = entry._value._arm
|
|
29
|
+
const change = {action, type}
|
|
29
30
|
switch (action) {
|
|
30
31
|
case 'state':
|
|
31
32
|
state = stateData
|
|
@@ -44,6 +45,11 @@ function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
|
44
45
|
change.after = stateData
|
|
45
46
|
change.type = stateData.entry
|
|
46
47
|
break
|
|
48
|
+
case 'restored':
|
|
49
|
+
change.before = state
|
|
50
|
+
change.after = stateData
|
|
51
|
+
change.type = stateData.entry
|
|
52
|
+
break
|
|
47
53
|
case 'removed':
|
|
48
54
|
if (!state && type === 'ttl')
|
|
49
55
|
continue //skip expiration processing for now
|
|
@@ -54,9 +60,17 @@ function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
|
54
60
|
default:
|
|
55
61
|
throw new TxMetaEffectParserError(`Unknown change entry type: ${action}`)
|
|
56
62
|
}
|
|
63
|
+
if (change.type === 'ttl') {
|
|
64
|
+
containsTtl = true
|
|
65
|
+
}
|
|
57
66
|
changes.push(change)
|
|
58
67
|
state = null
|
|
59
68
|
}
|
|
69
|
+
if (containsTtl) { //put ttl entries into the end of array
|
|
70
|
+
changes.sort((a, b) =>
|
|
71
|
+
a.type !== 'ttl' && b.type === 'ttl' ?
|
|
72
|
+
-1 : 0)
|
|
73
|
+
}
|
|
60
74
|
return changes
|
|
61
75
|
}
|
|
62
76
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {StrKey, LiquidityPoolId, scValToBigInt,
|
|
1
|
+
const {xdr, StrKey, LiquidityPoolId, Asset, scValToBigInt, encodeMuxedAccount, encodeMuxedAccountToAddress} = require('@stellar/stellar-base')
|
|
2
2
|
const {TxMetaEffectParserError} = require('../errors')
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -26,10 +26,9 @@ function toStellarAsset(assetDescriptor) {
|
|
|
26
26
|
/**
|
|
27
27
|
* Parse account address from XDR representation
|
|
28
28
|
* @param accountId
|
|
29
|
-
* @
|
|
30
|
-
* @return {String|{muxedId: String, primary: String}}
|
|
29
|
+
* @return {String}
|
|
31
30
|
*/
|
|
32
|
-
function xdrParseAccountAddress(accountId
|
|
31
|
+
function xdrParseAccountAddress(accountId) {
|
|
33
32
|
if (!accountId)
|
|
34
33
|
return undefined
|
|
35
34
|
if (accountId.arm) {
|
|
@@ -37,8 +36,6 @@ function xdrParseAccountAddress(accountId, muxedAccountsSupported = false) {
|
|
|
37
36
|
case 'ed25519':
|
|
38
37
|
return StrKey.encodeEd25519PublicKey(accountId.ed25519())
|
|
39
38
|
case 'med25519':
|
|
40
|
-
if (!muxedAccountsSupported)
|
|
41
|
-
throw new TxMetaEffectParserError(`Muxed accounts not supported here`)
|
|
42
39
|
return {
|
|
43
40
|
primary: StrKey.encodeEd25519PublicKey(accountId.value().ed25519()),
|
|
44
41
|
muxedId: accountId.value().id().toString()
|
|
@@ -53,6 +50,17 @@ function xdrParseAccountAddress(accountId, muxedAccountsSupported = false) {
|
|
|
53
50
|
throw new TypeError(`Failed to identify and parse account address: ${accountId}`)
|
|
54
51
|
}
|
|
55
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Parse muxed account address from ScAddress XDR representation
|
|
55
|
+
* @param {{}} value
|
|
56
|
+
* @return {string}
|
|
57
|
+
*/
|
|
58
|
+
function xdrParseMuxedScAddress(value) {
|
|
59
|
+
const {ed25519, id} = value._attributes
|
|
60
|
+
const muxed = encodeMuxedAccount(StrKey.encodeEd25519PublicKey(ed25519), id._value.toString())
|
|
61
|
+
return encodeMuxedAccountToAddress(muxed)
|
|
62
|
+
}
|
|
63
|
+
|
|
56
64
|
/**
|
|
57
65
|
* Parse Contract ID from raw bytes
|
|
58
66
|
* @param {Buffer} rawContractId
|
|
@@ -257,11 +265,15 @@ function xdrParseScVal(value, treatBytesAsContractId = false) {
|
|
|
257
265
|
case 'duration':
|
|
258
266
|
return scValToBigInt(value).toString()
|
|
259
267
|
case 'address':
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
268
|
+
switch (value._value._arm) {
|
|
269
|
+
case 'accountId':
|
|
270
|
+
return xdrParseAccountAddress(value._value.value())
|
|
271
|
+
case 'contractId':
|
|
272
|
+
return xdrParseContractAddress(value._value.value())
|
|
273
|
+
case 'muxedAccount':
|
|
274
|
+
return xdrParseMuxedScAddress(value._value.value())
|
|
275
|
+
}
|
|
276
|
+
throw new TxMetaEffectParserError('Not supported XDR primitive type: ' + value._value._arm.toString())
|
|
265
277
|
case 'bytes':
|
|
266
278
|
return treatBytesAsContractId ? xdrParseContractAddress(value.value()) : value._value.toString('base64')
|
|
267
279
|
case 'i32':
|
|
@@ -298,6 +310,7 @@ module.exports = {
|
|
|
298
310
|
xdrParseAsset,
|
|
299
311
|
xdrParseAccountAddress,
|
|
300
312
|
xdrParseContractAddress,
|
|
313
|
+
xdrParseMuxedScAddress,
|
|
301
314
|
xdrParseClaimant,
|
|
302
315
|
xdrParseClaimedOffer,
|
|
303
316
|
xdrParseTradeAtom,
|