@ledgerhq/coin-canton 0.7.0-nightly.2 → 0.7.0-nightly.3
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 +17 -0
- package/lib/api/lastBlock.integ.test.js +0 -15
- package/lib/api/lastBlock.integ.test.js.map +1 -1
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +2 -5
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/onboard.d.ts +11 -6
- package/lib/bridge/onboard.d.ts.map +1 -1
- package/lib/bridge/onboard.integ.test.js +49 -27
- package/lib/bridge/onboard.integ.test.js.map +1 -1
- package/lib/bridge/onboard.js +45 -152
- package/lib/bridge/onboard.js.map +1 -1
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +5 -5
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/sync.d.ts +3 -2
- package/lib/bridge/sync.d.ts.map +1 -1
- package/lib/bridge/sync.integ.test.js +31 -14
- package/lib/bridge/sync.integ.test.js.map +1 -1
- package/lib/bridge/sync.js +71 -57
- package/lib/bridge/sync.js.map +1 -1
- package/lib/common-logic/utils.js +2 -2
- package/lib/common-logic/utils.js.map +1 -1
- package/lib/common-logic/utils.test.js +21 -6
- package/lib/common-logic/utils.test.js.map +1 -1
- package/lib/config.d.ts +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/network/gateway.d.ts +9 -9
- package/lib/network/gateway.d.ts.map +1 -1
- package/lib/network/gateway.integ.test.js +31 -17
- package/lib/network/gateway.integ.test.js.map +1 -1
- package/lib/network/gateway.js +33 -15
- package/lib/network/gateway.js.map +1 -1
- package/lib/types/bridge.d.ts +6 -16
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/onboard.d.ts +5 -5
- package/lib/types/onboard.d.ts.map +1 -1
- package/lib/types/onboard.js +10 -10
- package/lib/types/onboard.js.map +1 -1
- package/lib-es/api/lastBlock.integ.test.js +0 -15
- package/lib-es/api/lastBlock.integ.test.js.map +1 -1
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +3 -6
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/onboard.d.ts +11 -6
- package/lib-es/bridge/onboard.d.ts.map +1 -1
- package/lib-es/bridge/onboard.integ.test.js +37 -15
- package/lib-es/bridge/onboard.integ.test.js.map +1 -1
- package/lib-es/bridge/onboard.js +44 -152
- package/lib-es/bridge/onboard.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +5 -5
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/sync.d.ts +3 -2
- package/lib-es/bridge/sync.d.ts.map +1 -1
- package/lib-es/bridge/sync.integ.test.js +26 -9
- package/lib-es/bridge/sync.integ.test.js.map +1 -1
- package/lib-es/bridge/sync.js +71 -56
- package/lib-es/bridge/sync.js.map +1 -1
- package/lib-es/common-logic/utils.js +2 -2
- package/lib-es/common-logic/utils.js.map +1 -1
- package/lib-es/common-logic/utils.test.js +21 -6
- package/lib-es/common-logic/utils.test.js.map +1 -1
- package/lib-es/config.d.ts +1 -1
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/network/gateway.d.ts +9 -9
- package/lib-es/network/gateway.d.ts.map +1 -1
- package/lib-es/network/gateway.integ.test.js +31 -17
- package/lib-es/network/gateway.integ.test.js.map +1 -1
- package/lib-es/network/gateway.js +33 -15
- package/lib-es/network/gateway.js.map +1 -1
- package/lib-es/types/bridge.d.ts +6 -16
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/onboard.d.ts +5 -5
- package/lib-es/types/onboard.d.ts.map +1 -1
- package/lib-es/types/onboard.js +9 -9
- package/lib-es/types/onboard.js.map +1 -1
- package/package.json +5 -4
- package/src/api/lastBlock.integ.test.ts +0 -18
- package/src/bridge/index.ts +3 -6
- package/src/bridge/onboard.integ.test.ts +44 -31
- package/src/bridge/onboard.ts +61 -209
- package/src/bridge/signOperation.ts +5 -6
- package/src/bridge/sync.integ.test.ts +30 -10
- package/src/bridge/sync.ts +87 -72
- package/src/common-logic/utils.test.ts +21 -6
- package/src/common-logic/utils.ts +2 -2
- package/src/config.ts +1 -1
- package/src/network/gateway.integ.test.ts +48 -21
- package/src/network/gateway.ts +49 -34
- package/src/types/bridge.ts +8 -19
- package/src/types/onboard.ts +5 -5
- package/lib/bridge/serialization.d.ts +0 -4
- package/lib/bridge/serialization.d.ts.map +0 -1
- package/lib/bridge/serialization.js +0 -31
- package/lib/bridge/serialization.js.map +0 -1
- package/lib-es/bridge/serialization.d.ts +0 -4
- package/lib-es/bridge/serialization.d.ts.map +0 -1
- package/lib-es/bridge/serialization.js +0 -27
- package/lib-es/bridge/serialization.js.map +0 -1
- package/src/bridge/serialization.ts +0 -36
package/src/bridge/onboard.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Observable } from "rxjs";
|
|
2
2
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { CantonAccount, CantonSigner } from "../types";
|
|
7
|
-
import type { Account, DerivationMode } from "@ledgerhq/types-live";
|
|
3
|
+
import type { Account, Operation } from "@ledgerhq/types-live";
|
|
4
|
+
import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
5
|
+
import { log } from "@ledgerhq/logs";
|
|
8
6
|
import {
|
|
9
7
|
prepareOnboarding,
|
|
10
8
|
submitOnboarding,
|
|
@@ -16,148 +14,84 @@ import {
|
|
|
16
14
|
} from "../network/gateway";
|
|
17
15
|
import {
|
|
18
16
|
OnboardStatus,
|
|
19
|
-
|
|
17
|
+
AuthorizeStatus,
|
|
20
18
|
CantonOnboardProgress,
|
|
21
19
|
CantonOnboardResult,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
PrepareTransactionResponse,
|
|
20
|
+
CantonAuthorizeProgress,
|
|
21
|
+
CantonAuthorizeResult,
|
|
25
22
|
} from "../types/onboard";
|
|
26
23
|
import resolver from "../signer";
|
|
27
|
-
import {
|
|
24
|
+
import type { CantonSigner } from "../types";
|
|
28
25
|
|
|
29
|
-
async
|
|
30
|
-
signerContext: SignerContext<CantonSigner>,
|
|
31
|
-
deviceId: string,
|
|
32
|
-
derivationPath: string,
|
|
33
|
-
) {
|
|
34
|
-
return signerContext(deviceId, async signer => {
|
|
35
|
-
const { publicKey, address } = await signer.getAddress(derivationPath);
|
|
36
|
-
return { signer, publicKey: publicKey.replace("0x", ""), address };
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const isAccountOnboarded = async (
|
|
41
|
-
currency: CryptoCurrency,
|
|
42
|
-
publicKey: string,
|
|
43
|
-
): Promise<{ isOnboarded: boolean; party_id?: string }> => {
|
|
26
|
+
export const isAccountOnboarded = async (currency: CryptoCurrency, publicKey: string) => {
|
|
44
27
|
try {
|
|
45
28
|
const { party_id } = await getPartyByPubKey(currency, publicKey);
|
|
46
29
|
|
|
47
30
|
if (party_id) {
|
|
48
|
-
return { isOnboarded: true, party_id };
|
|
31
|
+
return { isOnboarded: true, partyId: party_id };
|
|
49
32
|
} else {
|
|
50
33
|
return { isOnboarded: false };
|
|
51
34
|
}
|
|
52
35
|
} catch (err) {
|
|
53
|
-
log("[isAccountOnboarded] Error checking party status (likely not onboarded):", err);
|
|
54
36
|
return { isOnboarded: false };
|
|
55
37
|
}
|
|
56
38
|
};
|
|
57
39
|
|
|
40
|
+
export const isAccountAuthorized = async (operations: Operation[], partyId: string) => {
|
|
41
|
+
// temporary solution to check if the account is authorized
|
|
42
|
+
return operations.some(operation => operation.senders.includes(partyId));
|
|
43
|
+
};
|
|
44
|
+
|
|
58
45
|
export const buildOnboardAccount =
|
|
59
46
|
(signerContext: SignerContext<CantonSigner>) =>
|
|
60
47
|
(
|
|
61
48
|
currency: CryptoCurrency,
|
|
62
49
|
deviceId: string,
|
|
63
|
-
|
|
50
|
+
account: Account,
|
|
64
51
|
): Observable<CantonOnboardProgress | CantonOnboardResult> =>
|
|
65
|
-
new Observable(
|
|
52
|
+
new Observable(o => {
|
|
66
53
|
async function main() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
const derivationMode = getDerivationModesForCurrency(currency)[0];
|
|
54
|
+
o.next({ status: OnboardStatus.INIT });
|
|
55
|
+
|
|
71
56
|
const getAddress = resolver(signerContext);
|
|
72
|
-
const {
|
|
73
|
-
path:
|
|
57
|
+
const { publicKey } = await getAddress(deviceId, {
|
|
58
|
+
path: account.freshAddressPath,
|
|
74
59
|
currency,
|
|
75
|
-
derivationMode: derivationMode
|
|
60
|
+
derivationMode: account.derivationMode,
|
|
76
61
|
});
|
|
77
62
|
|
|
78
|
-
|
|
79
|
-
status: OnboardStatus.PREPARE,
|
|
80
|
-
});
|
|
63
|
+
o.next({ status: OnboardStatus.PREPARE });
|
|
81
64
|
|
|
82
|
-
|
|
65
|
+
let { partyId } = await isAccountOnboarded(currency, publicKey);
|
|
83
66
|
if (partyId) {
|
|
84
|
-
|
|
85
|
-
address,
|
|
86
|
-
derivationPath,
|
|
87
|
-
partyId,
|
|
88
|
-
currency,
|
|
89
|
-
derivationMode,
|
|
90
|
-
});
|
|
91
|
-
observer.next({
|
|
92
|
-
partyId,
|
|
93
|
-
account,
|
|
94
|
-
});
|
|
95
|
-
observer.complete();
|
|
67
|
+
o.next({ partyId, account }); // success
|
|
96
68
|
return;
|
|
97
69
|
}
|
|
98
70
|
|
|
99
|
-
const preparedTransaction = await prepareOnboarding(currency, publicKey
|
|
71
|
+
const preparedTransaction = await prepareOnboarding(currency, publicKey);
|
|
72
|
+
partyId = preparedTransaction.party_id;
|
|
100
73
|
|
|
101
|
-
|
|
102
|
-
status: OnboardStatus.SIGN,
|
|
103
|
-
});
|
|
74
|
+
o.next({ status: OnboardStatus.SIGN });
|
|
104
75
|
|
|
105
76
|
const signature = await signerContext(deviceId, signer =>
|
|
106
|
-
signer.signTransaction(
|
|
77
|
+
signer.signTransaction(
|
|
78
|
+
account.freshAddressPath,
|
|
79
|
+
preparedTransaction.transactions.combined_hash,
|
|
80
|
+
),
|
|
107
81
|
);
|
|
108
82
|
|
|
109
|
-
|
|
110
|
-
status: OnboardStatus.SUBMIT,
|
|
111
|
-
});
|
|
83
|
+
o.next({ status: OnboardStatus.SUBMIT });
|
|
112
84
|
|
|
113
|
-
|
|
114
|
-
currency,
|
|
115
|
-
{ public_key: publicKey, public_key_type: "ed25519" },
|
|
116
|
-
preparedTransaction,
|
|
117
|
-
signature,
|
|
118
|
-
).catch(async err => {
|
|
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
|
-
});
|
|
127
|
-
observer.next({
|
|
128
|
-
partyId: preparedTransaction.party_id,
|
|
129
|
-
account,
|
|
130
|
-
});
|
|
131
|
-
return observer.complete();
|
|
132
|
-
}
|
|
133
|
-
throw err;
|
|
134
|
-
});
|
|
135
|
-
|
|
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
|
-
}
|
|
85
|
+
await submitOnboarding(currency, publicKey, preparedTransaction, signature);
|
|
152
86
|
|
|
153
|
-
|
|
87
|
+
o.next({ partyId, account }); // success
|
|
154
88
|
}
|
|
155
89
|
|
|
156
90
|
main().then(
|
|
157
|
-
() =>
|
|
91
|
+
() => o.complete(),
|
|
158
92
|
error => {
|
|
159
|
-
log("[
|
|
160
|
-
|
|
93
|
+
log("[canton:onboard] onboardAccount failed:", error);
|
|
94
|
+
o.error(error);
|
|
161
95
|
},
|
|
162
96
|
);
|
|
163
97
|
});
|
|
@@ -167,146 +101,64 @@ export const buildAuthorizePreapproval =
|
|
|
167
101
|
(
|
|
168
102
|
currency: CryptoCurrency,
|
|
169
103
|
deviceId: string,
|
|
170
|
-
|
|
104
|
+
account: Account,
|
|
171
105
|
partyId: string,
|
|
172
|
-
): Observable<
|
|
173
|
-
new Observable(
|
|
106
|
+
): Observable<CantonAuthorizeProgress | CantonAuthorizeResult> =>
|
|
107
|
+
new Observable(o => {
|
|
174
108
|
async function main() {
|
|
175
|
-
|
|
176
|
-
status: PreApprovalStatus.PREPARE,
|
|
177
|
-
});
|
|
109
|
+
o.next({ status: AuthorizeStatus.INIT });
|
|
178
110
|
|
|
179
|
-
const
|
|
180
|
-
currency,
|
|
181
|
-
partyId,
|
|
182
|
-
);
|
|
111
|
+
const isAuthorized = await isAccountAuthorized(account.operations, partyId);
|
|
183
112
|
|
|
184
|
-
|
|
185
|
-
status:
|
|
186
|
-
});
|
|
113
|
+
if (!isAuthorized) {
|
|
114
|
+
o.next({ status: AuthorizeStatus.PREPARE });
|
|
187
115
|
|
|
188
|
-
|
|
189
|
-
signer.signTransaction(derivationPath, preparedTransaction.hash),
|
|
190
|
-
);
|
|
116
|
+
const preparedTransaction = await preparePreApprovalTransaction(currency, partyId);
|
|
191
117
|
|
|
192
|
-
|
|
193
|
-
status: PreApprovalStatus.SUBMIT,
|
|
194
|
-
});
|
|
118
|
+
o.next({ status: AuthorizeStatus.SIGN });
|
|
195
119
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
preparedTransaction,
|
|
200
|
-
signature,
|
|
201
|
-
);
|
|
120
|
+
const signature = await signerContext(deviceId, signer =>
|
|
121
|
+
signer.signTransaction(account.freshAddressPath, preparedTransaction.hash),
|
|
122
|
+
);
|
|
202
123
|
|
|
203
|
-
|
|
204
|
-
status: PreApprovalStatus.SUCCESS,
|
|
205
|
-
});
|
|
124
|
+
o.next({ status: AuthorizeStatus.SUBMIT });
|
|
206
125
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
126
|
+
await submitPreApprovalTransaction(currency, partyId, preparedTransaction, signature);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
o.next({ isApproved: true }); // success
|
|
210
130
|
|
|
211
131
|
const handleTapRequest = async () => {
|
|
212
132
|
try {
|
|
213
|
-
const { serialized, hash } = await prepareTapRequest(currency, {
|
|
214
|
-
partyId,
|
|
215
|
-
});
|
|
133
|
+
const { serialized, hash } = await prepareTapRequest(currency, { partyId });
|
|
216
134
|
|
|
217
135
|
if (serialized && hash) {
|
|
218
|
-
|
|
219
|
-
status: PreApprovalStatus.SIGN,
|
|
220
|
-
});
|
|
136
|
+
o.next({ status: AuthorizeStatus.SIGN });
|
|
221
137
|
|
|
222
138
|
const signature = await signerContext(deviceId, signer =>
|
|
223
|
-
signer.signTransaction(
|
|
139
|
+
signer.signTransaction(account.freshAddressPath, hash),
|
|
224
140
|
);
|
|
225
141
|
|
|
226
|
-
|
|
227
|
-
status: PreApprovalStatus.SUBMIT,
|
|
228
|
-
});
|
|
142
|
+
o.next({ status: AuthorizeStatus.SUBMIT });
|
|
229
143
|
|
|
230
144
|
await submitTapRequest(currency, {
|
|
231
145
|
partyId,
|
|
232
146
|
serialized,
|
|
233
147
|
signature,
|
|
234
148
|
});
|
|
235
|
-
|
|
236
|
-
observer.next({
|
|
237
|
-
status: PreApprovalStatus.SUCCESS,
|
|
238
|
-
});
|
|
239
149
|
}
|
|
240
150
|
} catch (err) {
|
|
241
151
|
// Tap request failure should not break the pre-approval flow
|
|
242
152
|
}
|
|
243
153
|
};
|
|
244
154
|
await handleTapRequest();
|
|
245
|
-
|
|
246
|
-
observer.complete();
|
|
247
155
|
}
|
|
248
156
|
|
|
249
157
|
main().then(
|
|
250
|
-
() =>
|
|
158
|
+
() => o.complete(),
|
|
251
159
|
error => {
|
|
252
|
-
log("[
|
|
253
|
-
|
|
160
|
+
log("[canton:onboard] authorizePreapproval failed:", error);
|
|
161
|
+
o.error(error);
|
|
254
162
|
},
|
|
255
163
|
);
|
|
256
164
|
});
|
|
257
|
-
|
|
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[]) => {
|
|
310
|
-
// eslint-disable-next-line no-console
|
|
311
|
-
console.log(message, ...rest);
|
|
312
|
-
};
|
|
@@ -4,6 +4,7 @@ import { FeeNotLoaded } from "@ledgerhq/errors";
|
|
|
4
4
|
import { AccountBridge, Operation } from "@ledgerhq/types-live";
|
|
5
5
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
6
6
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
7
|
+
import { decodeAccountId } from "@ledgerhq/coin-framework/account";
|
|
7
8
|
import { combine, craftTransaction } from "../common-logic";
|
|
8
9
|
import { Transaction, CantonSigner } from "../types";
|
|
9
10
|
|
|
@@ -22,10 +23,8 @@ export const buildSignOperation =
|
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
const signature = await signerContext(deviceId, async signer => {
|
|
25
|
-
const { freshAddressPath: derivationPath } = account;
|
|
26
|
-
const
|
|
27
|
-
.cantonResources.partyId;
|
|
28
|
-
|
|
26
|
+
const { id, freshAddressPath: derivationPath, xpub } = account;
|
|
27
|
+
const address = xpub ?? decodeAccountId(id).xpubOrAddress;
|
|
29
28
|
const params: {
|
|
30
29
|
recipient?: string;
|
|
31
30
|
amount: BigNumber;
|
|
@@ -45,13 +44,13 @@ export const buildSignOperation =
|
|
|
45
44
|
const { hash, serializedTransaction } = await craftTransaction(
|
|
46
45
|
account.currency,
|
|
47
46
|
{
|
|
48
|
-
address
|
|
47
|
+
address,
|
|
49
48
|
},
|
|
50
49
|
params,
|
|
51
50
|
);
|
|
52
51
|
const transactionSignature = await signer.signTransaction(derivationPath, hash);
|
|
53
52
|
|
|
54
|
-
return combine(serializedTransaction, `${transactionSignature}__PARTY__${
|
|
53
|
+
return combine(serializedTransaction, `${transactionSignature}__PARTY__${address}`);
|
|
55
54
|
});
|
|
56
55
|
|
|
57
56
|
o.next({
|
|
@@ -9,7 +9,9 @@ import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
|
|
|
9
9
|
import { Account, Operation } from "@ledgerhq/types-live";
|
|
10
10
|
import coinConfig from "../config";
|
|
11
11
|
import * as gateway from "../network/gateway";
|
|
12
|
-
import {
|
|
12
|
+
import { generateMockKeyPair, createMockSigner } from "../test/cantonTestUtils";
|
|
13
|
+
import { CantonAccount } from "../types";
|
|
14
|
+
import { makeGetAccountShape } from "./sync";
|
|
13
15
|
|
|
14
16
|
const TEST_ADDRESS =
|
|
15
17
|
"b6400f93ea1c74aea86be39b0ccc846fc5de01f12b2ad0d7c31848d6fb6eb6d9::1220c81315e2bf2524a9141bcc6cbf19b61c151e0dcaa95343c0ccf53aed7415c4ec";
|
|
@@ -22,14 +24,25 @@ const derivationPath = runDerivationScheme(
|
|
|
22
24
|
account: 0,
|
|
23
25
|
},
|
|
24
26
|
);
|
|
25
|
-
const
|
|
27
|
+
const xpub = TEST_ADDRESS;
|
|
28
|
+
const ACCOUNT_SHAPE_INFO: AccountShapeInfo<CantonAccount> = {
|
|
26
29
|
address: TEST_ADDRESS,
|
|
27
30
|
currency,
|
|
28
31
|
derivationMode,
|
|
29
32
|
derivationPath,
|
|
30
33
|
index: 0,
|
|
34
|
+
initialAccount: {
|
|
35
|
+
xpub,
|
|
36
|
+
} as CantonAccount,
|
|
31
37
|
};
|
|
32
38
|
|
|
39
|
+
// Mock signer context for testing
|
|
40
|
+
const keyPair = generateMockKeyPair();
|
|
41
|
+
const mockSigner = createMockSigner(keyPair);
|
|
42
|
+
const mockSignerContext = jest.fn().mockImplementation((deviceId, callback) => {
|
|
43
|
+
return callback(mockSigner);
|
|
44
|
+
});
|
|
45
|
+
|
|
33
46
|
describe("sync (devnet)", () => {
|
|
34
47
|
beforeAll(async () => {
|
|
35
48
|
coinConfig.setCoinConfig(() => ({
|
|
@@ -43,13 +56,14 @@ describe("sync (devnet)", () => {
|
|
|
43
56
|
}));
|
|
44
57
|
});
|
|
45
58
|
|
|
46
|
-
describe("
|
|
59
|
+
describe("makeGetAccountShape", () => {
|
|
47
60
|
it("should fetch account shape for a valid address", async () => {
|
|
61
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
48
62
|
const result = await getAccountShape(ACCOUNT_SHAPE_INFO, { paginationConfig: {} });
|
|
49
63
|
|
|
50
64
|
expect(result).toBeDefined();
|
|
51
65
|
expect(result.id).toBeDefined();
|
|
52
|
-
expect(result.xpub).toBe(TEST_ADDRESS
|
|
66
|
+
expect(result.xpub).toBe(TEST_ADDRESS);
|
|
53
67
|
expect(result.blockHeight).toBeGreaterThan(0);
|
|
54
68
|
expect(result.balance).toBeDefined();
|
|
55
69
|
expect(result.spendableBalance).toBeDefined();
|
|
@@ -67,12 +81,15 @@ describe("sync (devnet)", () => {
|
|
|
67
81
|
});
|
|
68
82
|
|
|
69
83
|
it("should handle address with colons correctly", async () => {
|
|
84
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
70
85
|
const result = await getAccountShape(ACCOUNT_SHAPE_INFO, { paginationConfig: {} });
|
|
71
86
|
|
|
72
|
-
expect(result.xpub).
|
|
87
|
+
expect(result.xpub).toContain("::");
|
|
73
88
|
});
|
|
74
89
|
|
|
75
90
|
it("should merge operations correctly with initial account", async () => {
|
|
91
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
92
|
+
|
|
76
93
|
const operations: Operation[] = [
|
|
77
94
|
{
|
|
78
95
|
id: "test-op-1",
|
|
@@ -95,7 +112,7 @@ describe("sync (devnet)", () => {
|
|
|
95
112
|
{
|
|
96
113
|
...ACCOUNT_SHAPE_INFO,
|
|
97
114
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
98
|
-
initialAccount: { operations } as Account,
|
|
115
|
+
initialAccount: { xpub, operations } as Account,
|
|
99
116
|
},
|
|
100
117
|
{ paginationConfig: {} },
|
|
101
118
|
);
|
|
@@ -117,6 +134,7 @@ describe("sync (devnet)", () => {
|
|
|
117
134
|
},
|
|
118
135
|
]);
|
|
119
136
|
|
|
137
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
120
138
|
const result = await getAccountShape(ACCOUNT_SHAPE_INFO, { paginationConfig: {} });
|
|
121
139
|
|
|
122
140
|
expect(result.balance?.toNumber()).toBe(1000000);
|
|
@@ -125,7 +143,7 @@ describe("sync (devnet)", () => {
|
|
|
125
143
|
mockGetBalance.mockRestore();
|
|
126
144
|
});
|
|
127
145
|
|
|
128
|
-
it("should call getOperations with correct cursor based
|
|
146
|
+
it("should call getOperations with correct cursor based on initial account", async () => {
|
|
129
147
|
const mockGetOperations = jest.spyOn(gateway, "getOperations");
|
|
130
148
|
const operation: Operation = {
|
|
131
149
|
id: "test-op-1",
|
|
@@ -144,8 +162,9 @@ describe("sync (devnet)", () => {
|
|
|
144
162
|
};
|
|
145
163
|
|
|
146
164
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
147
|
-
const initialAccount = { operations: [operation] } as Account;
|
|
165
|
+
const initialAccount = { xpub, operations: [operation] } as Account;
|
|
148
166
|
|
|
167
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
149
168
|
const result = await getAccountShape(
|
|
150
169
|
{
|
|
151
170
|
...ACCOUNT_SHAPE_INFO,
|
|
@@ -154,7 +173,7 @@ describe("sync (devnet)", () => {
|
|
|
154
173
|
{ paginationConfig: {} },
|
|
155
174
|
);
|
|
156
175
|
|
|
157
|
-
expect(mockGetOperations).toHaveBeenCalledWith(TEST_ADDRESS, {
|
|
176
|
+
expect(mockGetOperations).toHaveBeenCalledWith(currency, TEST_ADDRESS, {
|
|
158
177
|
cursor: (operation.blockHeight || 0) + 1,
|
|
159
178
|
limit: 100,
|
|
160
179
|
});
|
|
@@ -165,12 +184,13 @@ describe("sync (devnet)", () => {
|
|
|
165
184
|
it("should call getOperations with cursor 0 when no initial account", async () => {
|
|
166
185
|
const mockGetOperations = jest.spyOn(gateway, "getOperations");
|
|
167
186
|
|
|
187
|
+
const getAccountShape = makeGetAccountShape(mockSignerContext);
|
|
168
188
|
const result = await getAccountShape(ACCOUNT_SHAPE_INFO, { paginationConfig: {} });
|
|
169
189
|
|
|
170
190
|
expect(result.operations).toBeDefined();
|
|
171
191
|
expect(result.operationsCount).toBeGreaterThanOrEqual(1);
|
|
172
192
|
|
|
173
|
-
expect(mockGetOperations).toHaveBeenCalledWith(TEST_ADDRESS, {
|
|
193
|
+
expect(mockGetOperations).toHaveBeenCalledWith(currency, TEST_ADDRESS, {
|
|
174
194
|
cursor: 0,
|
|
175
195
|
limit: 100,
|
|
176
196
|
});
|