@stellar-expert/tx-meta-effects-parser 7.0.0-rc.19 → 7.0.0-rc.20

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.
@@ -1,336 +1,332 @@
1
- const {StrKey} = require('@stellar/stellar-base')
2
- const {TxMetaEffectParserError, UnexpectedTxMetaChangeError} = require('../errors')
3
- const {xdrParseAsset, xdrParseAccountAddress, xdrParseClaimant, xdrParsePrice, xdrParseSignerKey} = require('./tx-xdr-parser-utils')
4
- const {generateContractStateEntryHash, generateContractCodeEntryHash} = require('./ledger-key')
5
-
6
- /**
7
- * @typedef {{}} ParsedLedgerEntryMeta
8
- * @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'|'ttl'} type - Ledger entry type
9
- * @property {'created'|'updated'|'removed'|'restored'} action - Ledger modification action
10
- * @property {{}} before - Ledger entry state before changes applied
11
- * @property {{}} after - Ledger entry state after changes application
12
- */
13
-
14
- /**
15
- * @param {LedgerEntryChange[]} ledgerEntryChanges
16
- * @param {Set<string>} [filter]
17
- * @return {ParsedLedgerEntryMeta[]}
18
- */
19
- function parseLedgerEntryChanges(ledgerEntryChanges, filter = undefined) {
20
- const changes = []
21
- let state
22
- let containsTtl = false
23
- for (let i = 0; i < ledgerEntryChanges.length; i++) {
24
- const entry = ledgerEntryChanges[i]
25
- const type = entry._value._arm || entry._value._attributes.data._arm
26
- if (filter && !filter.has(type)) //skip filtered ledger entry types
27
- continue
28
- const action = entry._arm
29
- const stateData = parseEntry(entry, action)
30
- if (stateData === undefined)
31
- continue
32
- const change = {action, type}
33
- switch (action) {
34
- case 'state':
35
- state = stateData
36
- continue
37
- case 'created':
38
- if (type === 'contractCode')
39
- continue //processed in operation handler
40
- change.before = null
41
- change.after = stateData
42
- change.type = stateData.entry
43
- break
44
- case 'updated':
45
- if (type === 'contractCode')
46
- console.error(new UnexpectedTxMetaChangeError({type, action})) //happens only in protocol 20
47
- if (!state && stateData.keyHash) { //likely, restored state
48
- const restored = changes.find(ch => ch.action === 'restored' && ch.type === stateData.entry && ch.after.keyHash === stateData.keyHash)
49
- state = restored?.after
50
- }
51
- change.before = state
52
- change.after = stateData
53
- change.type = stateData.entry
54
- break
55
- case 'restored':
56
- change.before = stateData
57
- change.after = stateData
58
- change.type = stateData.entry
59
- break
60
- case 'removed':
61
- if (!state && type === 'ttl')
62
- continue //skip expiration processing for now
63
- change.before = state
64
- change.after = null
65
- change.type = state.entry
66
- break
67
- default:
68
- throw new TxMetaEffectParserError(`Unknown change entry type: ${action}`)
69
- }
70
- if (change.type === 'ttl') {
71
- containsTtl = true
72
- }
73
- changes.push(change)
74
- state = null
75
- }
76
- if (containsTtl) { //put ttl entries into the end of array
77
- changes.sort((a, b) =>
78
- a.type !== 'ttl' && b.type === 'ttl' ?
79
- -1 : 0)
80
- }
81
- return changes
82
- }
83
-
84
- function parseEntry(entry, actionType) {
85
- if (actionType === 'removed')
86
- return null
87
- const value = entry.value()
88
- const parsed = parseEntryData(value.data())
89
- if (parsed === null)
90
- return null
91
- //parsed.modified = entry.lastModifiedLedgerSeq()
92
- return parseLedgerEntryExt(parsed, value)
93
- }
94
-
95
- function parseEntryData(data) {
96
- const updatedEntryType = data.arm()
97
- switch (updatedEntryType) {
98
- case 'account':
99
- return parseAccountEntry(data)
100
- case 'trustline':
101
- case 'trustLine':
102
- return parseTrustlineEntry(data)
103
- case 'offer':
104
- return parseOfferEntry(data)
105
- case 'data':
106
- case 'datum':
107
- return parseDataEntry(data)
108
- case 'claimableBalance':
109
- return parseClaimableBalanceEntry(data)
110
- case 'liquidityPool':
111
- return parseLiquidityPoolEntry(data)
112
- case 'contractData':
113
- return parseContractData(data)
114
- case 'contractCode':
115
- return parseContractCode(data)
116
- case 'ttl':
117
- return parseTtl(data)
118
- default:
119
- throw new TxMetaEffectParserError(`Unknown meta entry type: ${updatedEntryType}`)
120
- }
121
- }
122
-
123
- function parseLedgerEntryExt(data, entry) {
124
- const v1 = entry.ext()?.v1()
125
- if (v1) {
126
- const sponsor = v1.sponsoringId()
127
- if (sponsor) {
128
- data.sponsor = xdrParseAccountAddress(sponsor)
129
- }
130
- }
131
- return data
132
- }
133
-
134
- function parseAccountEntry(value) {
135
- const accountEntryXdr = value.value()
136
- const data = {
137
- entry: 'account',
138
- address: xdrParseAccountAddress(accountEntryXdr.accountId()),
139
- sequence: accountEntryXdr.seqNum().toString(),
140
- balance: accountEntryXdr.balance().toString(),
141
- homeDomain: accountEntryXdr.homeDomain().toString('UTF8'),
142
- inflationDest: xdrParseAccountAddress(accountEntryXdr.inflationDest()),
143
- flags: accountEntryXdr.flags(),
144
- signers: accountEntryXdr.signers().map(signer => ({
145
- key: xdrParseSignerKey(signer.key()),
146
- weight: signer.weight()
147
- }))
148
- }
149
- const thresholds = accountEntryXdr.thresholds()
150
- data.thresholds = thresholds.slice(1).join()
151
- data.masterWeight = thresholds[0]
152
- const extV1 = accountEntryXdr.ext()?.v1()
153
- if (extV1) {
154
- const extV2 = extV1.ext()?.v2()
155
- if (extV2) {
156
- const sponsoringIDs = extV2.signerSponsoringIDs()
157
- if (sponsoringIDs.length > 0) {
158
- for (let i = 0; i < data.signers.length; i++) {
159
- const sponsor = sponsoringIDs[i]
160
- if (sponsor) { //attach sponsors directly to the signers
161
- data.signers[i].sponsor = xdrParseAccountAddress(sponsor)
162
- }
163
- }
164
- }
165
- }
166
- }
167
- //ignored fields: numSubEntries, extV1.liabilities, extV2.numSponsored, extV2.numSponsoring, extV3.seqLedger, extv3.seqTime
168
- return data
169
- }
170
-
171
- function parseTrustlineEntry(value) {
172
- const trustlineEntryXdr = value.value()
173
- const trustlineAsset = trustlineEntryXdr.asset()
174
- const trustlineType = trustlineAsset.switch()
175
- let asset
176
- switch (trustlineType.value) {
177
- case 0:
178
- case 1:
179
- case 2:
180
- asset = xdrParseAsset(trustlineAsset)
181
- break
182
- case 3:
183
- asset = trustlineEntryXdr.asset().liquidityPoolId().toString('hex')
184
- //data.liquidityPoolUseCount = trustlineEntryXdr.liquidityPoolUseCount()
185
- break
186
- default:
187
- throw new TxMetaEffectParserError(`Unsupported trustline type ` + trustlineType)
188
- }
189
- const data = {
190
- entry: 'trustline',
191
- account: xdrParseAccountAddress(trustlineEntryXdr.accountId()),
192
- asset,
193
- balance: trustlineEntryXdr.balance().toString(),
194
- limit: trustlineEntryXdr.limit().toString(),
195
- flags: trustlineEntryXdr.flags()
196
- }
197
-
198
- /*
199
- //ignored
200
- const extV1 = trustlineEntryXdr.ext()?.v1()
201
- if (extV1) {
202
- const liabilities = extV1.liabilities()
203
- data.buying_liabilities = liabilities.buying().toString()
204
- data.selling_liabilities = liabilities.selling().toString()
205
- }*/
206
-
207
- return data
208
- }
209
-
210
- function parseDataEntry(value) {
211
- const dataEntryXdr = value.value()
212
- return {
213
- entry: 'data',
214
- account: xdrParseAccountAddress(dataEntryXdr.accountId()),
215
- name: dataEntryXdr.dataName().toString(),
216
- value: dataEntryXdr.dataValue().toString('base64')
217
- }
218
- }
219
-
220
- function parseLiquidityPoolEntry(value) {
221
- const liquidityPoolEntryXdr = value.value()
222
- const body = liquidityPoolEntryXdr.body().value()
223
- const params = body.params()
224
- return {
225
- entry: 'liquidityPool',
226
- pool: liquidityPoolEntryXdr.liquidityPoolId().toString('hex'),
227
- asset: [xdrParseAsset(params.assetA()), xdrParseAsset(params.assetB())],
228
- fee: params.fee(),
229
- amount: [body.reserveA().toString(), body.reserveB().toString()],
230
- shares: body.totalPoolShares().toString(),
231
- accounts: body.poolSharesTrustLineCount().low
232
- }
233
- }
234
-
235
- function parseOfferEntry(value) {
236
- const offerEntryXdr = value.value()
237
- const rprice = offerEntryXdr.price()
238
- const data = {
239
- entry: 'offer',
240
- id: offerEntryXdr.offerId().toString(),
241
- account: xdrParseAccountAddress(offerEntryXdr.sellerId()),
242
- asset: [xdrParseAsset(offerEntryXdr.selling()), xdrParseAsset(offerEntryXdr.buying())],
243
- amount: offerEntryXdr.amount().toString(),
244
- price: xdrParsePrice(rprice),
245
- rprice: rprice._attributes,
246
- flags: offerEntryXdr.flags()
247
- }
248
- return data
249
- }
250
-
251
- function parseClaimableBalanceEntry(value) {
252
- const claimableBalanceXdr = value.value()
253
- const data = {
254
- balanceId: Buffer.from(claimableBalanceXdr.balanceId().value()).toString('hex'),
255
- entry: 'claimableBalance',
256
- asset: xdrParseAsset(claimableBalanceXdr.asset()),
257
- amount: claimableBalanceXdr.amount().toString(),
258
- claimants: claimableBalanceXdr.claimants().map(claimant => xdrParseClaimant(claimant))
259
- }
260
- const extV1 = claimableBalanceXdr.ext()?.v1()
261
- if (extV1) {
262
- data.flags = extV1.flags()
263
- }
264
- return data
265
- }
266
-
267
- function parseContractData(value) {
268
- const data = value.value()
269
- const owner = parseStateOwnerDataAddress(data.contract())
270
-
271
- const valueAttr = data.val()
272
- const entry = {
273
- entry: 'contractData',
274
- owner,
275
- key: data.key().toXDR('base64'),
276
- value: valueAttr.toXDR('base64'),
277
- durability: data.durability().name,
278
- keyHash: generateContractStateEntryHash(data)
279
- }
280
- if (data.key().switch()?.name === 'scvLedgerKeyContractInstance' && entry.durability === 'persistent') {
281
- entry.durability = 'instance'
282
- const instance = valueAttr.instance()._attributes
283
- const type = instance.executable._switch.name
284
- switch (type) {
285
- case 'contractExecutableStellarAsset':
286
- entry.kind = 'fromAsset'
287
- if (instance.storage?.length) { //if not -- the asset has been created "fromAddress" - no metadata in this case
288
- const metaArgs = instance.storage[0]._attributes
289
- if (metaArgs.key._value.toString() !== 'METADATA')
290
- throw new TxMetaEffectParserError('Unexpected asset initialization metadata')
291
- entry.asset = xdrParseAsset(metaArgs.val._value[1]._attributes.val._value.toString())
292
- }
293
- break
294
- case 'contractExecutableWasm':
295
- entry.kind = 'wasm'
296
- entry.wasmHash = instance.executable.wasmHash().toString('hex')
297
- break
298
- default:
299
- throw new TxMetaEffectParserError('Unsupported executable type: ' + type)
300
- }
301
- if (instance.storage?.length) {
302
- entry.storage = instance.storage.map(entry => ({
303
- key: entry.key().toXDR('base64'),
304
- val: entry.val().toXDR('base64')
305
- }))
306
- }
307
- }
308
- return entry
309
- }
310
-
311
- function parseTtl(data) {
312
- const attrs = data._value._attributes
313
- return {
314
- entry: 'ttl',
315
- keyHash: attrs.keyHash.toString('hex'),
316
- ttl: attrs.liveUntilLedgerSeq
317
- }
318
- }
319
-
320
- function parseStateOwnerDataAddress(contract) {
321
- if (contract.switch().name === 'scAddressTypeContract')
322
- return StrKey.encodeContract(contract.contractId())
323
- return xdrParseAccountAddress(contract.accountId())
324
- }
325
-
326
- function parseContractCode(value) {
327
- const contract = value.value()
328
- const hash = contract.hash()
329
- return {
330
- entry: 'contractCode',
331
- hash: hash.toString('hex'),
332
- keyHash: generateContractCodeEntryHash(hash)
333
- }
334
- }
335
-
1
+ const {StrKey} = require('@stellar/stellar-base')
2
+ const {TxMetaEffectParserError, UnexpectedTxMetaChangeError} = require('../errors')
3
+ const {xdrParseAsset, xdrParseAccountAddress, xdrParseClaimant, xdrParsePrice, xdrParseSignerKey} = require('./tx-xdr-parser-utils')
4
+ const {generateContractStateEntryHash, generateContractCodeEntryHash} = require('./ledger-key')
5
+
6
+ /**
7
+ * @typedef {{}} ParsedLedgerEntryMeta
8
+ * @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'|'ttl'} type - Ledger entry type
9
+ * @property {'created'|'updated'|'removed'|'restored'} action - Ledger modification action
10
+ * @property {{}} before - Ledger entry state before changes applied
11
+ * @property {{}} after - Ledger entry state after changes application
12
+ */
13
+
14
+ /**
15
+ * @param {LedgerEntryChange[]} ledgerEntryChanges
16
+ * @param {Set<string>} [filter]
17
+ * @return {ParsedLedgerEntryMeta[]}
18
+ */
19
+ function parseLedgerEntryChanges(ledgerEntryChanges, filter = undefined) {
20
+ const changes = []
21
+ let state
22
+ let containsTtl = false
23
+ for (let i = 0; i < ledgerEntryChanges.length; i++) {
24
+ const entry = ledgerEntryChanges[i]
25
+ const type = entry._value._arm || entry._value._attributes.data._arm
26
+ if (filter && !filter.has(type)) //skip filtered ledger entry types
27
+ continue
28
+ const action = entry._arm
29
+ const stateData = parseEntry(entry, action)
30
+ if (stateData === undefined)
31
+ continue
32
+ const change = {action, type}
33
+ switch (action) {
34
+ case 'state':
35
+ state = stateData
36
+ continue
37
+ case 'created':
38
+ if (type === 'contractCode')
39
+ continue //processed in operation handler
40
+ change.before = null
41
+ change.after = stateData
42
+ change.type = stateData.entry
43
+ break
44
+ case 'updated':
45
+ if (type === 'contractCode')
46
+ console.warn(new UnexpectedTxMetaChangeError({type, action})) //happens only in protocol 20
47
+ change.before = state
48
+ change.after = stateData
49
+ change.type = stateData.entry
50
+ break
51
+ case 'restored':
52
+ change.before = stateData
53
+ change.after = stateData
54
+ change.type = stateData.entry
55
+ state = change.after
56
+ break
57
+ case 'removed':
58
+ if (!state && type === 'ttl')
59
+ continue //skip expiration processing for now
60
+ change.before = state
61
+ change.after = null
62
+ change.type = state.entry
63
+ break
64
+ default:
65
+ throw new TxMetaEffectParserError(`Unknown change entry type: ${action}`)
66
+ }
67
+ if (change.type === 'ttl') {
68
+ containsTtl = true
69
+ }
70
+ changes.push(change)
71
+ }
72
+ if (containsTtl) { //put ttl entries into the end of array
73
+ changes.sort((a, b) =>
74
+ a.type !== 'ttl' && b.type === 'ttl' ?
75
+ -1 : 0)
76
+ }
77
+ return changes
78
+ }
79
+
80
+ function parseEntry(entry, actionType) {
81
+ if (actionType === 'removed')
82
+ return null
83
+ const value = entry.value()
84
+ const parsed = parseEntryData(value.data())
85
+ if (parsed === null)
86
+ return null
87
+ //parsed.modified = entry.lastModifiedLedgerSeq()
88
+ return parseLedgerEntryExt(parsed, value)
89
+ }
90
+
91
+ function parseEntryData(data) {
92
+ const updatedEntryType = data.arm()
93
+ switch (updatedEntryType) {
94
+ case 'account':
95
+ return parseAccountEntry(data)
96
+ case 'trustline':
97
+ case 'trustLine':
98
+ return parseTrustlineEntry(data)
99
+ case 'offer':
100
+ return parseOfferEntry(data)
101
+ case 'data':
102
+ case 'datum':
103
+ return parseDataEntry(data)
104
+ case 'claimableBalance':
105
+ return parseClaimableBalanceEntry(data)
106
+ case 'liquidityPool':
107
+ return parseLiquidityPoolEntry(data)
108
+ case 'contractData':
109
+ return parseContractData(data)
110
+ case 'contractCode':
111
+ return parseContractCode(data)
112
+ case 'ttl':
113
+ return parseTtl(data)
114
+ default:
115
+ throw new TxMetaEffectParserError(`Unknown meta entry type: ${updatedEntryType}`)
116
+ }
117
+ }
118
+
119
+ function parseLedgerEntryExt(data, entry) {
120
+ const v1 = entry.ext()?.v1()
121
+ if (v1) {
122
+ const sponsor = v1.sponsoringId()
123
+ if (sponsor) {
124
+ data.sponsor = xdrParseAccountAddress(sponsor)
125
+ }
126
+ }
127
+ return data
128
+ }
129
+
130
+ function parseAccountEntry(value) {
131
+ const accountEntryXdr = value.value()
132
+ const data = {
133
+ entry: 'account',
134
+ address: xdrParseAccountAddress(accountEntryXdr.accountId()),
135
+ sequence: accountEntryXdr.seqNum().toString(),
136
+ balance: accountEntryXdr.balance().toString(),
137
+ homeDomain: accountEntryXdr.homeDomain().toString('UTF8'),
138
+ inflationDest: xdrParseAccountAddress(accountEntryXdr.inflationDest()),
139
+ flags: accountEntryXdr.flags(),
140
+ signers: accountEntryXdr.signers().map(signer => ({
141
+ key: xdrParseSignerKey(signer.key()),
142
+ weight: signer.weight()
143
+ }))
144
+ }
145
+ const thresholds = accountEntryXdr.thresholds()
146
+ data.thresholds = thresholds.slice(1).join()
147
+ data.masterWeight = thresholds[0]
148
+ const extV1 = accountEntryXdr.ext()?.v1()
149
+ if (extV1) {
150
+ const extV2 = extV1.ext()?.v2()
151
+ if (extV2) {
152
+ const sponsoringIDs = extV2.signerSponsoringIDs()
153
+ if (sponsoringIDs.length > 0) {
154
+ for (let i = 0; i < data.signers.length; i++) {
155
+ const sponsor = sponsoringIDs[i]
156
+ if (sponsor) { //attach sponsors directly to the signers
157
+ data.signers[i].sponsor = xdrParseAccountAddress(sponsor)
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ //ignored fields: numSubEntries, extV1.liabilities, extV2.numSponsored, extV2.numSponsoring, extV3.seqLedger, extv3.seqTime
164
+ return data
165
+ }
166
+
167
+ function parseTrustlineEntry(value) {
168
+ const trustlineEntryXdr = value.value()
169
+ const trustlineAsset = trustlineEntryXdr.asset()
170
+ const trustlineType = trustlineAsset.switch()
171
+ let asset
172
+ switch (trustlineType.value) {
173
+ case 0:
174
+ case 1:
175
+ case 2:
176
+ asset = xdrParseAsset(trustlineAsset)
177
+ break
178
+ case 3:
179
+ asset = trustlineEntryXdr.asset().liquidityPoolId().toString('hex')
180
+ //data.liquidityPoolUseCount = trustlineEntryXdr.liquidityPoolUseCount()
181
+ break
182
+ default:
183
+ throw new TxMetaEffectParserError(`Unsupported trustline type ` + trustlineType)
184
+ }
185
+ const data = {
186
+ entry: 'trustline',
187
+ account: xdrParseAccountAddress(trustlineEntryXdr.accountId()),
188
+ asset,
189
+ balance: trustlineEntryXdr.balance().toString(),
190
+ limit: trustlineEntryXdr.limit().toString(),
191
+ flags: trustlineEntryXdr.flags()
192
+ }
193
+
194
+ /*
195
+ //ignored
196
+ const extV1 = trustlineEntryXdr.ext()?.v1()
197
+ if (extV1) {
198
+ const liabilities = extV1.liabilities()
199
+ data.buying_liabilities = liabilities.buying().toString()
200
+ data.selling_liabilities = liabilities.selling().toString()
201
+ }*/
202
+
203
+ return data
204
+ }
205
+
206
+ function parseDataEntry(value) {
207
+ const dataEntryXdr = value.value()
208
+ return {
209
+ entry: 'data',
210
+ account: xdrParseAccountAddress(dataEntryXdr.accountId()),
211
+ name: dataEntryXdr.dataName().toString(),
212
+ value: dataEntryXdr.dataValue().toString('base64')
213
+ }
214
+ }
215
+
216
+ function parseLiquidityPoolEntry(value) {
217
+ const liquidityPoolEntryXdr = value.value()
218
+ const body = liquidityPoolEntryXdr.body().value()
219
+ const params = body.params()
220
+ return {
221
+ entry: 'liquidityPool',
222
+ pool: liquidityPoolEntryXdr.liquidityPoolId().toString('hex'),
223
+ asset: [xdrParseAsset(params.assetA()), xdrParseAsset(params.assetB())],
224
+ fee: params.fee(),
225
+ amount: [body.reserveA().toString(), body.reserveB().toString()],
226
+ shares: body.totalPoolShares().toString(),
227
+ accounts: body.poolSharesTrustLineCount().low
228
+ }
229
+ }
230
+
231
+ function parseOfferEntry(value) {
232
+ const offerEntryXdr = value.value()
233
+ const rprice = offerEntryXdr.price()
234
+ const data = {
235
+ entry: 'offer',
236
+ id: offerEntryXdr.offerId().toString(),
237
+ account: xdrParseAccountAddress(offerEntryXdr.sellerId()),
238
+ asset: [xdrParseAsset(offerEntryXdr.selling()), xdrParseAsset(offerEntryXdr.buying())],
239
+ amount: offerEntryXdr.amount().toString(),
240
+ price: xdrParsePrice(rprice),
241
+ rprice: rprice._attributes,
242
+ flags: offerEntryXdr.flags()
243
+ }
244
+ return data
245
+ }
246
+
247
+ function parseClaimableBalanceEntry(value) {
248
+ const claimableBalanceXdr = value.value()
249
+ const data = {
250
+ balanceId: Buffer.from(claimableBalanceXdr.balanceId().value()).toString('hex'),
251
+ entry: 'claimableBalance',
252
+ asset: xdrParseAsset(claimableBalanceXdr.asset()),
253
+ amount: claimableBalanceXdr.amount().toString(),
254
+ claimants: claimableBalanceXdr.claimants().map(claimant => xdrParseClaimant(claimant))
255
+ }
256
+ const extV1 = claimableBalanceXdr.ext()?.v1()
257
+ if (extV1) {
258
+ data.flags = extV1.flags()
259
+ }
260
+ return data
261
+ }
262
+
263
+ function parseContractData(value) {
264
+ const data = value.value()
265
+ const owner = parseStateOwnerDataAddress(data.contract())
266
+
267
+ const valueAttr = data.val()
268
+ const entry = {
269
+ entry: 'contractData',
270
+ owner,
271
+ key: data.key().toXDR('base64'),
272
+ value: valueAttr.toXDR('base64'),
273
+ durability: data.durability().name,
274
+ keyHash: generateContractStateEntryHash(data)
275
+ }
276
+ if (data.key().switch()?.name === 'scvLedgerKeyContractInstance' && entry.durability === 'persistent') {
277
+ entry.durability = 'instance'
278
+ const instance = valueAttr.instance()._attributes
279
+ const type = instance.executable._switch.name
280
+ switch (type) {
281
+ case 'contractExecutableStellarAsset':
282
+ entry.kind = 'fromAsset'
283
+ if (instance.storage?.length) { //if not -- the asset has been created "fromAddress" - no metadata in this case
284
+ const metaArgs = instance.storage[0]._attributes
285
+ if (metaArgs.key._value.toString() !== 'METADATA')
286
+ throw new TxMetaEffectParserError('Unexpected asset initialization metadata')
287
+ entry.asset = xdrParseAsset(metaArgs.val._value[1]._attributes.val._value.toString())
288
+ }
289
+ break
290
+ case 'contractExecutableWasm':
291
+ entry.kind = 'wasm'
292
+ entry.wasmHash = instance.executable.wasmHash().toString('hex')
293
+ break
294
+ default:
295
+ throw new TxMetaEffectParserError('Unsupported executable type: ' + type)
296
+ }
297
+ if (instance.storage?.length) {
298
+ entry.storage = instance.storage.map(entry => ({
299
+ key: entry.key().toXDR('base64'),
300
+ val: entry.val().toXDR('base64')
301
+ }))
302
+ }
303
+ }
304
+ return entry
305
+ }
306
+
307
+ function parseTtl(data) {
308
+ const attrs = data._value._attributes
309
+ return {
310
+ entry: 'ttl',
311
+ keyHash: attrs.keyHash.toString('hex'),
312
+ ttl: attrs.liveUntilLedgerSeq
313
+ }
314
+ }
315
+
316
+ function parseStateOwnerDataAddress(contract) {
317
+ if (contract.switch().name === 'scAddressTypeContract')
318
+ return StrKey.encodeContract(contract.contractId())
319
+ return xdrParseAccountAddress(contract.accountId())
320
+ }
321
+
322
+ function parseContractCode(value) {
323
+ const contract = value.value()
324
+ const hash = contract.hash()
325
+ return {
326
+ entry: 'contractCode',
327
+ hash: hash.toString('hex'),
328
+ keyHash: generateContractCodeEntryHash(hash)
329
+ }
330
+ }
331
+
336
332
  module.exports = {parseLedgerEntryChanges}