@canton-network/wallet-gateway-remote 0.25.0 → 0.27.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/dist/auth/jwt-auth-service.d.ts.map +1 -1
- package/dist/auth/jwt-auth-service.js +25 -0
- package/dist/config/Config.d.ts +5 -2
- package/dist/config/Config.d.ts.map +1 -1
- package/dist/config/Config.js +6 -0
- package/dist/config/Config.test.js +1 -1
- 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 +29 -2
- 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 +3 -2
- package/dist/dapp-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/dapp-api/server.test.js +1 -1
- package/dist/env.d.ts +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -0
- package/dist/example-config.d.ts +1 -0
- package/dist/example-config.d.ts.map +1 -1
- package/dist/example-config.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +9 -4
- package/dist/ledger/party-allocation-service.test.js +19 -17
- package/dist/ledger/transaction-service.d.ts +1 -0
- package/dist/ledger/transaction-service.d.ts.map +1 -1
- package/dist/ledger/transaction-service.js +77 -56
- package/dist/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.d.ts.map +1 -1
- package/dist/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.js +2 -1
- package/dist/ledger/wallet-allocation/wallet-allocation-service.test.js +22 -22
- package/dist/ledger/wallet-sync-service.js +1 -1
- package/dist/ledger/wallet-sync-service.test.js +15 -13
- package/dist/middleware/rateLimit.d.ts +5 -0
- package/dist/middleware/rateLimit.d.ts.map +1 -1
- package/dist/middleware/rateLimit.js +40 -0
- package/dist/middleware/rateLimit.test.d.ts +2 -0
- package/dist/middleware/rateLimit.test.d.ts.map +1 -0
- package/dist/middleware/rateLimit.test.js +30 -0
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +16 -12
- package/dist/user-api/rpc-gen/typings.d.ts +26 -20
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/user-api/server.test.js +1 -1
- 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 +5 -4
- package/dist/web/frontend/assets/404-CEXKCUlr.js +5 -0
- package/dist/web/frontend/assets/{activities-Da48Liee.js → activities-CPXS4OC3.js} +5 -3
- package/dist/web/frontend/assets/addIdentityProvider-BJjhu--M.js +28 -0
- package/dist/web/frontend/assets/{addNetwork-Dr3W42IN.js → addNetwork-B0olMmyv.js} +3 -3
- package/dist/web/frontend/assets/addParty-PUjps7Ie.js +38 -0
- package/dist/web/frontend/assets/approve-CARzty9R.js +21 -0
- package/dist/web/frontend/assets/{callback-OyzKCduG.js → callback-BqE26RlP.js} +1 -1
- package/dist/web/frontend/assets/{identityProviders-CNGCwCMd.js → identityProviders-Cnx8VIsD.js} +2 -2
- package/dist/web/frontend/assets/{index-CH8oXI5W.js → index-CgsIALyR.js} +1 -1
- package/dist/web/frontend/assets/index-UdyYJ_nU.js +4011 -0
- package/dist/web/frontend/assets/index-nOmkqkbK.js +91 -0
- package/dist/web/frontend/assets/{login-DcYD5VED.js → login-CkpIib74.js} +2 -2
- package/dist/web/frontend/assets/{networks--1UXXt0J.js → networks-D7iP_lGh.js} +2 -2
- package/dist/web/frontend/assets/reviewIdentityProvider-BRb38sGH.js +43 -0
- package/dist/web/frontend/assets/{reviewNetwork-CGV3UYev.js → reviewNetwork-BVdYGugz.js} +3 -3
- package/dist/web/frontend/assets/{settings-DnbEcRUK.js → settings-CxEU64oG.js} +2 -2
- package/dist/web/frontend/assets/{state-Da4wx0rb.js → state-CypMU0cY.js} +1 -1
- package/dist/web/frontend/assets/utils-V1qa66Nv.js +1 -0
- 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 +4 -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 -3
- package/dist/web/frontend/parties/index.html +4 -3
- package/dist/web/frontend/settings/index.html +3 -3
- package/package.json +25 -28
- package/dist/web/frontend/assets/404-F1JWultf.js +0 -5
- package/dist/web/frontend/assets/addIdentityProvider-DC3NxrKJ.js +0 -35
- package/dist/web/frontend/assets/addParty-C6FKG-e0.js +0 -38
- package/dist/web/frontend/assets/approve-BcD3DHcB.js +0 -21
- package/dist/web/frontend/assets/index-6feHRhfj.js +0 -3901
- package/dist/web/frontend/assets/parties-CjUMJ1Qt.js +0 -91
- package/dist/web/frontend/assets/reviewIdentityProvider-BT1CChnu.js +0 -43
|
@@ -15,6 +15,13 @@ export class TransactionService {
|
|
|
15
15
|
this.signingDrivers = signingDrivers;
|
|
16
16
|
this.notifier = notifier;
|
|
17
17
|
}
|
|
18
|
+
async loadPreparedTransactionForSigning(transactionId) {
|
|
19
|
+
const existingTx = await this.store.getTransaction(transactionId);
|
|
20
|
+
if (!existingTx) {
|
|
21
|
+
throw new Error(`Transaction not found with id: ${transactionId}`);
|
|
22
|
+
}
|
|
23
|
+
return existingTx;
|
|
24
|
+
}
|
|
18
25
|
signWithParticipant(wallet) {
|
|
19
26
|
return {
|
|
20
27
|
status: 'signed',
|
|
@@ -29,11 +36,11 @@ export class TransactionService {
|
|
|
29
36
|
throw new Error('Wallet Kernel signing driver not available');
|
|
30
37
|
}
|
|
31
38
|
const driver = signingProvider.controller(userId);
|
|
32
|
-
const
|
|
39
|
+
const tx = await this.loadPreparedTransactionForSigning(signParams.transactionId);
|
|
33
40
|
const { signature } = await driver
|
|
34
41
|
.signTransaction({
|
|
35
|
-
tx: preparedTransaction,
|
|
36
|
-
txHash: preparedTransactionHash,
|
|
42
|
+
tx: tx.preparedTransaction,
|
|
43
|
+
txHash: tx.preparedTransactionHash,
|
|
37
44
|
keyIdentifier: {
|
|
38
45
|
publicKey: wallet.publicKey,
|
|
39
46
|
},
|
|
@@ -42,20 +49,20 @@ export class TransactionService {
|
|
|
42
49
|
if (!signature) {
|
|
43
50
|
throw new Error('Failed to sign transaction: ' + JSON.stringify(signature));
|
|
44
51
|
}
|
|
45
|
-
const existingTx = await this.store.getTransaction(commandId);
|
|
46
52
|
const now = new Date();
|
|
47
53
|
const signedTx = {
|
|
48
|
-
|
|
54
|
+
id: tx.id,
|
|
55
|
+
commandId: tx.commandId,
|
|
49
56
|
status: 'signed',
|
|
50
|
-
preparedTransaction,
|
|
51
|
-
preparedTransactionHash,
|
|
52
|
-
origin:
|
|
53
|
-
...(
|
|
54
|
-
createdAt:
|
|
57
|
+
preparedTransaction: tx.preparedTransaction,
|
|
58
|
+
preparedTransactionHash: tx.preparedTransactionHash,
|
|
59
|
+
origin: tx?.origin ?? null,
|
|
60
|
+
...(tx?.createdAt && {
|
|
61
|
+
createdAt: tx.createdAt,
|
|
55
62
|
}),
|
|
56
63
|
signedAt: now,
|
|
57
64
|
};
|
|
58
|
-
this.store.
|
|
65
|
+
await this.store.setTransactionSigned(tx.id, now);
|
|
59
66
|
this.notifier.emit('txChanged', signedTx);
|
|
60
67
|
return {
|
|
61
68
|
status: 'signed',
|
|
@@ -70,14 +77,13 @@ export class TransactionService {
|
|
|
70
77
|
throw new Error('Blockdaemon signing driver not available');
|
|
71
78
|
}
|
|
72
79
|
const driver = signingProvider.controller(userId);
|
|
73
|
-
const
|
|
80
|
+
const tx = await this.loadPreparedTransactionForSigning(signParams.transactionId);
|
|
74
81
|
let signingResult;
|
|
75
|
-
|
|
76
|
-
if (existingTx && existingTx.externalTxId) {
|
|
82
|
+
if (tx && tx.externalTxId) {
|
|
77
83
|
signingResult = await driver
|
|
78
84
|
.getTransaction({
|
|
79
85
|
userId,
|
|
80
|
-
txId:
|
|
86
|
+
txId: tx.externalTxId,
|
|
81
87
|
})
|
|
82
88
|
.then(handleSigningError);
|
|
83
89
|
}
|
|
@@ -88,8 +94,8 @@ export class TransactionService {
|
|
|
88
94
|
.substring(0, 16);
|
|
89
95
|
signingResult = await driver
|
|
90
96
|
.signTransaction({
|
|
91
|
-
tx: preparedTransaction,
|
|
92
|
-
txHash: preparedTransactionHash,
|
|
97
|
+
tx: tx.preparedTransaction,
|
|
98
|
+
txHash: tx.preparedTransactionHash,
|
|
93
99
|
keyIdentifier: {
|
|
94
100
|
publicKey: wallet.publicKey,
|
|
95
101
|
},
|
|
@@ -103,18 +109,19 @@ export class TransactionService {
|
|
|
103
109
|
throw new Error('No signature returned from signing driver');
|
|
104
110
|
}
|
|
105
111
|
const signedTx = {
|
|
106
|
-
|
|
112
|
+
id: tx.id,
|
|
113
|
+
commandId: tx.commandId,
|
|
107
114
|
status: signingResult.status,
|
|
108
|
-
preparedTransaction,
|
|
109
|
-
preparedTransactionHash,
|
|
110
|
-
origin:
|
|
111
|
-
...(
|
|
112
|
-
createdAt:
|
|
115
|
+
preparedTransaction: tx.preparedTransaction,
|
|
116
|
+
preparedTransactionHash: tx.preparedTransactionHash,
|
|
117
|
+
origin: tx?.origin ?? null,
|
|
118
|
+
...(tx?.createdAt && {
|
|
119
|
+
createdAt: tx.createdAt,
|
|
113
120
|
}),
|
|
114
121
|
signedAt: now,
|
|
115
122
|
externalTxId: signingResult.txId,
|
|
116
123
|
};
|
|
117
|
-
this.store.
|
|
124
|
+
await this.store.setTransactionSigned(tx.id, now, signingResult.txId);
|
|
118
125
|
this.notifier.emit('txChanged', signedTx);
|
|
119
126
|
return {
|
|
120
127
|
status: signingResult.status,
|
|
@@ -127,17 +134,20 @@ export class TransactionService {
|
|
|
127
134
|
else {
|
|
128
135
|
const status = signingResult.status === 'pending' ? 'pending' : 'failed';
|
|
129
136
|
const pendingTx = {
|
|
130
|
-
|
|
137
|
+
id: tx.id,
|
|
138
|
+
commandId: tx.commandId,
|
|
131
139
|
status,
|
|
132
|
-
preparedTransaction,
|
|
133
|
-
preparedTransactionHash,
|
|
140
|
+
preparedTransaction: tx.preparedTransaction,
|
|
141
|
+
preparedTransactionHash: tx.preparedTransactionHash,
|
|
134
142
|
externalTxId: signingResult.txId,
|
|
135
|
-
origin:
|
|
136
|
-
...(
|
|
137
|
-
createdAt:
|
|
143
|
+
origin: tx?.origin ?? null,
|
|
144
|
+
...(tx?.createdAt && {
|
|
145
|
+
createdAt: tx.createdAt,
|
|
138
146
|
}),
|
|
139
147
|
};
|
|
140
|
-
this.store.
|
|
148
|
+
await this.store.setTransactionStatus(tx.id, status, {
|
|
149
|
+
externalTxId: signingResult.txId,
|
|
150
|
+
});
|
|
141
151
|
this.notifier.emit('txChanged', pendingTx);
|
|
142
152
|
return {
|
|
143
153
|
status: signingResult.status,
|
|
@@ -152,14 +162,13 @@ export class TransactionService {
|
|
|
152
162
|
throw new Error('Fireblocks signing driver not available');
|
|
153
163
|
}
|
|
154
164
|
const driver = signingProvider.controller(userId);
|
|
155
|
-
const
|
|
165
|
+
const tx = await this.loadPreparedTransactionForSigning(signParams.transactionId);
|
|
156
166
|
let signingResult;
|
|
157
|
-
|
|
158
|
-
if (existingTx && existingTx.externalTxId) {
|
|
167
|
+
if (tx && tx.externalTxId) {
|
|
159
168
|
signingResult = await driver
|
|
160
169
|
.getTransaction({
|
|
161
170
|
userId,
|
|
162
|
-
txId:
|
|
171
|
+
txId: tx.externalTxId,
|
|
163
172
|
})
|
|
164
173
|
.then(handleSigningError);
|
|
165
174
|
}
|
|
@@ -167,8 +176,8 @@ export class TransactionService {
|
|
|
167
176
|
signingResult = await driver
|
|
168
177
|
.signTransaction({
|
|
169
178
|
userId,
|
|
170
|
-
tx: preparedTransaction,
|
|
171
|
-
txHash: Buffer.from(preparedTransactionHash, 'base64').toString('hex'),
|
|
179
|
+
tx: tx.preparedTransaction,
|
|
180
|
+
txHash: Buffer.from(tx.preparedTransactionHash, 'base64').toString('hex'),
|
|
172
181
|
keyIdentifier: {
|
|
173
182
|
publicKey: wallet.publicKey,
|
|
174
183
|
},
|
|
@@ -181,18 +190,19 @@ export class TransactionService {
|
|
|
181
190
|
throw new Error('No signature returned from signing driver');
|
|
182
191
|
}
|
|
183
192
|
const signedTx = {
|
|
184
|
-
|
|
193
|
+
id: tx.id,
|
|
194
|
+
commandId: tx.commandId,
|
|
185
195
|
status: signingResult.status,
|
|
186
|
-
preparedTransaction,
|
|
187
|
-
preparedTransactionHash,
|
|
188
|
-
origin:
|
|
189
|
-
...(
|
|
190
|
-
createdAt:
|
|
196
|
+
preparedTransaction: tx.preparedTransaction,
|
|
197
|
+
preparedTransactionHash: tx.preparedTransactionHash,
|
|
198
|
+
origin: tx?.origin ?? null,
|
|
199
|
+
...(tx?.createdAt && {
|
|
200
|
+
createdAt: tx.createdAt,
|
|
191
201
|
}),
|
|
192
202
|
signedAt: now,
|
|
193
203
|
externalTxId: signingResult.txId,
|
|
194
204
|
};
|
|
195
|
-
this.store.
|
|
205
|
+
await this.store.setTransactionSigned(tx.id, now, signingResult.txId);
|
|
196
206
|
this.notifier.emit('txChanged', signedTx);
|
|
197
207
|
// return signature in format that is already usable in execute
|
|
198
208
|
const decodedSignature = Buffer.from(signingResult.signature, 'hex').toString('base64');
|
|
@@ -207,17 +217,20 @@ export class TransactionService {
|
|
|
207
217
|
else {
|
|
208
218
|
const status = signingResult.status === 'pending' ? 'pending' : 'failed';
|
|
209
219
|
const pendingTx = {
|
|
210
|
-
|
|
220
|
+
id: tx.id,
|
|
221
|
+
commandId: tx.commandId,
|
|
211
222
|
status,
|
|
212
|
-
preparedTransaction,
|
|
213
|
-
preparedTransactionHash,
|
|
223
|
+
preparedTransaction: tx.preparedTransaction,
|
|
224
|
+
preparedTransactionHash: tx.preparedTransactionHash,
|
|
214
225
|
externalTxId: signingResult.txId,
|
|
215
|
-
origin:
|
|
216
|
-
...(
|
|
217
|
-
createdAt:
|
|
226
|
+
origin: tx?.origin ?? null,
|
|
227
|
+
...(tx?.createdAt && {
|
|
228
|
+
createdAt: tx.createdAt,
|
|
218
229
|
}),
|
|
219
230
|
};
|
|
220
|
-
this.store.
|
|
231
|
+
await this.store.setTransactionStatus(tx.id, status, {
|
|
232
|
+
externalTxId: signingResult.txId,
|
|
233
|
+
});
|
|
221
234
|
this.notifier.emit('txChanged', pendingTx);
|
|
222
235
|
return {
|
|
223
236
|
status: signingResult.status,
|
|
@@ -227,11 +240,13 @@ export class TransactionService {
|
|
|
227
240
|
}
|
|
228
241
|
}
|
|
229
242
|
async executeWithParticipant(userId, executeParams, transaction, ledgerClient, network) {
|
|
230
|
-
const {
|
|
243
|
+
const { partyId } = executeParams;
|
|
244
|
+
const { commandId } = transaction;
|
|
231
245
|
const synchronizerId = network.synchronizerId ?? (await ledgerClient.getSynchronizerId());
|
|
232
246
|
const prep = ledgerPrepareParams(userId, partyId, synchronizerId, transaction.payload);
|
|
233
247
|
const res = await ledgerClient.postWithRetry('/v2/commands/submit-and-wait', prep);
|
|
234
248
|
const executedTx = {
|
|
249
|
+
id: transaction.id,
|
|
235
250
|
commandId,
|
|
236
251
|
status: 'executed',
|
|
237
252
|
preparedTransaction: transaction.preparedTransaction,
|
|
@@ -245,13 +260,16 @@ export class TransactionService {
|
|
|
245
260
|
signedAt: transaction.signedAt,
|
|
246
261
|
}),
|
|
247
262
|
};
|
|
248
|
-
this.store.
|
|
263
|
+
await this.store.setTransactionStatus(transaction.id, 'executed', {
|
|
264
|
+
payload: res,
|
|
265
|
+
});
|
|
249
266
|
this.notifier.emit('txChanged', executedTx);
|
|
250
267
|
return res;
|
|
251
268
|
}
|
|
252
269
|
async executeWithExternal(userId, executeParams, transaction, ledgerClient) {
|
|
253
|
-
const {
|
|
254
|
-
const
|
|
270
|
+
const { partyId, signature, signedBy } = executeParams;
|
|
271
|
+
const { commandId } = transaction;
|
|
272
|
+
const result = await ledgerClient.postWithRetry('/v2/interactive-submission/executeAndWait', {
|
|
255
273
|
userId,
|
|
256
274
|
preparedTransaction: transaction.preparedTransaction,
|
|
257
275
|
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2',
|
|
@@ -276,6 +294,7 @@ export class TransactionService {
|
|
|
276
294
|
},
|
|
277
295
|
});
|
|
278
296
|
const executedTx = {
|
|
297
|
+
id: transaction.id,
|
|
279
298
|
commandId,
|
|
280
299
|
status: 'executed',
|
|
281
300
|
preparedTransaction: transaction.preparedTransaction,
|
|
@@ -289,7 +308,9 @@ export class TransactionService {
|
|
|
289
308
|
signedAt: transaction.signedAt,
|
|
290
309
|
}),
|
|
291
310
|
};
|
|
292
|
-
this.store.
|
|
311
|
+
await this.store.setTransactionStatus(transaction.id, 'executed', {
|
|
312
|
+
payload: result,
|
|
313
|
+
});
|
|
293
314
|
this.notifier.emit('txChanged', executedTx);
|
|
294
315
|
return result;
|
|
295
316
|
}
|
package/dist/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blockdaemon-wallet-allocator.d.ts","sourceRoot":"","sources":["../../../../src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAA;AACzD,OAAO,EAAE,KAAK,EAAgB,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAC/E,OAAO,EAEH,sBAAsB,EAEzB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAC1E,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAYtE,qBAAa,0BAA2B,YAAW,eAAe;IAE1D,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;gBAHb,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,sBAAsB,EACtC,aAAa,EAAE,sBAAsB;IAG3C,YAAY,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC,MAAM,CAAC;IAwGZ,aAAa,CACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"blockdaemon-wallet-allocator.d.ts","sourceRoot":"","sources":["../../../../src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAA;AACzD,OAAO,EAAE,KAAK,EAAgB,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAC/E,OAAO,EAEH,sBAAsB,EAEzB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAC1E,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAYtE,qBAAa,0BAA2B,YAAW,eAAe;IAE1D,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;gBAHb,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,sBAAsB,EACtC,aAAa,EAAE,sBAAsB;IAG3C,YAAY,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC,MAAM,CAAC;IAwGZ,aAAa,CACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;CAgEnB"}
|
|
@@ -102,7 +102,7 @@ export class BlockdaemonWalletAllocator {
|
|
|
102
102
|
throw new Error('Existing wallet is missing field externalTxId or topologyTransactions');
|
|
103
103
|
}
|
|
104
104
|
const driver = this.signingDriver.controller(email);
|
|
105
|
-
const { signature, status } = await driver
|
|
105
|
+
const { signature, status, metadata } = await driver
|
|
106
106
|
.getTransaction({
|
|
107
107
|
txId: existingWallet.externalTxId,
|
|
108
108
|
})
|
|
@@ -131,6 +131,7 @@ export class BlockdaemonWalletAllocator {
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
else {
|
|
134
|
+
this.logger.warn(`Topology transaction for wallet ${existingWallet.partyId} was ${status} with ${JSON.stringify(metadata)}`);
|
|
134
135
|
const reason = status === 'rejected'
|
|
135
136
|
? WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_REJECTED
|
|
136
137
|
: WALLET_DISABLED_REASON.TOPOLOGY_TRANSACTION_FAILED;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import {
|
|
3
|
+
import { vi, describe, it, expect, beforeEach, afterEach, } from 'vitest';
|
|
4
4
|
import { pino } from 'pino';
|
|
5
5
|
import { sink } from 'pino-test';
|
|
6
6
|
import { WalletAllocationService } from './wallet-allocation-service.js';
|
|
@@ -34,14 +34,14 @@ function createFireblocksDriver(options) {
|
|
|
34
34
|
};
|
|
35
35
|
const getTransactionResult = options.getTransactionResult ?? signTransactionResult;
|
|
36
36
|
return {
|
|
37
|
-
controller:
|
|
38
|
-
getKeys:
|
|
37
|
+
controller: vi.fn().mockReturnValue({
|
|
38
|
+
getKeys: vi
|
|
39
39
|
.fn()
|
|
40
40
|
.mockResolvedValue(getKeysResult),
|
|
41
|
-
signTransaction:
|
|
41
|
+
signTransaction: vi
|
|
42
42
|
.fn()
|
|
43
43
|
.mockResolvedValue(signTransactionResult),
|
|
44
|
-
getTransaction:
|
|
44
|
+
getTransaction: vi
|
|
45
45
|
.fn()
|
|
46
46
|
.mockResolvedValue(getTransactionResult),
|
|
47
47
|
}),
|
|
@@ -54,16 +54,16 @@ function createBlockdaemonDriver(options) {
|
|
|
54
54
|
};
|
|
55
55
|
const getTransactionResult = options.getTransactionResult ?? signTransactionResult;
|
|
56
56
|
return {
|
|
57
|
-
controller:
|
|
58
|
-
createKey:
|
|
57
|
+
controller: vi.fn().mockReturnValue({
|
|
58
|
+
createKey: vi
|
|
59
59
|
.fn()
|
|
60
60
|
.mockResolvedValue({
|
|
61
61
|
publicKey: 'bd-pk',
|
|
62
62
|
}),
|
|
63
|
-
signTransaction:
|
|
63
|
+
signTransaction: vi
|
|
64
64
|
.fn()
|
|
65
65
|
.mockResolvedValue(signTransactionResult),
|
|
66
|
-
getTransaction:
|
|
66
|
+
getTransaction: vi
|
|
67
67
|
.fn()
|
|
68
68
|
.mockResolvedValue(getTransactionResult),
|
|
69
69
|
}),
|
|
@@ -80,19 +80,19 @@ describe('WalletAllocationService', () => {
|
|
|
80
80
|
beforeEach(async () => {
|
|
81
81
|
mockLogger = pino(sink());
|
|
82
82
|
mockStore = {
|
|
83
|
-
getWallets:
|
|
84
|
-
removeWallet:
|
|
85
|
-
addWallet:
|
|
86
|
-
updateWallet:
|
|
87
|
-
getCurrentNetwork:
|
|
83
|
+
getWallets: vi.fn(),
|
|
84
|
+
removeWallet: vi.fn(),
|
|
85
|
+
addWallet: vi.fn(),
|
|
86
|
+
updateWallet: vi.fn(),
|
|
87
|
+
getCurrentNetwork: vi
|
|
88
88
|
.fn()
|
|
89
89
|
.mockResolvedValue({ id: 'network1' }),
|
|
90
90
|
};
|
|
91
91
|
mockPartyAllocator = {
|
|
92
|
-
allocateParty:
|
|
93
|
-
allocatePartyWithExistingWallet:
|
|
94
|
-
createFingerprintFromKey:
|
|
95
|
-
generateTopologyTransactions:
|
|
92
|
+
allocateParty: vi.fn(),
|
|
93
|
+
allocatePartyWithExistingWallet: vi.fn(),
|
|
94
|
+
createFingerprintFromKey: vi.fn().mockReturnValue('fingerprint'),
|
|
95
|
+
generateTopologyTransactions: vi
|
|
96
96
|
.fn()
|
|
97
97
|
.mockResolvedValue({
|
|
98
98
|
topologyTransactions: ['tx1'],
|
|
@@ -100,14 +100,14 @@ describe('WalletAllocationService', () => {
|
|
|
100
100
|
}),
|
|
101
101
|
};
|
|
102
102
|
mockController = {
|
|
103
|
-
createKey:
|
|
103
|
+
createKey: vi
|
|
104
104
|
.fn()
|
|
105
105
|
.mockResolvedValue({
|
|
106
106
|
id: 'key-id',
|
|
107
107
|
name: 'test-key',
|
|
108
108
|
publicKey: 'new-public-key',
|
|
109
109
|
}),
|
|
110
|
-
signTransaction:
|
|
110
|
+
signTransaction: vi
|
|
111
111
|
.fn()
|
|
112
112
|
.mockResolvedValue({
|
|
113
113
|
txId: 'tx-id',
|
|
@@ -116,14 +116,14 @@ describe('WalletAllocationService', () => {
|
|
|
116
116
|
}),
|
|
117
117
|
};
|
|
118
118
|
mockWalletKernelDriver = {
|
|
119
|
-
controller:
|
|
119
|
+
controller: vi.fn(() => mockController),
|
|
120
120
|
};
|
|
121
121
|
service = createService({
|
|
122
122
|
[SigningProvider.WALLET_KERNEL]: mockWalletKernelDriver,
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
125
|
afterEach(() => {
|
|
126
|
-
|
|
126
|
+
vi.restoreAllMocks();
|
|
127
127
|
});
|
|
128
128
|
describe('Participant', () => {
|
|
129
129
|
it('createWallet allocates new party and adds wallet', async () => {
|
|
@@ -346,7 +346,7 @@ export class WalletSyncService {
|
|
|
346
346
|
const needsPrimaryReset = primaryWallet?.status === 'initialized' ||
|
|
347
347
|
(!primaryWallet && allocatedWallets.length > 0);
|
|
348
348
|
if (needsPrimaryReset && allocatedWallets.length > 0) {
|
|
349
|
-
this.store.setPrimaryWallet(allocatedWallets[0].partyId);
|
|
349
|
+
await this.store.setPrimaryWallet(allocatedWallets[0].partyId);
|
|
350
350
|
this.logger.info(`Set ${allocatedWallets[0].partyId} as primary wallet in network ${network.id}`);
|
|
351
351
|
}
|
|
352
352
|
const disabled = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import {
|
|
3
|
+
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
4
4
|
import { pino } from 'pino';
|
|
5
5
|
import { sink } from 'pino-test';
|
|
6
6
|
import { SigningProvider, } from '@canton-network/core-signing-lib';
|
|
@@ -11,9 +11,11 @@ import { PartyLevelRight, } from '@canton-network/core-wallet-store';
|
|
|
11
11
|
import { StoreInternal } from '@canton-network/core-wallet-store-inmemory';
|
|
12
12
|
import { WalletSyncService } from './wallet-sync-service.js';
|
|
13
13
|
import { PartyAllocationService } from './party-allocation-service.js';
|
|
14
|
-
const mockLedgerGet =
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const { mockLedgerGet } = vi.hoisted(() => ({
|
|
15
|
+
mockLedgerGet: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
vi.mock('@canton-network/core-ledger-client', () => ({
|
|
18
|
+
LedgerClient: vi.fn(function LedgerClientMock() {
|
|
17
19
|
return {
|
|
18
20
|
getWithRetry: mockLedgerGet,
|
|
19
21
|
};
|
|
@@ -83,7 +85,7 @@ describe('WalletSyncService - resolveSigningProvider', () => {
|
|
|
83
85
|
}, partyAllocator);
|
|
84
86
|
});
|
|
85
87
|
afterEach(() => {
|
|
86
|
-
|
|
88
|
+
vi.restoreAllMocks();
|
|
87
89
|
mockLedgerGet.mockClear();
|
|
88
90
|
});
|
|
89
91
|
it('resolves participant when namespace matches participant namespace', async () => {
|
|
@@ -128,8 +130,8 @@ describe('WalletSyncService - resolveSigningProvider', () => {
|
|
|
128
130
|
const normalizedKey = partyAllocator.normalizePublicKeyToBase64(fireblocksPublicKeyHex);
|
|
129
131
|
const namespace = partyAllocator.createFingerprintFromKey(normalizedKey);
|
|
130
132
|
const mockFireblocksDriver = {
|
|
131
|
-
controller:
|
|
132
|
-
getKeys:
|
|
133
|
+
controller: vi.fn().mockReturnValue({
|
|
134
|
+
getKeys: vi
|
|
133
135
|
.fn()
|
|
134
136
|
.mockResolvedValue({
|
|
135
137
|
keys: [
|
|
@@ -253,7 +255,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
253
255
|
service = new WalletSyncService(store, mockLedgerClient, authContext, mockLogger, {}, partyAllocator);
|
|
254
256
|
});
|
|
255
257
|
afterEach(() => {
|
|
256
|
-
|
|
258
|
+
vi.restoreAllMocks();
|
|
257
259
|
mockLedgerGet.mockClear();
|
|
258
260
|
});
|
|
259
261
|
it('isWalletSyncNeeded should filter by current network', async () => {
|
|
@@ -305,7 +307,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
305
307
|
await store.addNetwork(network1);
|
|
306
308
|
await setSession('network1');
|
|
307
309
|
await store.addWallet(createWallet('party1::namespace', 'network1'));
|
|
308
|
-
const addWalletSpy =
|
|
310
|
+
const addWalletSpy = vi.spyOn(store, 'addWallet');
|
|
309
311
|
mockLedgerGet
|
|
310
312
|
.mockResolvedValueOnce({
|
|
311
313
|
rights: [
|
|
@@ -542,7 +544,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
542
544
|
.mockResolvedValueOnce({
|
|
543
545
|
participantId: 'participant1::namespace',
|
|
544
546
|
});
|
|
545
|
-
const updateWalletSpy =
|
|
547
|
+
const updateWalletSpy = vi.spyOn(store, 'updateWallet');
|
|
546
548
|
await service.syncWallets();
|
|
547
549
|
expect(updateWalletSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
548
550
|
partyId: 'party1::namespace',
|
|
@@ -575,7 +577,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
575
577
|
.mockResolvedValueOnce({
|
|
576
578
|
participantId: 'participant1::namespace',
|
|
577
579
|
});
|
|
578
|
-
const updateWalletSpy =
|
|
580
|
+
const updateWalletSpy = vi.spyOn(store, 'updateWallet');
|
|
579
581
|
await service.syncWallets();
|
|
580
582
|
expect(updateWalletSpy).not.toHaveBeenCalled();
|
|
581
583
|
const wallets = await store.getWallets();
|
|
@@ -603,7 +605,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
603
605
|
.mockResolvedValueOnce({
|
|
604
606
|
participantId: 'participant1::namespace',
|
|
605
607
|
});
|
|
606
|
-
const updateWalletSpy =
|
|
608
|
+
const updateWalletSpy = vi.spyOn(store, 'updateWallet');
|
|
607
609
|
await service.syncWallets();
|
|
608
610
|
expect(updateWalletSpy).toHaveBeenCalledTimes(2);
|
|
609
611
|
expect(updateWalletSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
@@ -639,7 +641,7 @@ describe('WalletSyncService - multi-network features', () => {
|
|
|
639
641
|
.mockResolvedValueOnce({
|
|
640
642
|
participantId: 'participant1::namespace',
|
|
641
643
|
});
|
|
642
|
-
const updateWalletSpy =
|
|
644
|
+
const updateWalletSpy = vi.spyOn(store, 'updateWallet');
|
|
643
645
|
await service.syncWallets();
|
|
644
646
|
expect(updateWalletSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
645
647
|
partyId: 'party1::namespace',
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
import type { Request } from 'express';
|
|
2
|
+
export declare function ipRateLimitKeyGenerator(req: Request): string;
|
|
3
|
+
export declare function rateLimitKeyGenerator(req: Request): string;
|
|
1
4
|
export declare function rateLimiter(requestRateLimit: number): import("express-rate-limit").RateLimitRequestHandler;
|
|
5
|
+
export declare function preAuthIpRateLimiter(requestRateLimit: number): import("express-rate-limit").RateLimitRequestHandler;
|
|
6
|
+
export declare function authenticatedRateLimiter(requestRateLimit: number): import("express-rate-limit").RateLimitRequestHandler;
|
|
2
7
|
//# sourceMappingURL=rateLimit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../../src/middleware/rateLimit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../../src/middleware/rateLimit.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAWtC,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE5D;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAO1D;AAED,wBAAgB,WAAW,CAAC,gBAAgB,EAAE,MAAM,wDAQnD;AAED,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,wDAU5D;AAED,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,wDAUhE"}
|
|
@@ -1,10 +1,50 @@
|
|
|
1
1
|
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import rateLimit from 'express-rate-limit';
|
|
4
|
+
function hasBearerToken(req) {
|
|
5
|
+
const authHeader = req.headers.authorization;
|
|
6
|
+
if (typeof authHeader === 'string' && authHeader.startsWith('Bearer ')) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
return typeof req.query.token === 'string' && req.query.token.length > 0;
|
|
10
|
+
}
|
|
11
|
+
export function ipRateLimitKeyGenerator(req) {
|
|
12
|
+
return `ip:${req.ip || req.socket.remoteAddress || 'unknown'}`;
|
|
13
|
+
}
|
|
14
|
+
export function rateLimitKeyGenerator(req) {
|
|
15
|
+
// Prefer authenticated identity to avoid shared proxy IP buckets.
|
|
16
|
+
if (req.authContext?.userId) {
|
|
17
|
+
return `user:${req.authContext.userId}`;
|
|
18
|
+
}
|
|
19
|
+
return ipRateLimitKeyGenerator(req);
|
|
20
|
+
}
|
|
4
21
|
export function rateLimiter(requestRateLimit) {
|
|
5
22
|
return rateLimit({
|
|
6
23
|
windowMs: 1 * 60 * 1000, // 1 minute
|
|
7
24
|
max: requestRateLimit, // limit each IP to requestRateLimit requests per windowMs
|
|
25
|
+
keyGenerator: rateLimitKeyGenerator,
|
|
26
|
+
standardHeaders: true,
|
|
27
|
+
legacyHeaders: false,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function preAuthIpRateLimiter(requestRateLimit) {
|
|
31
|
+
return rateLimit({
|
|
32
|
+
windowMs: 1 * 60 * 1000,
|
|
33
|
+
max: requestRateLimit,
|
|
34
|
+
keyGenerator: ipRateLimitKeyGenerator,
|
|
35
|
+
// Only protect unauthenticated traffic before JWT verification.
|
|
36
|
+
skip: hasBearerToken,
|
|
37
|
+
standardHeaders: true,
|
|
38
|
+
legacyHeaders: false,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function authenticatedRateLimiter(requestRateLimit) {
|
|
42
|
+
return rateLimit({
|
|
43
|
+
windowMs: 1 * 60 * 1000,
|
|
44
|
+
max: requestRateLimit,
|
|
45
|
+
keyGenerator: rateLimitKeyGenerator,
|
|
46
|
+
// Apply only after JWT middleware has attached an authenticated context.
|
|
47
|
+
skip: (req) => !req.authContext?.userId,
|
|
8
48
|
standardHeaders: true,
|
|
9
49
|
legacyHeaders: false,
|
|
10
50
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.test.d.ts","sourceRoot":"","sources":["../../src/middleware/rateLimit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { describe, expect, test } from 'vitest';
|
|
4
|
+
import { ipRateLimitKeyGenerator, rateLimitKeyGenerator } from './rateLimit.js';
|
|
5
|
+
describe('ipRateLimitKeyGenerator', () => {
|
|
6
|
+
test('uses request ip address', () => {
|
|
7
|
+
const req = {
|
|
8
|
+
ip: '198.51.100.42',
|
|
9
|
+
socket: { remoteAddress: '10.0.0.1' },
|
|
10
|
+
};
|
|
11
|
+
expect(ipRateLimitKeyGenerator(req)).toBe('ip:198.51.100.42');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe('rateLimitKeyGenerator', () => {
|
|
15
|
+
test('uses authenticated user id when available', () => {
|
|
16
|
+
const req = {
|
|
17
|
+
authContext: { userId: 'alice' },
|
|
18
|
+
ip: '203.0.113.10',
|
|
19
|
+
socket: { remoteAddress: '10.0.0.1' },
|
|
20
|
+
};
|
|
21
|
+
expect(rateLimitKeyGenerator(req)).toBe('user:alice');
|
|
22
|
+
});
|
|
23
|
+
test('falls back to request ip when user is not authenticated', () => {
|
|
24
|
+
const req = {
|
|
25
|
+
ip: '198.51.100.42',
|
|
26
|
+
socket: { remoteAddress: '10.0.0.1' },
|
|
27
|
+
};
|
|
28
|
+
expect(rateLimitKeyGenerator(req)).toBe('ip:198.51.100.42');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/user-api/controller.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,KAAK,EAAW,MAAM,mCAAmC,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAEH,WAAW,EAKd,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EACH,sBAAsB,EACtB,eAAe,EAClB,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/user-api/controller.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,KAAK,EAAW,MAAM,mCAAmC,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAEH,WAAW,EAKd,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EACH,sBAAsB,EACtB,eAAe,EAClB,MAAM,kCAAkC,CAAA;AASzC,KAAK,uBAAuB,GAAG,OAAO,CAClC,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAClD,CAAA;AAED,eAAO,MAAM,cAAc,GACvB,YAAY,UAAU,EACtB,SAAS,MAAM,EACf,OAAO,KAAK,EACZ,qBAAqB,mBAAmB,EACxC,aAAa,WAAW,GAAG,SAAS,EACpC,SAAS,uBAAuB,EAChC,SAAS,MAAM,EACf,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;CAowBvB,CAAA"}
|