@ledgerhq/coin-stellar 6.26.0 → 6.26.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/.oxlintrc.json +7 -0
- package/CHANGELOG.md +6 -0
- package/LICENSE +194 -0
- package/knip.json +12 -0
- package/lib/api/index.d.ts +5 -5
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +12 -10
- package/lib/api/index.js.map +1 -1
- package/lib/config.d.ts +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +2 -0
- package/lib/config.js.map +1 -1
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +3 -1
- package/lib/constants.js.map +1 -1
- package/lib/logic/broadcast.d.ts.map +1 -1
- package/lib/logic/broadcast.js +2 -0
- package/lib/logic/broadcast.js.map +1 -1
- package/lib/logic/combine.d.ts +1 -1
- package/lib/logic/combine.d.ts.map +1 -1
- package/lib/logic/combine.js +2 -0
- package/lib/logic/combine.js.map +1 -1
- package/lib/logic/common.d.ts +1 -1
- package/lib/logic/common.d.ts.map +1 -1
- package/lib/logic/common.js +4 -2
- package/lib/logic/common.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +1 -1
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +10 -8
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +2 -0
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/getBalance.d.ts +1 -1
- package/lib/logic/getBalance.d.ts.map +1 -1
- package/lib/logic/getBalance.js +4 -2
- package/lib/logic/getBalance.js.map +1 -1
- package/lib/logic/getBlock.d.ts +1 -1
- package/lib/logic/getBlock.d.ts.map +1 -1
- package/lib/logic/getBlock.js +39 -34
- package/lib/logic/getBlock.js.map +1 -1
- package/lib/logic/getBlockInfo.d.ts +1 -1
- package/lib/logic/getBlockInfo.d.ts.map +1 -1
- package/lib/logic/getBlockInfo.js +2 -0
- package/lib/logic/getBlockInfo.js.map +1 -1
- package/lib/logic/index.d.ts +12 -12
- package/lib/logic/index.d.ts.map +1 -1
- package/lib/logic/index.js +2 -0
- package/lib/logic/index.js.map +1 -1
- package/lib/logic/lastBlock.d.ts +1 -1
- package/lib/logic/lastBlock.d.ts.map +1 -1
- package/lib/logic/lastBlock.js +2 -0
- package/lib/logic/lastBlock.js.map +1 -1
- package/lib/logic/listOperations.d.ts +1 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +6 -4
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/sdkWrapper.d.ts +1 -1
- package/lib/logic/sdkWrapper.d.ts.map +1 -1
- package/lib/logic/sdkWrapper.js +2 -0
- package/lib/logic/sdkWrapper.js.map +1 -1
- package/lib/logic/utils.d.ts.map +1 -1
- package/lib/logic/utils.js +4 -2
- package/lib/logic/utils.js.map +1 -1
- package/lib/logic/validateAddress.d.ts +1 -1
- package/lib/logic/validateAddress.d.ts.map +1 -1
- package/lib/logic/validateAddress.js +2 -0
- package/lib/logic/validateAddress.js.map +1 -1
- package/lib/logic/validateIntent.d.ts +2 -2
- package/lib/logic/validateIntent.d.ts.map +1 -1
- package/lib/logic/validateIntent.js +21 -19
- package/lib/logic/validateIntent.js.map +1 -1
- package/lib/logic/validateMemo.d.ts +1 -1
- package/lib/logic/validateMemo.d.ts.map +1 -1
- package/lib/logic/validateMemo.js +7 -5
- package/lib/logic/validateMemo.js.map +1 -1
- package/lib/network/horizon.d.ts +6 -7
- package/lib/network/horizon.d.ts.map +1 -1
- package/lib/network/horizon.js +71 -68
- package/lib/network/horizon.js.map +1 -1
- package/lib/network/horizonLedgerErrors.d.ts.map +1 -1
- package/lib/network/horizonLedgerErrors.js +5 -3
- package/lib/network/horizonLedgerErrors.js.map +1 -1
- package/lib/network/index.d.ts +1 -1
- package/lib/network/index.d.ts.map +1 -1
- package/lib/network/index.js +2 -0
- package/lib/network/index.js.map +1 -1
- package/lib/network/serialization.d.ts +6 -4
- package/lib/network/serialization.d.ts.map +1 -1
- package/lib/network/serialization.js +95 -91
- package/lib/network/serialization.js.map +1 -1
- package/lib/polyfill.d.ts.map +1 -1
- package/lib/polyfill.js +6 -4
- package/lib/polyfill.js.map +1 -1
- package/lib/supportedFeatures.d.ts +1 -1
- package/lib/supportedFeatures.d.ts.map +1 -1
- package/lib/supportedFeatures.js +3 -1
- package/lib/supportedFeatures.js.map +1 -1
- package/lib/types/errors.d.ts.map +1 -1
- package/lib/types/errors.js +14 -12
- package/lib/types/errors.js.map +1 -1
- package/lib/types/index.d.ts +2 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -0
- package/lib/types/index.js.map +1 -1
- package/lib/types/model.d.ts +6 -6
- package/lib/types/model.d.ts.map +1 -1
- package/lib/types/model.js +7 -5
- package/lib/types/model.js.map +1 -1
- package/lib-es/api/index.d.ts +5 -5
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +20 -18
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/config.d.ts +1 -1
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js +3 -1
- package/lib-es/config.js.map +1 -1
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +3 -1
- package/lib-es/constants.js.map +1 -1
- package/lib-es/logic/broadcast.d.ts.map +1 -1
- package/lib-es/logic/broadcast.js +3 -1
- package/lib-es/logic/broadcast.js.map +1 -1
- package/lib-es/logic/combine.d.ts +1 -1
- package/lib-es/logic/combine.d.ts.map +1 -1
- package/lib-es/logic/combine.js +3 -1
- package/lib-es/logic/combine.js.map +1 -1
- package/lib-es/logic/common.d.ts +1 -1
- package/lib-es/logic/common.d.ts.map +1 -1
- package/lib-es/logic/common.js +5 -3
- package/lib-es/logic/common.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +1 -1
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +15 -13
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +3 -1
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/getBalance.d.ts +1 -1
- package/lib-es/logic/getBalance.d.ts.map +1 -1
- package/lib-es/logic/getBalance.js +5 -3
- package/lib-es/logic/getBalance.js.map +1 -1
- package/lib-es/logic/getBlock.d.ts +1 -1
- package/lib-es/logic/getBlock.d.ts.map +1 -1
- package/lib-es/logic/getBlock.js +42 -37
- package/lib-es/logic/getBlock.js.map +1 -1
- package/lib-es/logic/getBlockInfo.d.ts +1 -1
- package/lib-es/logic/getBlockInfo.d.ts.map +1 -1
- package/lib-es/logic/getBlockInfo.js +3 -1
- package/lib-es/logic/getBlockInfo.js.map +1 -1
- package/lib-es/logic/index.d.ts +12 -12
- package/lib-es/logic/index.d.ts.map +1 -1
- package/lib-es/logic/index.js +14 -12
- package/lib-es/logic/index.js.map +1 -1
- package/lib-es/logic/lastBlock.d.ts +1 -1
- package/lib-es/logic/lastBlock.d.ts.map +1 -1
- package/lib-es/logic/lastBlock.js +3 -1
- package/lib-es/logic/lastBlock.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts +1 -1
- package/lib-es/logic/listOperations.d.ts.map +1 -1
- package/lib-es/logic/listOperations.js +7 -5
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/sdkWrapper.d.ts +1 -1
- package/lib-es/logic/sdkWrapper.d.ts.map +1 -1
- package/lib-es/logic/sdkWrapper.js +4 -2
- package/lib-es/logic/sdkWrapper.js.map +1 -1
- package/lib-es/logic/utils.d.ts.map +1 -1
- package/lib-es/logic/utils.js +6 -4
- package/lib-es/logic/utils.js.map +1 -1
- package/lib-es/logic/validateAddress.d.ts +1 -1
- package/lib-es/logic/validateAddress.d.ts.map +1 -1
- package/lib-es/logic/validateAddress.js +3 -1
- package/lib-es/logic/validateAddress.js.map +1 -1
- package/lib-es/logic/validateIntent.d.ts +2 -2
- package/lib-es/logic/validateIntent.d.ts.map +1 -1
- package/lib-es/logic/validateIntent.js +30 -28
- package/lib-es/logic/validateIntent.js.map +1 -1
- package/lib-es/logic/validateMemo.d.ts +1 -1
- package/lib-es/logic/validateMemo.d.ts.map +1 -1
- package/lib-es/logic/validateMemo.js +8 -6
- package/lib-es/logic/validateMemo.js.map +1 -1
- package/lib-es/network/horizon.d.ts +6 -7
- package/lib-es/network/horizon.d.ts.map +1 -1
- package/lib-es/network/horizon.js +80 -77
- package/lib-es/network/horizon.js.map +1 -1
- package/lib-es/network/horizonLedgerErrors.d.ts.map +1 -1
- package/lib-es/network/horizonLedgerErrors.js +7 -5
- package/lib-es/network/horizonLedgerErrors.js.map +1 -1
- package/lib-es/network/index.d.ts +1 -1
- package/lib-es/network/index.d.ts.map +1 -1
- package/lib-es/network/index.js +3 -1
- package/lib-es/network/index.js.map +1 -1
- package/lib-es/network/serialization.d.ts +6 -4
- package/lib-es/network/serialization.d.ts.map +1 -1
- package/lib-es/network/serialization.js +97 -95
- package/lib-es/network/serialization.js.map +1 -1
- package/lib-es/polyfill.d.ts.map +1 -1
- package/lib-es/polyfill.js +7 -5
- package/lib-es/polyfill.js.map +1 -1
- package/lib-es/supportedFeatures.d.ts +1 -1
- package/lib-es/supportedFeatures.d.ts.map +1 -1
- package/lib-es/supportedFeatures.js +3 -1
- package/lib-es/supportedFeatures.js.map +1 -1
- package/lib-es/types/errors.d.ts.map +1 -1
- package/lib-es/types/errors.js +15 -13
- package/lib-es/types/errors.js.map +1 -1
- package/lib-es/types/index.d.ts +2 -2
- package/lib-es/types/index.d.ts.map +1 -1
- package/lib-es/types/index.js +4 -2
- package/lib-es/types/index.js.map +1 -1
- package/lib-es/types/model.d.ts +6 -6
- package/lib-es/types/model.d.ts.map +1 -1
- package/lib-es/types/model.js +7 -5
- package/lib-es/types/model.js.map +1 -1
- package/package.json +13 -16
- package/src/api/index.integ.test.ts +165 -162
- package/src/api/index.test.ts +106 -103
- package/src/api/index.ts +49 -46
- package/src/api/index_error.test.ts +48 -25
- package/src/config.ts +15 -12
- package/src/constants.ts +4 -1
- package/src/globals.d.ts +7 -5
- package/src/logic/broadcast.integ.test.ts +22 -19
- package/src/logic/broadcast.ts +5 -2
- package/src/logic/combine.test.ts +18 -15
- package/src/logic/combine.ts +8 -5
- package/src/logic/common.ts +9 -6
- package/src/logic/craftTransaction.test.ts +76 -75
- package/src/logic/craftTransaction.ts +46 -43
- package/src/logic/estimateFees.ts +6 -3
- package/src/logic/getBalance.test.ts +31 -28
- package/src/logic/getBalance.ts +13 -10
- package/src/logic/getBlock.integ.test.ts +40 -39
- package/src/logic/getBlock.test.ts +462 -415
- package/src/logic/getBlock.ts +142 -127
- package/src/logic/getBlockInfo.test.ts +72 -69
- package/src/logic/getBlockInfo.ts +15 -12
- package/src/logic/index.ts +15 -12
- package/src/logic/lastBlock.ts +6 -3
- package/src/logic/listOperations.ts +14 -11
- package/src/logic/listOperations.unit.test.ts +212 -209
- package/src/logic/networkWrappers.test.ts +32 -29
- package/src/logic/sdkWrapper.ts +19 -16
- package/src/logic/utils.ts +13 -10
- package/src/logic/validateAddress.test.ts +21 -18
- package/src/logic/validateAddress.ts +7 -4
- package/src/logic/validateIntent.test.ts +62 -59
- package/src/logic/validateIntent.ts +87 -84
- package/src/logic/validateMemo.test.ts +50 -47
- package/src/logic/validateMemo.ts +16 -13
- package/src/network/broadcastTransaction.test.ts +60 -60
- package/src/network/fetchLedgerOperations.unit.test.ts +155 -0
- package/src/network/horizon.integ.test.ts +45 -42
- package/src/network/horizon.test.ts +17 -14
- package/src/network/horizon.ts +279 -281
- package/src/network/horizon.unit.test.ts +238 -237
- package/src/network/horizonLedgerErrors.test.ts +81 -78
- package/src/network/horizonLedgerErrors.ts +22 -19
- package/src/network/index.ts +4 -1
- package/src/network/registerHorizonInterceptors.test.ts +163 -160
- package/src/network/serialization.ts +232 -227
- package/src/network/serialization.unit.test.ts +801 -798
- package/src/polyfill.ts +18 -15
- package/src/supportedFeatures.ts +6 -3
- package/src/types/errors.ts +33 -32
- package/src/types/index.ts +5 -2
- package/src/types/model.ts +55 -52
- package/tsconfig.json +1 -1
- package/.unimportedrc.json +0 -17
- package/LICENSE.txt +0 -21
- package/src/network/fetchLedgerOperations.nock.unit.test.ts +0 -156
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { BalanceAsset, RawOperation, StellarMemo } from '../types'
|
|
1
5
|
/*
|
|
2
6
|
* Serialization functions from Horizon to Ledger Live types
|
|
3
7
|
*/
|
|
4
|
-
import type { Operation } from
|
|
5
|
-
import { Horizon } from
|
|
6
|
-
import BigNumber from
|
|
7
|
-
import
|
|
8
|
-
import { parseAPIValue } from "../logic/common";
|
|
8
|
+
import type { Operation } from '@ledgerhq/coin-module-framework/api/types'
|
|
9
|
+
import { Horizon } from '@stellar/stellar-sdk'
|
|
10
|
+
import BigNumber from 'bignumber.js'
|
|
11
|
+
import { parseAPIValue } from '../logic/common'
|
|
9
12
|
|
|
10
13
|
// Constants
|
|
11
|
-
const BASE_RESERVE_MIN_COUNT = 2
|
|
12
|
-
export const BASE_RESERVE = 0.5
|
|
13
|
-
export const MIN_BALANCE = 1
|
|
14
|
+
const BASE_RESERVE_MIN_COUNT = 2
|
|
15
|
+
export const BASE_RESERVE = 0.5
|
|
16
|
+
export const MIN_BALANCE = 1
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Stellar operation types that produce a typed (non-FEES) Operation when the
|
|
@@ -18,37 +21,37 @@ export const MIN_BALANCE = 1;
|
|
|
18
21
|
* the address paid the fee) — see `formatFeeOnlyOperation`.
|
|
19
22
|
*/
|
|
20
23
|
const SUPPORTED_OPERATION_TYPES = new Set<string>([
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
])
|
|
24
|
+
'create_account',
|
|
25
|
+
'payment',
|
|
26
|
+
'path_payment_strict_send',
|
|
27
|
+
'path_payment_strict_receive',
|
|
28
|
+
'change_trust',
|
|
29
|
+
'liquidity_pool_deposit',
|
|
30
|
+
'liquidity_pool_withdraw',
|
|
31
|
+
])
|
|
29
32
|
|
|
30
33
|
export function getReservedBalance(account: Horizon.ServerApi.AccountRecord): BigNumber {
|
|
31
|
-
const numOfSponsoringEntries = Number(account.num_sponsoring)
|
|
32
|
-
const numOfSponsoredEntries = Number(account.num_sponsored)
|
|
34
|
+
const numOfSponsoringEntries = Number(account.num_sponsoring)
|
|
35
|
+
const numOfSponsoredEntries = Number(account.num_sponsored)
|
|
33
36
|
|
|
34
|
-
const nativeAsset = account.balances?.find(b => b.asset_type ===
|
|
37
|
+
const nativeAsset = account.balances?.find((b) => b.asset_type === 'native') as BalanceAsset
|
|
35
38
|
|
|
36
|
-
const amountInOffers = new BigNumber(nativeAsset?.selling_liabilities || 0)
|
|
37
|
-
const numOfEntries = new BigNumber(account.subentry_count || 0)
|
|
39
|
+
const amountInOffers = new BigNumber(nativeAsset?.selling_liabilities || 0)
|
|
40
|
+
const numOfEntries = new BigNumber(account.subentry_count || 0)
|
|
38
41
|
|
|
39
42
|
return new BigNumber(BASE_RESERVE_MIN_COUNT)
|
|
40
43
|
.plus(numOfEntries)
|
|
41
44
|
.plus(numOfSponsoringEntries)
|
|
42
45
|
.minus(numOfSponsoredEntries)
|
|
43
46
|
.times(BASE_RESERVE)
|
|
44
|
-
.plus(amountInOffers)
|
|
47
|
+
.plus(amountInOffers)
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export async function rawOperationsToOperations(
|
|
48
51
|
operations: RawOperation[],
|
|
49
52
|
addr: string,
|
|
50
53
|
accountId: string,
|
|
51
|
-
minHeight: number
|
|
54
|
+
minHeight: number
|
|
52
55
|
): Promise<Operation[]> {
|
|
53
56
|
// First pass: per raw op, format it when it passes the address+type filters.
|
|
54
57
|
// A single raw op can produce zero, one, or several `Operation` rows (e.g.
|
|
@@ -56,16 +59,16 @@ export async function rawOperationsToOperations(
|
|
|
56
59
|
// token destination credit; a liquidity_pool_deposit surfaces one row per
|
|
57
60
|
// deposited reserve).
|
|
58
61
|
const formatted = await Promise.all(
|
|
59
|
-
operations.map(async operation => {
|
|
60
|
-
if (!operationInvolvesAddress(operation, addr)) return []
|
|
61
|
-
if (!SUPPORTED_OPERATION_TYPES.has(operation.type)) return []
|
|
62
|
-
return formatOperation(operation, accountId, addr, minHeight)
|
|
63
|
-
})
|
|
64
|
-
)
|
|
62
|
+
operations.map(async (operation) => {
|
|
63
|
+
if (!operationInvolvesAddress(operation, addr)) return []
|
|
64
|
+
if (!SUPPORTED_OPERATION_TYPES.has(operation.type)) return []
|
|
65
|
+
return formatOperation(operation, accountId, addr, minHeight)
|
|
66
|
+
})
|
|
67
|
+
)
|
|
65
68
|
|
|
66
69
|
// Stellar transactions whose fee is already carried by at least one surfaced
|
|
67
70
|
// Operation. We never emit a redundant fee row for these.
|
|
68
|
-
const txHashesAlreadySurfaced = new Set(formatted.flat().map(op => op.tx.hash))
|
|
71
|
+
const txHashesAlreadySurfaced = new Set(formatted.flat().map((op) => op.tx.hash))
|
|
69
72
|
|
|
70
73
|
// Second pass: for every Stellar tx the address actually paid the fee on but
|
|
71
74
|
// that produced no surfaced Operation (e.g. `create_claimable_balance`-only,
|
|
@@ -73,23 +76,23 @@ export async function rawOperationsToOperations(
|
|
|
73
76
|
// Operation so its `fee_charged` is not silently dropped from the operations
|
|
74
77
|
// list. We slot it at the position of the first raw op of that tx in the
|
|
75
78
|
// input order to preserve the page's descending order.
|
|
76
|
-
const feeOnlyEmitted = new Set<string>()
|
|
79
|
+
const feeOnlyEmitted = new Set<string>()
|
|
77
80
|
const feeOnly = await Promise.all(
|
|
78
|
-
operations.map(async operation => {
|
|
79
|
-
if (txHashesAlreadySurfaced.has(operation.transaction_hash)) return undefined
|
|
80
|
-
if (feeOnlyEmitted.has(operation.transaction_hash)) return undefined
|
|
81
|
-
feeOnlyEmitted.add(operation.transaction_hash)
|
|
82
|
-
return formatFeeOnlyOperation(operation, accountId, addr, minHeight)
|
|
83
|
-
})
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
const result: Operation[] = []
|
|
81
|
+
operations.map(async (operation) => {
|
|
82
|
+
if (txHashesAlreadySurfaced.has(operation.transaction_hash)) return undefined
|
|
83
|
+
if (feeOnlyEmitted.has(operation.transaction_hash)) return undefined
|
|
84
|
+
feeOnlyEmitted.add(operation.transaction_hash)
|
|
85
|
+
return formatFeeOnlyOperation(operation, accountId, addr, minHeight)
|
|
86
|
+
})
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const result: Operation[] = []
|
|
87
90
|
for (let i = 0; i < operations.length; i++) {
|
|
88
|
-
const feeOp = feeOnly[i]
|
|
89
|
-
if (feeOp) result.push(feeOp)
|
|
90
|
-
result.push(...formatted[i])
|
|
91
|
+
const feeOp = feeOnly[i]
|
|
92
|
+
if (feeOp) result.push(feeOp)
|
|
93
|
+
result.push(...formatted[i])
|
|
91
94
|
}
|
|
92
|
-
return result
|
|
95
|
+
return result
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
function operationInvolvesAddress(operation: RawOperation, addr: string): boolean {
|
|
@@ -100,38 +103,38 @@ function operationInvolvesAddress(operation: RawOperation, addr: string): boolea
|
|
|
100
103
|
operation.account === addr ||
|
|
101
104
|
operation.trustor === addr ||
|
|
102
105
|
operation.source_account === addr
|
|
103
|
-
)
|
|
106
|
+
)
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
type FormatCtx = {
|
|
107
|
-
rawOperation: RawOperation
|
|
108
|
-
accountId: string
|
|
109
|
-
addr: string
|
|
110
|
-
transaction: Awaited<ReturnType<RawOperation[
|
|
111
|
-
baseTxFields: Operation[
|
|
110
|
+
rawOperation: RawOperation
|
|
111
|
+
accountId: string
|
|
112
|
+
addr: string
|
|
113
|
+
transaction: Awaited<ReturnType<RawOperation['transaction']>>
|
|
114
|
+
baseTxFields: Operation['tx']
|
|
112
115
|
baseDetails: {
|
|
113
|
-
pagingToken: string
|
|
114
|
-
blockTime: Date
|
|
115
|
-
index: string
|
|
116
|
-
memo: StellarMemo | undefined
|
|
117
|
-
sequence: string | undefined
|
|
118
|
-
}
|
|
119
|
-
}
|
|
116
|
+
pagingToken: string
|
|
117
|
+
blockTime: Date
|
|
118
|
+
index: string
|
|
119
|
+
memo: StellarMemo | undefined
|
|
120
|
+
sequence: string | undefined
|
|
121
|
+
}
|
|
122
|
+
}
|
|
120
123
|
|
|
121
124
|
async function formatOperation(
|
|
122
125
|
rawOperation: RawOperation,
|
|
123
126
|
accountId: string,
|
|
124
127
|
addr: string,
|
|
125
|
-
minHeight: number
|
|
128
|
+
minHeight: number
|
|
126
129
|
): Promise<Operation[]> {
|
|
127
|
-
const transaction = await rawOperation.transaction()
|
|
130
|
+
const transaction = await rawOperation.transaction()
|
|
128
131
|
|
|
129
|
-
if (transaction.ledger_attr < minHeight) return []
|
|
132
|
+
if (transaction.ledger_attr < minHeight) return []
|
|
130
133
|
|
|
131
|
-
const { hash: blockHash, closed_at: blockTime } = await transaction.ledger()
|
|
132
|
-
const memo = decodeMemo(transaction)
|
|
134
|
+
const { hash: blockHash, closed_at: blockTime } = await transaction.ledger()
|
|
135
|
+
const memo = decodeMemo(transaction)
|
|
133
136
|
|
|
134
|
-
const baseTxFields: Operation[
|
|
137
|
+
const baseTxFields: Operation['tx'] = {
|
|
135
138
|
hash: rawOperation.transaction_hash,
|
|
136
139
|
block: {
|
|
137
140
|
hash: blockHash,
|
|
@@ -142,7 +145,7 @@ async function formatOperation(
|
|
|
142
145
|
date: new Date(rawOperation.created_at),
|
|
143
146
|
failed: !rawOperation.transaction_successful,
|
|
144
147
|
...(transaction.fee_account ? { feesPayer: transaction.fee_account } : {}),
|
|
145
|
-
}
|
|
148
|
+
}
|
|
146
149
|
|
|
147
150
|
const baseDetails = {
|
|
148
151
|
pagingToken: rawOperation.paging_token,
|
|
@@ -150,7 +153,7 @@ async function formatOperation(
|
|
|
150
153
|
index: rawOperation.id,
|
|
151
154
|
memo,
|
|
152
155
|
sequence: parseSequence(transaction.source_account_sequence),
|
|
153
|
-
}
|
|
156
|
+
}
|
|
154
157
|
|
|
155
158
|
const ctx: FormatCtx = {
|
|
156
159
|
rawOperation,
|
|
@@ -159,24 +162,24 @@ async function formatOperation(
|
|
|
159
162
|
transaction,
|
|
160
163
|
baseTxFields,
|
|
161
164
|
baseDetails,
|
|
162
|
-
}
|
|
165
|
+
}
|
|
163
166
|
|
|
164
167
|
switch (rawOperation.type) {
|
|
165
|
-
case
|
|
166
|
-
case
|
|
167
|
-
return formatPathPayment(ctx)
|
|
168
|
-
case
|
|
169
|
-
return formatLiquidityPoolDeposit(ctx)
|
|
170
|
-
case
|
|
171
|
-
return formatLiquidityPoolWithdraw(ctx)
|
|
168
|
+
case 'path_payment_strict_send':
|
|
169
|
+
case 'path_payment_strict_receive':
|
|
170
|
+
return formatPathPayment(ctx)
|
|
171
|
+
case 'liquidity_pool_deposit':
|
|
172
|
+
return formatLiquidityPoolDeposit(ctx)
|
|
173
|
+
case 'liquidity_pool_withdraw':
|
|
174
|
+
return formatLiquidityPoolWithdraw(ctx)
|
|
172
175
|
default:
|
|
173
|
-
return formatSimpleOperation(ctx)
|
|
176
|
+
return formatSimpleOperation(ctx)
|
|
174
177
|
}
|
|
175
178
|
}
|
|
176
179
|
|
|
177
|
-
function parseSequence(seq: string | number | undefined): string | undefined {
|
|
178
|
-
const bn = new BigNumber(seq ??
|
|
179
|
-
return bn.isNaN() ? undefined : bn.toString()
|
|
180
|
+
export function parseSequence(seq: string | number | undefined): string | undefined {
|
|
181
|
+
const bn = new BigNumber(seq ?? '')
|
|
182
|
+
return bn.isNaN() ? undefined : bn.toString()
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
/**
|
|
@@ -187,14 +190,14 @@ function parseSequence(seq: string | number | undefined): string | undefined {
|
|
|
187
190
|
* on `details.assetAmount` for the sub-account adapter to consume.
|
|
188
191
|
*/
|
|
189
192
|
function formatSimpleOperation(ctx: FormatCtx): Operation[] {
|
|
190
|
-
const { rawOperation, accountId, transaction, baseTxFields, baseDetails, addr } = ctx
|
|
191
|
-
const type = getSimpleOperationType(rawOperation, addr)
|
|
192
|
-
const value = getSimpleOperationValue(rawOperation, transaction, type)
|
|
193
|
-
const recipients = getRecipients(rawOperation)
|
|
193
|
+
const { rawOperation, accountId, transaction, baseTxFields, baseDetails, addr } = ctx
|
|
194
|
+
const type = getSimpleOperationType(rawOperation, addr)
|
|
195
|
+
const value = getSimpleOperationValue(rawOperation, transaction, type)
|
|
196
|
+
const recipients = getRecipients(rawOperation)
|
|
194
197
|
|
|
195
|
-
const isToken = !!(rawOperation.asset_code && rawOperation.asset_issuer)
|
|
196
|
-
const finalType = isToken && ![
|
|
197
|
-
const finalValue = isToken ? BigInt(transaction.fee_charged) : BigInt(value.toString())
|
|
198
|
+
const isToken = !!(rawOperation.asset_code && rawOperation.asset_issuer)
|
|
199
|
+
const finalType = isToken && !['OPT_IN', 'OPT_OUT'].includes(type) ? 'NONE' : type
|
|
200
|
+
const finalValue = isToken ? BigInt(transaction.fee_charged) : BigInt(value.toString())
|
|
198
201
|
|
|
199
202
|
return [
|
|
200
203
|
{
|
|
@@ -207,11 +210,11 @@ function formatSimpleOperation(ctx: FormatCtx): Operation[] {
|
|
|
207
210
|
asset:
|
|
208
211
|
isToken && rawOperation.asset_code && rawOperation.asset_issuer
|
|
209
212
|
? {
|
|
210
|
-
type:
|
|
213
|
+
type: 'token',
|
|
211
214
|
assetReference: rawOperation.asset_code,
|
|
212
215
|
assetOwner: rawOperation.asset_issuer,
|
|
213
216
|
}
|
|
214
|
-
: { type:
|
|
217
|
+
: { type: 'native' },
|
|
215
218
|
details: {
|
|
216
219
|
...baseDetails,
|
|
217
220
|
assetCode: rawOperation.asset_code,
|
|
@@ -220,7 +223,7 @@ function formatSimpleOperation(ctx: FormatCtx): Operation[] {
|
|
|
220
223
|
ledgerOpType: type,
|
|
221
224
|
},
|
|
222
225
|
},
|
|
223
|
-
]
|
|
226
|
+
]
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
// ===== path_payment_strict_send / path_payment_strict_receive =====
|
|
@@ -240,57 +243,57 @@ function formatSimpleOperation(ctx: FormatCtx): Operation[] {
|
|
|
240
243
|
* convention with the real token amount written to `details.assetAmount`.
|
|
241
244
|
*/
|
|
242
245
|
function formatPathPayment(ctx: FormatCtx): Operation[] {
|
|
243
|
-
const { rawOperation, addr } = ctx
|
|
244
|
-
const ops: Operation[] = []
|
|
245
|
-
const isSource = rawOperation.from === addr
|
|
246
|
-
const isDest = rawOperation.to === addr
|
|
247
|
-
const isMultiLeg = isSource && isDest
|
|
248
|
-
const sourceAsset = readSourceAsset(rawOperation)
|
|
249
|
-
const destAsset = readDestAsset(rawOperation)
|
|
246
|
+
const { rawOperation, addr } = ctx
|
|
247
|
+
const ops: Operation[] = []
|
|
248
|
+
const isSource = rawOperation.from === addr
|
|
249
|
+
const isDest = rawOperation.to === addr
|
|
250
|
+
const isMultiLeg = isSource && isDest
|
|
251
|
+
const sourceAsset = readSourceAsset(rawOperation)
|
|
252
|
+
const destAsset = readDestAsset(rawOperation)
|
|
250
253
|
const pathOp = rawOperation as RawOperation & {
|
|
251
|
-
source_amount?: string
|
|
252
|
-
amount?: string
|
|
253
|
-
}
|
|
254
|
+
source_amount?: string
|
|
255
|
+
amount?: string
|
|
256
|
+
}
|
|
254
257
|
|
|
255
258
|
if (isSource) {
|
|
256
|
-
const amountStr = pathOp.source_amount ?? pathOp.amount ??
|
|
257
|
-
ops.push(buildPathPaymentLeg(ctx,
|
|
259
|
+
const amountStr = pathOp.source_amount ?? pathOp.amount ?? '0'
|
|
260
|
+
ops.push(buildPathPaymentLeg(ctx, 'OUT', sourceAsset, parseAPIValue(amountStr), isMultiLeg))
|
|
258
261
|
}
|
|
259
262
|
|
|
260
263
|
if (isDest) {
|
|
261
|
-
const amountStr = pathOp.amount ??
|
|
262
|
-
ops.push(buildPathPaymentLeg(ctx,
|
|
264
|
+
const amountStr = pathOp.amount ?? '0'
|
|
265
|
+
ops.push(buildPathPaymentLeg(ctx, 'IN', destAsset, parseAPIValue(amountStr), isMultiLeg))
|
|
263
266
|
}
|
|
264
267
|
|
|
265
|
-
return ops
|
|
268
|
+
return ops
|
|
266
269
|
}
|
|
267
270
|
|
|
268
|
-
type AssetInfo = { type:
|
|
271
|
+
type AssetInfo = { type: 'native' } | { type: 'token'; code: string; issuer: string }
|
|
269
272
|
|
|
270
273
|
function readSourceAsset(rawOperation: RawOperation): AssetInfo {
|
|
271
274
|
const o = rawOperation as RawOperation & {
|
|
272
|
-
source_asset_type?: string
|
|
273
|
-
source_asset_code?: string
|
|
274
|
-
source_asset_issuer?: string
|
|
275
|
-
}
|
|
276
|
-
if (o.source_asset_type ===
|
|
275
|
+
source_asset_type?: string
|
|
276
|
+
source_asset_code?: string
|
|
277
|
+
source_asset_issuer?: string
|
|
278
|
+
}
|
|
279
|
+
if (o.source_asset_type === 'native') return { type: 'native' }
|
|
277
280
|
if (o.source_asset_code && o.source_asset_issuer) {
|
|
278
|
-
return { type:
|
|
281
|
+
return { type: 'token', code: o.source_asset_code, issuer: o.source_asset_issuer }
|
|
279
282
|
}
|
|
280
|
-
return { type:
|
|
283
|
+
return { type: 'native' }
|
|
281
284
|
}
|
|
282
285
|
|
|
283
286
|
function readDestAsset(rawOperation: RawOperation): AssetInfo {
|
|
284
|
-
const o = rawOperation as RawOperation & { asset_type?: string }
|
|
285
|
-
if (o.asset_type ===
|
|
287
|
+
const o = rawOperation as RawOperation & { asset_type?: string }
|
|
288
|
+
if (o.asset_type === 'native') return { type: 'native' }
|
|
286
289
|
if (rawOperation.asset_code && rawOperation.asset_issuer) {
|
|
287
290
|
return {
|
|
288
|
-
type:
|
|
291
|
+
type: 'token',
|
|
289
292
|
code: rawOperation.asset_code,
|
|
290
293
|
issuer: rawOperation.asset_issuer,
|
|
291
|
-
}
|
|
294
|
+
}
|
|
292
295
|
}
|
|
293
|
-
return { type:
|
|
296
|
+
return { type: 'native' }
|
|
294
297
|
}
|
|
295
298
|
|
|
296
299
|
// Match the existing failed-tx convention: IN rows go to 0, OUT rows carry the
|
|
@@ -298,79 +301,79 @@ function readDestAsset(rawOperation: RawOperation): AssetInfo {
|
|
|
298
301
|
// non-path-payment failure (see `getSimpleOperationValue`).
|
|
299
302
|
function computeLegValue(
|
|
300
303
|
isFailed: boolean,
|
|
301
|
-
direction:
|
|
304
|
+
direction: 'IN' | 'OUT',
|
|
302
305
|
isNative: boolean,
|
|
303
306
|
amount: BigNumber,
|
|
304
|
-
feeCharged: string | number
|
|
307
|
+
feeCharged: string | number
|
|
305
308
|
): bigint {
|
|
306
309
|
if (isFailed) {
|
|
307
|
-
return direction ===
|
|
310
|
+
return direction === 'IN' ? 0n : BigInt(feeCharged)
|
|
308
311
|
}
|
|
309
|
-
return isNative ? BigInt(amount.toString()) : BigInt(feeCharged)
|
|
312
|
+
return isNative ? BigInt(amount.toString()) : BigInt(feeCharged)
|
|
310
313
|
}
|
|
311
314
|
|
|
312
315
|
type LegAssetFields = {
|
|
313
|
-
label: string
|
|
314
|
-
asset: Operation[
|
|
315
|
-
assetCode: string | undefined
|
|
316
|
-
assetIssuer: string | undefined
|
|
317
|
-
assetAmount: string | undefined
|
|
318
|
-
}
|
|
316
|
+
label: string
|
|
317
|
+
asset: Operation['asset']
|
|
318
|
+
assetCode: string | undefined
|
|
319
|
+
assetIssuer: string | undefined
|
|
320
|
+
assetAmount: string | undefined
|
|
321
|
+
}
|
|
319
322
|
|
|
320
323
|
function describeLegAsset(asset: AssetInfo, amount: BigNumber): LegAssetFields {
|
|
321
|
-
if (asset.type ===
|
|
324
|
+
if (asset.type === 'native') {
|
|
322
325
|
return {
|
|
323
|
-
label:
|
|
324
|
-
asset: { type:
|
|
326
|
+
label: 'NATIVE',
|
|
327
|
+
asset: { type: 'native' },
|
|
325
328
|
assetCode: undefined,
|
|
326
329
|
assetIssuer: undefined,
|
|
327
330
|
assetAmount: undefined,
|
|
328
|
-
}
|
|
331
|
+
}
|
|
329
332
|
}
|
|
330
333
|
return {
|
|
331
334
|
label: `TOKEN-${asset.code}`,
|
|
332
|
-
asset: { type:
|
|
335
|
+
asset: { type: 'token', assetReference: asset.code, assetOwner: asset.issuer },
|
|
333
336
|
assetCode: asset.code,
|
|
334
337
|
assetIssuer: asset.issuer,
|
|
335
338
|
assetAmount: amount.toString(),
|
|
336
|
-
}
|
|
339
|
+
}
|
|
337
340
|
}
|
|
338
341
|
|
|
339
342
|
function buildPathPaymentLeg(
|
|
340
343
|
{ rawOperation, accountId, addr, transaction, baseTxFields, baseDetails }: FormatCtx,
|
|
341
|
-
direction:
|
|
344
|
+
direction: 'IN' | 'OUT',
|
|
342
345
|
asset: AssetInfo,
|
|
343
346
|
amount: BigNumber,
|
|
344
|
-
isMultiLeg: boolean
|
|
347
|
+
isMultiLeg: boolean
|
|
345
348
|
): Operation {
|
|
346
|
-
const isNative = asset.type ===
|
|
349
|
+
const isNative = asset.type === 'native'
|
|
347
350
|
const value = computeLegValue(
|
|
348
351
|
!rawOperation.transaction_successful,
|
|
349
352
|
direction,
|
|
350
353
|
isNative,
|
|
351
354
|
amount,
|
|
352
|
-
transaction.fee_charged
|
|
353
|
-
)
|
|
355
|
+
transaction.fee_charged
|
|
356
|
+
)
|
|
354
357
|
|
|
355
|
-
const ledgerOpType = isNative ? direction :
|
|
358
|
+
const ledgerOpType = isNative ? direction : 'NONE'
|
|
356
359
|
const {
|
|
357
360
|
label,
|
|
358
361
|
asset: opAsset,
|
|
359
362
|
assetCode,
|
|
360
363
|
assetIssuer,
|
|
361
364
|
assetAmount,
|
|
362
|
-
} = describeLegAsset(asset, amount)
|
|
363
|
-
const legSuffix = isMultiLeg ? `-${direction}-${label}` :
|
|
365
|
+
} = describeLegAsset(asset, amount)
|
|
366
|
+
const legSuffix = isMultiLeg ? `-${direction}-${label}` : ''
|
|
364
367
|
|
|
365
368
|
// Counterparties: for the OUT leg the recipient is whatever Horizon recorded
|
|
366
369
|
// as `to`; for the IN leg the sender is whoever Horizon recorded as `from`
|
|
367
370
|
// (or the operation's `source_account` when `from` is missing in test
|
|
368
371
|
// fixtures).
|
|
369
372
|
const senders =
|
|
370
|
-
direction ===
|
|
373
|
+
direction === 'OUT'
|
|
371
374
|
? [rawOperation.source_account]
|
|
372
|
-
: [rawOperation.from || rawOperation.source_account]
|
|
373
|
-
const recipients = direction ===
|
|
375
|
+
: [rawOperation.from || rawOperation.source_account]
|
|
376
|
+
const recipients = direction === 'OUT' ? [rawOperation.to || addr] : [addr]
|
|
374
377
|
|
|
375
378
|
return {
|
|
376
379
|
id: `${accountId}-${rawOperation.transaction_hash}-${ledgerOpType}${legSuffix}`,
|
|
@@ -388,7 +391,7 @@ function buildPathPaymentLeg(
|
|
|
388
391
|
assetAmount,
|
|
389
392
|
ledgerOpType,
|
|
390
393
|
},
|
|
391
|
-
}
|
|
394
|
+
}
|
|
392
395
|
}
|
|
393
396
|
|
|
394
397
|
// ===== liquidity_pool_deposit / liquidity_pool_withdraw =====
|
|
@@ -399,8 +402,8 @@ function buildPathPaymentLeg(
|
|
|
399
402
|
* which mirror the `liquidity_pool_deposited` effect).
|
|
400
403
|
*/
|
|
401
404
|
function formatLiquidityPoolDeposit(ctx: FormatCtx): Operation[] {
|
|
402
|
-
const reserves = readPoolReserves(ctx.rawOperation,
|
|
403
|
-
return reserves.map(reserve => buildPoolLeg(ctx,
|
|
405
|
+
const reserves = readPoolReserves(ctx.rawOperation, 'reserves_deposited')
|
|
406
|
+
return reserves.map((reserve) => buildPoolLeg(ctx, 'OUT', reserve, reserves.length > 1))
|
|
404
407
|
}
|
|
405
408
|
|
|
406
409
|
/**
|
|
@@ -409,63 +412,63 @@ function formatLiquidityPoolDeposit(ctx: FormatCtx): Operation[] {
|
|
|
409
412
|
* `reserves_received`, which mirror the `liquidity_pool_withdrew` effect).
|
|
410
413
|
*/
|
|
411
414
|
function formatLiquidityPoolWithdraw(ctx: FormatCtx): Operation[] {
|
|
412
|
-
const reserves = readPoolReserves(ctx.rawOperation,
|
|
413
|
-
return reserves.map(reserve => buildPoolLeg(ctx,
|
|
415
|
+
const reserves = readPoolReserves(ctx.rawOperation, 'reserves_received')
|
|
416
|
+
return reserves.map((reserve) => buildPoolLeg(ctx, 'IN', reserve, reserves.length > 1))
|
|
414
417
|
}
|
|
415
418
|
|
|
416
|
-
type PoolReserve = { asset: AssetInfo; amount: BigNumber }
|
|
419
|
+
type PoolReserve = { asset: AssetInfo; amount: BigNumber }
|
|
417
420
|
|
|
418
421
|
function readPoolReserves(
|
|
419
422
|
rawOperation: RawOperation,
|
|
420
|
-
field:
|
|
423
|
+
field: 'reserves_deposited' | 'reserves_received'
|
|
421
424
|
): PoolReserve[] {
|
|
422
425
|
const arr = (
|
|
423
426
|
rawOperation as RawOperation & {
|
|
424
|
-
reserves_deposited?: Array<{ asset: string; amount: string }
|
|
425
|
-
reserves_received?: Array<{ asset: string; amount: string }
|
|
427
|
+
reserves_deposited?: Array<{ asset: string; amount: string }>
|
|
428
|
+
reserves_received?: Array<{ asset: string; amount: string }>
|
|
426
429
|
}
|
|
427
|
-
)[field]
|
|
428
|
-
if (!arr || arr.length === 0) return []
|
|
429
|
-
return arr.map(r => ({
|
|
430
|
+
)[field]
|
|
431
|
+
if (!arr || arr.length === 0) return []
|
|
432
|
+
return arr.map((r) => ({
|
|
430
433
|
asset: parseAssetString(r.asset),
|
|
431
434
|
amount: parseAPIValue(r.amount),
|
|
432
|
-
}))
|
|
435
|
+
}))
|
|
433
436
|
}
|
|
434
437
|
|
|
435
438
|
function parseAssetString(asset: string): AssetInfo {
|
|
436
|
-
if (asset ===
|
|
437
|
-
const idx = asset.indexOf(
|
|
438
|
-
if (idx === -1) return { type:
|
|
439
|
+
if (asset === 'native') return { type: 'native' }
|
|
440
|
+
const idx = asset.indexOf(':')
|
|
441
|
+
if (idx === -1) return { type: 'native' }
|
|
439
442
|
return {
|
|
440
|
-
type:
|
|
443
|
+
type: 'token',
|
|
441
444
|
code: asset.slice(0, idx),
|
|
442
445
|
issuer: asset.slice(idx + 1),
|
|
443
|
-
}
|
|
446
|
+
}
|
|
444
447
|
}
|
|
445
448
|
|
|
446
449
|
function buildPoolLeg(
|
|
447
450
|
{ rawOperation, accountId, addr, transaction, baseTxFields, baseDetails }: FormatCtx,
|
|
448
|
-
direction:
|
|
451
|
+
direction: 'IN' | 'OUT',
|
|
449
452
|
reserve: PoolReserve,
|
|
450
|
-
isMultiLeg: boolean
|
|
453
|
+
isMultiLeg: boolean
|
|
451
454
|
): Operation {
|
|
452
|
-
const { asset, amount } = reserve
|
|
453
|
-
const isFailed = !rawOperation.transaction_successful
|
|
455
|
+
const { asset, amount } = reserve
|
|
456
|
+
const isFailed = !rawOperation.transaction_successful
|
|
454
457
|
const value = isFailed
|
|
455
|
-
? direction ===
|
|
458
|
+
? direction === 'IN'
|
|
456
459
|
? 0n
|
|
457
460
|
: BigInt(transaction.fee_charged)
|
|
458
|
-
: asset.type ===
|
|
461
|
+
: asset.type === 'native'
|
|
459
462
|
? BigInt(amount.toString())
|
|
460
|
-
: BigInt(transaction.fee_charged)
|
|
463
|
+
: BigInt(transaction.fee_charged)
|
|
461
464
|
|
|
462
|
-
const ledgerOpType = asset.type ===
|
|
465
|
+
const ledgerOpType = asset.type === 'native' ? direction : 'NONE'
|
|
463
466
|
// Pool ops always involve at least 2 reserves (one of which is usually
|
|
464
467
|
// native), so we always disambiguate per-leg ids/indices to avoid clashes
|
|
465
468
|
// when a single raw op produces multiple rows.
|
|
466
469
|
const legSuffix = isMultiLeg
|
|
467
|
-
? `-${asset.type ===
|
|
468
|
-
:
|
|
470
|
+
? `-${asset.type === 'native' ? 'NATIVE' : `TOKEN-${asset.code}`}`
|
|
471
|
+
: ''
|
|
469
472
|
|
|
470
473
|
return {
|
|
471
474
|
id: `${accountId}-${rawOperation.transaction_hash}-${ledgerOpType}${legSuffix}`,
|
|
@@ -475,18 +478,18 @@ function buildPoolLeg(
|
|
|
475
478
|
recipients: [],
|
|
476
479
|
tx: baseTxFields,
|
|
477
480
|
asset:
|
|
478
|
-
asset.type ===
|
|
479
|
-
? { type:
|
|
480
|
-
: { type:
|
|
481
|
+
asset.type === 'native'
|
|
482
|
+
? { type: 'native' }
|
|
483
|
+
: { type: 'token', assetReference: asset.code, assetOwner: asset.issuer },
|
|
481
484
|
details: {
|
|
482
485
|
...baseDetails,
|
|
483
486
|
index: isMultiLeg ? `${rawOperation.id}${legSuffix}` : rawOperation.id,
|
|
484
|
-
assetCode: asset.type ===
|
|
485
|
-
assetIssuer: asset.type ===
|
|
486
|
-
assetAmount: asset.type ===
|
|
487
|
+
assetCode: asset.type === 'native' ? undefined : asset.code,
|
|
488
|
+
assetIssuer: asset.type === 'native' ? undefined : asset.issuer,
|
|
489
|
+
assetAmount: asset.type === 'native' ? undefined : amount.toString(),
|
|
487
490
|
ledgerOpType,
|
|
488
491
|
},
|
|
489
|
-
}
|
|
492
|
+
}
|
|
490
493
|
}
|
|
491
494
|
|
|
492
495
|
/**
|
|
@@ -500,25 +503,25 @@ async function formatFeeOnlyOperation(
|
|
|
500
503
|
rawOperation: RawOperation,
|
|
501
504
|
accountId: string,
|
|
502
505
|
addr: string,
|
|
503
|
-
minHeight: number
|
|
506
|
+
minHeight: number
|
|
504
507
|
): Promise<Operation | undefined> {
|
|
505
|
-
const transaction = await rawOperation.transaction()
|
|
508
|
+
const transaction = await rawOperation.transaction()
|
|
506
509
|
|
|
507
|
-
if (transaction.ledger_attr < minHeight) return undefined
|
|
510
|
+
if (transaction.ledger_attr < minHeight) return undefined
|
|
508
511
|
|
|
509
512
|
// For non-fee-bump transactions Horizon sets `fee_account === source_account`;
|
|
510
513
|
// for fee-bump transactions it is the outer fee payer. Only emit a fee row
|
|
511
514
|
// when the address we are listing is the actual payer of the network fee.
|
|
512
|
-
const feePayer = transaction.fee_account ?? transaction.source_account
|
|
513
|
-
if (feePayer !== addr) return undefined
|
|
515
|
+
const feePayer = transaction.fee_account ?? transaction.source_account
|
|
516
|
+
if (feePayer !== addr) return undefined
|
|
514
517
|
|
|
515
|
-
const { hash: blockHash, closed_at: blockTime } = await transaction.ledger()
|
|
516
|
-
const memo = decodeMemo(transaction)
|
|
518
|
+
const { hash: blockHash, closed_at: blockTime } = await transaction.ledger()
|
|
519
|
+
const memo = decodeMemo(transaction)
|
|
517
520
|
|
|
518
521
|
return {
|
|
519
522
|
id: `${accountId}-${rawOperation.transaction_hash}-FEES`,
|
|
520
523
|
value: 0n,
|
|
521
|
-
type:
|
|
524
|
+
type: 'FEES',
|
|
522
525
|
senders: [feePayer],
|
|
523
526
|
recipients: [],
|
|
524
527
|
tx: {
|
|
@@ -533,107 +536,109 @@ async function formatFeeOnlyOperation(
|
|
|
533
536
|
failed: !rawOperation.transaction_successful,
|
|
534
537
|
...(transaction.fee_account ? { feesPayer: transaction.fee_account } : {}),
|
|
535
538
|
},
|
|
536
|
-
asset: { type:
|
|
539
|
+
asset: { type: 'native' },
|
|
537
540
|
details: {
|
|
538
541
|
pagingToken: rawOperation.paging_token,
|
|
539
542
|
assetCode: undefined,
|
|
540
543
|
assetIssuer: undefined,
|
|
541
544
|
assetAmount: undefined,
|
|
542
|
-
ledgerOpType:
|
|
545
|
+
ledgerOpType: 'FEES',
|
|
543
546
|
blockTime: new Date(blockTime),
|
|
544
547
|
index: rawOperation.id,
|
|
545
548
|
memo,
|
|
546
549
|
sequence: parseSequence(transaction.source_account_sequence),
|
|
547
550
|
},
|
|
548
|
-
}
|
|
551
|
+
}
|
|
549
552
|
}
|
|
550
553
|
|
|
551
|
-
function decodeMemo(
|
|
554
|
+
export function decodeMemo(
|
|
555
|
+
transaction: Horizon.ServerApi.TransactionRecord
|
|
556
|
+
): StellarMemo | undefined {
|
|
552
557
|
switch (transaction.memo_type) {
|
|
553
|
-
case
|
|
554
|
-
return { type:
|
|
555
|
-
case
|
|
556
|
-
return transaction.memo ? { type:
|
|
557
|
-
case
|
|
558
|
-
return transaction.memo ? { type:
|
|
559
|
-
case
|
|
558
|
+
case 'none':
|
|
559
|
+
return { type: 'NO_MEMO' }
|
|
560
|
+
case 'id':
|
|
561
|
+
return transaction.memo ? { type: 'MEMO_ID', value: transaction.memo } : undefined
|
|
562
|
+
case 'text':
|
|
563
|
+
return transaction.memo ? { type: 'MEMO_TEXT', value: transaction.memo } : undefined
|
|
564
|
+
case 'return':
|
|
560
565
|
return transaction.memo
|
|
561
566
|
? {
|
|
562
|
-
type:
|
|
563
|
-
value: Buffer.from(transaction.memo,
|
|
567
|
+
type: 'MEMO_RETURN',
|
|
568
|
+
value: Buffer.from(transaction.memo, 'base64').toString('hex'),
|
|
564
569
|
}
|
|
565
|
-
: undefined
|
|
566
|
-
case
|
|
570
|
+
: undefined
|
|
571
|
+
case 'hash':
|
|
567
572
|
return transaction.memo
|
|
568
573
|
? {
|
|
569
|
-
type:
|
|
570
|
-
value: Buffer.from(transaction.memo,
|
|
574
|
+
type: 'MEMO_HASH',
|
|
575
|
+
value: Buffer.from(transaction.memo, 'base64').toString('hex'),
|
|
571
576
|
}
|
|
572
|
-
: undefined
|
|
577
|
+
: undefined
|
|
573
578
|
default:
|
|
574
|
-
return undefined
|
|
579
|
+
return undefined
|
|
575
580
|
}
|
|
576
581
|
}
|
|
577
582
|
|
|
578
583
|
function getRecipients(operation: RawOperation): string[] {
|
|
579
584
|
switch (operation.type) {
|
|
580
|
-
case
|
|
581
|
-
return [operation.account]
|
|
585
|
+
case 'create_account':
|
|
586
|
+
return [operation.account]
|
|
582
587
|
|
|
583
|
-
case
|
|
584
|
-
return [operation.to_muxed || operation.to]
|
|
588
|
+
case 'payment':
|
|
589
|
+
return [operation.to_muxed || operation.to]
|
|
585
590
|
|
|
586
591
|
default:
|
|
587
|
-
return []
|
|
592
|
+
return []
|
|
588
593
|
}
|
|
589
594
|
}
|
|
590
595
|
|
|
591
596
|
function getSimpleOperationValue(
|
|
592
597
|
operation: RawOperation,
|
|
593
598
|
transaction: Horizon.ServerApi.TransactionRecord,
|
|
594
|
-
type: string
|
|
599
|
+
type: string
|
|
595
600
|
): BigNumber {
|
|
596
|
-
let value = new BigNumber(0)
|
|
601
|
+
let value = new BigNumber(0)
|
|
597
602
|
|
|
598
603
|
if (!operation.transaction_successful) {
|
|
599
|
-
return type ===
|
|
604
|
+
return type === 'IN' ? value : new BigNumber(transaction.fee_charged || 0)
|
|
600
605
|
}
|
|
601
606
|
|
|
602
607
|
switch (operation.type) {
|
|
603
|
-
case
|
|
604
|
-
return parseAPIValue(operation.starting_balance)
|
|
605
|
-
case
|
|
606
|
-
return parseAPIValue(operation.amount)
|
|
608
|
+
case 'create_account':
|
|
609
|
+
return parseAPIValue(operation.starting_balance)
|
|
610
|
+
case 'payment':
|
|
611
|
+
return parseAPIValue(operation.amount)
|
|
607
612
|
|
|
608
613
|
default:
|
|
609
|
-
return type !==
|
|
614
|
+
return type !== 'IN' ? new BigNumber(transaction.fee_charged) : value
|
|
610
615
|
}
|
|
611
616
|
}
|
|
612
617
|
|
|
613
618
|
function getSimpleOperationType(operation: RawOperation, addr: string): string {
|
|
614
619
|
switch (operation.type) {
|
|
615
|
-
case
|
|
616
|
-
return operation.funder === addr ?
|
|
620
|
+
case 'create_account':
|
|
621
|
+
return operation.funder === addr ? 'OUT' : 'IN'
|
|
617
622
|
|
|
618
|
-
case
|
|
623
|
+
case 'payment':
|
|
619
624
|
if (operation.from === addr && operation.to !== addr) {
|
|
620
|
-
return
|
|
625
|
+
return 'OUT'
|
|
621
626
|
}
|
|
622
627
|
|
|
623
|
-
return
|
|
628
|
+
return 'IN'
|
|
624
629
|
|
|
625
|
-
case
|
|
630
|
+
case 'change_trust':
|
|
626
631
|
if (new BigNumber(operation.limit).eq(0)) {
|
|
627
|
-
return
|
|
632
|
+
return 'OPT_OUT'
|
|
628
633
|
}
|
|
629
634
|
|
|
630
|
-
return
|
|
635
|
+
return 'OPT_IN'
|
|
631
636
|
|
|
632
637
|
default:
|
|
633
638
|
if (operation.source_account === addr) {
|
|
634
|
-
return
|
|
639
|
+
return 'OUT'
|
|
635
640
|
}
|
|
636
641
|
|
|
637
|
-
return
|
|
642
|
+
return 'IN'
|
|
638
643
|
}
|
|
639
644
|
}
|