@ledgerhq/live-common 34.52.0-nightly.0 → 34.52.0-nightly.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/lib/bridge/generic-alpaca/buildSubAccounts.d.ts +5 -8
- package/lib/bridge/generic-alpaca/buildSubAccounts.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/buildSubAccounts.js +37 -9
- package/lib/bridge/generic-alpaca/buildSubAccounts.js.map +1 -1
- package/lib/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/getAccountShape.js +18 -17
- package/lib/bridge/generic-alpaca/getAccountShape.js.map +1 -1
- package/lib/bridge/generic-alpaca/types.d.ts +4 -1
- package/lib/bridge/generic-alpaca/types.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/utils.d.ts +2 -1
- package/lib/bridge/generic-alpaca/utils.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/utils.js +35 -3
- package/lib/bridge/generic-alpaca/utils.js.map +1 -1
- package/lib-es/bridge/generic-alpaca/buildSubAccounts.d.ts +5 -8
- package/lib-es/bridge/generic-alpaca/buildSubAccounts.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/buildSubAccounts.js +35 -7
- package/lib-es/bridge/generic-alpaca/buildSubAccounts.js.map +1 -1
- package/lib-es/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/getAccountShape.js +20 -19
- package/lib-es/bridge/generic-alpaca/getAccountShape.js.map +1 -1
- package/lib-es/bridge/generic-alpaca/types.d.ts +4 -1
- package/lib-es/bridge/generic-alpaca/types.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/utils.d.ts +2 -1
- package/lib-es/bridge/generic-alpaca/utils.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/utils.js +33 -2
- package/lib-es/bridge/generic-alpaca/utils.js.map +1 -1
- package/package.json +10 -10
- package/src/bridge/generic-alpaca/buildSubAccounts.test.ts +537 -0
- package/src/bridge/generic-alpaca/buildSubAccounts.ts +58 -21
- package/src/bridge/generic-alpaca/getAccountShape.ts +26 -23
- package/src/bridge/generic-alpaca/tests/getAccountShape.test.ts +10 -1
- package/src/bridge/generic-alpaca/types.ts +5 -1
- package/src/bridge/generic-alpaca/utils.test.ts +31 -1
- package/src/bridge/generic-alpaca/utils.ts +48 -4
|
@@ -3,10 +3,18 @@ import { GetAccountShape, mergeOps } from "@ledgerhq/coin-framework/bridge/jsHel
|
|
|
3
3
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
4
4
|
import BigNumber from "bignumber.js";
|
|
5
5
|
import { getAlpacaApi } from "./alpaca";
|
|
6
|
-
import { adaptCoreOperationToLiveOperation, extractBalance } from "./utils";
|
|
6
|
+
import { adaptCoreOperationToLiveOperation, cleanedOperation, extractBalance } from "./utils";
|
|
7
7
|
import { inferSubOperations } from "@ledgerhq/coin-framework/serialization";
|
|
8
|
-
import { buildSubAccounts,
|
|
9
|
-
import { Pagination } from "@ledgerhq/coin-framework/api/types";
|
|
8
|
+
import { buildSubAccounts, mergeSubAccounts } from "./buildSubAccounts";
|
|
9
|
+
import type { Operation, Pagination } from "@ledgerhq/coin-framework/api/types";
|
|
10
|
+
import type { OperationCommon } from "./types";
|
|
11
|
+
|
|
12
|
+
function isNftCoreOp(operation: Operation): boolean {
|
|
13
|
+
return (
|
|
14
|
+
typeof operation.details?.ledgerOpType === "string" &&
|
|
15
|
+
["NFT_IN", "NFT_OUT"].includes(operation.details?.ledgerOpType)
|
|
16
|
+
);
|
|
17
|
+
}
|
|
10
18
|
|
|
11
19
|
export function genericGetAccountShape(network: string, kind: string): GetAccountShape {
|
|
12
20
|
return async (info, syncConfig) => {
|
|
@@ -56,39 +64,34 @@ export function genericGetAccountShape(network: string, kind: string): GetAccoun
|
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
const [newCoreOps] = await alpacaApi.listOperations(address, paginationParams);
|
|
59
|
-
const newOps = newCoreOps
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const mergedOps = mergeOps(oldOps, newOps) as OperationCommon[];
|
|
67
|
+
const newOps = newCoreOps
|
|
68
|
+
.filter(op => !isNftCoreOp(op))
|
|
69
|
+
.map(op => adaptCoreOperationToLiveOperation(accountId, op)) as OperationCommon[];
|
|
63
70
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
if (
|
|
71
|
+
const newAssetOperations = newOps.filter(
|
|
72
|
+
operation =>
|
|
67
73
|
operation?.extra?.assetReference &&
|
|
68
74
|
operation?.extra?.assetOwner &&
|
|
69
|
-
!["OPT_IN", "OPT_OUT"].includes(operation.type)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const subAccounts = await buildSubAccounts({
|
|
76
|
-
currency,
|
|
75
|
+
!["OPT_IN", "OPT_OUT"].includes(operation.type),
|
|
76
|
+
);
|
|
77
|
+
const newSubAccounts = await buildSubAccounts({
|
|
77
78
|
accountId,
|
|
78
79
|
allTokenAssetsBalances,
|
|
79
80
|
syncConfig,
|
|
80
|
-
operations:
|
|
81
|
+
operations: newAssetOperations,
|
|
81
82
|
getTokenFromAsset: alpacaApi.getTokenFromAsset,
|
|
82
83
|
});
|
|
84
|
+
const subAccounts = mergeSubAccounts(initialAccount?.subAccounts ?? [], newSubAccounts);
|
|
83
85
|
|
|
84
|
-
const
|
|
85
|
-
const subOperations = inferSubOperations(op.hash,
|
|
86
|
+
const newOpsWithSubs = newOps.map(op => {
|
|
87
|
+
const subOperations = inferSubOperations(op.hash, newSubAccounts);
|
|
86
88
|
|
|
87
|
-
return {
|
|
89
|
+
return cleanedOperation({
|
|
88
90
|
...op,
|
|
89
91
|
subOperations,
|
|
90
|
-
};
|
|
92
|
+
});
|
|
91
93
|
});
|
|
94
|
+
const operations = mergeOps(oldOps, newOpsWithSubs) as OperationCommon[];
|
|
92
95
|
|
|
93
96
|
const res = {
|
|
94
97
|
id: accountId,
|
|
@@ -29,9 +29,11 @@ jest.mock("../alpaca", () => ({
|
|
|
29
29
|
|
|
30
30
|
const adaptCoreOperationToLiveOperationMock = jest.fn();
|
|
31
31
|
const extractBalanceMock = jest.fn();
|
|
32
|
+
const cleanedOperationMock = jest.fn();
|
|
32
33
|
jest.mock("../utils", () => ({
|
|
33
34
|
adaptCoreOperationToLiveOperation: (...a: any[]) => adaptCoreOperationToLiveOperationMock(...a),
|
|
34
35
|
extractBalance: (...a: any[]) => extractBalanceMock(...a),
|
|
36
|
+
cleanedOperation: (...a: any[]) => cleanedOperationMock(...a),
|
|
35
37
|
}));
|
|
36
38
|
|
|
37
39
|
const inferSubOperationsMock = jest.fn();
|
|
@@ -40,8 +42,10 @@ jest.mock("@ledgerhq/coin-framework/serialization", () => ({
|
|
|
40
42
|
}));
|
|
41
43
|
|
|
42
44
|
const buildSubAccountsMock = jest.fn();
|
|
45
|
+
const mergeSubAccountsMock = jest.fn();
|
|
43
46
|
jest.mock("../buildSubAccounts", () => ({
|
|
44
47
|
buildSubAccounts: (...a: any[]) => buildSubAccountsMock(...a),
|
|
48
|
+
mergeSubAccounts: (...a: any[]) => mergeSubAccountsMock(...a),
|
|
45
49
|
}));
|
|
46
50
|
|
|
47
51
|
// Test matrix for Stellar & XRP
|
|
@@ -51,7 +55,7 @@ const chains = [
|
|
|
51
55
|
{ currency: { id: "tezos", name: "Tezos" }, network: "mainnet" },
|
|
52
56
|
];
|
|
53
57
|
|
|
54
|
-
describe("genericGetAccountShape
|
|
58
|
+
describe("genericGetAccountShape", () => {
|
|
55
59
|
beforeEach(() => {
|
|
56
60
|
jest.clearAllMocks();
|
|
57
61
|
});
|
|
@@ -88,6 +92,11 @@ describe("genericGetAccountShape (stellar & xrp)", () => {
|
|
|
88
92
|
}));
|
|
89
93
|
|
|
90
94
|
mergeOpsMock.mockImplementation((oldOps, newOps) => [...newOps, ...oldOps]);
|
|
95
|
+
cleanedOperationMock.mockImplementation(operation => operation);
|
|
96
|
+
mergeSubAccountsMock.mockImplementation((oldSubAccounts, newSubAccounts) => [
|
|
97
|
+
...newSubAccounts,
|
|
98
|
+
...oldSubAccounts,
|
|
99
|
+
]);
|
|
91
100
|
|
|
92
101
|
buildSubAccountsMock.mockReturnValue([
|
|
93
102
|
{ id: `${currency.id}_subAcc1`, type: "TokenAccount" },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TransactionCommon } from "@ledgerhq/types-live";
|
|
1
|
+
import type { Operation, TransactionCommon } from "@ledgerhq/types-live";
|
|
2
2
|
import BigNumber from "bignumber.js";
|
|
3
3
|
import type { Unit } from "@ledgerhq/types-cryptoassets";
|
|
4
4
|
|
|
@@ -32,3 +32,7 @@ export type GenericTransaction = TransactionCommon & {
|
|
|
32
32
|
assetOwner?: string;
|
|
33
33
|
networkInfo?: NetworkInfo | null;
|
|
34
34
|
};
|
|
35
|
+
|
|
36
|
+
export interface OperationCommon extends Operation {
|
|
37
|
+
extra: Record<string, any>;
|
|
38
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
adaptCoreOperationToLiveOperation,
|
|
3
|
+
cleanedOperation,
|
|
3
4
|
extractBalance,
|
|
4
5
|
findCryptoCurrencyByNetwork,
|
|
5
6
|
transactionToIntent,
|
|
@@ -7,9 +8,38 @@ import {
|
|
|
7
8
|
import BigNumber from "bignumber.js";
|
|
8
9
|
import { Operation as CoreOperation } from "@ledgerhq/coin-framework/api/types";
|
|
9
10
|
import { Account } from "@ledgerhq/types-live";
|
|
10
|
-
import { GenericTransaction } from "./types";
|
|
11
|
+
import { GenericTransaction, OperationCommon } from "./types";
|
|
11
12
|
|
|
12
13
|
describe("Alpaca utils", () => {
|
|
14
|
+
describe("cleanedOperation", () => {
|
|
15
|
+
it("creates a cleaned version of an operation without mutating it", () => {
|
|
16
|
+
const dirty = {
|
|
17
|
+
id: "id",
|
|
18
|
+
hash: "hash",
|
|
19
|
+
senders: ["sender"],
|
|
20
|
+
recipients: ["recipient"],
|
|
21
|
+
extra: { assetAmount: 5, assetReference: "USDC", paginationToken: "pagination" },
|
|
22
|
+
} as unknown as OperationCommon;
|
|
23
|
+
|
|
24
|
+
const clean = cleanedOperation(dirty);
|
|
25
|
+
|
|
26
|
+
expect(clean).toEqual({
|
|
27
|
+
id: "id",
|
|
28
|
+
hash: "hash",
|
|
29
|
+
senders: ["sender"],
|
|
30
|
+
recipients: ["recipient"],
|
|
31
|
+
extra: { paginationToken: "pagination" },
|
|
32
|
+
});
|
|
33
|
+
expect(dirty).toEqual({
|
|
34
|
+
id: "id",
|
|
35
|
+
hash: "hash",
|
|
36
|
+
senders: ["sender"],
|
|
37
|
+
recipients: ["recipient"],
|
|
38
|
+
extra: { assetAmount: 5, assetReference: "USDC", paginationToken: "pagination" },
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
13
43
|
describe("transactionToIntent", () => {
|
|
14
44
|
describe("type", () => {
|
|
15
45
|
it("fallbacks to 'Payment' without a transaction mode", () => {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "@ledgerhq/coin-framework/api/types";
|
|
10
10
|
import { findCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
|
|
11
11
|
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
12
|
-
import { GenericTransaction } from "./types";
|
|
12
|
+
import { GenericTransaction, OperationCommon } from "./types";
|
|
13
13
|
|
|
14
14
|
export function findCryptoCurrencyByNetwork(network: string): CryptoCurrency | undefined {
|
|
15
15
|
const networksRemap = {
|
|
@@ -27,6 +27,30 @@ export function extractBalance(balances: Balance[], type: string): Balance {
|
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function isStringArray(value: unknown): value is string[] {
|
|
31
|
+
return Array.isArray(value) && value.every(item => typeof item === "string");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function cleanedOperation(operation: OperationCommon): OperationCommon {
|
|
35
|
+
if (!operation.extra) return operation;
|
|
36
|
+
|
|
37
|
+
const extraToClean = new Set([
|
|
38
|
+
"assetReference",
|
|
39
|
+
"assetAmount",
|
|
40
|
+
"assetOwner",
|
|
41
|
+
"assetSenders",
|
|
42
|
+
"assetRecipients",
|
|
43
|
+
"parentSenders",
|
|
44
|
+
"parentRecipients",
|
|
45
|
+
"ledgerOpType",
|
|
46
|
+
]);
|
|
47
|
+
const cleanedExtra = Object.fromEntries(
|
|
48
|
+
Object.entries(operation.extra).filter(([key]) => !extraToClean.has(key)),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return { ...operation, extra: cleanedExtra };
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
export function adaptCoreOperationToLiveOperation(accountId: string, op: CoreOperation): Operation {
|
|
31
55
|
const opType = op.type as OperationType;
|
|
32
56
|
|
|
@@ -34,6 +58,10 @@ export function adaptCoreOperationToLiveOperation(accountId: string, op: CoreOpe
|
|
|
34
58
|
assetReference?: string;
|
|
35
59
|
assetOwner?: string;
|
|
36
60
|
assetAmount?: string | undefined;
|
|
61
|
+
assetSenders?: string[];
|
|
62
|
+
assetRecipients?: string[];
|
|
63
|
+
parentSenders?: string[];
|
|
64
|
+
parentRecipients?: string[];
|
|
37
65
|
ledgerOpType?: string | undefined;
|
|
38
66
|
memo?: string | undefined;
|
|
39
67
|
} = {};
|
|
@@ -46,6 +74,22 @@ export function adaptCoreOperationToLiveOperation(accountId: string, op: CoreOpe
|
|
|
46
74
|
extra.assetAmount = op.details.assetAmount as string;
|
|
47
75
|
}
|
|
48
76
|
|
|
77
|
+
if (isStringArray(op.details?.assetSenders)) {
|
|
78
|
+
extra.assetSenders = op.details?.assetSenders;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isStringArray(op.details?.assetRecipients)) {
|
|
82
|
+
extra.assetRecipients = op.details?.assetRecipients;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (isStringArray(op.details?.parentSenders)) {
|
|
86
|
+
extra.parentSenders = op.details?.parentSenders;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (isStringArray(op.details?.parentRecipients)) {
|
|
90
|
+
extra.parentRecipients = op.details?.parentRecipients;
|
|
91
|
+
}
|
|
92
|
+
|
|
49
93
|
if (op.asset?.type !== "native") {
|
|
50
94
|
extra.assetReference =
|
|
51
95
|
"assetReference" in (op.asset ?? {}) ? (op.asset as any).assetReference : "";
|
|
@@ -67,11 +111,11 @@ export function adaptCoreOperationToLiveOperation(accountId: string, op: CoreOpe
|
|
|
67
111
|
fee: bnFees,
|
|
68
112
|
blockHash: op.tx.block.hash,
|
|
69
113
|
blockHeight: op.tx.block.height,
|
|
70
|
-
senders: op.senders,
|
|
71
|
-
recipients: op.recipients,
|
|
114
|
+
senders: extra.parentSenders ?? op.senders,
|
|
115
|
+
recipients: extra.parentRecipients ?? op.recipients,
|
|
72
116
|
date: op.tx.date,
|
|
73
117
|
transactionSequenceNumber: op.details?.sequence as number,
|
|
74
|
-
hasFailed:
|
|
118
|
+
hasFailed: op.details?.status === "failed",
|
|
75
119
|
extra,
|
|
76
120
|
};
|
|
77
121
|
|