@stellar-expert/tx-meta-effects-parser 5.7.1 → 6.0.1
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 +529 -137
- package/package.json +1 -1
- package/src/effect-types.js +4 -1
- package/src/effects-analyzer.js +86 -33
- package/src/index.js +1 -1
- package/src/parser/ledger-entry-changes-parser.js +63 -51
- package/src/parser/ledger-key.js +19 -0
- package/src/parser/tx-xdr-parser-utils.js +0 -1
package/package.json
CHANGED
package/src/effect-types.js
CHANGED
|
@@ -81,6 +81,7 @@ const effectTypes = {
|
|
|
81
81
|
signerSponsorshipRemoved: 'signerSponsorshipRemoved',
|
|
82
82
|
|
|
83
83
|
contractCodeUploaded: 'contractCodeUploaded',
|
|
84
|
+
contractCodeRemoved: 'contractCodeRemoved',
|
|
84
85
|
|
|
85
86
|
contractCreated: 'contractCreated',
|
|
86
87
|
contractUpdated: 'contractUpdated',
|
|
@@ -93,7 +94,9 @@ const effectTypes = {
|
|
|
93
94
|
contractDataRemoved: 'contractDataRemoved',
|
|
94
95
|
|
|
95
96
|
contractEvent: 'contractEvent',
|
|
96
|
-
contractMetrics: 'contractMetrics'
|
|
97
|
+
contractMetrics: 'contractMetrics',
|
|
98
|
+
|
|
99
|
+
setTtl: 'setTtl'
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
module.exports = effectTypes
|
package/src/effects-analyzer.js
CHANGED
|
@@ -8,6 +8,7 @@ const EventsAnalyzer = require('./aggregation/events-analyzer')
|
|
|
8
8
|
const AssetSupplyAnalyzer = require('./aggregation/asset-supply-analyzer')
|
|
9
9
|
const {mapSacContract} = require('./aggregation/sac-contract-mapper')
|
|
10
10
|
const {UnexpectedTxMetaChangeError, TxMetaEffectParserError} = require('./errors')
|
|
11
|
+
const {generateContractCodeEntryHash} = require('./parser/ledger-key')
|
|
11
12
|
|
|
12
13
|
class EffectsAnalyzer {
|
|
13
14
|
constructor({operation, meta, result, network, events, diagnosticEvents, mapSac, processSystemEvents, processFailedOpEffects}) {
|
|
@@ -95,16 +96,16 @@ class EffectsAnalyzer {
|
|
|
95
96
|
if (parse) {
|
|
96
97
|
parse.call(this)
|
|
97
98
|
}
|
|
99
|
+
//process Soroban events
|
|
100
|
+
new EventsAnalyzer(this).analyze()
|
|
101
|
+
//process state data changes in the end
|
|
102
|
+
this.processStateChanges()
|
|
98
103
|
//process ledger entry changes
|
|
99
104
|
this.processChanges()
|
|
100
105
|
//handle effects that are processed indirectly
|
|
101
106
|
this.processSponsorshipEffects()
|
|
102
|
-
//process Soroban events
|
|
103
|
-
new EventsAnalyzer(this).analyze()
|
|
104
107
|
//calculate minted/burned assets
|
|
105
108
|
new AssetSupplyAnalyzer(this).analyze()
|
|
106
|
-
//process state data changes in the end
|
|
107
|
-
this.processStateChanges()
|
|
108
109
|
return this.effects
|
|
109
110
|
}
|
|
110
111
|
|
|
@@ -311,10 +312,10 @@ class EffectsAnalyzer {
|
|
|
311
312
|
|
|
312
313
|
liquidityPoolDeposit() {
|
|
313
314
|
const {liquidityPoolId} = this.operation
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
315
|
+
const poolUpdatedChanges = this.changes.find(ch => ch.type === 'liquidityPool' && ch.action === 'updated' && ch.after.pool === liquidityPoolId)
|
|
316
|
+
if (!poolUpdatedChanges) //tx failed
|
|
317
|
+
return
|
|
318
|
+
const {before, after} = poolUpdatedChanges
|
|
318
319
|
this.addEffect({
|
|
319
320
|
type: effectTypes.liquidityPoolDeposited,
|
|
320
321
|
pool: this.operation.liquidityPoolId,
|
|
@@ -358,13 +359,16 @@ class EffectsAnalyzer {
|
|
|
358
359
|
this.addEffect(effect)
|
|
359
360
|
}
|
|
360
361
|
break
|
|
361
|
-
case 'wasm':
|
|
362
|
+
case 'wasm': {
|
|
363
|
+
const codeHash = hash(value)
|
|
362
364
|
this.addEffect({
|
|
363
365
|
type: effectTypes.contractCodeUploaded,
|
|
364
366
|
wasm: value.toString('base64'),
|
|
365
|
-
wasmHash:
|
|
367
|
+
wasmHash: codeHash.toString('hex'),
|
|
368
|
+
keyHash: generateContractCodeEntryHash(codeHash)
|
|
366
369
|
})
|
|
367
370
|
break
|
|
371
|
+
}
|
|
368
372
|
case 'createContract':
|
|
369
373
|
const preimage = value.contractIdPreimage()
|
|
370
374
|
const executable = value.executable()
|
|
@@ -398,7 +402,7 @@ class EffectsAnalyzer {
|
|
|
398
402
|
default:
|
|
399
403
|
throw new TxMetaEffectParserError('Unknown contract type: ' + executableType)
|
|
400
404
|
}
|
|
401
|
-
this.addEffect(effect)
|
|
405
|
+
this.addEffect(effect, 0)
|
|
402
406
|
break
|
|
403
407
|
default:
|
|
404
408
|
throw new TxMetaEffectParserError('Unknown host function call type: ' + func.arm())
|
|
@@ -765,7 +769,7 @@ class EffectsAnalyzer {
|
|
|
765
769
|
const balanceEffects = this.effects.filter(e => (e.type === effectTypes.accountCredited || e.type === effectTypes.accountDebited) && e.source === account && e.asset === effect.owner)
|
|
766
770
|
if (balanceEffects.length !== 1) //we can set balance only when we found 1-1 mapping, if there are several balance changes, we can't establish balance relation
|
|
767
771
|
return
|
|
768
|
-
if (effect.type === effectTypes.contractDataRemoved) { //balance completely removed
|
|
772
|
+
if (effect.type === effectTypes.contractDataRemoved) { //balance completely removed - this may be a reversible operation if the balance simply expired
|
|
769
773
|
balanceEffects[0].balance = '0'
|
|
770
774
|
return
|
|
771
775
|
}
|
|
@@ -782,8 +786,8 @@ class EffectsAnalyzer {
|
|
|
782
786
|
processContractChanges({action, before, after}) {
|
|
783
787
|
if (action !== 'created' && action !== 'updated')
|
|
784
788
|
throw new UnexpectedTxMetaChangeError({type: 'contract', action})
|
|
785
|
-
const {kind, contract} = after
|
|
786
|
-
|
|
789
|
+
const {kind, owner: contract, keyHash} = after
|
|
790
|
+
let effect = {
|
|
787
791
|
type: effectTypes.contractCreated,
|
|
788
792
|
contract,
|
|
789
793
|
kind
|
|
@@ -793,33 +797,38 @@ class EffectsAnalyzer {
|
|
|
793
797
|
effect.asset = after.asset
|
|
794
798
|
break
|
|
795
799
|
case 'wasm':
|
|
796
|
-
effect.wasmHash = after.
|
|
800
|
+
effect.wasmHash = after.wasmHash
|
|
797
801
|
break
|
|
798
802
|
default:
|
|
799
803
|
throw new TxMetaEffectParserError('Unexpected contract type: ' + kind)
|
|
800
804
|
}
|
|
801
805
|
if (action === 'created') {
|
|
802
|
-
if (this.effects.some(e => e.contract === contract))
|
|
803
|
-
|
|
806
|
+
if (this.effects.some(e => e.type === effectTypes.contractCreated && e.contract === contract)) {
|
|
807
|
+
effect = undefined //skip contract creation effects processed by top-level createContract operation call
|
|
808
|
+
}
|
|
804
809
|
} else if (action === 'updated') {
|
|
805
810
|
effect.type = effectTypes.contractUpdated
|
|
806
|
-
effect.prevWasmHash = before.
|
|
807
|
-
if (before.
|
|
808
|
-
|
|
811
|
+
effect.prevWasmHash = before.wasmHash
|
|
812
|
+
if (before.wasmHash === after.wasmHash) {//skip if hash unchanged
|
|
813
|
+
effect = undefined
|
|
809
814
|
}
|
|
810
|
-
if (before.hash === after.hash) //skip if hash unchanged
|
|
811
|
-
return
|
|
812
815
|
}
|
|
813
|
-
|
|
816
|
+
if (effect) {
|
|
817
|
+
this.addEffect(effect, effect.type === effectTypes.contractCreated ? 0 : undefined)
|
|
818
|
+
}
|
|
819
|
+
if (before?.storage?.length || after?.storage?.length) {
|
|
820
|
+
this.processInstanceDataChanges(before, after)
|
|
821
|
+
}
|
|
814
822
|
}
|
|
815
823
|
|
|
816
824
|
processContractStateEntryChanges({action, before, after}) {
|
|
817
|
-
const {owner, key, durability} = after || before
|
|
825
|
+
const {owner, key, durability, keyHash} = after || before
|
|
818
826
|
const effect = {
|
|
819
827
|
type: '',
|
|
820
828
|
owner,
|
|
829
|
+
key,
|
|
821
830
|
durability,
|
|
822
|
-
|
|
831
|
+
keyHash
|
|
823
832
|
}
|
|
824
833
|
switch (action) {
|
|
825
834
|
case 'created':
|
|
@@ -842,9 +851,27 @@ class EffectsAnalyzer {
|
|
|
842
851
|
this.processContractBalance(effect)
|
|
843
852
|
}
|
|
844
853
|
|
|
854
|
+
processContractCodeChanges({type, action, before, after}) {
|
|
855
|
+
const {hash, keyHash} = after || before
|
|
856
|
+
switch (action) {
|
|
857
|
+
case 'created':
|
|
858
|
+
break //processed separately
|
|
859
|
+
case 'updated':
|
|
860
|
+
break //it doesn't change the state
|
|
861
|
+
case 'removed':
|
|
862
|
+
const effect = {
|
|
863
|
+
type: effectTypes.contractCodeRemoved,
|
|
864
|
+
wasmHash: hash,
|
|
865
|
+
keyHash
|
|
866
|
+
}
|
|
867
|
+
this.addEffect(effect)
|
|
868
|
+
break
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
845
872
|
processInstanceDataChanges(before, after) {
|
|
846
|
-
const storageBefore = before
|
|
847
|
-
const storageAfter = [...(after
|
|
873
|
+
const storageBefore = before?.storage || []
|
|
874
|
+
const storageAfter = [...(after?.storage || [])]
|
|
848
875
|
for (const {key, val} of storageBefore) {
|
|
849
876
|
let newVal
|
|
850
877
|
for (let i = 0; i < storageAfter.length; i++) {
|
|
@@ -858,7 +885,7 @@ class EffectsAnalyzer {
|
|
|
858
885
|
if (newVal === undefined) { //removed
|
|
859
886
|
const effect = {
|
|
860
887
|
type: effectTypes.contractDataRemoved,
|
|
861
|
-
owner: after
|
|
888
|
+
owner: after?.owner || before.owner,
|
|
862
889
|
key,
|
|
863
890
|
prevValue: val,
|
|
864
891
|
durability: 'instance'
|
|
@@ -871,7 +898,7 @@ class EffectsAnalyzer {
|
|
|
871
898
|
|
|
872
899
|
const effect = {
|
|
873
900
|
type: effectTypes.contractDataUpdated,
|
|
874
|
-
owner: after
|
|
901
|
+
owner: after?.owner || before.owner,
|
|
875
902
|
key,
|
|
876
903
|
value: newVal,
|
|
877
904
|
prevValue: val,
|
|
@@ -883,7 +910,7 @@ class EffectsAnalyzer {
|
|
|
883
910
|
for (const {key, val} of storageAfter) {
|
|
884
911
|
const effect = {
|
|
885
912
|
type: effectTypes.contractDataCreated,
|
|
886
|
-
owner: after
|
|
913
|
+
owner: after?.owner || before.owner,
|
|
887
914
|
key,
|
|
888
915
|
value: val,
|
|
889
916
|
durability: 'instance'
|
|
@@ -892,6 +919,27 @@ class EffectsAnalyzer {
|
|
|
892
919
|
}
|
|
893
920
|
}
|
|
894
921
|
|
|
922
|
+
processTtlChanges({action, before, after}) {
|
|
923
|
+
/*if (action === 'removed')
|
|
924
|
+
throw new UnexpectedTxMetaChangeError({type: 'ttl', action})*/
|
|
925
|
+
const {keyHash, ttl} = after || before
|
|
926
|
+
const stateEffect = this.effects.find(e => e.keyHash === keyHash && e.type !== effectTypes.setTtl)
|
|
927
|
+
const effect = {
|
|
928
|
+
type: effectTypes.setTtl,
|
|
929
|
+
keyHash,
|
|
930
|
+
ttl
|
|
931
|
+
}
|
|
932
|
+
if (stateEffect) {
|
|
933
|
+
if (stateEffect.type.includes('contractCode')) {
|
|
934
|
+
effect.kind = 'contractCode'
|
|
935
|
+
} else if (stateEffect.type.includes('contractData')) {
|
|
936
|
+
effect.kind = 'contractData'
|
|
937
|
+
effect.owner = stateEffect.owner
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
this.addEffect(effect)
|
|
941
|
+
}
|
|
942
|
+
|
|
895
943
|
processChanges() {
|
|
896
944
|
for (const change of this.changes)
|
|
897
945
|
switch (change.type) {
|
|
@@ -914,10 +962,15 @@ class EffectsAnalyzer {
|
|
|
914
962
|
this.processDataEntryChanges(change)
|
|
915
963
|
break
|
|
916
964
|
case 'contractData':
|
|
917
|
-
|
|
965
|
+
if (change.before?.kind || change.after?.kind) {
|
|
966
|
+
this.processContractChanges(change)
|
|
967
|
+
}
|
|
968
|
+
break
|
|
969
|
+
case 'contractCode':
|
|
970
|
+
this.processContractCodeChanges(change)
|
|
918
971
|
break
|
|
919
|
-
case '
|
|
920
|
-
this.
|
|
972
|
+
case 'ttl':
|
|
973
|
+
this.processTtlChanges(change)
|
|
921
974
|
break
|
|
922
975
|
default:
|
|
923
976
|
throw new UnexpectedTxMetaChangeError(change)
|
package/src/index.js
CHANGED
|
@@ -26,7 +26,7 @@ function parseTxOperationsMeta({network, tx, result, meta, mapSac = false, proce
|
|
|
26
26
|
if (!network)
|
|
27
27
|
throw new TypeError(`Network passphrase argument is required.`)
|
|
28
28
|
if (typeof network !== 'string')
|
|
29
|
-
throw new TypeError(`Invalid network passphrase
|
|
29
|
+
throw new TypeError(`Invalid network passphrase: "${network}".`)
|
|
30
30
|
if (!tx)
|
|
31
31
|
throw new TypeError(`Transaction envelope argument is required.`)
|
|
32
32
|
const isEphemeral = !meta
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const {StrKey} = require('@stellar/stellar-base')
|
|
2
|
-
const {TxMetaEffectParserError} = require('../errors')
|
|
2
|
+
const {TxMetaEffectParserError, UnexpectedTxMetaChangeError} = require('../errors')
|
|
3
3
|
const {xdrParseAsset, xdrParseAccountAddress, xdrParseClaimant, xdrParsePrice, xdrParseSignerKey} = require('./tx-xdr-parser-utils')
|
|
4
|
+
const {generateContractStateEntryHash, generateContractCodeEntryHash} = require('./ledger-key')
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {{}} ParsedLedgerEntryMeta
|
|
7
|
-
* @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'} type - Ledger entry type
|
|
8
|
+
* @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'|'ttl'} type - Ledger entry type
|
|
8
9
|
* @property {'created'|'updated'|'removed'} action - Ledger modification action
|
|
9
10
|
* @property {{}} before - Ledger entry state before changes applied
|
|
10
11
|
* @property {{}} after - Ledger entry state after changes application
|
|
@@ -19,35 +20,39 @@ function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
|
19
20
|
let state
|
|
20
21
|
for (let i = 0; i < ledgerEntryChanges.length; i++) {
|
|
21
22
|
const entry = ledgerEntryChanges[i]
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const stateData = parseEntry(entry.value(), actionType)
|
|
23
|
+
const action = entry._arm
|
|
24
|
+
const stateData = parseEntry(entry, action)
|
|
25
25
|
if (stateData === undefined)
|
|
26
26
|
continue
|
|
27
|
-
const change = {action
|
|
28
|
-
|
|
27
|
+
const change = {action}
|
|
28
|
+
const type = entry._value._arm
|
|
29
|
+
switch (action) {
|
|
29
30
|
case 'state':
|
|
30
31
|
state = stateData
|
|
31
32
|
continue
|
|
32
33
|
case 'created':
|
|
34
|
+
if (type === 'contractCode')
|
|
35
|
+
continue //processed in operation handler
|
|
33
36
|
change.before = null
|
|
34
37
|
change.after = stateData
|
|
35
38
|
change.type = stateData.entry
|
|
36
39
|
break
|
|
37
40
|
case 'updated':
|
|
41
|
+
if (type === 'contractCode')
|
|
42
|
+
throw new UnexpectedTxMetaChangeError({type, action})
|
|
38
43
|
change.before = state
|
|
39
44
|
change.after = stateData
|
|
40
45
|
change.type = stateData.entry
|
|
41
46
|
break
|
|
42
47
|
case 'removed':
|
|
43
|
-
if (!state &&
|
|
48
|
+
if (!state && type === 'ttl')
|
|
44
49
|
continue //skip expiration processing for now
|
|
45
50
|
change.before = state
|
|
46
51
|
change.after = null
|
|
47
52
|
change.type = state.entry
|
|
48
53
|
break
|
|
49
54
|
default:
|
|
50
|
-
throw new TxMetaEffectParserError(`Unknown change entry type: ${
|
|
55
|
+
throw new TxMetaEffectParserError(`Unknown change entry type: ${action}`)
|
|
51
56
|
}
|
|
52
57
|
changes.push(change)
|
|
53
58
|
state = null
|
|
@@ -57,12 +62,13 @@ function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
|
57
62
|
|
|
58
63
|
function parseEntry(entry, actionType) {
|
|
59
64
|
if (actionType === 'removed')
|
|
60
|
-
return null
|
|
61
|
-
const
|
|
65
|
+
return null
|
|
66
|
+
const value = entry.value()
|
|
67
|
+
const parsed = parseEntryData(value.data())
|
|
62
68
|
if (parsed === null)
|
|
63
69
|
return null
|
|
64
70
|
//parsed.modified = entry.lastModifiedLedgerSeq()
|
|
65
|
-
return parseLedgerEntryExt(parsed,
|
|
71
|
+
return parseLedgerEntryExt(parsed, value)
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
function parseEntryData(data) {
|
|
@@ -85,9 +91,9 @@ function parseEntryData(data) {
|
|
|
85
91
|
case 'contractData':
|
|
86
92
|
return parseContractData(data)
|
|
87
93
|
case 'contractCode':
|
|
88
|
-
return
|
|
94
|
+
return parseContractCode(data)
|
|
89
95
|
case 'ttl':
|
|
90
|
-
return
|
|
96
|
+
return parseTtl(data)
|
|
91
97
|
default:
|
|
92
98
|
throw new TxMetaEffectParserError(`Unknown meta entry type: ${updatedEntryType}`)
|
|
93
99
|
}
|
|
@@ -240,46 +246,51 @@ function parseContractData(value) {
|
|
|
240
246
|
const owner = parseStateOwnerDataAddress(data.contract())
|
|
241
247
|
|
|
242
248
|
const valueAttr = data.val()
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
249
|
+
const entry = {
|
|
250
|
+
entry: 'contractData',
|
|
251
|
+
owner,
|
|
252
|
+
key: data.key().toXDR('base64'),
|
|
253
|
+
value: valueAttr.toXDR('base64'),
|
|
254
|
+
durability: data.durability().name,
|
|
255
|
+
keyHash: generateContractStateEntryHash(data)
|
|
256
|
+
}
|
|
257
|
+
if (data.key().switch()?.name === 'scvLedgerKeyContractInstance' && entry.durability === 'persistent') {
|
|
258
|
+
entry.durability = 'instance'
|
|
259
|
+
const instance = valueAttr.instance()._attributes
|
|
260
|
+
const type = instance.executable._switch.name
|
|
261
|
+
switch (type) {
|
|
262
|
+
case 'contractExecutableStellarAsset':
|
|
263
|
+
entry.kind = 'fromAsset'
|
|
264
|
+
if (instance.storage?.length) { //if not -- the asset has been created "fromAddress" - no metadata in this case
|
|
256
265
|
const metaArgs = instance.storage[0]._attributes
|
|
257
266
|
if (metaArgs.key._value.toString() !== 'METADATA')
|
|
258
267
|
throw new TxMetaEffectParserError('Unexpected asset initialization metadata')
|
|
259
268
|
entry.asset = xdrParseAsset(metaArgs.val._value[1]._attributes.val._value.toString())
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
269
|
+
}
|
|
270
|
+
break
|
|
271
|
+
case 'contractExecutableWasm':
|
|
272
|
+
entry.kind = 'wasm'
|
|
273
|
+
entry.wasmHash = instance.executable.wasmHash().toString('hex')
|
|
274
|
+
break
|
|
275
|
+
default:
|
|
276
|
+
throw new TxMetaEffectParserError('Unsupported executable type: ' + type)
|
|
277
|
+
}
|
|
278
|
+
if (instance.storage?.length) {
|
|
279
|
+
entry.storage = instance.storage.map(entry => ({
|
|
280
|
+
key: entry.key().toXDR('base64'),
|
|
281
|
+
val: entry.val().toXDR('base64')
|
|
282
|
+
}))
|
|
283
|
+
}
|
|
275
284
|
}
|
|
285
|
+
return entry
|
|
286
|
+
}
|
|
276
287
|
|
|
288
|
+
function parseTtl(data) {
|
|
289
|
+
const attrs = data._value._attributes
|
|
277
290
|
return {
|
|
278
|
-
entry: '
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
value: valueAttr.toXDR('base64'),
|
|
282
|
-
durability: data.durability().name
|
|
291
|
+
entry: 'ttl',
|
|
292
|
+
keyHash: attrs.keyHash.toString('hex'),
|
|
293
|
+
ttl: attrs.liveUntilLedgerSeq
|
|
283
294
|
}
|
|
284
295
|
}
|
|
285
296
|
|
|
@@ -289,13 +300,14 @@ function parseStateOwnerDataAddress(contract) {
|
|
|
289
300
|
return xdrParseAccountAddress(contract.accountId())
|
|
290
301
|
}
|
|
291
302
|
|
|
292
|
-
|
|
303
|
+
function parseContractCode(value) {
|
|
293
304
|
const contract = value.value()
|
|
305
|
+
const hash = contract.hash()
|
|
294
306
|
return {
|
|
295
307
|
entry: 'contractCode',
|
|
296
|
-
hash:
|
|
297
|
-
|
|
308
|
+
hash: hash.toString('hex'),
|
|
309
|
+
keyHash: generateContractCodeEntryHash(hash)
|
|
298
310
|
}
|
|
299
|
-
}
|
|
311
|
+
}
|
|
300
312
|
|
|
301
313
|
module.exports = {parseLedgerEntryChanges}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const {xdr, hash} = require('@stellar/stellar-base')
|
|
2
|
+
|
|
3
|
+
function generateContractStateEntryHash(data) {
|
|
4
|
+
const {contract, durability, key} = data._attributes
|
|
5
|
+
const contractDataKey = new xdr.LedgerKeyContractData({contract, durability, key})
|
|
6
|
+
const ledgerKey = xdr.LedgerKey.contractData(contractDataKey)
|
|
7
|
+
return hash(ledgerKey.toXDR()).toString('hex')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function generateContractCodeEntryHash(wasmHash) {
|
|
11
|
+
const contractDataKey = new xdr.LedgerKeyContractCode({hash: wasmHash})
|
|
12
|
+
const ledgerKey = xdr.LedgerKey.contractCode(contractDataKey)
|
|
13
|
+
return hash(ledgerKey.toXDR()).toString('hex')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
generateContractStateEntryHash,
|
|
18
|
+
generateContractCodeEntryHash
|
|
19
|
+
}
|
|
@@ -234,7 +234,6 @@ function xdrParseAsset(src) {
|
|
|
234
234
|
return `${src.code}-${src.issuer}-${src.type || (src.code.length > 4 ? 2 : 1)}`
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
|
|
238
237
|
function xdrParseScVal(value, treatBytesAsContractId = false) {
|
|
239
238
|
if (typeof value === 'string') {
|
|
240
239
|
value = xdr.ScVal.fromXDR(value, 'base64')
|