@ledgerhq/coin-canton 0.5.0-nightly.3 → 0.5.0-nightly.5
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +24 -0
- package/lib/api/getBalance.integ.test.js +8 -4
- package/lib/api/getBalance.integ.test.js.map +1 -1
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +20 -28
- package/lib/api/index.js.map +1 -1
- package/lib/api/lastBlock.integ.test.js +1 -1
- package/lib/api/lastBlock.integ.test.js.map +1 -1
- package/lib/api/listOperations.integ.test.js +1 -1
- package/lib/api/listOperations.integ.test.js.map +1 -1
- package/lib/bridge/broadcast.d.ts.map +1 -1
- package/lib/bridge/broadcast.js +2 -2
- package/lib/bridge/broadcast.js.map +1 -1
- package/lib/bridge/broadcast.test.js +9 -0
- package/lib/bridge/broadcast.test.js.map +1 -1
- package/lib/bridge/createTransaction.js +1 -1
- package/lib/bridge/createTransaction.js.map +1 -1
- package/lib/bridge/getTransactionStatus.js +1 -1
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +3 -0
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/onboard.d.ts +7 -5
- package/lib/bridge/onboard.d.ts.map +1 -1
- package/lib/bridge/onboard.integ.test.js +13 -10
- package/lib/bridge/onboard.integ.test.js.map +1 -1
- package/lib/bridge/onboard.js +110 -42
- package/lib/bridge/onboard.js.map +1 -1
- package/lib/bridge/prepareTransaction.js +1 -1
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/serialization.d.ts +4 -0
- package/lib/bridge/serialization.d.ts.map +1 -0
- package/lib/bridge/serialization.js +31 -0
- package/lib/bridge/serialization.js.map +1 -0
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +10 -5
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/sync.d.ts +2 -1
- package/lib/bridge/sync.d.ts.map +1 -1
- package/lib/bridge/sync.integ.test.js +2 -2
- package/lib/bridge/sync.integ.test.js.map +1 -1
- package/lib/bridge/sync.js +33 -20
- package/lib/bridge/sync.js.map +1 -1
- package/lib/common-logic/account/getBalance.d.ts +2 -1
- package/lib/common-logic/account/getBalance.d.ts.map +1 -1
- package/lib/common-logic/account/getBalance.js +7 -7
- package/lib/common-logic/account/getBalance.js.map +1 -1
- package/lib/common-logic/account/getBalance.unit.test.js +6 -3
- package/lib/common-logic/account/getBalance.unit.test.js.map +1 -1
- package/lib/common-logic/history/lastBlock.d.ts +2 -1
- package/lib/common-logic/history/lastBlock.d.ts.map +1 -1
- package/lib/common-logic/history/lastBlock.js +3 -3
- package/lib/common-logic/history/lastBlock.js.map +1 -1
- package/lib/common-logic/history/lastBlock.test.js +5 -2
- package/lib/common-logic/history/lastBlock.test.js.map +1 -1
- package/lib/common-logic/history/listOperations.d.ts +2 -1
- package/lib/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib/common-logic/history/listOperations.js +2 -2
- package/lib/common-logic/history/listOperations.js.map +1 -1
- package/lib/common-logic/transaction/broadcast.d.ts +2 -1
- package/lib/common-logic/transaction/broadcast.d.ts.map +1 -1
- package/lib/common-logic/transaction/broadcast.js +4 -4
- package/lib/common-logic/transaction/broadcast.js.map +1 -1
- package/lib/common-logic/transaction/broadcast.test.js +6 -3
- package/lib/common-logic/transaction/broadcast.test.js.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.d.ts +3 -1
- package/lib/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.js +8 -4
- package/lib/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib/common-logic/transaction/estimateFees.d.ts +2 -1
- package/lib/common-logic/transaction/estimateFees.d.ts.map +1 -1
- package/lib/common-logic/transaction/estimateFees.js +7 -3
- package/lib/common-logic/transaction/estimateFees.js.map +1 -1
- package/lib/config.d.ts +1 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/network/gateway.d.ts +28 -26
- package/lib/network/gateway.d.ts.map +1 -1
- package/lib/network/gateway.integ.test.js +19 -15
- package/lib/network/gateway.integ.test.js.map +1 -1
- package/lib/network/gateway.js +40 -33
- package/lib/network/gateway.js.map +1 -1
- package/lib/signer/getAddress.d.ts.map +1 -1
- package/lib/signer/getAddress.js +2 -2
- package/lib/signer/getAddress.js.map +1 -1
- package/lib/types/bridge.d.ts +18 -3
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/onboard.d.ts +2 -0
- package/lib/types/onboard.d.ts.map +1 -1
- package/lib/types/onboard.js.map +1 -1
- package/lib/types/signer.d.ts +2 -1
- package/lib/types/signer.d.ts.map +1 -1
- package/lib-es/api/getBalance.integ.test.js +8 -4
- package/lib-es/api/getBalance.integ.test.js.map +1 -1
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +19 -27
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/api/lastBlock.integ.test.js +1 -1
- package/lib-es/api/lastBlock.integ.test.js.map +1 -1
- package/lib-es/api/listOperations.integ.test.js +1 -1
- package/lib-es/api/listOperations.integ.test.js.map +1 -1
- package/lib-es/bridge/broadcast.d.ts.map +1 -1
- package/lib-es/bridge/broadcast.js +2 -2
- package/lib-es/bridge/broadcast.js.map +1 -1
- package/lib-es/bridge/broadcast.test.js +9 -0
- package/lib-es/bridge/broadcast.test.js.map +1 -1
- package/lib-es/bridge/createTransaction.js +1 -1
- package/lib-es/bridge/createTransaction.js.map +1 -1
- package/lib-es/bridge/getTransactionStatus.js +1 -1
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +3 -0
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/onboard.d.ts +7 -5
- package/lib-es/bridge/onboard.d.ts.map +1 -1
- package/lib-es/bridge/onboard.integ.test.js +13 -10
- package/lib-es/bridge/onboard.integ.test.js.map +1 -1
- package/lib-es/bridge/onboard.js +107 -42
- package/lib-es/bridge/onboard.js.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +1 -1
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/serialization.d.ts +4 -0
- package/lib-es/bridge/serialization.d.ts.map +1 -0
- package/lib-es/bridge/serialization.js +27 -0
- package/lib-es/bridge/serialization.js.map +1 -0
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +10 -5
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/sync.d.ts +2 -1
- package/lib-es/bridge/sync.d.ts.map +1 -1
- package/lib-es/bridge/sync.integ.test.js +2 -2
- package/lib-es/bridge/sync.integ.test.js.map +1 -1
- package/lib-es/bridge/sync.js +34 -21
- package/lib-es/bridge/sync.js.map +1 -1
- package/lib-es/common-logic/account/getBalance.d.ts +2 -1
- package/lib-es/common-logic/account/getBalance.d.ts.map +1 -1
- package/lib-es/common-logic/account/getBalance.js +7 -7
- package/lib-es/common-logic/account/getBalance.js.map +1 -1
- package/lib-es/common-logic/account/getBalance.unit.test.js +6 -3
- package/lib-es/common-logic/account/getBalance.unit.test.js.map +1 -1
- package/lib-es/common-logic/history/lastBlock.d.ts +2 -1
- package/lib-es/common-logic/history/lastBlock.d.ts.map +1 -1
- package/lib-es/common-logic/history/lastBlock.js +3 -3
- package/lib-es/common-logic/history/lastBlock.js.map +1 -1
- package/lib-es/common-logic/history/lastBlock.test.js +5 -2
- package/lib-es/common-logic/history/lastBlock.test.js.map +1 -1
- package/lib-es/common-logic/history/listOperations.d.ts +2 -1
- package/lib-es/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib-es/common-logic/history/listOperations.js +2 -2
- package/lib-es/common-logic/history/listOperations.js.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.d.ts +2 -1
- package/lib-es/common-logic/transaction/broadcast.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.js +4 -4
- package/lib-es/common-logic/transaction/broadcast.js.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.test.js +6 -3
- package/lib-es/common-logic/transaction/broadcast.test.js.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.d.ts +3 -1
- package/lib-es/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.js +9 -5
- package/lib-es/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib-es/common-logic/transaction/estimateFees.d.ts +2 -1
- package/lib-es/common-logic/transaction/estimateFees.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/estimateFees.js +4 -3
- package/lib-es/common-logic/transaction/estimateFees.js.map +1 -1
- package/lib-es/config.d.ts +1 -0
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js.map +1 -1
- package/lib-es/network/gateway.d.ts +28 -26
- package/lib-es/network/gateway.d.ts.map +1 -1
- package/lib-es/network/gateway.integ.test.js +19 -15
- package/lib-es/network/gateway.integ.test.js.map +1 -1
- package/lib-es/network/gateway.js +40 -33
- package/lib-es/network/gateway.js.map +1 -1
- package/lib-es/signer/getAddress.d.ts.map +1 -1
- package/lib-es/signer/getAddress.js +2 -2
- package/lib-es/signer/getAddress.js.map +1 -1
- package/lib-es/types/bridge.d.ts +18 -3
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/onboard.d.ts +2 -0
- package/lib-es/types/onboard.d.ts.map +1 -1
- package/lib-es/types/onboard.js.map +1 -1
- package/lib-es/types/signer.d.ts +2 -1
- package/lib-es/types/signer.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/getBalance.integ.test.ts +8 -4
- package/src/api/index.ts +22 -51
- package/src/api/lastBlock.integ.test.ts +1 -1
- package/src/api/listOperations.integ.test.ts +1 -1
- package/src/bridge/broadcast.test.ts +11 -0
- package/src/bridge/broadcast.ts +5 -2
- package/src/bridge/createTransaction.ts +1 -1
- package/src/bridge/getTransactionStatus.ts +1 -1
- package/src/bridge/index.ts +3 -0
- package/src/bridge/onboard.integ.test.ts +24 -12
- package/src/bridge/onboard.ts +143 -51
- package/src/bridge/prepareTransaction.ts +1 -1
- package/src/bridge/serialization.ts +36 -0
- package/src/bridge/signOperation.ts +20 -7
- package/src/bridge/sync.integ.test.ts +2 -2
- package/src/bridge/sync.ts +40 -29
- package/src/common-logic/account/getBalance.ts +12 -7
- package/src/common-logic/account/getBalance.unit.test.ts +8 -3
- package/src/common-logic/history/lastBlock.test.ts +7 -2
- package/src/common-logic/history/lastBlock.ts +5 -3
- package/src/common-logic/history/listOperations.ts +3 -2
- package/src/common-logic/transaction/broadcast.test.ts +8 -3
- package/src/common-logic/transaction/broadcast.ts +6 -3
- package/src/common-logic/transaction/craftTransaction.ts +22 -5
- package/src/common-logic/transaction/estimateFees.ts +7 -3
- package/src/config.ts +1 -0
- package/src/network/gateway.integ.test.ts +31 -12
- package/src/network/gateway.ts +78 -53
- package/src/signer/getAddress.ts +6 -4
- package/src/types/bridge.ts +21 -0
- package/src/types/onboard.ts +3 -0
- package/src/types/signer.ts +2 -1
package/src/bridge/onboard.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { Observable } from "rxjs";
|
|
2
2
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
3
|
-
import {
|
|
3
|
+
import { emptyHistoryCache } from "@ledgerhq/coin-framework/account/index";
|
|
4
|
+
import { getDerivationModesForCurrency } from "@ledgerhq/coin-framework/derivation";
|
|
5
|
+
import { getAccountShape } from "./sync";
|
|
6
|
+
import { CantonAccount, CantonSigner } from "../types";
|
|
7
|
+
import type { Account, DerivationMode } from "@ledgerhq/types-live";
|
|
4
8
|
import {
|
|
5
9
|
prepareOnboarding,
|
|
6
10
|
submitOnboarding,
|
|
@@ -19,8 +23,10 @@ import {
|
|
|
19
23
|
CantonPreApprovalResult,
|
|
20
24
|
PrepareTransactionResponse,
|
|
21
25
|
} from "../types/onboard";
|
|
26
|
+
import resolver from "../signer";
|
|
27
|
+
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
22
28
|
|
|
23
|
-
async function
|
|
29
|
+
async function _getKeypair(
|
|
24
30
|
signerContext: SignerContext<CantonSigner>,
|
|
25
31
|
deviceId: string,
|
|
26
32
|
derivationPath: string,
|
|
@@ -32,25 +38,27 @@ async function getKeypair(
|
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
export const isAccountOnboarded = async (
|
|
41
|
+
currency: CryptoCurrency,
|
|
35
42
|
publicKey: string,
|
|
36
|
-
): Promise<
|
|
43
|
+
): Promise<{ isOnboarded: boolean; party_id?: string }> => {
|
|
37
44
|
try {
|
|
38
|
-
const { party_id } = await getPartyByPubKey(publicKey);
|
|
45
|
+
const { party_id } = await getPartyByPubKey(currency, publicKey);
|
|
39
46
|
|
|
40
47
|
if (party_id) {
|
|
41
|
-
return { party_id };
|
|
48
|
+
return { isOnboarded: true, party_id };
|
|
42
49
|
} else {
|
|
43
|
-
return false;
|
|
50
|
+
return { isOnboarded: false };
|
|
44
51
|
}
|
|
45
52
|
} catch (err) {
|
|
46
53
|
log("[isAccountOnboarded] Error checking party status (likely not onboarded):", err);
|
|
47
|
-
return false;
|
|
54
|
+
return { isOnboarded: false };
|
|
48
55
|
}
|
|
49
56
|
};
|
|
50
57
|
|
|
51
58
|
export const buildOnboardAccount =
|
|
52
59
|
(signerContext: SignerContext<CantonSigner>) =>
|
|
53
60
|
(
|
|
61
|
+
currency: CryptoCurrency,
|
|
54
62
|
deviceId: string,
|
|
55
63
|
derivationPath: string,
|
|
56
64
|
): Observable<CantonOnboardProgress | CantonOnboardResult> =>
|
|
@@ -59,22 +67,36 @@ export const buildOnboardAccount =
|
|
|
59
67
|
observer.next({
|
|
60
68
|
status: OnboardStatus.INIT,
|
|
61
69
|
});
|
|
62
|
-
const
|
|
70
|
+
const derivationMode = getDerivationModesForCurrency(currency)[0];
|
|
71
|
+
const getAddress = resolver(signerContext);
|
|
72
|
+
const { address, publicKey } = await getAddress(deviceId, {
|
|
73
|
+
path: derivationPath,
|
|
74
|
+
currency,
|
|
75
|
+
derivationMode: derivationMode || "",
|
|
76
|
+
});
|
|
63
77
|
|
|
64
78
|
observer.next({
|
|
65
79
|
status: OnboardStatus.PREPARE,
|
|
66
80
|
});
|
|
67
81
|
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
82
|
+
const { party_id: partyId } = await isAccountOnboarded(currency, publicKey);
|
|
83
|
+
if (partyId) {
|
|
84
|
+
const account = await createAccount({
|
|
85
|
+
address,
|
|
86
|
+
derivationPath,
|
|
87
|
+
partyId,
|
|
88
|
+
currency,
|
|
89
|
+
derivationMode,
|
|
90
|
+
});
|
|
70
91
|
observer.next({
|
|
71
|
-
partyId
|
|
92
|
+
partyId,
|
|
93
|
+
account,
|
|
72
94
|
});
|
|
73
95
|
observer.complete();
|
|
74
96
|
return;
|
|
75
97
|
}
|
|
76
98
|
|
|
77
|
-
const preparedTransaction = await prepareOnboarding(
|
|
99
|
+
const preparedTransaction = await prepareOnboarding(currency, publicKey, "ed25519");
|
|
78
100
|
|
|
79
101
|
observer.next({
|
|
80
102
|
status: OnboardStatus.SIGN,
|
|
@@ -89,26 +111,44 @@ export const buildOnboardAccount =
|
|
|
89
111
|
});
|
|
90
112
|
|
|
91
113
|
const result = await submitOnboarding(
|
|
92
|
-
|
|
114
|
+
currency,
|
|
115
|
+
{ public_key: publicKey, public_key_type: "ed25519" },
|
|
93
116
|
preparedTransaction,
|
|
94
117
|
signature,
|
|
95
|
-
).catch(err => {
|
|
118
|
+
).catch(async err => {
|
|
96
119
|
if (err.type === "PARTY_ALREADY_EXISTS") {
|
|
120
|
+
const account = await createAccount({
|
|
121
|
+
address,
|
|
122
|
+
derivationPath,
|
|
123
|
+
partyId: preparedTransaction.party_id,
|
|
124
|
+
currency,
|
|
125
|
+
derivationMode,
|
|
126
|
+
});
|
|
97
127
|
observer.next({
|
|
98
128
|
partyId: preparedTransaction.party_id,
|
|
129
|
+
account,
|
|
99
130
|
});
|
|
100
131
|
return observer.complete();
|
|
101
132
|
}
|
|
102
133
|
throw err;
|
|
103
134
|
});
|
|
104
135
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
136
|
+
if (result) {
|
|
137
|
+
observer.next({
|
|
138
|
+
status: OnboardStatus.SUCCESS,
|
|
139
|
+
});
|
|
140
|
+
const account = await createAccount({
|
|
141
|
+
address,
|
|
142
|
+
derivationPath,
|
|
143
|
+
partyId: result.party.party_id,
|
|
144
|
+
currency,
|
|
145
|
+
derivationMode,
|
|
146
|
+
});
|
|
147
|
+
observer.next({
|
|
148
|
+
partyId: result.party.party_id,
|
|
149
|
+
account,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
112
152
|
|
|
113
153
|
observer.complete();
|
|
114
154
|
}
|
|
@@ -125,6 +165,7 @@ export const buildOnboardAccount =
|
|
|
125
165
|
export const buildAuthorizePreapproval =
|
|
126
166
|
(signerContext: SignerContext<CantonSigner>) =>
|
|
127
167
|
(
|
|
168
|
+
currency: CryptoCurrency,
|
|
128
169
|
deviceId: string,
|
|
129
170
|
derivationPath: string,
|
|
130
171
|
partyId: string,
|
|
@@ -135,8 +176,10 @@ export const buildAuthorizePreapproval =
|
|
|
135
176
|
status: PreApprovalStatus.PREPARE,
|
|
136
177
|
});
|
|
137
178
|
|
|
138
|
-
const preparedTransaction: PrepareTransactionResponse =
|
|
139
|
-
|
|
179
|
+
const preparedTransaction: PrepareTransactionResponse = await preparePreApprovalTransaction(
|
|
180
|
+
currency,
|
|
181
|
+
partyId,
|
|
182
|
+
);
|
|
140
183
|
|
|
141
184
|
observer.next({
|
|
142
185
|
status: PreApprovalStatus.SIGN,
|
|
@@ -151,6 +194,7 @@ export const buildAuthorizePreapproval =
|
|
|
151
194
|
});
|
|
152
195
|
|
|
153
196
|
const { isApproved } = await submitPreApprovalTransaction(
|
|
197
|
+
currency,
|
|
154
198
|
partyId,
|
|
155
199
|
preparedTransaction,
|
|
156
200
|
signature,
|
|
@@ -164,38 +208,35 @@ export const buildAuthorizePreapproval =
|
|
|
164
208
|
isApproved,
|
|
165
209
|
});
|
|
166
210
|
|
|
167
|
-
// TODO: remove after demo
|
|
168
211
|
const handleTapRequest = async () => {
|
|
169
212
|
try {
|
|
170
|
-
|
|
171
|
-
status: PreApprovalStatus.PREPARE,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const { serialized, hash } = await prepareTapRequest({
|
|
175
|
-
partyId,
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
observer.next({
|
|
179
|
-
status: PreApprovalStatus.SIGN,
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
const signature = await signerContext(deviceId, signer =>
|
|
183
|
-
signer.signTransaction(derivationPath, hash),
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
observer.next({
|
|
187
|
-
status: PreApprovalStatus.SUBMIT,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
await submitTapRequest({
|
|
213
|
+
const { serialized, hash } = await prepareTapRequest(currency, {
|
|
191
214
|
partyId,
|
|
192
|
-
serialized,
|
|
193
|
-
signature,
|
|
194
215
|
});
|
|
195
216
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
217
|
+
if (serialized && hash) {
|
|
218
|
+
observer.next({
|
|
219
|
+
status: PreApprovalStatus.SIGN,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const signature = await signerContext(deviceId, signer =>
|
|
223
|
+
signer.signTransaction(derivationPath, hash),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
observer.next({
|
|
227
|
+
status: PreApprovalStatus.SUBMIT,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
await submitTapRequest(currency, {
|
|
231
|
+
partyId,
|
|
232
|
+
serialized,
|
|
233
|
+
signature,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
observer.next({
|
|
237
|
+
status: PreApprovalStatus.SUCCESS,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
199
240
|
} catch (err) {
|
|
200
241
|
// Tap request failure should not break the pre-approval flow
|
|
201
242
|
}
|
|
@@ -214,7 +255,58 @@ export const buildAuthorizePreapproval =
|
|
|
214
255
|
);
|
|
215
256
|
});
|
|
216
257
|
|
|
217
|
-
const
|
|
258
|
+
const createAccount = async ({
|
|
259
|
+
address,
|
|
260
|
+
partyId,
|
|
261
|
+
derivationPath,
|
|
262
|
+
currency,
|
|
263
|
+
derivationMode,
|
|
264
|
+
index = 0,
|
|
265
|
+
}: {
|
|
266
|
+
address: string;
|
|
267
|
+
derivationPath: string;
|
|
268
|
+
partyId: string;
|
|
269
|
+
currency: CryptoCurrency;
|
|
270
|
+
derivationMode: DerivationMode;
|
|
271
|
+
index?: number;
|
|
272
|
+
}): Promise<Partial<Account>> => {
|
|
273
|
+
const accountShape = await getAccountShape(
|
|
274
|
+
{
|
|
275
|
+
address,
|
|
276
|
+
currency,
|
|
277
|
+
derivationMode,
|
|
278
|
+
derivationPath,
|
|
279
|
+
index,
|
|
280
|
+
rest: {
|
|
281
|
+
cantonResources: {
|
|
282
|
+
partyId,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
{ paginationConfig: {} },
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
const account: Partial<CantonAccount> = {
|
|
290
|
+
...accountShape,
|
|
291
|
+
type: "Account",
|
|
292
|
+
xpub: partyId.replace(/:/g, "_"),
|
|
293
|
+
index,
|
|
294
|
+
// operations: [],
|
|
295
|
+
currency,
|
|
296
|
+
derivationMode,
|
|
297
|
+
lastSyncDate: new Date(),
|
|
298
|
+
pendingOperations: [],
|
|
299
|
+
seedIdentifier: address,
|
|
300
|
+
balanceHistoryCache: emptyHistoryCache,
|
|
301
|
+
cantonResources: {
|
|
302
|
+
partyId,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return account;
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const log = (message: string, ...rest: unknown[]) => {
|
|
218
310
|
// eslint-disable-next-line no-console
|
|
219
311
|
console.log(message, ...rest);
|
|
220
312
|
};
|
|
@@ -10,7 +10,7 @@ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"
|
|
|
10
10
|
) => {
|
|
11
11
|
let fee = transaction.fee;
|
|
12
12
|
if (!fee || fee.eq(0)) {
|
|
13
|
-
fee = BigNumber((await estimateFees(
|
|
13
|
+
fee = BigNumber((await estimateFees(account.currency)).toString());
|
|
14
14
|
}
|
|
15
15
|
return updateTransaction(transaction, { fee });
|
|
16
16
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Account, AccountRaw } from "@ledgerhq/types-live";
|
|
2
|
+
import type {
|
|
3
|
+
CantonAccount,
|
|
4
|
+
CantonAccountRaw,
|
|
5
|
+
CantonResources,
|
|
6
|
+
CantonResourcesRaw,
|
|
7
|
+
} from "../types";
|
|
8
|
+
|
|
9
|
+
function toResourcesRaw(r: CantonResources): CantonResourcesRaw {
|
|
10
|
+
const { partyId } = r;
|
|
11
|
+
return {
|
|
12
|
+
partyId,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function fromResourcesRaw(r: CantonResourcesRaw): CantonResources {
|
|
16
|
+
const { partyId } = r;
|
|
17
|
+
return {
|
|
18
|
+
partyId,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function assignToAccountRaw(account: Account, accountRaw: AccountRaw): void {
|
|
23
|
+
const cantonAccount = account as CantonAccount;
|
|
24
|
+
const cantonAccountRaw = accountRaw as CantonAccountRaw;
|
|
25
|
+
if (cantonAccount.cantonResources) {
|
|
26
|
+
cantonAccountRaw.cantonResources = toResourcesRaw(cantonAccount.cantonResources);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function assignFromAccountRaw(accountRaw: AccountRaw, account: Account): void {
|
|
31
|
+
const cantonResourcesRaw = (accountRaw as CantonAccountRaw).cantonResources;
|
|
32
|
+
const cantonAccount = account as CantonAccount;
|
|
33
|
+
if (cantonResourcesRaw) {
|
|
34
|
+
cantonAccount.cantonResources = fromResourcesRaw(cantonResourcesRaw);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Observable } from "rxjs";
|
|
2
|
+
import BigNumber from "bignumber.js";
|
|
2
3
|
import { FeeNotLoaded } from "@ledgerhq/errors";
|
|
3
4
|
import { AccountBridge, Operation } from "@ledgerhq/types-live";
|
|
4
5
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
@@ -22,18 +23,30 @@ export const buildSignOperation =
|
|
|
22
23
|
|
|
23
24
|
const signature = await signerContext(deviceId, async signer => {
|
|
24
25
|
const { freshAddressPath: derivationPath } = account;
|
|
25
|
-
const partyId = account
|
|
26
|
+
const partyId = (account as unknown as { cantonResources: { partyId: string } })
|
|
27
|
+
.cantonResources.partyId;
|
|
28
|
+
const params: {
|
|
29
|
+
recipient?: string;
|
|
30
|
+
amount: BigNumber;
|
|
31
|
+
tokenId: string;
|
|
32
|
+
expireInSeconds: number;
|
|
33
|
+
memo?: string;
|
|
34
|
+
} = {
|
|
35
|
+
recipient: transaction.recipient,
|
|
36
|
+
amount: transaction.amount,
|
|
37
|
+
expireInSeconds: 60 * 60,
|
|
38
|
+
tokenId: "Amulet",
|
|
39
|
+
};
|
|
40
|
+
if (transaction.memo) {
|
|
41
|
+
params.memo = transaction.memo;
|
|
42
|
+
}
|
|
26
43
|
|
|
27
44
|
const { hash, serializedTransaction } = await craftTransaction(
|
|
45
|
+
account.currency,
|
|
28
46
|
{
|
|
29
47
|
address: partyId,
|
|
30
48
|
},
|
|
31
|
-
|
|
32
|
-
recipient: transaction.recipient,
|
|
33
|
-
amount: transaction.amount,
|
|
34
|
-
expireInSeconds: 60 * 60,
|
|
35
|
-
tokenId: "Amulet",
|
|
36
|
-
},
|
|
49
|
+
params,
|
|
37
50
|
);
|
|
38
51
|
const transactionSignature = await signer.signTransaction(derivationPath, hash);
|
|
39
52
|
|
|
@@ -110,7 +110,7 @@ describe("sync (devnet)", () => {
|
|
|
110
110
|
|
|
111
111
|
mockGetBalance.mockResolvedValue([
|
|
112
112
|
{
|
|
113
|
-
instrument_id: "
|
|
113
|
+
instrument_id: "Amulet",
|
|
114
114
|
amount: 1000000,
|
|
115
115
|
locked: true,
|
|
116
116
|
},
|
|
@@ -167,7 +167,7 @@ describe("sync (devnet)", () => {
|
|
|
167
167
|
const result = await getAccountShape(ACCOUNT_SHAPE_INFO, { paginationConfig: {} });
|
|
168
168
|
|
|
169
169
|
expect(result.operations).toBeDefined();
|
|
170
|
-
expect(result.operationsCount).
|
|
170
|
+
expect(result.operationsCount).toBeGreaterThanOrEqual(1);
|
|
171
171
|
|
|
172
172
|
expect(mockGetOperations).toHaveBeenCalledWith(TEST_ADDRESS, {
|
|
173
173
|
cursor: 0,
|
package/src/bridge/sync.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
-
import { Operation } from "@ledgerhq/types-live";
|
|
3
|
-
import { encodeAccountId } from "@ledgerhq/coin-framework/account/index";
|
|
2
|
+
import { Operation, OperationType } from "@ledgerhq/types-live";
|
|
3
|
+
import { decodeAccountId, encodeAccountId } from "@ledgerhq/coin-framework/account/index";
|
|
4
4
|
import { GetAccountShape, mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
5
|
-
import { getBalance, getLedgerEnd, getOperations, type OperationInfo } from "../network/gateway";
|
|
6
|
-
|
|
7
5
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
6
|
+
import { getBalance, getLedgerEnd, getOperations, type OperationInfo } from "../network/gateway";
|
|
7
|
+
import { CantonAccount } from "../types";
|
|
8
8
|
import coinConfig from "../config";
|
|
9
9
|
|
|
10
10
|
const txInfoToOperationAdapter =
|
|
11
|
-
(accountId: string,
|
|
11
|
+
(accountId: string, partyId: string) =>
|
|
12
12
|
(txInfo: OperationInfo): Operation => {
|
|
13
13
|
const {
|
|
14
14
|
transaction_hash,
|
|
@@ -18,11 +18,17 @@ const txInfoToOperationAdapter =
|
|
|
18
18
|
recipients,
|
|
19
19
|
transaction_timestamp,
|
|
20
20
|
fee: { value: fee },
|
|
21
|
-
transfers: [{ value: transferValue }],
|
|
21
|
+
transfers: [{ value: transferValue, details }],
|
|
22
22
|
} = txInfo;
|
|
23
|
-
|
|
23
|
+
let type: OperationType = "UNKNOWN";
|
|
24
|
+
if (txInfo.type === "Send") {
|
|
25
|
+
type = senders.includes(partyId) ? "OUT" : "IN";
|
|
26
|
+
} else if (txInfo.type === "Receive") {
|
|
27
|
+
type = "IN";
|
|
28
|
+
}
|
|
24
29
|
const value = new BigNumber(transferValue);
|
|
25
30
|
const feeValue = new BigNumber(fee);
|
|
31
|
+
const memo = details.metadata.reason;
|
|
26
32
|
|
|
27
33
|
const op: Operation = {
|
|
28
34
|
id: encodeOperationId(accountId, transaction_hash, type),
|
|
@@ -39,6 +45,7 @@ const txInfoToOperationAdapter =
|
|
|
39
45
|
transactionSequenceNumber: height,
|
|
40
46
|
extra: {
|
|
41
47
|
uid,
|
|
48
|
+
memo,
|
|
42
49
|
},
|
|
43
50
|
};
|
|
44
51
|
|
|
@@ -48,42 +55,43 @@ const txInfoToOperationAdapter =
|
|
|
48
55
|
const filterOperations = (
|
|
49
56
|
transactions: OperationInfo[],
|
|
50
57
|
accountId: string,
|
|
51
|
-
|
|
58
|
+
partyId: string,
|
|
52
59
|
): Operation[] => {
|
|
53
|
-
return transactions
|
|
54
|
-
.filter(tx => tx.type === "Receive" || tx.type === "Send")
|
|
55
|
-
.map(txInfoToOperationAdapter(accountId, address));
|
|
60
|
+
return transactions.map(txInfoToOperationAdapter(accountId, partyId));
|
|
56
61
|
};
|
|
57
62
|
|
|
58
|
-
export const getAccountShape: GetAccountShape = async info => {
|
|
59
|
-
const { address, initialAccount, currency, derivationMode } = info;
|
|
60
|
-
|
|
61
|
-
const xpubOrAddress =
|
|
63
|
+
export const getAccountShape: GetAccountShape<CantonAccount> = async info => {
|
|
64
|
+
const { address, initialAccount, currency, derivationMode, derivationPath, rest } = info;
|
|
65
|
+
|
|
66
|
+
const xpubOrAddress = (
|
|
67
|
+
(initialAccount && initialAccount.id && decodeAccountId(initialAccount.id).xpubOrAddress) ||
|
|
68
|
+
""
|
|
69
|
+
).replace(/:/g, "_");
|
|
70
|
+
const partyId =
|
|
71
|
+
rest?.cantonResources?.partyId ||
|
|
72
|
+
initialAccount?.cantonResources?.partyId ||
|
|
73
|
+
xpubOrAddress.replace(/_/g, ":");
|
|
62
74
|
|
|
63
75
|
const accountId = encodeAccountId({
|
|
64
76
|
type: "js",
|
|
65
77
|
version: "2",
|
|
66
78
|
currencyId: currency.id,
|
|
67
79
|
xpubOrAddress,
|
|
68
|
-
derivationMode
|
|
80
|
+
derivationMode,
|
|
69
81
|
});
|
|
70
82
|
|
|
71
|
-
// blockheight retrieval
|
|
72
|
-
const blockHeight = await getLedgerEnd();
|
|
73
|
-
|
|
74
83
|
// Account info retrieval + spendable balance calculation
|
|
75
84
|
// const accountInfo = await getAccountInfo(address);
|
|
76
|
-
const balances = await getBalance(
|
|
85
|
+
const balances = await getBalance(currency, partyId);
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
const balanceData = balances.find(balance => balance.instrument_id.includes("Amulet")) || {
|
|
87
|
+
const balanceData = balances.find(balance => balance.instrument_id === "Amulet") || {
|
|
80
88
|
instrument_id: "Amulet",
|
|
81
89
|
amount: 0,
|
|
82
90
|
locked: false,
|
|
83
91
|
};
|
|
84
92
|
|
|
85
93
|
const balance = new BigNumber(balanceData.amount);
|
|
86
|
-
const reserveMin = coinConfig.getCoinConfig().minReserve || 0;
|
|
94
|
+
const reserveMin = coinConfig.getCoinConfig(currency).minReserve || 0;
|
|
87
95
|
const lockedAmount = balanceData.locked ? balance : new BigNumber(0);
|
|
88
96
|
const spendableBalance = BigNumber.max(
|
|
89
97
|
0,
|
|
@@ -93,16 +101,14 @@ export const getAccountShape: GetAccountShape = async info => {
|
|
|
93
101
|
// Tx history fetching
|
|
94
102
|
const oldOperations = initialAccount?.operations || [];
|
|
95
103
|
const startAt = oldOperations.length ? (oldOperations[0].blockHeight || 0) + 1 : 0;
|
|
96
|
-
const transactionData = await getOperations(
|
|
104
|
+
const transactionData = await getOperations(currency, partyId, {
|
|
97
105
|
cursor: startAt,
|
|
98
106
|
limit: 100,
|
|
99
107
|
});
|
|
108
|
+
// blockheight retrieval
|
|
109
|
+
const blockHeight = await getLedgerEnd(currency);
|
|
100
110
|
|
|
101
|
-
const newOperations = filterOperations(
|
|
102
|
-
transactionData.operations,
|
|
103
|
-
accountId,
|
|
104
|
-
address.replace(/_/g, ":"),
|
|
105
|
-
);
|
|
111
|
+
const newOperations = filterOperations(transactionData.operations, accountId, partyId);
|
|
106
112
|
const operations = mergeOps(oldOperations, newOperations);
|
|
107
113
|
|
|
108
114
|
// We return the new account shape
|
|
@@ -114,6 +120,11 @@ export const getAccountShape: GetAccountShape = async info => {
|
|
|
114
120
|
spendableBalance,
|
|
115
121
|
operations,
|
|
116
122
|
operationsCount: operations.length,
|
|
123
|
+
freshAddress: address,
|
|
124
|
+
freshAddressPath: derivationPath,
|
|
125
|
+
cantonResources: {
|
|
126
|
+
partyId,
|
|
127
|
+
},
|
|
117
128
|
};
|
|
118
129
|
|
|
119
130
|
return shape;
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { Balance } from "@ledgerhq/coin-framework/api/types";
|
|
2
2
|
import { getBalance as gatewayGetBalance, type InstrumentBalance } from "../../network/gateway";
|
|
3
3
|
import coinConfig from "../../config";
|
|
4
|
+
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
4
5
|
|
|
5
|
-
const useGateway = () =>
|
|
6
|
-
|
|
6
|
+
const useGateway = (currency: CryptoCurrency) =>
|
|
7
|
+
coinConfig.getCoinConfig(currency).useGateway === true;
|
|
8
|
+
const getNativeId = (currency: CryptoCurrency) =>
|
|
9
|
+
coinConfig.getCoinConfig(currency).nativeInstrumentId;
|
|
7
10
|
|
|
8
|
-
function adaptInstrument(instrument: InstrumentBalance): Balance {
|
|
11
|
+
function adaptInstrument(currency: CryptoCurrency, instrument: InstrumentBalance): Balance {
|
|
9
12
|
return {
|
|
10
13
|
value: BigInt(instrument.amount),
|
|
11
14
|
locked: instrument.locked === true ? BigInt(instrument.amount) : BigInt(0),
|
|
12
15
|
asset:
|
|
13
|
-
getNativeId() === instrument.instrument_id
|
|
16
|
+
getNativeId(currency) === instrument.instrument_id
|
|
14
17
|
? { type: "native" }
|
|
15
18
|
: { type: "token", assetReference: instrument.instrument_id },
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
export async function getBalance(partyId: string): Promise<Balance[]> {
|
|
20
|
-
if (useGateway())
|
|
21
|
-
return (await gatewayGetBalance(partyId)).map(instrument =>
|
|
22
|
+
export async function getBalance(currency: CryptoCurrency, partyId: string): Promise<Balance[]> {
|
|
23
|
+
if (useGateway(currency))
|
|
24
|
+
return (await gatewayGetBalance(currency, partyId)).map(instrument =>
|
|
25
|
+
adaptInstrument(currency, instrument),
|
|
26
|
+
);
|
|
22
27
|
else throw new Error("Not implemented");
|
|
23
28
|
}
|
|
@@ -2,6 +2,11 @@ import { getBalance as getBalanceFromNetwork } from "../../network/gateway";
|
|
|
2
2
|
import * as coinConfigModule from "../../config";
|
|
3
3
|
import { getBalance } from "./getBalance";
|
|
4
4
|
import { Balance } from "@ledgerhq/coin-framework/api/types";
|
|
5
|
+
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
6
|
+
|
|
7
|
+
const mockCurrency = {
|
|
8
|
+
id: "canton_network",
|
|
9
|
+
} as unknown as CryptoCurrency;
|
|
5
10
|
|
|
6
11
|
jest.mock("../../network/gateway", () => ({
|
|
7
12
|
getBalance: jest.fn(),
|
|
@@ -35,9 +40,9 @@ describe("getBalance", () => {
|
|
|
35
40
|
|
|
36
41
|
(getBalanceFromNetwork as jest.Mock).mockResolvedValue(mockInstruments);
|
|
37
42
|
|
|
38
|
-
const result = await getBalance("party-id");
|
|
43
|
+
const result = await getBalance(mockCurrency, "party-id");
|
|
39
44
|
|
|
40
|
-
expect(getBalanceFromNetwork).toHaveBeenCalledWith("party-id");
|
|
45
|
+
expect(getBalanceFromNetwork).toHaveBeenCalledWith(mockCurrency, "party-id");
|
|
41
46
|
expect(result).toEqual<Balance[]>([
|
|
42
47
|
{
|
|
43
48
|
value: BigInt(1000),
|
|
@@ -57,7 +62,7 @@ describe("getBalance", () => {
|
|
|
57
62
|
useGateway: false,
|
|
58
63
|
} as any);
|
|
59
64
|
|
|
60
|
-
await expect(getBalance("party-id")).rejects.toThrow("Not implemented");
|
|
65
|
+
await expect(getBalance(mockCurrency, "party-id")).rejects.toThrow("Not implemented");
|
|
61
66
|
expect(getBalanceFromNetwork).not.toHaveBeenCalled();
|
|
62
67
|
});
|
|
63
68
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { lastBlock } from "./lastBlock";
|
|
2
2
|
import { getLedgerEnd as gatewayGetLedgerEnd } from "../../network/gateway";
|
|
3
3
|
import { getLedgerEnd as nodeGetLedgerEnd } from "../../network/node";
|
|
4
|
+
import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
4
5
|
|
|
5
6
|
jest.mock("../../network/gateway", () => ({
|
|
6
7
|
getLedgerEnd: jest.fn(),
|
|
@@ -18,6 +19,10 @@ jest.mock("../../config", () => ({
|
|
|
18
19
|
|
|
19
20
|
import coinConfig from "../../config";
|
|
20
21
|
|
|
22
|
+
const mockCurrency = {
|
|
23
|
+
id: "canton_network",
|
|
24
|
+
} as unknown as CryptoCurrency;
|
|
25
|
+
|
|
21
26
|
describe("lastBlock", () => {
|
|
22
27
|
beforeEach(() => {
|
|
23
28
|
jest.clearAllMocks();
|
|
@@ -27,7 +32,7 @@ describe("lastBlock", () => {
|
|
|
27
32
|
(coinConfig.getCoinConfig as jest.Mock).mockReturnValue({ useGateway: true });
|
|
28
33
|
(gatewayGetLedgerEnd as jest.Mock).mockResolvedValue(100);
|
|
29
34
|
|
|
30
|
-
const result = await lastBlock();
|
|
35
|
+
const result = await lastBlock(mockCurrency);
|
|
31
36
|
|
|
32
37
|
expect(result).toEqual({ height: 100 });
|
|
33
38
|
expect(gatewayGetLedgerEnd).toHaveBeenCalledTimes(1);
|
|
@@ -38,7 +43,7 @@ describe("lastBlock", () => {
|
|
|
38
43
|
(coinConfig.getCoinConfig as jest.Mock).mockReturnValue({ useGateway: false });
|
|
39
44
|
(nodeGetLedgerEnd as jest.Mock).mockResolvedValue(200);
|
|
40
45
|
|
|
41
|
-
const result = await lastBlock();
|
|
46
|
+
const result = await lastBlock(mockCurrency);
|
|
42
47
|
|
|
43
48
|
expect(result).toEqual({ height: 200 });
|
|
44
49
|
expect(nodeGetLedgerEnd).toHaveBeenCalledTimes(1);
|
|
@@ -2,11 +2,13 @@ import type { BlockInfo } from "@ledgerhq/coin-framework/api/index";
|
|
|
2
2
|
import { getLedgerEnd as nodeGetLedgerEnd } from "../../network/node";
|
|
3
3
|
import { getLedgerEnd } from "../../network/gateway";
|
|
4
4
|
import coinConfig from "../../config";
|
|
5
|
+
import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
5
6
|
|
|
6
|
-
const useGateway = () =>
|
|
7
|
+
const useGateway = (currency: CryptoCurrency) =>
|
|
8
|
+
coinConfig.getCoinConfig(currency).useGateway === true;
|
|
7
9
|
|
|
8
|
-
export async function lastBlock(): Promise<BlockInfo> {
|
|
10
|
+
export async function lastBlock(currency: CryptoCurrency): Promise<BlockInfo> {
|
|
9
11
|
return {
|
|
10
|
-
height: useGateway() ? await getLedgerEnd() : await nodeGetLedgerEnd(),
|
|
12
|
+
height: useGateway(currency) ? await getLedgerEnd(currency) : await nodeGetLedgerEnd(),
|
|
11
13
|
};
|
|
12
14
|
}
|