@ledgerhq/coin-canton 0.5.0-nightly.1 → 0.5.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/.unimportedrc.json +12 -4
- package/CHANGELOG.md +32 -0
- package/lib/api/getBalance.integ.test.js +1 -1
- package/lib/api/getBalance.integ.test.js.map +1 -1
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +11 -8
- package/lib/api/index.js.map +1 -1
- package/lib/bridge/broadcast.d.ts.map +1 -1
- package/lib/bridge/broadcast.js +2 -1
- package/lib/bridge/broadcast.js.map +1 -1
- package/lib/bridge/createTransaction.test.js +1 -1
- package/lib/bridge/createTransaction.test.js.map +1 -1
- package/lib/bridge/index.d.ts +3 -3
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +9 -1
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/onboard.d.ts +10 -0
- package/lib/bridge/onboard.d.ts.map +1 -0
- package/lib/bridge/onboard.integ.test.d.ts +2 -0
- package/lib/bridge/onboard.integ.test.d.ts.map +1 -0
- package/lib/bridge/onboard.integ.test.js +156 -0
- package/lib/bridge/onboard.integ.test.js.map +1 -0
- package/lib/bridge/onboard.js +139 -0
- package/lib/bridge/onboard.js.map +1 -0
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +5 -7
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +7 -9
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/sync.d.ts.map +1 -1
- package/lib/bridge/sync.integ.test.d.ts +2 -0
- package/lib/bridge/sync.integ.test.d.ts.map +1 -0
- package/lib/bridge/sync.integ.test.js +175 -0
- package/lib/bridge/sync.integ.test.js.map +1 -0
- package/lib/bridge/sync.js +40 -36
- package/lib/bridge/sync.js.map +1 -1
- package/lib/bridge/updateTransaction.d.ts.map +1 -1
- package/lib/bridge/updateTransaction.js +0 -4
- package/lib/bridge/updateTransaction.js.map +1 -1
- package/lib/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib/common-logic/history/listOperations.js +19 -31
- package/lib/common-logic/history/listOperations.js.map +1 -1
- package/lib/common-logic/transaction/broadcast.d.ts.map +1 -1
- package/lib/common-logic/transaction/broadcast.js +2 -1
- package/lib/common-logic/transaction/broadcast.js.map +1 -1
- package/lib/common-logic/transaction/broadcast.test.js +3 -3
- package/lib/common-logic/transaction/broadcast.test.js.map +1 -1
- package/lib/common-logic/transaction/combine.d.ts +1 -1
- package/lib/common-logic/transaction/combine.d.ts.map +1 -1
- package/lib/common-logic/transaction/combine.js +2 -3
- package/lib/common-logic/transaction/combine.js.map +1 -1
- package/lib/common-logic/transaction/combine.test.js +3 -13
- package/lib/common-logic/transaction/combine.test.js.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.d.ts +5 -3
- package/lib/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.js +11 -12
- package/lib/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib/network/gateway.d.ts +196 -5
- package/lib/network/gateway.d.ts.map +1 -1
- package/lib/network/gateway.integ.test.js +121 -11
- package/lib/network/gateway.integ.test.js.map +1 -1
- package/lib/network/gateway.js +99 -21
- package/lib/network/gateway.js.map +1 -1
- package/lib/network/node.d.ts +2 -2
- package/lib/network/node.d.ts.map +1 -1
- package/lib/network/node.js.map +1 -1
- package/lib/network/types.d.ts +1 -1
- package/lib/network/types.d.ts.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/test/cantonTestUtils.d.ts +33 -0
- package/lib/test/cantonTestUtils.d.ts.map +1 -0
- package/lib/test/cantonTestUtils.js +159 -0
- package/lib/test/cantonTestUtils.js.map +1 -0
- package/lib/types/bridge.d.ts +7 -1
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -10
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +1 -0
- package/lib/types/index.js.map +1 -1
- package/lib/types/onboard.d.ts +55 -0
- package/lib/types/onboard.d.ts.map +1 -0
- package/lib/types/onboard.js +22 -0
- package/lib/types/onboard.js.map +1 -0
- package/lib-es/api/getBalance.integ.test.js +1 -1
- 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 +12 -9
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/bridge/broadcast.d.ts.map +1 -1
- package/lib-es/bridge/broadcast.js +2 -1
- package/lib-es/bridge/broadcast.js.map +1 -1
- package/lib-es/bridge/createTransaction.test.js +1 -1
- package/lib-es/bridge/createTransaction.test.js.map +1 -1
- package/lib-es/bridge/index.d.ts +3 -3
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +9 -1
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/onboard.d.ts +10 -0
- package/lib-es/bridge/onboard.d.ts.map +1 -0
- package/lib-es/bridge/onboard.integ.test.d.ts +2 -0
- package/lib-es/bridge/onboard.integ.test.d.ts.map +1 -0
- package/lib-es/bridge/onboard.integ.test.js +151 -0
- package/lib-es/bridge/onboard.integ.test.js.map +1 -0
- package/lib-es/bridge/onboard.js +133 -0
- package/lib-es/bridge/onboard.js.map +1 -0
- package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +6 -8
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +8 -10
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/sync.d.ts.map +1 -1
- package/lib-es/bridge/sync.integ.test.d.ts +2 -0
- package/lib-es/bridge/sync.integ.test.d.ts.map +1 -0
- package/lib-es/bridge/sync.integ.test.js +137 -0
- package/lib-es/bridge/sync.integ.test.js.map +1 -0
- package/lib-es/bridge/sync.js +39 -35
- package/lib-es/bridge/sync.js.map +1 -1
- package/lib-es/bridge/updateTransaction.d.ts.map +1 -1
- package/lib-es/bridge/updateTransaction.js +0 -4
- package/lib-es/bridge/updateTransaction.js.map +1 -1
- package/lib-es/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib-es/common-logic/history/listOperations.js +20 -29
- package/lib-es/common-logic/history/listOperations.js.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.js +2 -1
- package/lib-es/common-logic/transaction/broadcast.js.map +1 -1
- package/lib-es/common-logic/transaction/broadcast.test.js +3 -3
- package/lib-es/common-logic/transaction/broadcast.test.js.map +1 -1
- package/lib-es/common-logic/transaction/combine.d.ts +1 -1
- package/lib-es/common-logic/transaction/combine.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/combine.js +2 -3
- package/lib-es/common-logic/transaction/combine.js.map +1 -1
- package/lib-es/common-logic/transaction/combine.test.js +3 -13
- package/lib-es/common-logic/transaction/combine.test.js.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.d.ts +5 -3
- package/lib-es/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.js +11 -12
- package/lib-es/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib-es/network/gateway.d.ts +196 -5
- package/lib-es/network/gateway.d.ts.map +1 -1
- package/lib-es/network/gateway.integ.test.js +122 -12
- package/lib-es/network/gateway.integ.test.js.map +1 -1
- package/lib-es/network/gateway.js +93 -20
- package/lib-es/network/gateway.js.map +1 -1
- package/lib-es/network/node.d.ts +2 -2
- package/lib-es/network/node.d.ts.map +1 -1
- package/lib-es/network/node.js.map +1 -1
- package/lib-es/network/types.d.ts +1 -1
- package/lib-es/network/types.d.ts.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/test/cantonTestUtils.d.ts +33 -0
- package/lib-es/test/cantonTestUtils.d.ts.map +1 -0
- package/lib-es/test/cantonTestUtils.js +151 -0
- package/lib-es/test/cantonTestUtils.js.map +1 -0
- package/lib-es/types/bridge.d.ts +7 -1
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/index.d.ts +1 -10
- package/lib-es/types/index.d.ts.map +1 -1
- package/lib-es/types/index.js +1 -0
- package/lib-es/types/index.js.map +1 -1
- package/lib-es/types/onboard.d.ts +55 -0
- package/lib-es/types/onboard.d.ts.map +1 -0
- package/lib-es/types/onboard.js +19 -0
- package/lib-es/types/onboard.js.map +1 -0
- package/package.json +7 -7
- package/src/api/getBalance.integ.test.ts +1 -2
- package/src/api/index.ts +33 -26
- package/src/bridge/broadcast.ts +2 -3
- package/src/bridge/createTransaction.test.ts +1 -1
- package/src/bridge/index.ts +14 -4
- package/src/bridge/onboard.integ.test.ts +219 -0
- package/src/bridge/onboard.ts +220 -0
- package/src/bridge/prepareTransaction.ts +6 -15
- package/src/bridge/signOperation.ts +9 -16
- package/src/bridge/sync.integ.test.ts +180 -0
- package/src/bridge/sync.ts +61 -49
- package/src/bridge/updateTransaction.ts +0 -5
- package/src/common-logic/history/listOperations.ts +20 -31
- package/src/common-logic/transaction/broadcast.test.ts +3 -3
- package/src/common-logic/transaction/broadcast.ts +2 -1
- package/src/common-logic/transaction/combine.test.ts +3 -13
- package/src/common-logic/transaction/combine.ts +2 -4
- package/src/common-logic/transaction/craftTransaction.ts +15 -17
- package/src/network/gateway.integ.test.ts +156 -17
- package/src/network/gateway.ts +337 -30
- package/src/network/node.ts +3 -3
- package/src/network/types.ts +1 -1
- package/src/signer/getAddress.ts +3 -5
- package/src/test/cantonTestUtils.ts +181 -0
- package/src/types/bridge.ts +20 -0
- package/src/types/index.ts +1 -11
- package/src/types/onboard.ts +65 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { firstValueFrom, toArray } from "rxjs";
|
|
2
|
+
import { generateMockKeyPair, createMockSigner } from "../test/cantonTestUtils";
|
|
3
|
+
import { buildOnboardAccount, isAccountOnboarded, buildAuthorizePreapproval } from "./onboard";
|
|
4
|
+
import {
|
|
5
|
+
OnboardStatus,
|
|
6
|
+
PreApprovalStatus,
|
|
7
|
+
CantonOnboardProgress,
|
|
8
|
+
CantonOnboardResult,
|
|
9
|
+
CantonPreApprovalProgress,
|
|
10
|
+
CantonPreApprovalResult,
|
|
11
|
+
} from "../types/onboard";
|
|
12
|
+
import coinConfig from "../config";
|
|
13
|
+
|
|
14
|
+
describe("onboard (devnet)", () => {
|
|
15
|
+
const mockDeviceId = "test-device-id";
|
|
16
|
+
const mockDerivationPath = "44'/6767'/0'/0'/0'";
|
|
17
|
+
|
|
18
|
+
let onboardedAccount: {
|
|
19
|
+
keyPair: ReturnType<typeof generateMockKeyPair>;
|
|
20
|
+
mockSigner: ReturnType<typeof createMockSigner>;
|
|
21
|
+
mockSignerContext: jest.Mock;
|
|
22
|
+
onboardResult: CantonOnboardResult;
|
|
23
|
+
} | null = null;
|
|
24
|
+
|
|
25
|
+
beforeAll(() => {
|
|
26
|
+
coinConfig.setCoinConfig(() => ({
|
|
27
|
+
gatewayUrl: "https://canton-gateway.api.live.ledger-test.com",
|
|
28
|
+
useGateway: true,
|
|
29
|
+
networkType: "devnet",
|
|
30
|
+
status: {
|
|
31
|
+
type: "active",
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const getOnboardedAccount = () => {
|
|
37
|
+
if (!onboardedAccount) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
"onboardedAccount is null. Ensure isAccountOnboarded test runs first to set it.",
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return onboardedAccount;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
describe("isAccountOnboarded", () => {
|
|
46
|
+
it("should return true for onboarded account", async () => {
|
|
47
|
+
// GIVEN
|
|
48
|
+
const keyPair = generateMockKeyPair();
|
|
49
|
+
const mockSigner = createMockSigner(keyPair);
|
|
50
|
+
const mockSignerContext = jest.fn().mockImplementation((deviceId, callback) => {
|
|
51
|
+
return callback(mockSigner);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const onboardObservable = buildOnboardAccount(mockSignerContext);
|
|
55
|
+
const onboardValues = await firstValueFrom(
|
|
56
|
+
onboardObservable(mockDeviceId, mockDerivationPath).pipe(toArray()),
|
|
57
|
+
);
|
|
58
|
+
const onboardResult = onboardValues.find(
|
|
59
|
+
(value): value is CantonOnboardResult => "partyId" in value,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (!onboardResult) {
|
|
63
|
+
throw new Error("Failed to onboard account for shared test data");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Save onboarded account for all tests that need a valid party ID
|
|
67
|
+
onboardedAccount = {
|
|
68
|
+
keyPair,
|
|
69
|
+
mockSigner,
|
|
70
|
+
mockSignerContext,
|
|
71
|
+
onboardResult,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// WHEN
|
|
75
|
+
const result = await isAccountOnboarded(keyPair.publicKeyHex);
|
|
76
|
+
|
|
77
|
+
// THEN
|
|
78
|
+
expect(result).not.toBe(false);
|
|
79
|
+
if (typeof result === "object") {
|
|
80
|
+
expect(result.party_id).toBeDefined();
|
|
81
|
+
expect(result.party_id).toBe(onboardResult!.partyId);
|
|
82
|
+
}
|
|
83
|
+
}, 30000);
|
|
84
|
+
|
|
85
|
+
it("should return false for non-onboarded account with fresh keypair", async () => {
|
|
86
|
+
// GIVEN
|
|
87
|
+
const keyPair = generateMockKeyPair();
|
|
88
|
+
|
|
89
|
+
// WHEN
|
|
90
|
+
const result = await isAccountOnboarded(keyPair.publicKeyHex);
|
|
91
|
+
|
|
92
|
+
// THEN
|
|
93
|
+
expect(result).toBe(false);
|
|
94
|
+
}, 15000);
|
|
95
|
+
|
|
96
|
+
it("should handle errors gracefully when checking non-existent party", async () => {
|
|
97
|
+
// GIVEN
|
|
98
|
+
const keyPair = generateMockKeyPair();
|
|
99
|
+
|
|
100
|
+
// WHEN
|
|
101
|
+
const result = await isAccountOnboarded(keyPair.publicKeyHex);
|
|
102
|
+
|
|
103
|
+
// THEN
|
|
104
|
+
expect(result).toBe(false);
|
|
105
|
+
}, 15000);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("buildOnboardAccount", () => {
|
|
109
|
+
it("should complete full onboarding flow with fresh keypair", async () => {
|
|
110
|
+
// GIVEN
|
|
111
|
+
const keyPair = generateMockKeyPair();
|
|
112
|
+
const mockSigner = createMockSigner(keyPair);
|
|
113
|
+
const mockSignerContext = jest.fn().mockImplementation((deviceId, callback) => {
|
|
114
|
+
return callback(mockSigner);
|
|
115
|
+
});
|
|
116
|
+
const onboardObservable = buildOnboardAccount(mockSignerContext);
|
|
117
|
+
|
|
118
|
+
// WHEN
|
|
119
|
+
const allValues = await firstValueFrom(
|
|
120
|
+
onboardObservable(mockDeviceId, mockDerivationPath).pipe(toArray()),
|
|
121
|
+
);
|
|
122
|
+
const progressValues = allValues.filter(
|
|
123
|
+
(value): value is CantonOnboardProgress => "status" in value && !("partyId" in value),
|
|
124
|
+
);
|
|
125
|
+
const resultValues = allValues.filter(
|
|
126
|
+
(value): value is CantonOnboardResult => "partyId" in value,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// THEN
|
|
130
|
+
// Check expected status progression
|
|
131
|
+
expect(progressValues.some(p => p.status === OnboardStatus.INIT)).toBe(true);
|
|
132
|
+
expect(progressValues.some(p => p.status === OnboardStatus.PREPARE)).toBe(true);
|
|
133
|
+
expect(progressValues.some(p => p.status === OnboardStatus.SIGN)).toBe(true);
|
|
134
|
+
expect(progressValues.some(p => p.status === OnboardStatus.SUBMIT)).toBe(true);
|
|
135
|
+
|
|
136
|
+
// Check final result
|
|
137
|
+
expect(resultValues.length).toBeGreaterThan(0);
|
|
138
|
+
const finalResult = resultValues[resultValues.length - 1];
|
|
139
|
+
expect(finalResult.partyId).toBeDefined();
|
|
140
|
+
expect(typeof finalResult.partyId).toBe("string");
|
|
141
|
+
|
|
142
|
+
expect(mockSignerContext).toHaveBeenCalled();
|
|
143
|
+
}, 30000);
|
|
144
|
+
|
|
145
|
+
it("should complete full onboarding flow with already onboarded account", async () => {
|
|
146
|
+
// GIVEN
|
|
147
|
+
const { keyPair, mockSignerContext, onboardResult: firstResult } = getOnboardedAccount();
|
|
148
|
+
const secondOnboardObservable = buildOnboardAccount(mockSignerContext);
|
|
149
|
+
|
|
150
|
+
// WHEN
|
|
151
|
+
const secondOnboardValues = await firstValueFrom(
|
|
152
|
+
secondOnboardObservable(mockDeviceId, mockDerivationPath).pipe(toArray()),
|
|
153
|
+
);
|
|
154
|
+
const secondResult = secondOnboardValues.find(
|
|
155
|
+
(value): value is CantonOnboardResult => "partyId" in value,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// THEN
|
|
159
|
+
expect(secondResult).toBeDefined();
|
|
160
|
+
expect(secondResult!.partyId).toBe(firstResult.partyId);
|
|
161
|
+
expect(typeof secondResult!.partyId).toBe("string");
|
|
162
|
+
}, 30000);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("buildAuthorizePreapproval", () => {
|
|
166
|
+
it("should complete preapproval flow for onboarded account", async () => {
|
|
167
|
+
// GIVEN
|
|
168
|
+
const { mockSignerContext, onboardResult } = getOnboardedAccount();
|
|
169
|
+
const preapprovalObservable = buildAuthorizePreapproval(mockSignerContext);
|
|
170
|
+
|
|
171
|
+
// WHEN
|
|
172
|
+
const preapprovalValues = await firstValueFrom(
|
|
173
|
+
preapprovalObservable(mockDeviceId, mockDerivationPath, onboardResult.partyId).pipe(
|
|
174
|
+
toArray(),
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const progressValues = preapprovalValues.filter(
|
|
179
|
+
(value): value is CantonPreApprovalProgress =>
|
|
180
|
+
"status" in value && !("isApproved" in value),
|
|
181
|
+
);
|
|
182
|
+
const resultValues = preapprovalValues.filter(
|
|
183
|
+
(value): value is CantonPreApprovalResult => "isApproved" in value,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// THEN
|
|
187
|
+
// Check expected status progression
|
|
188
|
+
expect(progressValues.some(p => p.status === PreApprovalStatus.PREPARE)).toBe(true);
|
|
189
|
+
expect(progressValues.some(p => p.status === PreApprovalStatus.SIGN)).toBe(true);
|
|
190
|
+
expect(progressValues.some(p => p.status === PreApprovalStatus.SUBMIT)).toBe(true);
|
|
191
|
+
|
|
192
|
+
// Check final result (should be approved)
|
|
193
|
+
expect(resultValues.length).toBeGreaterThan(0);
|
|
194
|
+
const finalResult = resultValues[resultValues.length - 1];
|
|
195
|
+
expect(finalResult.isApproved).toBe(true);
|
|
196
|
+
expect(typeof finalResult.isApproved).toBe("boolean");
|
|
197
|
+
}, 30000);
|
|
198
|
+
|
|
199
|
+
it("should handle invalid party ID gracefully", async () => {
|
|
200
|
+
// GIVEN
|
|
201
|
+
const keyPair = generateMockKeyPair();
|
|
202
|
+
const mockSigner = createMockSigner(keyPair);
|
|
203
|
+
const mockSignerContext = jest.fn().mockImplementation((deviceId, callback) => {
|
|
204
|
+
return callback(mockSigner);
|
|
205
|
+
});
|
|
206
|
+
const preapprovalObservable = buildAuthorizePreapproval(mockSignerContext);
|
|
207
|
+
|
|
208
|
+
// WHEN & THEN
|
|
209
|
+
try {
|
|
210
|
+
await firstValueFrom(
|
|
211
|
+
preapprovalObservable(mockDeviceId, mockDerivationPath, "invalid-party-id-123"),
|
|
212
|
+
);
|
|
213
|
+
expect(true).toBe(true);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
expect(error).toBeDefined();
|
|
216
|
+
}
|
|
217
|
+
}, 30000);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Observable } from "rxjs";
|
|
2
|
+
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
3
|
+
import { CantonSigner } from "../types/signer";
|
|
4
|
+
import {
|
|
5
|
+
prepareOnboarding,
|
|
6
|
+
submitOnboarding,
|
|
7
|
+
getPartyByPubKey,
|
|
8
|
+
preparePreApprovalTransaction,
|
|
9
|
+
submitPreApprovalTransaction,
|
|
10
|
+
prepareTapRequest,
|
|
11
|
+
submitTapRequest,
|
|
12
|
+
} from "../network/gateway";
|
|
13
|
+
import {
|
|
14
|
+
OnboardStatus,
|
|
15
|
+
PreApprovalStatus,
|
|
16
|
+
CantonOnboardProgress,
|
|
17
|
+
CantonOnboardResult,
|
|
18
|
+
CantonPreApprovalProgress,
|
|
19
|
+
CantonPreApprovalResult,
|
|
20
|
+
PrepareTransactionResponse,
|
|
21
|
+
} from "../types/onboard";
|
|
22
|
+
|
|
23
|
+
async function getKeypair(
|
|
24
|
+
signerContext: SignerContext<CantonSigner>,
|
|
25
|
+
deviceId: string,
|
|
26
|
+
derivationPath: string,
|
|
27
|
+
) {
|
|
28
|
+
return signerContext(deviceId, async signer => {
|
|
29
|
+
const { publicKey, address } = await signer.getAddress(derivationPath);
|
|
30
|
+
return { signer, publicKey: publicKey.replace("0x", ""), address };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const isAccountOnboarded = async (
|
|
35
|
+
publicKey: string,
|
|
36
|
+
): Promise<false | { party_id: string }> => {
|
|
37
|
+
try {
|
|
38
|
+
const { party_id } = await getPartyByPubKey(publicKey);
|
|
39
|
+
|
|
40
|
+
if (party_id) {
|
|
41
|
+
return { party_id };
|
|
42
|
+
} else {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
log("[isAccountOnboarded] Error checking party status (likely not onboarded):", err);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const buildOnboardAccount =
|
|
52
|
+
(signerContext: SignerContext<CantonSigner>) =>
|
|
53
|
+
(
|
|
54
|
+
deviceId: string,
|
|
55
|
+
derivationPath: string,
|
|
56
|
+
): Observable<CantonOnboardProgress | CantonOnboardResult> =>
|
|
57
|
+
new Observable(observer => {
|
|
58
|
+
async function main() {
|
|
59
|
+
observer.next({
|
|
60
|
+
status: OnboardStatus.INIT,
|
|
61
|
+
});
|
|
62
|
+
const keypair = await getKeypair(signerContext, deviceId, derivationPath);
|
|
63
|
+
|
|
64
|
+
observer.next({
|
|
65
|
+
status: OnboardStatus.PREPARE,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const isOnboardedResult = await isAccountOnboarded(keypair.publicKey);
|
|
69
|
+
if (isOnboardedResult && isOnboardedResult.party_id) {
|
|
70
|
+
observer.next({
|
|
71
|
+
partyId: isOnboardedResult.party_id,
|
|
72
|
+
});
|
|
73
|
+
observer.complete();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const preparedTransaction = await prepareOnboarding(keypair.publicKey, "ed25519");
|
|
78
|
+
|
|
79
|
+
observer.next({
|
|
80
|
+
status: OnboardStatus.SIGN,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const signature = await signerContext(deviceId, signer =>
|
|
84
|
+
signer.signTransaction(derivationPath, preparedTransaction.transactions.combined_hash),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
observer.next({
|
|
88
|
+
status: OnboardStatus.SUBMIT,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const result = await submitOnboarding(
|
|
92
|
+
{ public_key: keypair.publicKey, public_key_type: "ed25519" },
|
|
93
|
+
preparedTransaction,
|
|
94
|
+
signature,
|
|
95
|
+
).catch(err => {
|
|
96
|
+
if (err.type === "PARTY_ALREADY_EXISTS") {
|
|
97
|
+
observer.next({
|
|
98
|
+
partyId: preparedTransaction.party_id,
|
|
99
|
+
});
|
|
100
|
+
return observer.complete();
|
|
101
|
+
}
|
|
102
|
+
throw err;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
observer.next({
|
|
106
|
+
status: OnboardStatus.SUCCESS,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
observer.next({
|
|
110
|
+
partyId: result?.party?.party_id || "unknown",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
observer.complete();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().then(
|
|
117
|
+
() => observer.complete(),
|
|
118
|
+
error => {
|
|
119
|
+
log("[onboardAccount] Error:", error);
|
|
120
|
+
observer.error(error);
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const buildAuthorizePreapproval =
|
|
126
|
+
(signerContext: SignerContext<CantonSigner>) =>
|
|
127
|
+
(
|
|
128
|
+
deviceId: string,
|
|
129
|
+
derivationPath: string,
|
|
130
|
+
partyId: string,
|
|
131
|
+
): Observable<CantonPreApprovalProgress | CantonPreApprovalResult> =>
|
|
132
|
+
new Observable(observer => {
|
|
133
|
+
async function main() {
|
|
134
|
+
observer.next({
|
|
135
|
+
status: PreApprovalStatus.PREPARE,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const preparedTransaction: PrepareTransactionResponse =
|
|
139
|
+
await preparePreApprovalTransaction(partyId);
|
|
140
|
+
|
|
141
|
+
observer.next({
|
|
142
|
+
status: PreApprovalStatus.SIGN,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const signature = await signerContext(deviceId, signer =>
|
|
146
|
+
signer.signTransaction(derivationPath, preparedTransaction.hash),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
observer.next({
|
|
150
|
+
status: PreApprovalStatus.SUBMIT,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const { isApproved } = await submitPreApprovalTransaction(
|
|
154
|
+
partyId,
|
|
155
|
+
preparedTransaction,
|
|
156
|
+
signature,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
observer.next({
|
|
160
|
+
status: PreApprovalStatus.SUCCESS,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
observer.next({
|
|
164
|
+
isApproved,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// TODO: remove after demo
|
|
168
|
+
const handleTapRequest = async () => {
|
|
169
|
+
try {
|
|
170
|
+
observer.next({
|
|
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({
|
|
191
|
+
partyId,
|
|
192
|
+
serialized,
|
|
193
|
+
signature,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
observer.next({
|
|
197
|
+
status: PreApprovalStatus.SUCCESS,
|
|
198
|
+
});
|
|
199
|
+
} catch (err) {
|
|
200
|
+
// Tap request failure should not break the pre-approval flow
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
await handleTapRequest();
|
|
204
|
+
|
|
205
|
+
observer.complete();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
main().then(
|
|
209
|
+
() => observer.complete(),
|
|
210
|
+
error => {
|
|
211
|
+
log("[buildAuthorizePreapproval] Error:", error);
|
|
212
|
+
observer.error(error);
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const log = (message: string, ...rest: any[]) => {
|
|
218
|
+
// eslint-disable-next-line no-console
|
|
219
|
+
console.log(message, ...rest);
|
|
220
|
+
};
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import { AccountBridge } from "@ledgerhq/types-live";
|
|
2
2
|
import { Transaction } from "../types";
|
|
3
|
-
import {
|
|
4
|
-
import { getNextSequence } from "../network/node";
|
|
3
|
+
import { estimateFees } from "../common-logic";
|
|
5
4
|
import BigNumber from "bignumber.js";
|
|
5
|
+
import { updateTransaction } from "./updateTransaction";
|
|
6
6
|
|
|
7
7
|
export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"] = async (
|
|
8
8
|
account,
|
|
9
9
|
transaction,
|
|
10
10
|
) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{ address: account.freshAddress, nextSequenceNumber: seq },
|
|
15
|
-
{ amount: transaction.amount, recipient: transaction.recipient },
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const fee = await estimateFees(craftedTransaction.serializedTransaction);
|
|
19
|
-
|
|
20
|
-
if (transaction.fee !== new BigNumber(fee.toString())) {
|
|
21
|
-
return { ...transaction, fee: new BigNumber(fee.toString()) };
|
|
11
|
+
let fee = transaction.fee;
|
|
12
|
+
if (!fee || fee.eq(0)) {
|
|
13
|
+
fee = BigNumber((await estimateFees("")).toString());
|
|
22
14
|
}
|
|
23
|
-
|
|
24
|
-
return transaction;
|
|
15
|
+
return updateTransaction(transaction, { fee });
|
|
25
16
|
};
|
|
@@ -3,8 +3,8 @@ import { FeeNotLoaded } from "@ledgerhq/errors";
|
|
|
3
3
|
import { AccountBridge, Operation } from "@ledgerhq/types-live";
|
|
4
4
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
5
5
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
6
|
-
import { combine, craftTransaction
|
|
7
|
-
import { Transaction, CantonSigner
|
|
6
|
+
import { combine, craftTransaction } from "../common-logic";
|
|
7
|
+
import { Transaction, CantonSigner } from "../types";
|
|
8
8
|
|
|
9
9
|
export const buildSignOperation =
|
|
10
10
|
(signerContext: SignerContext<CantonSigner>): AccountBridge<Transaction>["signOperation"] =>
|
|
@@ -20,30 +20,24 @@ export const buildSignOperation =
|
|
|
20
20
|
type: "device-signature-requested",
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
const nextSequenceNumber = await getNextValidSequence(account.freshAddress);
|
|
24
|
-
|
|
25
23
|
const signature = await signerContext(deviceId, async signer => {
|
|
26
24
|
const { freshAddressPath: derivationPath } = account;
|
|
27
|
-
const
|
|
25
|
+
const partyId = account.freshAddress.replace("__", "::");
|
|
28
26
|
|
|
29
|
-
const {
|
|
27
|
+
const { hash, serializedTransaction } = await craftTransaction(
|
|
30
28
|
{
|
|
31
|
-
address:
|
|
32
|
-
publicKey,
|
|
29
|
+
address: partyId,
|
|
33
30
|
},
|
|
34
31
|
{
|
|
35
32
|
recipient: transaction.recipient,
|
|
36
33
|
amount: transaction.amount,
|
|
37
|
-
|
|
34
|
+
expireInSeconds: 60 * 60,
|
|
35
|
+
tokenId: "Amulet",
|
|
38
36
|
},
|
|
39
37
|
);
|
|
38
|
+
const transactionSignature = await signer.signTransaction(derivationPath, hash);
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
derivationPath,
|
|
43
|
-
serializedTransaction,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
return combine(serializedTransaction, transactionSignature);
|
|
40
|
+
return combine(serializedTransaction, `${transactionSignature}__PARTY__${partyId}`);
|
|
47
41
|
});
|
|
48
42
|
|
|
49
43
|
o.next({
|
|
@@ -64,7 +58,6 @@ export const buildSignOperation =
|
|
|
64
58
|
senders: [account.freshAddress],
|
|
65
59
|
recipients: [transaction.recipient],
|
|
66
60
|
date: new Date(),
|
|
67
|
-
transactionSequenceNumber: nextSequenceNumber,
|
|
68
61
|
extra: {},
|
|
69
62
|
};
|
|
70
63
|
|