@canton-network/wallet-gateway-remote 1.4.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/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 +60 -4
- 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.map +1 -1
- package/dist/dapp-api/controller.js +54 -24
- 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 +3 -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.test.js +12 -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 +6 -4
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +111 -94
- 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 +12 -0
- package/dist/user-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/user-api/rpc-gen/index.js +4 -0
- package/dist/user-api/rpc-gen/typings.d.ts +52 -3
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/utils.d.ts +17 -1
- 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 -4
- package/dist/web/frontend/assets/404-MVLWUPwN.js +5 -0
- package/dist/web/frontend/assets/{activities-NY8oZAkH.js → activities-DaWkmGqA.js} +2 -2
- package/dist/web/frontend/assets/{addIdentityProvider-38ghz3RT.js → addIdentityProvider--rBb0ihb.js} +2 -2
- package/dist/web/frontend/assets/{addNetwork-BaDhbrZl.js → addNetwork-C6UDsRkU.js} +4 -4
- 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-BZ9h_VOJ.js → identityProviders-Dra4qG6t.js} +2 -2
- package/dist/web/frontend/assets/{index-B-HiKugW.js → index-Bm76pXA_.js} +2 -2
- package/dist/web/frontend/assets/index-D1dC4Cl9.js +4477 -0
- package/dist/web/frontend/assets/{login-CqwMEG9J.js → login-BC8a-kD_.js} +2 -2
- package/dist/web/frontend/assets/{networks-BJvRi47M.js → networks-B3ztsogL.js} +2 -2
- package/dist/web/frontend/assets/{reviewIdentityProvider-ySlQnw5R.js → reviewIdentityProvider-Co420Dbk.js} +3 -3
- package/dist/web/frontend/assets/{reviewNetwork-DrVxeHd4.js → reviewNetwork-B-Sh8pCH.js} +3 -3
- package/dist/web/frontend/assets/{settings-BVNkaUyJ.js → settings-DvyUjqLl.js} +1 -1
- package/dist/web/frontend/assets/{state-qAsNw5qf.js → state-Bq65GwdF.js} +1 -1
- package/dist/web/frontend/assets/{utils-BDkHxi8V.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 -3
- 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 +36 -32
- package/dist/web/frontend/assets/404-C7V2yl2z.js +0 -5
- package/dist/web/frontend/assets/addParty-j3JWZX5a.js +0 -41
- package/dist/web/frontend/assets/approve-43nVzAAC.js +0 -21
- package/dist/web/frontend/assets/callback-BBMiCjHR.js +0 -1
- package/dist/web/frontend/assets/index-DoNqknyE.js +0 -4042
|
@@ -4,7 +4,8 @@ import { assertConnected, AuthTokenProvider, } from '@canton-network/core-wallet
|
|
|
4
4
|
import buildController from './rpc-gen/index.js';
|
|
5
5
|
import { LedgerClient, } from '@canton-network/core-ledger-client';
|
|
6
6
|
import { v4 } from 'uuid';
|
|
7
|
-
import { networkStatus, ledgerPrepareParams } from '../utils.js';
|
|
7
|
+
import { networkStatus, ledgerPrepareParams, logDynamically } from '../utils.js';
|
|
8
|
+
import { rpcErrors } from '@canton-network/core-rpc-errors';
|
|
8
9
|
export const dappController = (kernelInfo, dappUrl, userUrl, store, notificationService, _logger, origin, context) => {
|
|
9
10
|
const logger = _logger.child({ component: 'dapp-controller' });
|
|
10
11
|
return buildController({
|
|
@@ -127,6 +128,7 @@ export const dappController = (kernelInfo, dappUrl, userUrl, store, notification
|
|
|
127
128
|
},
|
|
128
129
|
prepareExecute: async (params) => {
|
|
129
130
|
const wallet = await store.getPrimaryWallet();
|
|
131
|
+
const wallets = await store.getWallets();
|
|
130
132
|
const network = await store.getCurrentNetwork();
|
|
131
133
|
if (context === undefined) {
|
|
132
134
|
throw new Error('Unauthenticated context');
|
|
@@ -134,26 +136,54 @@ export const dappController = (kernelInfo, dappUrl, userUrl, store, notification
|
|
|
134
136
|
if (wallet === undefined) {
|
|
135
137
|
throw new Error('No primary wallet found');
|
|
136
138
|
}
|
|
139
|
+
let userId = context.userId;
|
|
140
|
+
const accessTokenProvider = AuthTokenProvider.fromToken(context.accessToken, logger);
|
|
141
|
+
if (context?.isApiKey) {
|
|
142
|
+
logger.info('Authenticated with API Key, fetching m2m token for ledger access');
|
|
143
|
+
userId = context.ledgerUserId;
|
|
144
|
+
}
|
|
137
145
|
const ledgerClient = new LedgerClient({
|
|
138
146
|
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
139
147
|
logger,
|
|
140
|
-
accessTokenProvider
|
|
148
|
+
accessTokenProvider,
|
|
141
149
|
});
|
|
142
|
-
const userId = context.userId;
|
|
143
150
|
const notifier = notificationService.getNotifier(userId);
|
|
144
|
-
|
|
145
|
-
const commandId = params.commandId;
|
|
151
|
+
const commandId = params.commandId || v4();
|
|
146
152
|
const transactionId = v4();
|
|
147
153
|
notifier.emit('txChanged', { status: 'pending', commandId });
|
|
148
154
|
const synchronizerId = network.synchronizerId ??
|
|
149
155
|
(await ledgerClient.getSynchronizerId());
|
|
150
|
-
|
|
156
|
+
let actAs = [wallet.partyId];
|
|
157
|
+
if (params.actAs && params.actAs.length > 0) {
|
|
158
|
+
actAs = params.actAs;
|
|
159
|
+
for (const actingParty of actAs) {
|
|
160
|
+
if (wallets.find((w) => w.partyId === actingParty) ===
|
|
161
|
+
undefined) {
|
|
162
|
+
throw rpcErrors.invalidRequest(`Acting party ${actingParty} does not belong to user`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
logDynamically(logger, 'prepareExecute: Submitting request to ledger', {
|
|
167
|
+
info: { transactionId },
|
|
168
|
+
debug: { commandId, userId, actAs },
|
|
169
|
+
});
|
|
170
|
+
const actAsParty = params.actAs || [wallet.partyId];
|
|
171
|
+
const prepared = await prepareSubmission(context.userId, actAsParty, synchronizerId, params, ledgerClient);
|
|
172
|
+
logDynamically(logger, 'prepareExecute: Received response from ledger', {
|
|
173
|
+
info: { transactionId },
|
|
174
|
+
debug: {
|
|
175
|
+
commandId,
|
|
176
|
+
userId,
|
|
177
|
+
partyId: actAsParty,
|
|
178
|
+
prepared,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
151
181
|
const transaction = {
|
|
152
182
|
id: transactionId,
|
|
153
183
|
commandId,
|
|
154
184
|
status: 'pending',
|
|
155
|
-
preparedTransaction:
|
|
156
|
-
preparedTransactionHash:
|
|
185
|
+
preparedTransaction: prepared.preparedTransaction,
|
|
186
|
+
preparedTransactionHash: prepared.preparedTransactionHash,
|
|
157
187
|
payload: params,
|
|
158
188
|
origin: origin || null,
|
|
159
189
|
createdAt: new Date(),
|
|
@@ -161,10 +191,10 @@ export const dappController = (kernelInfo, dappUrl, userUrl, store, notification
|
|
|
161
191
|
logger.info({
|
|
162
192
|
actAs: params.actAs || [wallet.partyId],
|
|
163
193
|
readAs: params.readAs || [],
|
|
164
|
-
userId
|
|
194
|
+
userId,
|
|
165
195
|
commandId,
|
|
166
196
|
commands: params.commands?.[0],
|
|
167
|
-
confirmationRequestTrafficCostEstimation:
|
|
197
|
+
confirmationRequestTrafficCostEstimation: prepared.costEstimation
|
|
168
198
|
?.confirmationRequestTrafficCostEstimation,
|
|
169
199
|
}, 'prepared transaction traffic estimation');
|
|
170
200
|
await store.setTransaction(transaction);
|
|
@@ -221,21 +251,9 @@ export const dappController = (kernelInfo, dappUrl, userUrl, store, notification
|
|
|
221
251
|
userUrl: `${userUrl}/login/`,
|
|
222
252
|
};
|
|
223
253
|
},
|
|
224
|
-
connected: async () => {
|
|
225
|
-
throw new Error('Only for events.');
|
|
226
|
-
},
|
|
227
|
-
onStatusChanged: async () => {
|
|
228
|
-
throw new Error('Only for events.');
|
|
229
|
-
},
|
|
230
|
-
accountsChanged: async () => {
|
|
231
|
-
throw new Error('Only for events.');
|
|
232
|
-
},
|
|
233
254
|
listAccounts: async () => {
|
|
234
255
|
return await store.getWallets();
|
|
235
256
|
},
|
|
236
|
-
txChanged: async () => {
|
|
237
|
-
throw new Error('Only for events.');
|
|
238
|
-
},
|
|
239
257
|
getActiveNetwork: async () => {
|
|
240
258
|
const network = await store.getCurrentNetwork();
|
|
241
259
|
return {
|
|
@@ -284,11 +302,23 @@ export const dappController = (kernelInfo, dappUrl, userUrl, store, notification
|
|
|
284
302
|
}
|
|
285
303
|
return wallet;
|
|
286
304
|
},
|
|
305
|
+
connected: async () => {
|
|
306
|
+
throw new Error('Only for events.');
|
|
307
|
+
},
|
|
308
|
+
onStatusChanged: async () => {
|
|
309
|
+
throw new Error('Only for events.');
|
|
310
|
+
},
|
|
311
|
+
accountsChanged: async () => {
|
|
312
|
+
throw new Error('Only for events.');
|
|
313
|
+
},
|
|
314
|
+
txChanged: async () => {
|
|
315
|
+
throw new Error('Only for events.');
|
|
316
|
+
},
|
|
287
317
|
messageSignature: function () {
|
|
288
318
|
throw new Error('Only for events.');
|
|
289
319
|
},
|
|
290
320
|
});
|
|
291
321
|
};
|
|
292
|
-
async function prepareSubmission(userId,
|
|
293
|
-
return await ledgerClient.postWithRetry('/v2/interactive-submission/prepare', ledgerPrepareParams(userId,
|
|
322
|
+
async function prepareSubmission(userId, partyIds, synchronizerId, params, ledgerClient) {
|
|
323
|
+
return await ledgerClient.postWithRetry('/v2/interactive-submission/prepare', ledgerPrepareParams(userId, partyIds, synchronizerId, params));
|
|
294
324
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4FA,QAAA,MAAM,OAAO;;;;;;;CAAiB,CAAA;AAE9B,MAAM,MAAM,UAAU,GAAG,OAAO,OAAO,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import z from 'zod';
|
|
|
13
13
|
import { rawConfigSchema } from './config/Config.js';
|
|
14
14
|
import exampleConfig from './example-config.js';
|
|
15
15
|
import { GATEWAY_VERSION } from './version.js';
|
|
16
|
+
import { nestedRedact } from './utils.js';
|
|
16
17
|
const program = new Command()
|
|
17
18
|
.name('wallet-gateway')
|
|
18
19
|
.version(GATEWAY_VERSION)
|
|
@@ -49,6 +50,15 @@ const program = new Command()
|
|
|
49
50
|
// Define project-global logger
|
|
50
51
|
const logger = pino({
|
|
51
52
|
name: 'main',
|
|
53
|
+
redact: {
|
|
54
|
+
paths: nestedRedact([
|
|
55
|
+
'accessToken',
|
|
56
|
+
'access_token',
|
|
57
|
+
'clientSecret',
|
|
58
|
+
'jwt',
|
|
59
|
+
]),
|
|
60
|
+
censor: '*****',
|
|
61
|
+
},
|
|
52
62
|
level: logLevel,
|
|
53
63
|
...(logFormat === 'pretty'
|
|
54
64
|
? {
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAyB7B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAuMvC,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAoKhE"}
|
package/dist/init.js
CHANGED
|
@@ -6,7 +6,7 @@ import { web } from './web/server.js';
|
|
|
6
6
|
import { StoreSql, bootstrap, connection, migrator, } from '@canton-network/core-wallet-store-sql';
|
|
7
7
|
import { StoreSql as SigningStoreSql, bootstrap as signingBootstrap, connection as signingConnection, migrator as signingMigrator, } from '@canton-network/core-signing-store-sql';
|
|
8
8
|
import { ConfigUtils } from './config/ConfigUtils.js';
|
|
9
|
-
import { SigningProvider
|
|
9
|
+
import { SigningProvider } from '@canton-network/core-signing-lib';
|
|
10
10
|
import { ParticipantSigningDriver } from '@canton-network/core-signing-participant';
|
|
11
11
|
import { InternalSigningDriver } from '@canton-network/core-signing-internal';
|
|
12
12
|
import DfnsSigningProvider from '@canton-network/core-signing-dfns';
|
|
@@ -23,6 +23,7 @@ import { sessionHandler } from './middleware/sessionHandler.js';
|
|
|
23
23
|
import { NotificationService } from './notification/NotificationService.js';
|
|
24
24
|
import { sql } from 'kysely';
|
|
25
25
|
import { Env } from './env.js';
|
|
26
|
+
import { apiKeyAuth } from './middleware/apiKeyAuth.js';
|
|
26
27
|
let isReady = false;
|
|
27
28
|
async function initializeDatabase(config, logger) {
|
|
28
29
|
logger.info('Checking for database migrations...');
|
|
@@ -227,11 +228,7 @@ export async function initialize(opts, logger) {
|
|
|
227
228
|
'selfSignedAccessToken',
|
|
228
229
|
],
|
|
229
230
|
};
|
|
230
|
-
app.use('/api/*splat', express.json());
|
|
231
|
-
app.use('/api/*splat', preAuthRateLimit);
|
|
232
|
-
app.use('/api/*splat', jwtAuth(authService, logger.child({ component: 'JwtHandler' })));
|
|
233
|
-
app.use('/api/*splat', postAuthRateLimit);
|
|
234
|
-
app.use('/api/*splat', sessionHandler(store, allowedPaths, logger.child({ component: 'SessionHandler' })));
|
|
231
|
+
app.use('/api/*splat', express.json(), preAuthRateLimit, apiKeyAuth(store, config.server.dappPath, logger.child({ component: 'ApiKeyHandler' })), jwtAuth(authService, logger.child({ component: 'JwtHandler' })), postAuthRateLimit, sessionHandler(store, allowedPaths, logger.child({ component: 'SessionHandler' })));
|
|
235
232
|
logger.info({ ...config.server, port }, 'Server configuration');
|
|
236
233
|
const kernelInfo = config.kernel;
|
|
237
234
|
// register dapp API handlers
|
|
@@ -2,35 +2,38 @@ import { Logger } from 'pino';
|
|
|
2
2
|
import { LedgerClient } from '@canton-network/core-ledger-client';
|
|
3
3
|
import { Store, Transaction, Wallet, Network } from '@canton-network/core-wallet-store';
|
|
4
4
|
import type { SignResult } from '../user-api/rpc-gen/typings.js';
|
|
5
|
-
import {
|
|
6
|
-
import { ExecuteParams, ExecuteResult, SignParams
|
|
5
|
+
import type { SigningDrivers } from '../signing/signing-drivers.js';
|
|
6
|
+
import { ExecuteParams, ExecuteResult, SignParams } from '../user-api/rpc-gen/typings.js';
|
|
7
7
|
import { UserId } from '../dapp-api/rpc-gen/typings.js';
|
|
8
8
|
import { Notifier } from '../notification/NotificationService.js';
|
|
9
|
+
import { AuthContext } from '@canton-network/core-wallet-auth';
|
|
9
10
|
export declare class TransactionService {
|
|
10
11
|
private store;
|
|
11
12
|
private logger;
|
|
12
13
|
private signingDrivers;
|
|
13
14
|
private notifier;
|
|
14
|
-
constructor(store: Store, logger: Logger, signingDrivers:
|
|
15
|
+
constructor(store: Store, logger: Logger, signingDrivers: SigningDrivers | undefined, notifier: Notifier);
|
|
16
|
+
sign(authContext: AuthContext, wallet: Wallet, signParams: SignParams): Promise<SignResult>;
|
|
17
|
+
execute(userId: UserId, wallet: Wallet, transaction: Transaction, executeParams?: ExecuteParams, ledgerClient?: LedgerClient, network?: Network): Promise<ExecuteResult>;
|
|
15
18
|
private loadPreparedTransactionForSigning;
|
|
16
|
-
signWithParticipant
|
|
17
|
-
signWithWalletKernel
|
|
18
|
-
signWithBlockdaemon
|
|
19
|
-
signWithFireblocks
|
|
19
|
+
private signWithParticipant;
|
|
20
|
+
private signWithWalletKernel;
|
|
21
|
+
private signWithBlockdaemon;
|
|
22
|
+
private signWithFireblocks;
|
|
20
23
|
/**
|
|
21
24
|
* Dfns broadcasts the prepared transaction to Canton itself, so we get back
|
|
22
25
|
* an updateId rather than a raw signature. We persist the updateId as the
|
|
23
26
|
* signature payload (the controller short-circuits Dfns execute) and surface
|
|
24
27
|
* the same SignResult shape the other external providers use.
|
|
25
28
|
*/
|
|
26
|
-
signWithDfns
|
|
29
|
+
private signWithDfns;
|
|
27
30
|
/**
|
|
28
31
|
* Dfns has already broadcast the transaction at sign-time, so execute is a
|
|
29
32
|
* state reconciliation: mark the stored transaction as executed and return
|
|
30
33
|
* the updateId Dfns gave us. We deliberately don't post to the ledger here.
|
|
31
34
|
*/
|
|
32
|
-
executeWithDfns
|
|
33
|
-
executeWithParticipant
|
|
34
|
-
executeWithExternal
|
|
35
|
+
private executeWithDfns;
|
|
36
|
+
private executeWithParticipant;
|
|
37
|
+
private executeWithExternal;
|
|
35
38
|
}
|
|
36
39
|
//# sourceMappingURL=transaction-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-service.d.ts","sourceRoot":"","sources":["../../src/ledger/transaction-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AACjE,OAAO,EACH,KAAK,EACL,WAAW,EACX,MAAM,EACN,OAAO,EACV,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"transaction-service.d.ts","sourceRoot":"","sources":["../../src/ledger/transaction-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AACjE,OAAO,EACH,KAAK,EACL,WAAW,EACX,MAAM,EACN,OAAO,EACV,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAOhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EACH,aAAa,EACb,aAAa,EACb,UAAU,EAEb,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAA;AAMjE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAW9D,qBAAa,kBAAkB;IAEvB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,QAAQ;gBAHR,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,YAAK,EACnC,QAAQ,EAAE,QAAQ;IAGjB,IAAI,CACb,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACvB,OAAO,CAAC,UAAU,CAAC;IAiDf,OAAO,CACV,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,EACxB,aAAa,CAAC,EAAE,aAAa,EAC7B,YAAY,CAAC,EAAE,YAAY,EAC3B,OAAO,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,aAAa,CAAC;YA6DX,iCAAiC;IAW/C,OAAO,CAAC,mBAAmB;YASb,oBAAoB;YAyDpB,mBAAmB;YAiHnB,kBAAkB;IAqHhC;;;;;OAKG;YACW,YAAY;IA2G1B;;;;OAIG;YACW,eAAe;YAgCf,sBAAsB;YAoDtB,mBAAmB;CAiEpC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
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 { SigningProvider, } from '@canton-network/core-signing-lib';
|
|
4
|
-
import { ledgerPrepareParams } from '../utils.js';
|
|
4
|
+
import { ledgerPrepareParams, logDynamically, } from '../utils.js';
|
|
5
5
|
function handleSigningError(result) {
|
|
6
6
|
if ('error' in result) {
|
|
7
7
|
throw new Error(`Error from signing driver: ${result.error_description}`);
|
|
@@ -15,6 +15,73 @@ export class TransactionService {
|
|
|
15
15
|
this.signingDrivers = signingDrivers;
|
|
16
16
|
this.notifier = notifier;
|
|
17
17
|
}
|
|
18
|
+
async sign(authContext, wallet, signParams) {
|
|
19
|
+
const signingProvider = wallet.signingProviderId;
|
|
20
|
+
const driver = this.signingDrivers[signingProvider]?.controller(authContext.userId);
|
|
21
|
+
if (!driver) {
|
|
22
|
+
throw new Error(`No driver found for ${signingProvider}`);
|
|
23
|
+
}
|
|
24
|
+
switch (signingProvider) {
|
|
25
|
+
case SigningProvider.PARTICIPANT: {
|
|
26
|
+
return this.signWithParticipant(wallet);
|
|
27
|
+
}
|
|
28
|
+
case SigningProvider.WALLET_KERNEL: {
|
|
29
|
+
return this.signWithWalletKernel(authContext.userId, wallet, signParams);
|
|
30
|
+
}
|
|
31
|
+
case SigningProvider.BLOCKDAEMON: {
|
|
32
|
+
if (!authContext.email) {
|
|
33
|
+
throw new Error('Email is required for Blockdaemon wallet allocation');
|
|
34
|
+
}
|
|
35
|
+
return this.signWithBlockdaemon(authContext.email, wallet, signParams);
|
|
36
|
+
}
|
|
37
|
+
case SigningProvider.FIREBLOCKS: {
|
|
38
|
+
return this.signWithFireblocks(authContext.userId, wallet, signParams);
|
|
39
|
+
}
|
|
40
|
+
case SigningProvider.DFNS: {
|
|
41
|
+
return this.signWithDfns(authContext.userId, wallet, signParams);
|
|
42
|
+
}
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`Unsupported signing provider: ${wallet.signingProviderId}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
execute(userId, wallet, transaction, executeParams, ledgerClient, network) {
|
|
48
|
+
switch (wallet.signingProviderId) {
|
|
49
|
+
case SigningProvider.PARTICIPANT: {
|
|
50
|
+
try {
|
|
51
|
+
if (!executeParams) {
|
|
52
|
+
throw new Error('Execute params are required for participant signing');
|
|
53
|
+
}
|
|
54
|
+
if (!ledgerClient) {
|
|
55
|
+
throw new Error('Ledger client is required for participant signing');
|
|
56
|
+
}
|
|
57
|
+
if (!network) {
|
|
58
|
+
throw new Error('Network is required for participant signing');
|
|
59
|
+
}
|
|
60
|
+
return this.executeWithParticipant(userId, executeParams, transaction, ledgerClient, network);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.logger.error(error, 'Failed to submit transaction');
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
case SigningProvider.WALLET_KERNEL:
|
|
68
|
+
case SigningProvider.BLOCKDAEMON:
|
|
69
|
+
case SigningProvider.FIREBLOCKS: {
|
|
70
|
+
if (!executeParams) {
|
|
71
|
+
throw new Error('Execute params are required for external signing');
|
|
72
|
+
}
|
|
73
|
+
if (!ledgerClient) {
|
|
74
|
+
throw new Error('Ledger client is required for external signing');
|
|
75
|
+
}
|
|
76
|
+
return this.executeWithExternal(userId, executeParams, transaction, ledgerClient);
|
|
77
|
+
}
|
|
78
|
+
case SigningProvider.DFNS: {
|
|
79
|
+
return this.executeWithDfns(transaction);
|
|
80
|
+
}
|
|
81
|
+
default:
|
|
82
|
+
throw new Error(`Unsupported signing provider: ${wallet.signingProviderId}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
18
85
|
async loadPreparedTransactionForSigning(transactionId) {
|
|
19
86
|
const existingTx = await this.store.getTransaction(transactionId);
|
|
20
87
|
if (!existingTx) {
|
|
@@ -79,7 +146,7 @@ export class TransactionService {
|
|
|
79
146
|
const driver = signingProvider.controller(userId);
|
|
80
147
|
const tx = await this.loadPreparedTransactionForSigning(signParams.transactionId);
|
|
81
148
|
let signingResult;
|
|
82
|
-
if (tx
|
|
149
|
+
if (tx.externalTxId) {
|
|
83
150
|
signingResult = await driver
|
|
84
151
|
.getTransaction({
|
|
85
152
|
userId,
|
|
@@ -104,6 +171,10 @@ export class TransactionService {
|
|
|
104
171
|
.then(handleSigningError);
|
|
105
172
|
}
|
|
106
173
|
const now = new Date();
|
|
174
|
+
logDynamically(this.logger, 'Blockdaemon signing result', {
|
|
175
|
+
info: { transactionId: tx.id, status: signingResult.status },
|
|
176
|
+
debug: { signingResult, tx },
|
|
177
|
+
});
|
|
107
178
|
if (signingResult.status === 'signed') {
|
|
108
179
|
if (!signingResult.signature) {
|
|
109
180
|
throw new Error('No signature returned from signing driver');
|
|
@@ -164,7 +235,7 @@ export class TransactionService {
|
|
|
164
235
|
const driver = signingProvider.controller(userId);
|
|
165
236
|
const tx = await this.loadPreparedTransactionForSigning(signParams.transactionId);
|
|
166
237
|
let signingResult;
|
|
167
|
-
if (tx
|
|
238
|
+
if (tx.externalTxId) {
|
|
168
239
|
signingResult = await driver
|
|
169
240
|
.getTransaction({
|
|
170
241
|
userId,
|
|
@@ -185,6 +256,10 @@ export class TransactionService {
|
|
|
185
256
|
.then(handleSigningError);
|
|
186
257
|
}
|
|
187
258
|
const now = new Date();
|
|
259
|
+
logDynamically(this.logger, 'Fireblocks signing result', {
|
|
260
|
+
info: { transactionId: tx.id, status: signingResult.status },
|
|
261
|
+
debug: { signingResult, tx },
|
|
262
|
+
});
|
|
188
263
|
if (signingResult.status === 'signed') {
|
|
189
264
|
if (!signingResult.signature) {
|
|
190
265
|
throw new Error('No signature returned from signing driver');
|
|
@@ -273,6 +348,10 @@ export class TransactionService {
|
|
|
273
348
|
.then(handleSigningError);
|
|
274
349
|
}
|
|
275
350
|
const now = new Date();
|
|
351
|
+
logDynamically(this.logger, 'Dfns signing result', {
|
|
352
|
+
info: { transactionId: tx.id, status: signingResult.status },
|
|
353
|
+
debug: { signingResult, tx },
|
|
354
|
+
});
|
|
276
355
|
if (signingResult.status === 'signed') {
|
|
277
356
|
if (!signingResult.signature) {
|
|
278
357
|
throw new Error('No updateId returned from Dfns');
|
|
@@ -359,15 +438,19 @@ export class TransactionService {
|
|
|
359
438
|
const { partyId } = executeParams;
|
|
360
439
|
const { commandId } = transaction;
|
|
361
440
|
const synchronizerId = network.synchronizerId ?? (await ledgerClient.getSynchronizerId());
|
|
362
|
-
const prep = ledgerPrepareParams(userId, partyId, synchronizerId, transaction.payload);
|
|
363
|
-
const
|
|
441
|
+
const prep = ledgerPrepareParams(userId, [partyId], synchronizerId, transaction.payload);
|
|
442
|
+
const result = await ledgerClient.postWithRetry('/v2/commands/submit-and-wait', prep);
|
|
443
|
+
logDynamically(this.logger, 'Participant execution result', {
|
|
444
|
+
info: { transactionId: transaction.id },
|
|
445
|
+
debug: { result, transaction, executeParams, userId },
|
|
446
|
+
});
|
|
364
447
|
const executedTx = {
|
|
365
448
|
id: transaction.id,
|
|
366
449
|
commandId,
|
|
367
450
|
status: 'executed',
|
|
368
451
|
preparedTransaction: transaction.preparedTransaction,
|
|
369
452
|
preparedTransactionHash: transaction.preparedTransactionHash,
|
|
370
|
-
payload:
|
|
453
|
+
payload: result,
|
|
371
454
|
origin: transaction.origin ?? null,
|
|
372
455
|
...(transaction.createdAt && {
|
|
373
456
|
createdAt: transaction.createdAt,
|
|
@@ -377,10 +460,10 @@ export class TransactionService {
|
|
|
377
460
|
}),
|
|
378
461
|
};
|
|
379
462
|
await this.store.setTransactionStatus(transaction.id, 'executed', {
|
|
380
|
-
payload:
|
|
463
|
+
payload: result,
|
|
381
464
|
});
|
|
382
465
|
this.notifier.emit('txChanged', executedTx);
|
|
383
|
-
return
|
|
466
|
+
return result;
|
|
384
467
|
}
|
|
385
468
|
async executeWithExternal(userId, executeParams, transaction, ledgerClient) {
|
|
386
469
|
const { partyId, signature, signedBy } = executeParams;
|
|
@@ -409,6 +492,10 @@ export class TransactionService {
|
|
|
409
492
|
],
|
|
410
493
|
},
|
|
411
494
|
});
|
|
495
|
+
logDynamically(this.logger, 'Externally signed execution result', {
|
|
496
|
+
info: { transactionId: transaction.id },
|
|
497
|
+
debug: { result, transaction, executeParams, userId },
|
|
498
|
+
});
|
|
412
499
|
const executedTx = {
|
|
413
500
|
id: transaction.id,
|
|
414
501
|
commandId,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction-service.test.d.ts","sourceRoot":"","sources":["../../src/ledger/transaction-service.test.ts"],"names":[],"mappings":""}
|