@stellar-expert/tx-meta-effects-parser 7.0.0-rc.2 → 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,309 +1,323 @@
1
- const {StrKey, LiquidityPoolId, scValToBigInt, xdr, Asset} = require('@stellar/stellar-base')
2
- const {TxMetaEffectParserError} = require('../errors')
3
-
4
- /**
5
- * @param {String} address
6
- * @return {Boolean}
7
- */
8
- function isContractAddress(address) {
9
- return address.length === 56 && address[0] === 'C'
10
- }
11
-
12
- /**
13
- * @param {String} assetDescriptor
14
- * @return {Asset}
15
- */
16
- function toStellarAsset(assetDescriptor) {
17
- if (assetDescriptor === 'XLM')
18
- return Asset.native()
19
- if (assetDescriptor.includes('-')) {
20
- const [code, issuer] = assetDescriptor.split('-')
21
- return new Asset(code, issuer)
22
- }
23
- throw new TypeError('Unsupported asset format ' + assetDescriptor)
24
- }
25
-
26
- /**
27
- * Parse account address from XDR representation
28
- * @param accountId
29
- * @param muxedAccountsSupported
30
- * @return {String|{muxedId: String, primary: String}}
31
- */
32
- function xdrParseAccountAddress(accountId, muxedAccountsSupported = false) {
33
- if (!accountId)
34
- return undefined
35
- if (accountId.arm) {
36
- switch (accountId.arm()) {
37
- case 'ed25519':
38
- return StrKey.encodeEd25519PublicKey(accountId.ed25519())
39
- case 'med25519':
40
- if (!muxedAccountsSupported)
41
- throw new TxMetaEffectParserError(`Muxed accounts not supported here`)
42
- return {
43
- primary: StrKey.encodeEd25519PublicKey(accountId.value().ed25519()),
44
- muxedId: accountId.value().id().toString()
45
- }
46
- default:
47
- throw new TxMetaEffectParserError(`Unsupported account type: ${accountId.arm()}`)
48
- }
49
- }
50
- if (accountId instanceof Uint8Array) {
51
- return StrKey.encodeEd25519PublicKey(accountId)
52
- }
53
- throw new TypeError(`Failed to identify and parse account address: ${accountId}`)
54
- }
55
-
56
- /**
57
- * Parse Contract ID from raw bytes
58
- * @param {Buffer} rawContractId
59
- * @return {String}
60
- */
61
- function xdrParseContractAddress(rawContractId) {
62
- return StrKey.encodeContract(rawContractId)
63
- }
64
-
65
- /**
66
- * Parse XDR price representation
67
- * @param {{n: Function, d: Function}} price
68
- * @return {Number}
69
- */
70
- function xdrParsePrice(price) {
71
- return price.n() / price.d()
72
- }
73
-
74
- /**
75
- * Parse account signer key XDR
76
- * @param {xdr.SignerKey} signer
77
- * @return {String}
78
- */
79
- function xdrParseSignerKey(signer) {
80
- const type = signer.arm()
81
- switch (type) {
82
- case 'ed25519':
83
- return StrKey.encodeEd25519PublicKey(signer.ed25519())
84
- case 'preAuthTx':
85
- return StrKey.encodePreAuthTx(signer.preAuthTx())
86
- case 'hashX':
87
- return StrKey.encodeSha256Hash(signer.hashX())
88
- case 'ed25519SignedPayload':
89
- return StrKey.encodeSignedPayload(signer.ed25519SignedPayload()) //TODO: check
90
- }
91
- throw new TxMetaEffectParserError(`Unsupported signer type: "${type}"`)
92
- }
93
-
94
-
95
- /**
96
- * @typedef {Object} ParsedOffer
97
- * @property {String} account
98
- * @property {Array<String>} asset
99
- * @property {Array<String>} amount
100
- * @property {String} offerId?
101
- * @property {Buffer} poolId?
102
- */
103
-
104
- /**
105
- * Parse maker offer descriptor from raw XDR.
106
- * @param {Object} offerXdr
107
- * @return {ParsedOffer}
108
- */
109
- function xdrParseTradeAtom(offerXdr) {
110
- return {
111
- offerId: offerXdr.offerId().toString(),
112
- account: xdrParseAccountAddress(offerXdr.sellerId()),
113
- asset: [xdrParseAsset(offerXdr.selling()).toString(), xdrParseAsset(offerXdr.buying()).toString()],
114
- //offer amount is always stored in terms of a selling asset, even for buy offers
115
- amount: (offerXdr.amount() || offerXdr.buyAmount()).toString(),
116
- //flags: offerXdr.flags()
117
- price: xdrParsePrice(offerXdr.price())
118
- }
119
- }
120
-
121
- /**
122
- * Parse claimed offer atom from raw XDR.
123
- * @param {xdr.ClaimAtom} claimedAtom
124
- * @return {ParsedOffer}
125
- */
126
- function xdrParseClaimedOffer(claimedAtom) {
127
- const atomType = claimedAtom.arm()
128
- let res
129
- switch (atomType) {
130
- case 'v0':
131
- claimedAtom = claimedAtom.v0()
132
- res = {
133
- account: xdrParseAccountAddress(claimedAtom.sellerEd25519()),
134
- offerId: claimedAtom.offerId().toString()
135
- }
136
- break
137
- case 'orderBook':
138
- claimedAtom = claimedAtom.orderBook()
139
- res = {
140
- account: xdrParseAccountAddress(claimedAtom.sellerId()),
141
- offerId: claimedAtom.offerId().toString()
142
- }
143
- break
144
- case 'liquidityPool':
145
- claimedAtom = claimedAtom.liquidityPool()
146
- res = {
147
- poolId: claimedAtom.liquidityPoolId()
148
- }
149
- break
150
- default:
151
- throw new TxMetaEffectParserError(`Unsupported claimed atom type: ` + atomType)
152
- }
153
- return {
154
- asset: [
155
- xdrParseAsset(claimedAtom.assetSold()),
156
- xdrParseAsset(claimedAtom.assetBought())
157
- ],
158
- amount: [
159
- claimedAtom.amountSold().toString(),
160
- claimedAtom.amountBought().toString()
161
- ],
162
- ...res
163
- }
164
- }
165
-
166
- function xdrParseClaimantPredicate(predicate) {
167
- if (!predicate) return {}
168
- const type = predicate.switch().name
169
- const value = predicate.value()
170
- switch (type) {
171
- case 'claimPredicateUnconditional':
172
- return {}
173
- case 'claimPredicateAnd':
174
- return {and: value.map(p => xdrParseClaimantPredicate(p))}
175
- case 'claimPredicateOr':
176
- return {or: value.map(p => xdrParseClaimantPredicate(p))}
177
- case 'claimPredicateNot':
178
- return {not: xdrParseClaimantPredicate(value)}
179
- case 'claimPredicateBeforeAbsoluteTime':
180
- return {absBefore: value.toString()}
181
- case 'claimPredicateBeforeRelativeTime':
182
- return {relBefore: value.toString()}
183
- default:
184
- throw new TxMetaEffectParserError(`Unknown claim condition predicate: ${type}`)
185
- }
186
- }
187
-
188
- function xdrParseClaimant(claimant) {
189
- const value = claimant.value()
190
- return {
191
- destination: xdrParseAccountAddress(value.destination()),
192
- predicate: xdrParseClaimantPredicate(value.predicate())
193
- }
194
- }
195
-
196
- function xdrParseAsset(src) {
197
- if (!src)
198
- return undefined
199
-
200
- if (src.arm) { //XDR
201
- switch (src.switch().name) {
202
- case 'assetTypeNative':
203
- return 'XLM'
204
- case 'assetTypePoolShare': {
205
- const poolId = src.value()
206
- if (poolId.length)
207
- return poolId.toString('hex')
208
- if (poolId.constantProduct)
209
- return LiquidityPoolId.fromOperation(poolId).getLiquidityPoolId()
210
- throw new TxMetaEffectParserError('Unsupported liquidity pool asset id format')
211
- }
212
- default: {
213
- const value = src.value()
214
- return `${value.assetCode().toString().replace(/\0+$/, '')}-${StrKey.encodeEd25519PublicKey(value.issuer().ed25519())}-${src.arm() === 'alphaNum4' ? 1 : 2}`
215
- }
216
- }
217
- }
218
-
219
- if (typeof src === 'string') {
220
- if (src === 'XLM' || src === 'native')
221
- return 'XLM'//already parsed value
222
- if (src.includes(':')) {
223
- const [code, issuer] = src.split(':')
224
- return `${code.replace(/\0+$/, '')}-${issuer}-${code.length > 4 ? 2 : 1}`
225
- }
226
- if (src.includes('-'))
227
- return src //already parsed
228
- if (src.length === 64)
229
- return src //pool id
230
- }
231
- if (src.type === 0 && !src.code || src.code === 'XLM' && !src.issuer)
232
- return 'XLM'
233
- if (src.code && src.issuer)
234
- return `${src.code}-${src.issuer}-${src.type || (src.code.length > 4 ? 2 : 1)}`
235
- }
236
-
237
- function xdrParseScVal(value, treatBytesAsContractId = false) {
238
- if (typeof value === 'string') {
239
- value = xdr.ScVal.fromXDR(value, 'base64')
240
- }
241
- switch (value._arm) {
242
- case 'vec':
243
- return value._value.map(xdrParseScVal)
244
- case 'map':
245
- const res = {}
246
- for (const entry of value._value) {
247
- res[xdrParseScVal(entry.key())] = xdrParseScVal(entry.val())
248
- }
249
- return res
250
- case 'i256':
251
- case 'u256':
252
- case 'i128':
253
- case 'u128':
254
- case 'i64':
255
- case 'u64':
256
- case 'timepoint':
257
- case 'duration':
258
- return scValToBigInt(value).toString()
259
- case 'address':
260
- if (value._value._arm === 'accountId')
261
- return xdrParseAccountAddress(value._value.value())
262
- if (value._value._arm === 'contractId')
263
- return xdrParseContractAddress(value._value.value())
264
- throw new TxMetaEffectParserError('Not supported XDR primitive type: ' + value.toString())
265
- case 'bytes':
266
- return treatBytesAsContractId ? xdrParseContractAddress(value.value()) : value._value.toString('base64')
267
- case 'i32':
268
- case 'u32':
269
- case 'b':
270
- return value._value
271
- case 'str':
272
- case 'sym':
273
- return value._value.toString()
274
- case 'nonceKey':
275
- return value._value.nonce()._value.toString()
276
- case 'instance':
277
- return value._value.executable.wasmHash().toString('base64')
278
- case 'error':
279
- return value.toXDR('base64')
280
- case 'contractId':
281
- return xdrParseContractAddress(value._value)
282
- default:
283
- switch (value._switch.name) {
284
- case 'scvVoid':
285
- return undefined
286
- case 'scvContractInstance':
287
- return '<ContractInstance>'
288
- case 'scvLedgerKeyContractInstance':
289
- return '<LedgerKeyContractInstance>'
290
- case 'scvLedgerKeyNonce':
291
- return '<LedgerKeyNonce>'
292
- }
293
- throw new TxMetaEffectParserError('Not supported XDR primitive type: ' + value.toXDR ? value.toXDR() : value.toString())
294
- }
295
- }
296
-
297
- module.exports = {
298
- xdrParseAsset,
299
- xdrParseAccountAddress,
300
- xdrParseContractAddress,
301
- xdrParseClaimant,
302
- xdrParseClaimedOffer,
303
- xdrParseTradeAtom,
304
- xdrParseSignerKey,
305
- xdrParsePrice,
306
- xdrParseScVal,
307
- isContractAddress,
308
- toStellarAsset
309
- }
1
+ const {xdr, StrKey, LiquidityPoolId, Asset, scValToBigInt, encodeMuxedAccount, encodeMuxedAccountToAddress} = require('@stellar/stellar-base')
2
+ const {TxMetaEffectParserError} = require('../errors')
3
+
4
+ /**
5
+ * @param {String} address
6
+ * @return {Boolean}
7
+ */
8
+ function isContractAddress(address) {
9
+ return address.length === 56 && address[0] === 'C'
10
+ }
11
+
12
+ /**
13
+ * @param {String} assetDescriptor
14
+ * @return {Asset}
15
+ */
16
+ function toStellarAsset(assetDescriptor) {
17
+ if (assetDescriptor === 'XLM')
18
+ return Asset.native()
19
+ if (assetDescriptor.includes('-')) {
20
+ const [code, issuer] = assetDescriptor.split('-')
21
+ return new Asset(code, issuer)
22
+ }
23
+ throw new TypeError('Unsupported asset format ' + assetDescriptor)
24
+ }
25
+
26
+ /**
27
+ * Parse account address from XDR representation
28
+ * @param accountId
29
+ * @return {String}
30
+ */
31
+ function xdrParseAccountAddress(accountId) {
32
+ if (!accountId)
33
+ return undefined
34
+ if (accountId.arm) {
35
+ switch (accountId.arm()) {
36
+ case 'ed25519':
37
+ return StrKey.encodeEd25519PublicKey(accountId.ed25519())
38
+ case 'med25519':
39
+ return {
40
+ primary: StrKey.encodeEd25519PublicKey(accountId.value().ed25519()),
41
+ muxedId: accountId.value().id().toString()
42
+ }
43
+ default:
44
+ throw new TxMetaEffectParserError(`Unsupported account type: ${accountId.arm()}`)
45
+ }
46
+ }
47
+ if (accountId instanceof Uint8Array) {
48
+ return StrKey.encodeEd25519PublicKey(accountId)
49
+ }
50
+ throw new TypeError(`Failed to identify and parse account address: ${accountId}`)
51
+ }
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
+
64
+ /**
65
+ * Parse Contract ID from raw bytes
66
+ * @param {Buffer} rawContractId
67
+ * @return {String}
68
+ */
69
+ function xdrParseContractAddress(rawContractId) {
70
+ return StrKey.encodeContract(rawContractId)
71
+ }
72
+
73
+ /**
74
+ * Parse XDR price representation
75
+ * @param {{n: Function, d: Function}} price
76
+ * @return {Number}
77
+ */
78
+ function xdrParsePrice(price) {
79
+ return price.n() / price.d()
80
+ }
81
+
82
+ /**
83
+ * Parse account signer key XDR
84
+ * @param {xdr.SignerKey} signer
85
+ * @return {String}
86
+ */
87
+ function xdrParseSignerKey(signer) {
88
+ const type = signer.arm()
89
+ switch (type) {
90
+ case 'ed25519':
91
+ return StrKey.encodeEd25519PublicKey(signer.ed25519())
92
+ case 'preAuthTx':
93
+ return StrKey.encodePreAuthTx(signer.preAuthTx())
94
+ case 'hashX':
95
+ return StrKey.encodeSha256Hash(signer.hashX())
96
+ case 'ed25519SignedPayload':
97
+ return StrKey.encodeSignedPayload(signer.ed25519SignedPayload()) //TODO: check
98
+ }
99
+ throw new TxMetaEffectParserError(`Unsupported signer type: "${type}"`)
100
+ }
101
+
102
+
103
+ /**
104
+ * @typedef {Object} ParsedOffer
105
+ * @property {String} account
106
+ * @property {Array<String>} asset
107
+ * @property {Array<String>} amount
108
+ * @property {String} offerId?
109
+ * @property {Buffer} poolId?
110
+ */
111
+
112
+ /**
113
+ * Parse maker offer descriptor from raw XDR.
114
+ * @param {Object} offerXdr
115
+ * @return {ParsedOffer}
116
+ */
117
+ function xdrParseTradeAtom(offerXdr) {
118
+ return {
119
+ offerId: offerXdr.offerId().toString(),
120
+ account: xdrParseAccountAddress(offerXdr.sellerId()),
121
+ asset: [xdrParseAsset(offerXdr.selling()).toString(), xdrParseAsset(offerXdr.buying()).toString()],
122
+ //offer amount is always stored in terms of a selling asset, even for buy offers
123
+ amount: (offerXdr.amount() || offerXdr.buyAmount()).toString(),
124
+ //flags: offerXdr.flags()
125
+ price: xdrParsePrice(offerXdr.price())
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Parse claimed offer atom from raw XDR.
131
+ * @param {xdr.ClaimAtom} claimedAtom
132
+ * @return {ParsedOffer}
133
+ */
134
+ function xdrParseClaimedOffer(claimedAtom) {
135
+ const atomType = claimedAtom.arm()
136
+ let res
137
+ switch (atomType) {
138
+ case 'v0':
139
+ claimedAtom = claimedAtom.v0()
140
+ res = {
141
+ account: xdrParseAccountAddress(claimedAtom.sellerEd25519()),
142
+ offerId: claimedAtom.offerId().toString()
143
+ }
144
+ break
145
+ case 'orderBook':
146
+ claimedAtom = claimedAtom.orderBook()
147
+ res = {
148
+ account: xdrParseAccountAddress(claimedAtom.sellerId()),
149
+ offerId: claimedAtom.offerId().toString()
150
+ }
151
+ break
152
+ case 'liquidityPool':
153
+ claimedAtom = claimedAtom.liquidityPool()
154
+ res = {
155
+ poolId: claimedAtom.liquidityPoolId()
156
+ }
157
+ break
158
+ default:
159
+ throw new TxMetaEffectParserError(`Unsupported claimed atom type: ` + atomType)
160
+ }
161
+ return {
162
+ asset: [
163
+ xdrParseAsset(claimedAtom.assetSold()),
164
+ xdrParseAsset(claimedAtom.assetBought())
165
+ ],
166
+ amount: [
167
+ claimedAtom.amountSold().toString(),
168
+ claimedAtom.amountBought().toString()
169
+ ],
170
+ ...res
171
+ }
172
+ }
173
+
174
+ function xdrParseClaimantPredicate(predicate) {
175
+ if (!predicate) return {}
176
+ const type = predicate.switch().name
177
+ const value = predicate.value()
178
+ switch (type) {
179
+ case 'claimPredicateUnconditional':
180
+ return {}
181
+ case 'claimPredicateAnd':
182
+ return {and: value.map(p => xdrParseClaimantPredicate(p))}
183
+ case 'claimPredicateOr':
184
+ return {or: value.map(p => xdrParseClaimantPredicate(p))}
185
+ case 'claimPredicateNot':
186
+ return {not: xdrParseClaimantPredicate(value)}
187
+ case 'claimPredicateBeforeAbsoluteTime':
188
+ return {absBefore: value.toString()}
189
+ case 'claimPredicateBeforeRelativeTime':
190
+ return {relBefore: value.toString()}
191
+ default:
192
+ throw new TxMetaEffectParserError(`Unknown claim condition predicate: ${type}`)
193
+ }
194
+ }
195
+
196
+ function xdrParseClaimant(claimant) {
197
+ const value = claimant.value()
198
+ return {
199
+ destination: xdrParseAccountAddress(value.destination()),
200
+ predicate: xdrParseClaimantPredicate(value.predicate())
201
+ }
202
+ }
203
+
204
+ function xdrParseAsset(src) {
205
+ if (!src)
206
+ return undefined
207
+
208
+ if (src.arm) { //XDR
209
+ switch (src.switch().name) {
210
+ case 'assetTypeNative':
211
+ return 'XLM'
212
+ case 'assetTypePoolShare': {
213
+ const poolId = src.value()
214
+ if (poolId.length)
215
+ return poolId.toString('hex')
216
+ if (poolId.constantProduct)
217
+ return LiquidityPoolId.fromOperation(poolId).getLiquidityPoolId()
218
+ throw new TxMetaEffectParserError('Unsupported liquidity pool asset id format')
219
+ }
220
+ default: {
221
+ const value = src.value()
222
+ return `${value.assetCode().toString().replace(/\0+$/, '')}-${StrKey.encodeEd25519PublicKey(value.issuer().ed25519())}-${src.arm() === 'alphaNum4' ? 1 : 2}`
223
+ }
224
+ }
225
+ }
226
+
227
+ if (typeof src === 'string') {
228
+ if (src === 'XLM' || src === 'native')
229
+ return 'XLM'//already parsed value
230
+ if (src.includes(':')) {
231
+ const [code, issuer] = src.split(':')
232
+ return `${code.replace(/\0+$/, '')}-${issuer}-${code.length > 4 ? 2 : 1}`
233
+ }
234
+ if (src.includes('-'))
235
+ return src //already parsed
236
+ if (src.length === 64)
237
+ return src //pool id
238
+ }
239
+ if (src.type === 0 && !src.code || src.code === 'XLM' && !src.issuer)
240
+ return 'XLM'
241
+ if (src.code && src.issuer)
242
+ return `${src.code}-${src.issuer}-${src.type || (src.code.length > 4 ? 2 : 1)}`
243
+ }
244
+
245
+ function xdrParseScVal(value, treatBytesAsContractId = false) {
246
+ if (typeof value === 'string') {
247
+ value = xdr.ScVal.fromXDR(value, 'base64')
248
+ }
249
+ switch (value._arm) {
250
+ case 'vec':
251
+ return value._value.map(xdrParseScVal)
252
+ case 'map':
253
+ const res = {}
254
+ for (const entry of value._value) {
255
+ res[xdrParseScVal(entry.key())] = xdrParseScVal(entry.val())
256
+ }
257
+ return res
258
+ case 'i256':
259
+ case 'u256':
260
+ case 'i128':
261
+ case 'u128':
262
+ case 'i64':
263
+ case 'u64':
264
+ return scValToBigInt(value).toString()
265
+ case 'timepoint':
266
+ case 'duration':
267
+ return value._value._value.toString()
268
+ case 'address':
269
+ switch (value._value._arm) {
270
+ case 'accountId':
271
+ return xdrParseAccountAddress(value._value.value())
272
+ case 'contractId':
273
+ return xdrParseContractAddress(value._value.value())
274
+ case 'muxedAccount':
275
+ return xdrParseMuxedScAddress(value._value.value())
276
+ }
277
+ throw new TxMetaEffectParserError('Not supported XDR primitive type: ' + value._value._arm.toString())
278
+ case 'bytes':
279
+ return treatBytesAsContractId ? xdrParseContractAddress(value.value()) : value._value.toString('base64')
280
+ case 'i32':
281
+ case 'u32':
282
+ case 'b':
283
+ return value._value
284
+ case 'str':
285
+ case 'sym':
286
+ return value._value.toString()
287
+ case 'nonceKey':
288
+ return value._value.nonce()._value.toString()
289
+ case 'instance':
290
+ return value._value.executable.wasmHash().toString('base64')
291
+ case 'error':
292
+ return value.toXDR('base64')
293
+ case 'contractId':
294
+ return xdrParseContractAddress(value._value)
295
+ default:
296
+ switch (value._switch.name) {
297
+ case 'scvVoid':
298
+ return undefined
299
+ case 'scvContractInstance':
300
+ return '<ContractInstance>'
301
+ case 'scvLedgerKeyContractInstance':
302
+ return '<LedgerKeyContractInstance>'
303
+ case 'scvLedgerKeyNonce':
304
+ return '<LedgerKeyNonce>'
305
+ }
306
+ throw new TxMetaEffectParserError('Not supported XDR primitive type: ' + value.toXDR ? value.toXDR() : value.toString())
307
+ }
308
+ }
309
+
310
+ module.exports = {
311
+ xdrParseAsset,
312
+ xdrParseAccountAddress,
313
+ xdrParseContractAddress,
314
+ xdrParseMuxedScAddress,
315
+ xdrParseClaimant,
316
+ xdrParseClaimedOffer,
317
+ xdrParseTradeAtom,
318
+ xdrParseSignerKey,
319
+ xdrParsePrice,
320
+ xdrParseScVal,
321
+ isContractAddress,
322
+ toStellarAsset
323
+ }