@canton-network/wallet-gateway-remote 1.3.0 → 1.5.0
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/README.md +1 -1
- package/dist/auth/jwt-auth-service.d.ts.map +1 -1
- package/dist/auth/jwt-auth-service.js +6 -5
- package/dist/auth/jwt-auth-service.test.d.ts +2 -0
- package/dist/auth/jwt-auth-service.test.d.ts.map +1 -0
- package/dist/auth/jwt-auth-service.test.js +259 -0
- package/dist/auth/jwt-unsafe-auth-service.test.d.ts +2 -0
- package/dist/auth/jwt-unsafe-auth-service.test.d.ts.map +1 -0
- package/dist/auth/jwt-unsafe-auth-service.test.js +120 -0
- package/dist/config/Config.d.ts +64 -8
- package/dist/config/Config.d.ts.map +1 -1
- package/dist/config/Config.js +1 -0
- package/dist/config/ConfigUtils.d.ts.map +1 -1
- package/dist/config/ConfigUtils.js +3 -0
- package/dist/dapp-api/controller.d.ts +1 -0
- package/dist/dapp-api/controller.d.ts.map +1 -1
- package/dist/dapp-api/controller.js +87 -26
- package/dist/dapp-api/controller.test.d.ts +2 -0
- package/dist/dapp-api/controller.test.d.ts.map +1 -0
- package/dist/dapp-api/controller.test.js +516 -0
- package/dist/dapp-api/rpc-gen/index.d.ts +3 -0
- package/dist/dapp-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/dapp-api/rpc-gen/index.js +1 -0
- package/dist/dapp-api/rpc-gen/typings.d.ts +99 -14
- package/dist/dapp-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/dapp-api/server.d.ts.map +1 -1
- package/dist/dapp-api/server.js +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +4 -6
- package/dist/ledger/transaction-service.d.ts +14 -11
- package/dist/ledger/transaction-service.d.ts.map +1 -1
- package/dist/ledger/transaction-service.js +95 -8
- package/dist/ledger/transaction-service.test.d.ts +2 -0
- package/dist/ledger/transaction-service.test.d.ts.map +1 -0
- package/dist/ledger/transaction-service.test.js +356 -0
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.d.ts +5 -2
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.d.ts.map +1 -1
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.js +7 -6
- package/dist/ledger/wallet-allocation/wallet-allocation-service.d.ts +11 -5
- package/dist/ledger/wallet-allocation/wallet-allocation-service.d.ts.map +1 -1
- package/dist/ledger/wallet-allocation/wallet-allocation-service.js +28 -14
- package/dist/ledger/wallet-allocation/wallet-allocation-service.test.js +550 -19
- package/dist/ledger/wallet-sync-service.js +3 -3
- package/dist/middleware/apiKeyAuth.d.ts +6 -0
- package/dist/middleware/apiKeyAuth.d.ts.map +1 -0
- package/dist/middleware/apiKeyAuth.js +88 -0
- package/dist/middleware/apiKeyAuth.test.d.ts +2 -0
- package/dist/middleware/apiKeyAuth.test.d.ts.map +1 -0
- package/dist/middleware/apiKeyAuth.test.js +126 -0
- package/dist/middleware/jsonRpcHandler.d.ts +11 -1
- package/dist/middleware/jsonRpcHandler.d.ts.map +1 -1
- package/dist/middleware/jsonRpcHandler.js +14 -15
- package/dist/middleware/jsonRpcHandler.test.d.ts +2 -0
- package/dist/middleware/jsonRpcHandler.test.d.ts.map +1 -0
- package/dist/middleware/jsonRpcHandler.test.js +254 -0
- package/dist/middleware/jwtAuth.d.ts.map +1 -1
- package/dist/middleware/jwtAuth.js +4 -0
- package/dist/middleware/jwtAuth.test.d.ts +2 -0
- package/dist/middleware/jwtAuth.test.d.ts.map +1 -0
- package/dist/middleware/jwtAuth.test.js +93 -0
- package/dist/middleware/rateLimit.js +2 -2
- package/dist/middleware/rateLimit.test.js +26 -0
- package/dist/middleware/sessionHandler.js +1 -1
- package/dist/middleware/sessionHandler.test.d.ts +2 -0
- package/dist/middleware/sessionHandler.test.d.ts.map +1 -0
- package/dist/middleware/sessionHandler.test.js +121 -0
- package/dist/notification/NotificationService.test.d.ts +2 -0
- package/dist/notification/NotificationService.test.d.ts.map +1 -0
- package/dist/notification/NotificationService.test.js +110 -0
- package/dist/signing/signing-drivers.d.ts +7 -0
- package/dist/signing/signing-drivers.d.ts.map +1 -0
- package/dist/signing/signing-drivers.js +3 -0
- package/dist/user-api/controller.d.ts +12 -4
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +330 -95
- package/dist/user-api/controller.test.d.ts +2 -0
- package/dist/user-api/controller.test.d.ts.map +1 -0
- package/dist/user-api/controller.test.js +862 -0
- package/dist/user-api/rpc-gen/index.d.ts +30 -0
- package/dist/user-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/user-api/rpc-gen/index.js +10 -0
- package/dist/user-api/rpc-gen/typings.d.ts +170 -25
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/user-api/server.test.js +53 -0
- package/dist/utils.d.ts +19 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +53 -2
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/dist/utils.test.js +24 -0
- package/dist/web/frontend/404/index.html +2 -2
- package/dist/web/frontend/activities/index.html +3 -3
- package/dist/web/frontend/approve/index.html +4 -5
- package/dist/web/frontend/assets/404-MVLWUPwN.js +5 -0
- package/dist/web/frontend/assets/activities-DaWkmGqA.js +61 -0
- package/dist/web/frontend/assets/addIdentityProvider--rBb0ihb.js +28 -0
- package/dist/web/frontend/assets/addNetwork-C6UDsRkU.js +38 -0
- package/dist/web/frontend/assets/addParty-B3fFD1eM.js +45 -0
- package/dist/web/frontend/assets/approve-WbGL4E82.js +21 -0
- package/dist/web/frontend/assets/callback--tihEryB.js +1 -0
- package/dist/web/frontend/assets/identityProviders-Dra4qG6t.js +71 -0
- package/dist/web/frontend/assets/index-Bm76pXA_.js +91 -0
- package/dist/web/frontend/assets/index-D1dC4Cl9.js +4477 -0
- package/dist/web/frontend/assets/login-BC8a-kD_.js +10 -0
- package/dist/web/frontend/assets/networks-B3ztsogL.js +73 -0
- package/dist/web/frontend/assets/reviewIdentityProvider-Co420Dbk.js +43 -0
- package/dist/web/frontend/assets/reviewNetwork-B-Sh8pCH.js +43 -0
- package/dist/web/frontend/assets/{settings-B1ga2TK0.js → settings-DvyUjqLl.js} +1 -1
- package/dist/web/frontend/assets/state-Bq65GwdF.js +1 -0
- package/dist/web/frontend/assets/{utils-CT9Hzi7v.js → utils-B2iziW8V.js} +1 -1
- package/dist/web/frontend/callback/index.html +2 -2
- package/dist/web/frontend/identity-providers/add/index.html +3 -3
- package/dist/web/frontend/identity-providers/index.html +3 -3
- package/dist/web/frontend/identity-providers/review/index.html +3 -3
- package/dist/web/frontend/index.html +1 -1
- package/dist/web/frontend/login/index.html +3 -4
- package/dist/web/frontend/networks/add/index.html +3 -3
- package/dist/web/frontend/networks/index.html +3 -3
- package/dist/web/frontend/networks/review/index.html +3 -3
- package/dist/web/frontend/parties/add/index.html +5 -5
- package/dist/web/frontend/parties/index.html +4 -4
- package/dist/web/frontend/settings/index.html +3 -3
- package/package.json +40 -33
- package/dist/web/frontend/assets/404-B-o9ppJB.js +0 -5
- package/dist/web/frontend/assets/activities-CGjCIjUH.js +0 -61
- package/dist/web/frontend/assets/addIdentityProvider-CR4Wm9Tl.js +0 -28
- package/dist/web/frontend/assets/addNetwork-Dx0-SN4j.js +0 -38
- package/dist/web/frontend/assets/addParty-COhk_rFn.js +0 -41
- package/dist/web/frontend/assets/approve-B2w66l0J.js +0 -21
- package/dist/web/frontend/assets/callback-BTVon_yQ.js +0 -1
- package/dist/web/frontend/assets/identityProviders-CK8zSrd3.js +0 -71
- package/dist/web/frontend/assets/index-CF4BKzgl.js +0 -91
- package/dist/web/frontend/assets/index-DWz_3f3y.js +0 -1
- package/dist/web/frontend/assets/index-_pMHlJoE.js +0 -4042
- package/dist/web/frontend/assets/login-CVoPNVDw.js +0 -10
- package/dist/web/frontend/assets/networks-D1nPvUzM.js +0 -73
- package/dist/web/frontend/assets/reviewIdentityProvider-CNSf2qQv.js +0 -43
- package/dist/web/frontend/assets/reviewNetwork-DGLK-Ume.js +0 -43
- package/dist/web/frontend/assets/state-B2k3ak7d.js +0 -1
|
@@ -24,8 +24,14 @@ const createAllocatedParty = (partyId, hint, namespace) => ({
|
|
|
24
24
|
hint,
|
|
25
25
|
namespace,
|
|
26
26
|
});
|
|
27
|
+
const authContext = {
|
|
28
|
+
userId: 'user-1',
|
|
29
|
+
accessToken: 'access-token',
|
|
30
|
+
email: 'user-1@example.com',
|
|
31
|
+
};
|
|
32
|
+
const FIREBLOCKS_VAULT_NAME = 'Canton Party';
|
|
27
33
|
function createFireblocksDriver(options) {
|
|
28
|
-
const getKeysResult = {
|
|
34
|
+
const getKeysResult = options.getKeysResult ?? {
|
|
29
35
|
keys: [{ id: 'key-1', name: 'Canton Party', publicKey: 'fb-pk' }],
|
|
30
36
|
};
|
|
31
37
|
const signTransactionResult = options.signTransactionResult ?? {
|
|
@@ -48,6 +54,9 @@ function createFireblocksDriver(options) {
|
|
|
48
54
|
};
|
|
49
55
|
}
|
|
50
56
|
function createBlockdaemonDriver(options) {
|
|
57
|
+
const createKeyResult = options.createKeyResult ?? {
|
|
58
|
+
publicKey: 'bd-pk',
|
|
59
|
+
};
|
|
51
60
|
const signTransactionResult = options.signTransactionResult ?? {
|
|
52
61
|
status: 'pending',
|
|
53
62
|
txId: 'tx-1',
|
|
@@ -57,9 +66,31 @@ function createBlockdaemonDriver(options) {
|
|
|
57
66
|
controller: vi.fn().mockReturnValue({
|
|
58
67
|
createKey: vi
|
|
59
68
|
.fn()
|
|
60
|
-
.mockResolvedValue(
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
.mockResolvedValue(createKeyResult),
|
|
70
|
+
signTransaction: vi
|
|
71
|
+
.fn()
|
|
72
|
+
.mockResolvedValue(signTransactionResult),
|
|
73
|
+
getTransaction: vi
|
|
74
|
+
.fn()
|
|
75
|
+
.mockResolvedValue(getTransactionResult),
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function createDfnsDriver(options) {
|
|
80
|
+
const createKeyResult = options.createKeyResult ?? {
|
|
81
|
+
id: 'key-1',
|
|
82
|
+
publicKey: 'dfns-pk',
|
|
83
|
+
};
|
|
84
|
+
const signTransactionResult = options.signTransactionResult ?? {
|
|
85
|
+
status: 'pending',
|
|
86
|
+
txId: 'tx-1',
|
|
87
|
+
};
|
|
88
|
+
const getTransactionResult = options.getTransactionResult ?? signTransactionResult;
|
|
89
|
+
return {
|
|
90
|
+
controller: vi.fn().mockReturnValue({
|
|
91
|
+
createKey: vi
|
|
92
|
+
.fn()
|
|
93
|
+
.mockResolvedValue(createKeyResult),
|
|
63
94
|
signTransaction: vi
|
|
64
95
|
.fn()
|
|
65
96
|
.mockResolvedValue(signTransactionResult),
|
|
@@ -129,8 +160,8 @@ describe('WalletAllocationService', () => {
|
|
|
129
160
|
it('createWallet allocates new party and adds wallet', async () => {
|
|
130
161
|
const expectedParty = createAllocatedParty('alice::participant1', 'alice', 'participant1');
|
|
131
162
|
mockPartyAllocator.allocateParty.mockResolvedValue(expectedParty);
|
|
132
|
-
const result = await service.createWallet(
|
|
133
|
-
expect(mockPartyAllocator.allocateParty).toHaveBeenCalledWith(
|
|
163
|
+
const result = await service.createWallet(authContext, 'alice', false, SigningProvider.PARTICIPANT);
|
|
164
|
+
expect(mockPartyAllocator.allocateParty).toHaveBeenCalledWith(authContext.userId, 'alice');
|
|
134
165
|
expect(mockStore.addWallet).toHaveBeenCalledWith(expect.objectContaining({
|
|
135
166
|
partyId: 'alice::participant1',
|
|
136
167
|
status: 'allocated',
|
|
@@ -147,8 +178,8 @@ describe('WalletAllocationService', () => {
|
|
|
147
178
|
namespace: 'namespace',
|
|
148
179
|
signingProviderId: SigningProvider.PARTICIPANT,
|
|
149
180
|
});
|
|
150
|
-
await service.allocateParty(
|
|
151
|
-
expect(mockPartyAllocator.allocateParty).toHaveBeenCalledWith(
|
|
181
|
+
await service.allocateParty(authContext, existingWallet, SigningProvider.PARTICIPANT);
|
|
182
|
+
expect(mockPartyAllocator.allocateParty).toHaveBeenCalledWith(authContext.userId, 'alice');
|
|
152
183
|
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
153
184
|
partyId: 'alice::participant1',
|
|
154
185
|
networkId: 'network1',
|
|
@@ -161,7 +192,7 @@ describe('WalletAllocationService', () => {
|
|
|
161
192
|
const expectedParty = createAllocatedParty('bob::fingerprint', 'bob', 'fingerprint');
|
|
162
193
|
mockPartyAllocator.createFingerprintFromKey.mockReturnValue('fingerprint');
|
|
163
194
|
mockPartyAllocator.allocateParty.mockResolvedValue(expectedParty);
|
|
164
|
-
const result = await service.createWallet(
|
|
195
|
+
const result = await service.createWallet(authContext, 'bob', false, SigningProvider.WALLET_KERNEL);
|
|
165
196
|
expect(mockStore.addWallet).toHaveBeenCalledWith(expect.objectContaining({
|
|
166
197
|
partyId: 'bob::fingerprint',
|
|
167
198
|
status: 'allocated',
|
|
@@ -169,7 +200,7 @@ describe('WalletAllocationService', () => {
|
|
|
169
200
|
}));
|
|
170
201
|
expect(result.partyId).toBe('bob::fingerprint');
|
|
171
202
|
expect(result.publicKey).toBe('new-public-key');
|
|
172
|
-
expect(mockWalletKernelDriver.controller).toHaveBeenCalledWith(
|
|
203
|
+
expect(mockWalletKernelDriver.controller).toHaveBeenCalledWith(authContext.userId);
|
|
173
204
|
expect(mockController.createKey).toHaveBeenCalledWith({
|
|
174
205
|
name: 'bob',
|
|
175
206
|
});
|
|
@@ -187,7 +218,7 @@ describe('WalletAllocationService', () => {
|
|
|
187
218
|
publicKey: 'existing-public-key',
|
|
188
219
|
signingProviderId: SigningProvider.WALLET_KERNEL,
|
|
189
220
|
});
|
|
190
|
-
await service.allocateParty(
|
|
221
|
+
await service.allocateParty(authContext, existingWallet, SigningProvider.WALLET_KERNEL);
|
|
191
222
|
expect(mockController.signTransaction).toHaveBeenCalledWith(expect.objectContaining({
|
|
192
223
|
txHash: 'test-hash',
|
|
193
224
|
keyIdentifier: { publicKey: 'existing-public-key' },
|
|
@@ -200,13 +231,56 @@ describe('WalletAllocationService', () => {
|
|
|
200
231
|
});
|
|
201
232
|
it('throws when Wallet Gateway signing driver not available', async () => {
|
|
202
233
|
const serviceWithoutDriver = createService({});
|
|
203
|
-
await expect(serviceWithoutDriver.createWallet(
|
|
234
|
+
await expect(serviceWithoutDriver.createWallet(authContext, 'bob', false, SigningProvider.WALLET_KERNEL)).rejects.toThrow('Wallet Gateway signing driver not available');
|
|
235
|
+
});
|
|
236
|
+
it('throws when createKey returns a signing error', async () => {
|
|
237
|
+
mockController.createKey.mockResolvedValue({
|
|
238
|
+
error: 'denied',
|
|
239
|
+
error_description: 'Key creation failed',
|
|
240
|
+
});
|
|
241
|
+
await expect(service.createWallet(authContext, 'bob', false, SigningProvider.WALLET_KERNEL)).rejects.toThrow('Error from signing driver: Key creation failed');
|
|
242
|
+
});
|
|
243
|
+
it('throws when signing the topology hash returns a driver error', async () => {
|
|
244
|
+
mockPartyAllocator.allocateParty.mockImplementation(async (_userId, _hint, _publicKey, signingCallback) => {
|
|
245
|
+
await signingCallback?.('hash');
|
|
246
|
+
return createAllocatedParty('bob::fingerprint', 'bob', 'fingerprint');
|
|
247
|
+
});
|
|
248
|
+
mockController.signTransaction.mockResolvedValue({
|
|
249
|
+
error: 'denied',
|
|
250
|
+
error_description: 'Signing failed',
|
|
251
|
+
});
|
|
252
|
+
await expect(service.createWallet(authContext, 'bob', false, SigningProvider.WALLET_KERNEL)).rejects.toThrow('Error from signing driver: Signing failed');
|
|
253
|
+
});
|
|
254
|
+
it('throws when signing the topology hash returns no signature', async () => {
|
|
255
|
+
mockPartyAllocator.allocateParty.mockImplementation(async (_userId, _hint, _publicKey, signingCallback) => {
|
|
256
|
+
await signingCallback?.('hash');
|
|
257
|
+
return createAllocatedParty('bob::fingerprint', 'bob', 'fingerprint');
|
|
258
|
+
});
|
|
259
|
+
mockController.signTransaction.mockResolvedValue({
|
|
260
|
+
signature: undefined,
|
|
261
|
+
});
|
|
262
|
+
await expect(service.createWallet(authContext, 'bob', false, SigningProvider.WALLET_KERNEL)).rejects.toThrow('No signature returned from signing driver');
|
|
263
|
+
});
|
|
264
|
+
it('throws when allocateParty signing callback returns no signature', async () => {
|
|
265
|
+
mockPartyAllocator.allocateParty.mockImplementation(async (_userId, _hint, _publicKey, signingCallback) => {
|
|
266
|
+
await signingCallback?.('hash');
|
|
267
|
+
return createAllocatedParty('bob::fingerprint', 'bob', 'fingerprint');
|
|
268
|
+
});
|
|
269
|
+
mockController.signTransaction.mockResolvedValue({
|
|
270
|
+
signature: undefined,
|
|
271
|
+
});
|
|
272
|
+
const existingWallet = createWallet('bob::namespace', {
|
|
273
|
+
hint: 'bob',
|
|
274
|
+
publicKey: 'existing-public-key',
|
|
275
|
+
signingProviderId: SigningProvider.WALLET_KERNEL,
|
|
276
|
+
});
|
|
277
|
+
await expect(service.allocateParty(authContext, existingWallet, SigningProvider.WALLET_KERNEL)).rejects.toThrow('No signature returned from signing driver');
|
|
204
278
|
});
|
|
205
279
|
});
|
|
206
280
|
describe('Fireblocks', () => {
|
|
207
281
|
it('throws when Fireblocks signing driver not available', async () => {
|
|
208
282
|
const serviceWithoutFireblocks = createService({});
|
|
209
|
-
await expect(serviceWithoutFireblocks.createWallet(
|
|
283
|
+
await expect(serviceWithoutFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS)).rejects.toThrow('Fireblocks signing driver not available');
|
|
210
284
|
});
|
|
211
285
|
it('createWallet returns allocated when signTransaction returns signed', async () => {
|
|
212
286
|
const serviceWithFireblocks = createService({
|
|
@@ -220,7 +294,7 @@ describe('WalletAllocationService', () => {
|
|
|
220
294
|
}),
|
|
221
295
|
});
|
|
222
296
|
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
223
|
-
const result = await serviceWithFireblocks.createWallet(
|
|
297
|
+
const result = await serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME);
|
|
224
298
|
expect(result.status).toBe('allocated');
|
|
225
299
|
expect(result.partyId).toBe('alice::namespace');
|
|
226
300
|
expect(mockPartyAllocator.allocatePartyWithExistingWallet).toHaveBeenCalled();
|
|
@@ -236,7 +310,7 @@ describe('WalletAllocationService', () => {
|
|
|
236
310
|
},
|
|
237
311
|
}),
|
|
238
312
|
});
|
|
239
|
-
const result = await serviceWithFireblocks.createWallet(
|
|
313
|
+
const result = await serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME);
|
|
240
314
|
expect(result.status).toBe('initialized');
|
|
241
315
|
expect(mockPartyAllocator.allocatePartyWithExistingWallet).not.toHaveBeenCalled();
|
|
242
316
|
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
@@ -254,17 +328,168 @@ describe('WalletAllocationService', () => {
|
|
|
254
328
|
},
|
|
255
329
|
}),
|
|
256
330
|
});
|
|
257
|
-
const result = await serviceWithFireblocks.createWallet(
|
|
331
|
+
const result = await serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME);
|
|
258
332
|
expect(result.status).toBe('removed');
|
|
259
333
|
expect(result.reason).toBe(expectedReason);
|
|
260
334
|
expect(mockPartyAllocator.allocatePartyWithExistingWallet).not.toHaveBeenCalled();
|
|
261
335
|
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
262
336
|
});
|
|
337
|
+
it('createWallet handles missing topology transactions from party allocator', async () => {
|
|
338
|
+
mockPartyAllocator.generateTopologyTransactions.mockResolvedValue({
|
|
339
|
+
topologyTransactions: undefined,
|
|
340
|
+
multiHash: 'multi-hash',
|
|
341
|
+
});
|
|
342
|
+
const serviceWithFireblocks = createService({
|
|
343
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
344
|
+
signTransactionResult: { status: 'pending', txId: 'tx-1' },
|
|
345
|
+
}),
|
|
346
|
+
});
|
|
347
|
+
const result = await serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME);
|
|
348
|
+
expect(result.topologyTransactions).toBe('');
|
|
349
|
+
});
|
|
350
|
+
it('throws when getKeys returns a signing error', async () => {
|
|
351
|
+
const serviceWithFireblocks = createService({
|
|
352
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
353
|
+
getKeysResult: {
|
|
354
|
+
error: 'denied',
|
|
355
|
+
error_description: 'Keys unavailable',
|
|
356
|
+
},
|
|
357
|
+
}),
|
|
358
|
+
});
|
|
359
|
+
await expect(serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME)).rejects.toThrow('Error from signing driver: Keys unavailable');
|
|
360
|
+
});
|
|
361
|
+
it('throws when vaultName is missing for Fireblocks', async () => {
|
|
362
|
+
const serviceWithFireblocks = createService({
|
|
363
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({}),
|
|
364
|
+
});
|
|
365
|
+
await expect(serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS)).rejects.toThrow('vaultName is required for creating a wallet with Fireblocks');
|
|
366
|
+
});
|
|
367
|
+
it('throws when the selected Fireblocks vault is missing', async () => {
|
|
368
|
+
const serviceWithFireblocks = createService({
|
|
369
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
370
|
+
getKeysResult: { keys: [] },
|
|
371
|
+
}),
|
|
372
|
+
});
|
|
373
|
+
await expect(serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, 'missing-vault')).rejects.toThrow('Fireblocks key not found');
|
|
374
|
+
});
|
|
375
|
+
it('getVaults returns vault names for Fireblocks', async () => {
|
|
376
|
+
const serviceWithFireblocks = createService({
|
|
377
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
378
|
+
getKeysResult: {
|
|
379
|
+
keys: [
|
|
380
|
+
{
|
|
381
|
+
id: 'key-1',
|
|
382
|
+
name: 'Vault A',
|
|
383
|
+
publicKey: 'fb-pk-a',
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
id: 'key-2',
|
|
387
|
+
name: 'Vault B',
|
|
388
|
+
publicKey: 'fb-pk-b',
|
|
389
|
+
},
|
|
390
|
+
],
|
|
391
|
+
},
|
|
392
|
+
}),
|
|
393
|
+
});
|
|
394
|
+
const result = await serviceWithFireblocks.getVaults(authContext, SigningProvider.FIREBLOCKS);
|
|
395
|
+
expect(result).toEqual({ vaults: ['Vault A', 'Vault B'] });
|
|
396
|
+
});
|
|
397
|
+
it('throws when listing vaults for an unsupported signing provider', async () => {
|
|
398
|
+
const serviceWithFireblocks = createService({
|
|
399
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({}),
|
|
400
|
+
});
|
|
401
|
+
await expect(serviceWithFireblocks.getVaults(authContext, SigningProvider.PARTICIPANT)).rejects.toThrow('Signing provider participant does not support listing vaults');
|
|
402
|
+
});
|
|
403
|
+
it('throws when a signed createWallet has no signature in getTransaction', async () => {
|
|
404
|
+
const serviceWithFireblocks = createService({
|
|
405
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
406
|
+
signTransactionResult: { status: 'signed', txId: 'tx-1' },
|
|
407
|
+
getTransactionResult: {
|
|
408
|
+
txId: 'tx-1',
|
|
409
|
+
status: 'signed',
|
|
410
|
+
},
|
|
411
|
+
}),
|
|
412
|
+
});
|
|
413
|
+
await expect(serviceWithFireblocks.createWallet(authContext, 'alice', false, SigningProvider.FIREBLOCKS, FIREBLOCKS_VAULT_NAME)).rejects.toThrow('Transaction signed but no signature found in result');
|
|
414
|
+
});
|
|
415
|
+
it('throws when allocateParty wallet is missing topology metadata', async () => {
|
|
416
|
+
const serviceWithFireblocks = createService({
|
|
417
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({}),
|
|
418
|
+
});
|
|
419
|
+
await expect(serviceWithFireblocks.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
420
|
+
signingProviderId: SigningProvider.FIREBLOCKS,
|
|
421
|
+
topologyTransactions: undefined,
|
|
422
|
+
externalTxId: 'tx-1',
|
|
423
|
+
}), SigningProvider.FIREBLOCKS)).rejects.toThrow('Existing wallet is missing field externalTxId or topologyTransactions');
|
|
424
|
+
});
|
|
425
|
+
it('allocateParty updates wallet to pending state', async () => {
|
|
426
|
+
const serviceWithFireblocks = createService({
|
|
427
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
428
|
+
getTransactionResult: { txId: 'tx-1', status: 'pending' },
|
|
429
|
+
}),
|
|
430
|
+
});
|
|
431
|
+
await serviceWithFireblocks.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
432
|
+
signingProviderId: SigningProvider.FIREBLOCKS,
|
|
433
|
+
topologyTransactions: 'tx1',
|
|
434
|
+
externalTxId: 'tx-1',
|
|
435
|
+
}), SigningProvider.FIREBLOCKS);
|
|
436
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
437
|
+
partyId: 'alice::fingerprint',
|
|
438
|
+
networkId: 'network1',
|
|
439
|
+
status: 'initialized',
|
|
440
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_PENDING,
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
it('allocateParty updates wallet to allocated when transaction is signed', async () => {
|
|
444
|
+
const hexSignature = 'deadbeef';
|
|
445
|
+
const serviceWithFireblocks = createService({
|
|
446
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
447
|
+
getTransactionResult: {
|
|
448
|
+
txId: 'tx-1',
|
|
449
|
+
status: 'signed',
|
|
450
|
+
signature: hexSignature,
|
|
451
|
+
},
|
|
452
|
+
}),
|
|
453
|
+
});
|
|
454
|
+
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
455
|
+
await serviceWithFireblocks.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
456
|
+
signingProviderId: SigningProvider.FIREBLOCKS,
|
|
457
|
+
namespace: 'fingerprint',
|
|
458
|
+
topologyTransactions: 'tx1',
|
|
459
|
+
externalTxId: 'tx-1',
|
|
460
|
+
}), SigningProvider.FIREBLOCKS);
|
|
461
|
+
expect(mockPartyAllocator.allocatePartyWithExistingWallet).toHaveBeenCalledWith('fingerprint', ['tx1'], Buffer.from(hexSignature, 'hex').toString('base64'), 'user-1');
|
|
462
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
463
|
+
networkId: 'network1',
|
|
464
|
+
partyId: 'alice::namespace',
|
|
465
|
+
status: 'allocated',
|
|
466
|
+
reason: '',
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
it('allocateParty disables wallet when transaction is rejected', async () => {
|
|
470
|
+
const serviceWithFireblocks = createService({
|
|
471
|
+
[SigningProvider.FIREBLOCKS]: createFireblocksDriver({
|
|
472
|
+
getTransactionResult: { txId: 'tx-1', status: 'rejected' },
|
|
473
|
+
}),
|
|
474
|
+
});
|
|
475
|
+
await serviceWithFireblocks.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
476
|
+
signingProviderId: SigningProvider.FIREBLOCKS,
|
|
477
|
+
topologyTransactions: 'tx1',
|
|
478
|
+
externalTxId: 'tx-1',
|
|
479
|
+
}), SigningProvider.FIREBLOCKS);
|
|
480
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
481
|
+
partyId: 'alice::fingerprint',
|
|
482
|
+
networkId: 'network1',
|
|
483
|
+
status: 'removed',
|
|
484
|
+
disabled: true,
|
|
485
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED,
|
|
486
|
+
});
|
|
487
|
+
});
|
|
263
488
|
});
|
|
264
489
|
describe('Blockdaemon', () => {
|
|
265
490
|
it('throws when Blockdaemon signing driver not available', async () => {
|
|
266
491
|
const serviceWithoutBlockdaemon = createService({});
|
|
267
|
-
await expect(serviceWithoutBlockdaemon.createWallet(
|
|
492
|
+
await expect(serviceWithoutBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON)).rejects.toThrow('Blockdaemon signing driver not available');
|
|
268
493
|
});
|
|
269
494
|
it('createWallet returns initialized when signTransaction returns pending', async () => {
|
|
270
495
|
const serviceWithBlockdaemon = createService({
|
|
@@ -272,7 +497,7 @@ describe('WalletAllocationService', () => {
|
|
|
272
497
|
signTransactionResult: { status: 'pending', txId: 'tx-1' },
|
|
273
498
|
}),
|
|
274
499
|
});
|
|
275
|
-
const result = await serviceWithBlockdaemon.createWallet(
|
|
500
|
+
const result = await serviceWithBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON);
|
|
276
501
|
expect(result.status).toBe('initialized');
|
|
277
502
|
expect(result.reason).toBe(WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_PENDING);
|
|
278
503
|
expect(result.externalTxId).toBe('tx-1');
|
|
@@ -292,11 +517,317 @@ describe('WalletAllocationService', () => {
|
|
|
292
517
|
}),
|
|
293
518
|
});
|
|
294
519
|
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
295
|
-
const result = await serviceWithBlockdaemon.createWallet(
|
|
520
|
+
const result = await serviceWithBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON);
|
|
521
|
+
expect(result.status).toBe('allocated');
|
|
522
|
+
expect(result.partyId).toBe('alice::namespace');
|
|
523
|
+
expect(mockPartyAllocator.allocatePartyWithExistingWallet).toHaveBeenCalled();
|
|
524
|
+
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
525
|
+
});
|
|
526
|
+
it('throws when createKey returns an error object', async () => {
|
|
527
|
+
const serviceWithBlockdaemon = createService({
|
|
528
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
529
|
+
createKeyResult: {
|
|
530
|
+
error: 'denied',
|
|
531
|
+
error_description: 'Cannot create key',
|
|
532
|
+
},
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
await expect(serviceWithBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON)).rejects.toThrow('Failed to create key: Cannot create key');
|
|
536
|
+
});
|
|
537
|
+
it('throws when a signed createWallet has no signature in getTransaction', async () => {
|
|
538
|
+
const serviceWithBlockdaemon = createService({
|
|
539
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
540
|
+
signTransactionResult: { status: 'signed', txId: 'tx-1' },
|
|
541
|
+
getTransactionResult: {
|
|
542
|
+
txId: 'tx-1',
|
|
543
|
+
status: 'signed',
|
|
544
|
+
},
|
|
545
|
+
}),
|
|
546
|
+
});
|
|
547
|
+
await expect(serviceWithBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON)).rejects.toThrow('Transaction signed but no signature found in result');
|
|
548
|
+
});
|
|
549
|
+
it.each([
|
|
550
|
+
['failed', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_FAILED],
|
|
551
|
+
['rejected', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED],
|
|
552
|
+
])('createWallet marks wallet removed when signTransaction returns %s', async (status, expectedReason) => {
|
|
553
|
+
const serviceWithBlockdaemon = createService({
|
|
554
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
555
|
+
signTransactionResult: { status, txId: 'tx-1' },
|
|
556
|
+
}),
|
|
557
|
+
});
|
|
558
|
+
const result = await serviceWithBlockdaemon.createWallet(authContext, 'alice', false, SigningProvider.BLOCKDAEMON);
|
|
559
|
+
expect(result.status).toBe('removed');
|
|
560
|
+
expect(result.disabled).toBe(true);
|
|
561
|
+
expect(result.reason).toBe(expectedReason);
|
|
562
|
+
});
|
|
563
|
+
it('throws when allocateParty wallet is missing topology metadata', async () => {
|
|
564
|
+
const serviceWithBlockdaemon = createService({
|
|
565
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({}),
|
|
566
|
+
});
|
|
567
|
+
await expect(serviceWithBlockdaemon.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
568
|
+
signingProviderId: SigningProvider.BLOCKDAEMON,
|
|
569
|
+
topologyTransactions: 'tx1',
|
|
570
|
+
externalTxId: undefined,
|
|
571
|
+
}), SigningProvider.BLOCKDAEMON)).rejects.toThrow('Existing wallet is missing field externalTxId or topologyTransactions');
|
|
572
|
+
});
|
|
573
|
+
it('allocateParty updates wallet to allocated when transaction is signed', async () => {
|
|
574
|
+
const serviceWithBlockdaemon = createService({
|
|
575
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
576
|
+
getTransactionResult: {
|
|
577
|
+
txId: 'tx-1',
|
|
578
|
+
status: 'signed',
|
|
579
|
+
signature: 'sig-base64',
|
|
580
|
+
},
|
|
581
|
+
}),
|
|
582
|
+
});
|
|
583
|
+
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
584
|
+
await serviceWithBlockdaemon.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
585
|
+
signingProviderId: SigningProvider.BLOCKDAEMON,
|
|
586
|
+
namespace: 'fingerprint',
|
|
587
|
+
topologyTransactions: 'tx1',
|
|
588
|
+
externalTxId: 'tx-1',
|
|
589
|
+
}), SigningProvider.BLOCKDAEMON);
|
|
590
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
591
|
+
networkId: 'network1',
|
|
592
|
+
partyId: 'alice::namespace',
|
|
593
|
+
status: 'allocated',
|
|
594
|
+
reason: '',
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
it('allocateParty updates wallet to pending state', async () => {
|
|
598
|
+
const serviceWithBlockdaemon = createService({
|
|
599
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
600
|
+
getTransactionResult: { txId: 'tx-1', status: 'pending' },
|
|
601
|
+
}),
|
|
602
|
+
});
|
|
603
|
+
await serviceWithBlockdaemon.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
604
|
+
signingProviderId: SigningProvider.BLOCKDAEMON,
|
|
605
|
+
topologyTransactions: 'tx1',
|
|
606
|
+
externalTxId: 'tx-1',
|
|
607
|
+
}), SigningProvider.BLOCKDAEMON);
|
|
608
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
609
|
+
partyId: 'alice::fingerprint',
|
|
610
|
+
networkId: 'network1',
|
|
611
|
+
status: 'initialized',
|
|
612
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_PENDING,
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
it('allocateParty disables wallet when transaction is rejected', async () => {
|
|
616
|
+
const serviceWithBlockdaemon = createService({
|
|
617
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
618
|
+
getTransactionResult: { txId: 'tx-1', status: 'rejected' },
|
|
619
|
+
}),
|
|
620
|
+
});
|
|
621
|
+
await serviceWithBlockdaemon.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
622
|
+
signingProviderId: SigningProvider.BLOCKDAEMON,
|
|
623
|
+
topologyTransactions: 'tx1',
|
|
624
|
+
externalTxId: 'tx-1',
|
|
625
|
+
}), SigningProvider.BLOCKDAEMON);
|
|
626
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
627
|
+
partyId: 'alice::fingerprint',
|
|
628
|
+
networkId: 'network1',
|
|
629
|
+
status: 'removed',
|
|
630
|
+
disabled: true,
|
|
631
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED,
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
it('allocateParty disables wallet when transaction failed', async () => {
|
|
635
|
+
const warnSpy = vi.spyOn(mockLogger, 'warn');
|
|
636
|
+
const serviceWithBlockdaemon = createService({
|
|
637
|
+
[SigningProvider.BLOCKDAEMON]: createBlockdaemonDriver({
|
|
638
|
+
getTransactionResult: {
|
|
639
|
+
txId: 'tx-1',
|
|
640
|
+
status: 'failed',
|
|
641
|
+
metadata: { code: 'X' },
|
|
642
|
+
},
|
|
643
|
+
}),
|
|
644
|
+
});
|
|
645
|
+
await serviceWithBlockdaemon.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
646
|
+
signingProviderId: SigningProvider.BLOCKDAEMON,
|
|
647
|
+
topologyTransactions: 'tx1',
|
|
648
|
+
externalTxId: 'tx-1',
|
|
649
|
+
}), SigningProvider.BLOCKDAEMON);
|
|
650
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
651
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
652
|
+
partyId: 'alice::fingerprint',
|
|
653
|
+
networkId: 'network1',
|
|
654
|
+
status: 'removed',
|
|
655
|
+
disabled: true,
|
|
656
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_FAILED,
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
describe('Dfns', () => {
|
|
661
|
+
it('throws when Dfns signing driver not available', async () => {
|
|
662
|
+
const serviceWithoutDfns = createService({});
|
|
663
|
+
await expect(serviceWithoutDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS)).rejects.toThrow('Dfns signing driver not available');
|
|
664
|
+
});
|
|
665
|
+
it('createWallet returns initialized when signTransaction returns pending', async () => {
|
|
666
|
+
const serviceWithDfns = createService({
|
|
667
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
668
|
+
signTransactionResult: { status: 'pending', txId: 'tx-1' },
|
|
669
|
+
getTransactionResult: { status: 'pending', txId: 'tx-1' },
|
|
670
|
+
}),
|
|
671
|
+
});
|
|
672
|
+
const result = await serviceWithDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS);
|
|
673
|
+
expect(result.status).toBe('initialized');
|
|
674
|
+
expect(result.reason).toBe(WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_PENDING);
|
|
675
|
+
expect(result.externalTxId).toBe('tx-1');
|
|
676
|
+
expect(result.partyId).toBe('alice::fingerprint');
|
|
677
|
+
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
678
|
+
});
|
|
679
|
+
it('createWallet returns allocated when signTransaction returns signed', async () => {
|
|
680
|
+
const serviceWithDfns = createService({
|
|
681
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
682
|
+
createKeyResult: { id: 'key-1', publicKey: 'dfns-pk' },
|
|
683
|
+
signTransactionResult: { status: 'signed', txId: 'tx-1' },
|
|
684
|
+
getTransactionResult: {
|
|
685
|
+
txId: 'tx-1',
|
|
686
|
+
status: 'signed',
|
|
687
|
+
signature: 'sig-base64',
|
|
688
|
+
},
|
|
689
|
+
}),
|
|
690
|
+
});
|
|
691
|
+
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
692
|
+
const result = await serviceWithDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS);
|
|
296
693
|
expect(result.status).toBe('allocated');
|
|
297
694
|
expect(result.partyId).toBe('alice::namespace');
|
|
298
695
|
expect(mockPartyAllocator.allocatePartyWithExistingWallet).toHaveBeenCalled();
|
|
299
696
|
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
300
697
|
});
|
|
698
|
+
it.each([
|
|
699
|
+
['failed', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_FAILED],
|
|
700
|
+
['rejected', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED],
|
|
701
|
+
])('createWallet returns status removed with reason when signTransaction returns %s', async (status, expectedReason) => {
|
|
702
|
+
const serviceWithDfns = createService({
|
|
703
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
704
|
+
signTransactionResult: { status, txId: 'tx-1' },
|
|
705
|
+
getTransactionResult: { status, txId: 'tx-1' },
|
|
706
|
+
}),
|
|
707
|
+
});
|
|
708
|
+
const result = await serviceWithDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS);
|
|
709
|
+
expect(result.status).toBe('removed');
|
|
710
|
+
expect(result.reason).toBe(expectedReason);
|
|
711
|
+
expect(result.disabled).toBe(true);
|
|
712
|
+
expect(mockStore.addWallet).toHaveBeenCalled();
|
|
713
|
+
});
|
|
714
|
+
it('throws when createKey returns a signing error', async () => {
|
|
715
|
+
const serviceWithDfns = createService({
|
|
716
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
717
|
+
createKeyResult: {
|
|
718
|
+
error: 'denied',
|
|
719
|
+
error_description: 'Dfns key error',
|
|
720
|
+
},
|
|
721
|
+
}),
|
|
722
|
+
});
|
|
723
|
+
await expect(serviceWithDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS)).rejects.toThrow('Error from signing driver: Dfns key error');
|
|
724
|
+
});
|
|
725
|
+
it('throws when a signed createWallet has no signature in getTransaction', async () => {
|
|
726
|
+
const serviceWithDfns = createService({
|
|
727
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
728
|
+
signTransactionResult: { status: 'signed', txId: 'tx-1' },
|
|
729
|
+
getTransactionResult: {
|
|
730
|
+
txId: 'tx-1',
|
|
731
|
+
status: 'signed',
|
|
732
|
+
},
|
|
733
|
+
}),
|
|
734
|
+
});
|
|
735
|
+
await expect(serviceWithDfns.createWallet(authContext, 'alice', false, SigningProvider.DFNS)).rejects.toThrow('Transaction signed but no signature found in result');
|
|
736
|
+
});
|
|
737
|
+
it('throws when allocateParty wallet is missing topology metadata', async () => {
|
|
738
|
+
const serviceWithDfns = createService({
|
|
739
|
+
[SigningProvider.DFNS]: createDfnsDriver({}),
|
|
740
|
+
});
|
|
741
|
+
await expect(serviceWithDfns.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
742
|
+
signingProviderId: SigningProvider.DFNS,
|
|
743
|
+
topologyTransactions: 'tx1',
|
|
744
|
+
externalTxId: undefined,
|
|
745
|
+
}), SigningProvider.DFNS)).rejects.toThrow('Existing wallet is missing field externalTxId or topologyTransactions');
|
|
746
|
+
});
|
|
747
|
+
it('allocateParty throws when signed transaction has no signature', async () => {
|
|
748
|
+
const serviceWithDfns = createService({
|
|
749
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
750
|
+
getTransactionResult: {
|
|
751
|
+
txId: 'tx-1',
|
|
752
|
+
status: 'signed',
|
|
753
|
+
},
|
|
754
|
+
}),
|
|
755
|
+
});
|
|
756
|
+
await expect(serviceWithDfns.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
757
|
+
signingProviderId: SigningProvider.DFNS,
|
|
758
|
+
topologyTransactions: 'tx1',
|
|
759
|
+
externalTxId: 'tx-1',
|
|
760
|
+
}), SigningProvider.DFNS)).rejects.toThrow('Transaction signed but no signature found in result');
|
|
761
|
+
});
|
|
762
|
+
it('allocateParty updates wallet to allocated when transaction is signed', async () => {
|
|
763
|
+
const driver = createDfnsDriver({
|
|
764
|
+
getTransactionResult: {
|
|
765
|
+
txId: 'tx-1',
|
|
766
|
+
status: 'signed',
|
|
767
|
+
signature: 'sig-base64',
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
const serviceWithDfns = createService({
|
|
771
|
+
[SigningProvider.DFNS]: driver,
|
|
772
|
+
});
|
|
773
|
+
mockPartyAllocator.allocatePartyWithExistingWallet.mockResolvedValue('alice::namespace');
|
|
774
|
+
await serviceWithDfns.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
775
|
+
signingProviderId: SigningProvider.DFNS,
|
|
776
|
+
namespace: 'fingerprint',
|
|
777
|
+
topologyTransactions: 'tx1',
|
|
778
|
+
externalTxId: 'tx-1',
|
|
779
|
+
}), SigningProvider.DFNS);
|
|
780
|
+
expect(mockPartyAllocator.allocatePartyWithExistingWallet).toHaveBeenCalledWith('fingerprint', ['tx1'], 'sig-base64', authContext.userId);
|
|
781
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
782
|
+
networkId: 'network1',
|
|
783
|
+
partyId: 'alice::namespace',
|
|
784
|
+
status: 'allocated',
|
|
785
|
+
reason: '',
|
|
786
|
+
});
|
|
787
|
+
});
|
|
788
|
+
it('allocateParty updates wallet to initialized when transaction is pending', async () => {
|
|
789
|
+
const serviceWithDfns = createService({
|
|
790
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
791
|
+
getTransactionResult: { txId: 'tx-1', status: 'pending' },
|
|
792
|
+
}),
|
|
793
|
+
});
|
|
794
|
+
await serviceWithDfns.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
795
|
+
signingProviderId: SigningProvider.DFNS,
|
|
796
|
+
topologyTransactions: 'tx1',
|
|
797
|
+
externalTxId: 'tx-1',
|
|
798
|
+
}), SigningProvider.DFNS);
|
|
799
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
800
|
+
partyId: 'alice::fingerprint',
|
|
801
|
+
networkId: 'network1',
|
|
802
|
+
status: 'initialized',
|
|
803
|
+
reason: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_PENDING,
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
it.each([
|
|
807
|
+
['failed', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_FAILED],
|
|
808
|
+
['rejected', WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED],
|
|
809
|
+
])('allocateParty disables wallet when transaction is %s', async (status, expectedReason) => {
|
|
810
|
+
const serviceWithDfns = createService({
|
|
811
|
+
[SigningProvider.DFNS]: createDfnsDriver({
|
|
812
|
+
getTransactionResult: {
|
|
813
|
+
txId: 'tx-1',
|
|
814
|
+
status,
|
|
815
|
+
metadata: { cause: 'test' },
|
|
816
|
+
},
|
|
817
|
+
}),
|
|
818
|
+
});
|
|
819
|
+
await serviceWithDfns.allocateParty(authContext, createWallet('alice::fingerprint', {
|
|
820
|
+
signingProviderId: SigningProvider.DFNS,
|
|
821
|
+
topologyTransactions: 'tx1',
|
|
822
|
+
externalTxId: 'tx-1',
|
|
823
|
+
}), SigningProvider.DFNS);
|
|
824
|
+
expect(mockStore.updateWallet).toHaveBeenCalledWith({
|
|
825
|
+
partyId: 'alice::fingerprint',
|
|
826
|
+
networkId: 'network1',
|
|
827
|
+
status: 'removed',
|
|
828
|
+
disabled: true,
|
|
829
|
+
reason: expectedReason,
|
|
830
|
+
});
|
|
831
|
+
});
|
|
301
832
|
});
|
|
302
833
|
});
|