diff --git a/core/signing-blockdaemon/src/index.ts b/core/signing-blockdaemon/src/index.ts index 346a35bf7..37f9590cb 100644 --- a/core/signing-blockdaemon/src/index.ts +++ b/core/signing-blockdaemon/src/index.ts @@ -47,7 +47,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface public partyMode = PartyMode.EXTERNAL public signingProvider = SigningProvider.BLOCKDAEMON - public controller = (userId: AuthContext['userId'] | undefined) => + public controller = (authContext: AuthContext | undefined) => buildController({ signTransaction: async ( params: SignTransactionParams @@ -67,7 +67,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface ...(params.internalTxId !== undefined && { internalTxId: params.internalTxId, }), - userIdentifier: userId, + userIdentifier: authContext?.email, }) return { txId: tx.txId, @@ -135,7 +135,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface const transactions = await this.client.getTransactions({ txIds: params.txIds!, publicKeys: params.publicKeys!, - userIdentifier: userId, + userIdentifier: authContext?.email, }) return { transactions: transactions.map((tx) => ({ @@ -175,7 +175,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface id: k.id, name: k.name, publicKey: k.publicKey, - userIdentifier: userId, + userIdentifier: authContext?.email, })), } } catch (error) { @@ -192,7 +192,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface try { const key = await this.client.createKey({ name: params.name, - userIdentifier: userId, + userIdentifier: authContext?.email, }) return { id: key.id, diff --git a/core/signing-dfns/src/index.ts b/core/signing-dfns/src/index.ts index 934291e2e..afc40b108 100644 --- a/core/signing-dfns/src/index.ts +++ b/core/signing-dfns/src/index.ts @@ -90,7 +90,7 @@ export default class DfnsSigningDriver implements SigningDriverInterface { public controller = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars - _userId: AuthContext['userId'] | undefined + authContext: AuthContext | undefined ) => buildController({ signTransaction: async ( diff --git a/core/signing-fireblocks/src/index.ts b/core/signing-fireblocks/src/index.ts index 666775776..fe4ea30d3 100644 --- a/core/signing-fireblocks/src/index.ts +++ b/core/signing-fireblocks/src/index.ts @@ -75,7 +75,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface { } public partyMode = PartyMode.EXTERNAL public signingProvider = SigningProvider.FIREBLOCKS - public controller = (userId: AuthContext['userId'] | undefined) => + public controller = (authContext: AuthContext | undefined) => buildController({ signTransaction: async ( params: SignTransactionParams @@ -84,7 +84,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface { try { const tx = await this.fireblocks.signTransaction( - userId, + authContext?.userId, params.txHash, params.keyIdentifier, params.internalTxId @@ -117,7 +117,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface { params: GetTransactionParams ): Promise => { const tx = await this.fireblocks.getTransaction( - userId, + authContext?.userId, params.txId ) if (tx) { @@ -144,7 +144,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface { const txIds = new Set(params.txIds) const publicKeys = new Set(params.publicKeys) for await (const tx of this.fireblocks.getTransactions( - userId + authContext?.userId )) { if ( txIds.has(tx.txId) || @@ -180,7 +180,9 @@ export default class FireblocksSigningDriver implements SigningDriverInterface { getKeys: async (): Promise => { try { - const keys = await this.fireblocks.getPublicKeys(userId) + const keys = await this.fireblocks.getPublicKeys( + authContext?.userId + ) return { keys: keys.map((k) => ({ id: k.derivationPath.join('-'), diff --git a/core/signing-internal/src/controller.ts b/core/signing-internal/src/controller.ts index cc4648149..aa90a99d0 100644 --- a/core/signing-internal/src/controller.ts +++ b/core/signing-internal/src/controller.ts @@ -36,7 +36,7 @@ import { SignMessageResult, } from '@canton-network/core-signing-lib' import { randomUUID } from 'node:crypto' -import { AuthContext } from '@canton-network/core-wallet-auth' +import { AuthAware, AuthContext } from '@canton-network/core-wallet-auth' interface InternalKey { id: string @@ -62,17 +62,18 @@ const convertInternalTransaction = (tx: InternalTransaction): Transaction => { } export class InternalSigningDriver implements SigningDriverInterface { - private store: SigningDriverStore - + private store: SigningDriverStore & AuthAware public partyMode = PartyMode.EXTERNAL public signingProvider = SigningProvider.WALLET_KERNEL - constructor(store: SigningDriverStore) { + constructor(store: SigningDriverStore & AuthAware) { this.store = store } - public controller = (_userId: AuthContext['userId'] | undefined) => - buildController({ + public controller = (authContext: AuthContext | undefined) => { + const scopedStore = this.store.withAuthContext(authContext) + const _userId = authContext?.userId + return buildController({ signTransaction: async ( params: SignTransactionParams ): Promise => { @@ -86,7 +87,7 @@ export class InternalSigningDriver implements SigningDriverInterface { }) } - const key = await this.store.getSigningKeyByPublicKey( + const key = await scopedStore.getSigningKeyByPublicKey( params.keyIdentifier.publicKey ) @@ -109,7 +110,7 @@ export class InternalSigningDriver implements SigningDriverInterface { signedAt: now, } - this.store.setSigningTransaction( + scopedStore.setSigningTransaction( _userId, internalTransaction ) @@ -146,7 +147,7 @@ export class InternalSigningDriver implements SigningDriverInterface { }) } - const key = await this.store.getSigningKeyByPublicKey( + const key = await scopedStore.getSigningKeyByPublicKey( params.keyIdentifier.publicKey ) if (!key?.privateKey) { @@ -172,7 +173,7 @@ export class InternalSigningDriver implements SigningDriverInterface { }) } - const storedTx = await this.store.getSigningTransaction( + const storedTx = await scopedStore.getSigningTransaction( _userId, params.txId ) @@ -204,7 +205,7 @@ export class InternalSigningDriver implements SigningDriverInterface { if (params.publicKeys || params.txIds) { const transactions = - await this.store.listSigningTransactionsByTxIdsAndPublicKeys( + await scopedStore.listSigningTransactionsByTxIdsAndPublicKeys( params.txIds || [], params.publicKeys || [] ) @@ -237,7 +238,7 @@ export class InternalSigningDriver implements SigningDriverInterface { }) } - const keys = await this.store.listSigningKeys(_userId) + const keys = await scopedStore.listSigningKeys(_userId) if (keys.length > 0) { return Promise.resolve({ keys: Array.from(keys).map((key) => ({ @@ -276,7 +277,7 @@ export class InternalSigningDriver implements SigningDriverInterface { updatedAt: now, } - await this.store.setSigningKey(_userId, internalKey) + await scopedStore.setSigningKey(_userId, internalKey) return { id, @@ -299,4 +300,5 @@ export class InternalSigningDriver implements SigningDriverInterface { ): Promise => Promise.resolve({} as SubscribeTransactionsResult), }) + } } diff --git a/core/signing-lib/src/index.ts b/core/signing-lib/src/index.ts index c8ee9a6df..9d6a61c15 100644 --- a/core/signing-lib/src/index.ts +++ b/core/signing-lib/src/index.ts @@ -38,7 +38,7 @@ export interface KeyPair { export interface SigningDriverInterface { partyMode: PartyMode signingProvider: SigningProvider - controller: (userId: AuthContext['userId'] | undefined) => Methods + controller: (authContext: AuthContext | undefined) => Methods } export const verifySignedTxHash = ( diff --git a/core/signing-participant/src/controller.ts b/core/signing-participant/src/controller.ts index 07eeebe27..8f1bf0a21 100644 --- a/core/signing-participant/src/controller.ts +++ b/core/signing-participant/src/controller.ts @@ -25,7 +25,7 @@ export class ParticipantSigningDriver implements SigningDriverInterface { public signingProvider = SigningProvider.PARTICIPANT public controller = ( - _userId: AuthContext['userId'] | undefined // eslint-disable-line @typescript-eslint/no-unused-vars + authContext: AuthContext | undefined // eslint-disable-line @typescript-eslint/no-unused-vars ) => buildController({ signTransaction: async ( diff --git a/core/signing-store-sql/src/store-sql.test.ts b/core/signing-store-sql/src/store-sql.test.ts new file mode 100644 index 000000000..7b87f43ea --- /dev/null +++ b/core/signing-store-sql/src/store-sql.test.ts @@ -0,0 +1,107 @@ +// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, test, beforeEach } from 'vitest' +import { AuthContext } from '@canton-network/core-wallet-auth' +import { Kysely } from 'kysely' +import { pino } from 'pino' +import { migrator } from './migrator.js' +import { DB } from './schema.js' +import { connection, StoreSql } from './store-sql.js' + +const userA: AuthContext = { + userId: 'user-a', + accessToken: 'token-a', +} + +const userB: AuthContext = { + userId: 'user-b', + accessToken: 'token-b', +} + +describe('StoreSql auth scoping', () => { + let db: Kysely + + beforeEach(async () => { + db = connection({ connection: { type: 'memory' } }) + const umzug = migrator(db) + await umzug.up() + }) + + test('returns empty for getSigningKeyByPublicKey owned by another user', async () => { + const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' })) + await storeWithoutAuth.setSigningKey(userB.userId, { + id: 'key-b', + name: 'key-b', + publicKey: 'user-b-public-key', + privateKey: 'private-key-b', + createdAt: new Date(), + updatedAt: new Date(), + }) + + const scopedStore = storeWithoutAuth.withAuthContext(userA) + const key = + await scopedStore.getSigningKeyByPublicKey('user-b-public-key') + + expect(key).toBeUndefined() + }) + + test('scopes getSigningKeyByPublicKey to authContext user', async () => { + const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' })) + await storeWithoutAuth.setSigningKey(userA.userId, { + id: 'key-a', + name: 'key-a', + publicKey: 'shared-public-key', + privateKey: 'private-key-a', + createdAt: new Date(), + updatedAt: new Date(), + }) + await storeWithoutAuth.setSigningKey(userB.userId, { + id: 'key-b', + name: 'key-b', + publicKey: 'shared-public-key', + privateKey: 'private-key-b', + createdAt: new Date(), + updatedAt: new Date(), + }) + + const scopedStore = storeWithoutAuth.withAuthContext(userA) + const key = + await scopedStore.getSigningKeyByPublicKey('shared-public-key') + + expect(key?.id).toBe('key-a') + expect(key?.privateKey).toBe('private-key-a') + }) + + test('scopes listSigningTransactionsByTxIdsAndPublicKeys to authContext user', async () => { + const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' })) + const now = new Date() + + await storeWithoutAuth.setSigningTransaction(userA.userId, { + id: 'tx-a', + hash: 'hash-a', + publicKey: 'public-key-a', + status: 'signed', + createdAt: now, + updatedAt: now, + }) + await storeWithoutAuth.setSigningTransaction(userB.userId, { + id: 'tx-b', + hash: 'hash-b', + publicKey: 'public-key-b', + status: 'signed', + createdAt: now, + updatedAt: now, + }) + + const scopedStore = storeWithoutAuth.withAuthContext(userA) + const transactions = + await scopedStore.listSigningTransactionsByTxIdsAndPublicKeys( + ['tx-a', 'tx-b'], + [] + ) + + expect(transactions).toHaveLength(1) + expect(transactions[0]?.id).toBe('tx-a') + }) +}) diff --git a/core/signing-store-sql/src/store-sql.ts b/core/signing-store-sql/src/store-sql.ts index 18141865b..101b851a6 100644 --- a/core/signing-store-sql/src/store-sql.ts +++ b/core/signing-store-sql/src/store-sql.ts @@ -78,6 +78,7 @@ export class StoreSql implements SigningDriverStore, AuthAware { .selectFrom('signingKeys') .selectAll() .where('publicKey', '=', publicKey) + .where('userId', '=', this.assertConnected()) .executeTakeFirst() return result ? toSigningKey(result) : undefined } @@ -240,6 +241,7 @@ export class StoreSql implements SigningDriverStore, AuthAware { eb('id', 'in', txIds), ]) ) + .where('userId', '=', this.assertConnected()) .execute() return results.map(toSigningTransaction) diff --git a/wallet-gateway/remote/src/ledger/party-allocation-service.ts b/wallet-gateway/remote/src/ledger/party-allocation-service.ts index 61487232d..4e549e115 100644 --- a/wallet-gateway/remote/src/ledger/party-allocation-service.ts +++ b/wallet-gateway/remote/src/ledger/party-allocation-service.ts @@ -6,7 +6,7 @@ import { LedgerClient, } from '@canton-network/core-ledger-client' import { createHash } from 'node:crypto' -import { AccessTokenProvider } from '@canton-network/core-wallet-auth' +import { AccessTokenProvider, UserId } from '@canton-network/core-wallet-auth' import { Logger } from 'pino' export type AllocatedParty = { @@ -165,14 +165,14 @@ export class PartyAllocationService { namespace: string, transactions: string[], signature: string, - userId: string + userId: UserId ): Promise async allocatePartyWithExistingWallet( namespace: string, transactions: string[], signature: string, - userId: string + userId: UserId ): Promise { const synchronizerId = this.synchronizerId ?? (await this.ledgerClient.getSynchronizerId()) diff --git a/wallet-gateway/remote/src/ledger/transaction-service.ts b/wallet-gateway/remote/src/ledger/transaction-service.ts index 041f99c45..ae2a19268 100644 --- a/wallet-gateway/remote/src/ledger/transaction-service.ts +++ b/wallet-gateway/remote/src/ledger/transaction-service.ts @@ -51,9 +51,8 @@ export class TransactionService { signParams: SignParams ): Promise { const signingProvider = wallet.signingProviderId as SigningProvider - const driver = this.signingDrivers[signingProvider]?.controller( - authContext.userId - ) + const driver = + this.signingDrivers[signingProvider]?.controller(authContext) if (!driver) { throw new Error(`No driver found for ${signingProvider}`) } @@ -64,7 +63,7 @@ export class TransactionService { } case SigningProvider.WALLET_KERNEL: { return this.signWithWalletKernel( - authContext.userId, + authContext, wallet, signParams ) @@ -75,21 +74,13 @@ export class TransactionService { 'Email is required for Blockdaemon wallet allocation' ) } - return this.signWithBlockdaemon( - authContext.email, - wallet, - signParams - ) + return this.signWithBlockdaemon(authContext, wallet, signParams) } case SigningProvider.FIREBLOCKS: { - return this.signWithFireblocks( - authContext.userId, - wallet, - signParams - ) + return this.signWithFireblocks(authContext, wallet, signParams) } case SigningProvider.DFNS: { - return this.signWithDfns(authContext.userId, wallet, signParams) + return this.signWithDfns(authContext, wallet, signParams) } default: throw new Error( @@ -186,8 +177,8 @@ export class TransactionService { } } - private async signWithWalletKernel( - userId: UserId, + public async signWithWalletKernel( + authContext: AuthContext, wallet: Wallet, signParams: SignParams ): Promise { @@ -196,7 +187,7 @@ export class TransactionService { if (!signingProvider) { throw new Error('Wallet Gateway signing driver not available') } - const driver = signingProvider.controller(userId) + const driver = signingProvider.controller(authContext) const tx = await this.loadPreparedTransactionForSigning( signParams.transactionId @@ -243,8 +234,8 @@ export class TransactionService { } } - private async signWithBlockdaemon( - userId: UserId, + public async signWithBlockdaemon( + authContext: AuthContext, wallet: Wallet, signParams: SignParams ): Promise { @@ -252,7 +243,7 @@ export class TransactionService { if (!signingProvider) { throw new Error('Blockdaemon signing driver not available') } - const driver = signingProvider.controller(userId) + const driver = signingProvider.controller(authContext) const tx = await this.loadPreparedTransactionForSigning( signParams.transactionId @@ -265,7 +256,7 @@ export class TransactionService { if (tx && tx.externalTxId) { signingResult = await driver .getTransaction({ - userId, + userId: authContext.userId, txId: tx.externalTxId, }) .then(handleSigningError) @@ -351,8 +342,8 @@ export class TransactionService { } } - private async signWithFireblocks( - userId: UserId, + public async signWithFireblocks( + authContext: AuthContext, wallet: Wallet, signParams: SignParams ): Promise { @@ -360,7 +351,7 @@ export class TransactionService { if (!signingProvider) { throw new Error('Fireblocks signing driver not available') } - const driver = signingProvider.controller(userId) + const driver = signingProvider.controller(authContext) const tx = await this.loadPreparedTransactionForSigning( signParams.transactionId @@ -373,14 +364,14 @@ export class TransactionService { if (tx && tx.externalTxId) { signingResult = await driver .getTransaction({ - userId, + userId: authContext.userId, txId: tx.externalTxId, }) .then(handleSigningError) } else { signingResult = await driver .signTransaction({ - userId, + userId: authContext.userId, tx: tx.preparedTransaction, txHash: Buffer.from( tx.preparedTransactionHash, @@ -469,8 +460,8 @@ export class TransactionService { * signature payload (the controller short-circuits Dfns execute) and surface * the same SignResult shape the other external providers use. */ - private async signWithDfns( - userId: UserId, + public async signWithDfns( + authContext: AuthContext, wallet: Wallet, signParams: SignParams ): Promise { @@ -478,7 +469,7 @@ export class TransactionService { if (!signingProvider) { throw new Error('Dfns signing driver not available') } - const driver = signingProvider.controller(userId) + const driver = signingProvider.controller(authContext) const tx = await this.loadPreparedTransactionForSigning( signParams.transactionId @@ -491,7 +482,7 @@ export class TransactionService { if (tx.externalTxId) { signingResult = await driver .getTransaction({ - userId, + userId: authContext.userId, txId: tx.externalTxId, }) .then(handleSigningError) diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts index a8939da37..bac8f7f2e 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/blockdaemon-wallet-allocator.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { UserId } from '@canton-network/core-wallet-auth' +import { AuthContext } from '@canton-network/core-wallet-auth' import { Store, UpdateWallet, Wallet } from '@canton-network/core-wallet-store' import { Error as SigningError, @@ -32,12 +32,11 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { ) {} async createWallet( - userId: UserId, - email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary = false ): Promise { - const driver = this.signingDriver.controller(email) + const driver = this.signingDriver.controller(authContext) const key = await driver.createKey({ name: partyHint, @@ -96,7 +95,7 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { if (status === 'signed') { const { signature } = await driver .getTransaction({ - userId, + userId: authContext.userId, txId, }) .then(handleSigningError) @@ -110,7 +109,7 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { namespace, topologyTransactions, signature, - userId + authContext.userId ) wallet = { ...walletBase, @@ -141,8 +140,7 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { } async allocateParty( - userId: UserId, - email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise { if ( @@ -153,7 +151,7 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { 'Existing wallet is missing field externalTxId or topologyTransactions' ) } - const driver = this.signingDriver.controller(email) + const driver = this.signingDriver.controller(authContext) const { signature, status, metadata } = await driver .getTransaction({ @@ -176,7 +174,7 @@ export class BlockdaemonWalletAllocator implements WalletAllocator { existingWallet.namespace, existingWallet.topologyTransactions.split(', '), signature, - userId + authContext.userId ) walletUpdate = { ...walletUpdate, diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/dfns-wallet-allocator.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/dfns-wallet-allocator.ts index 06d89c5cc..154b7b4aa 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/dfns-wallet-allocator.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/dfns-wallet-allocator.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { UserId } from '@canton-network/core-wallet-auth' +import { AuthContext, UserId } from '@canton-network/core-wallet-auth' import { Store, UpdateWallet, Wallet } from '@canton-network/core-wallet-store' import { Error as SigningError, @@ -37,12 +37,11 @@ export class DfnsWalletAllocator implements WalletAllocator { ) {} async createWallet( - userId: UserId, - _email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary = false ): Promise { - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const key = await driver .createKey({ name: partyHint }) @@ -89,7 +88,7 @@ export class DfnsWalletAllocator implements WalletAllocator { const wallet = await this.finalizeWallet( walletBase, - userId, + authContext.userId, status, txId, topologyTransactions, @@ -102,8 +101,7 @@ export class DfnsWalletAllocator implements WalletAllocator { } async allocateParty( - userId: UserId, - _email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise { if ( @@ -114,7 +112,7 @@ export class DfnsWalletAllocator implements WalletAllocator { 'Existing wallet is missing field externalTxId or topologyTransactions' ) } - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const { signature, status, metadata } = await driver .getTransaction({ txId: existingWallet.externalTxId }) @@ -135,7 +133,7 @@ export class DfnsWalletAllocator implements WalletAllocator { existingWallet.namespace, existingWallet.topologyTransactions.split(', '), signature, - userId + authContext.userId ) walletUpdate = { ...walletUpdate, diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.ts index 14f671181..ec6071a0e 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { UserId } from '@canton-network/core-wallet-auth' +import { AuthContext } from '@canton-network/core-wallet-auth' import { Store, UpdateWallet, Wallet } from '@canton-network/core-wallet-store' import { Error as SigningError, @@ -32,12 +32,11 @@ export class FireblocksWalletAllocator implements WalletAllocator { ) {} async createWallet( - userId: UserId, - email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary = false ): Promise { - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const keys = await driver.getKeys().then(handleSigningError) const key = keys?.keys?.find((k) => k.name === 'Canton Party') @@ -85,7 +84,7 @@ export class FireblocksWalletAllocator implements WalletAllocator { if (status === 'signed') { const { signature } = await driver .getTransaction({ - userId, + userId: authContext.userId, txId, }) .then(handleSigningError) @@ -99,7 +98,7 @@ export class FireblocksWalletAllocator implements WalletAllocator { namespace, topologyTransactions, Buffer.from(signature, 'hex').toString('base64'), - userId + authContext.userId ) wallet = { ...walletBase, @@ -130,8 +129,7 @@ export class FireblocksWalletAllocator implements WalletAllocator { } async allocateParty( - userId: UserId, - email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise { if ( @@ -143,14 +141,14 @@ export class FireblocksWalletAllocator implements WalletAllocator { ) } - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const keys = await driver.getKeys().then(handleSigningError) const key = keys?.keys?.find((k) => k.name === 'Canton Party') if (!key) throw new Error('Fireblocks key not found') const { signature, status } = await driver .getTransaction({ - userId, + userId: authContext.userId, txId: existingWallet.externalTxId, }) .then(handleSigningError) @@ -170,7 +168,7 @@ export class FireblocksWalletAllocator implements WalletAllocator { existingWallet.namespace, existingWallet.topologyTransactions.split(', '), Buffer.from(signature, 'hex').toString('base64'), - userId + authContext.userId ) walletUpdate = { ...walletUpdate, diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/kernel-wallet-allocator.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/kernel-wallet-allocator.ts index 88ac44b5d..9ab2203b0 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/kernel-wallet-allocator.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/kernel-wallet-allocator.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { UserId } from '@canton-network/core-wallet-auth' +import { AuthContext } from '@canton-network/core-wallet-auth' import { Store, UpdateWallet, Wallet } from '@canton-network/core-wallet-store' import { Error as SigningError, @@ -30,12 +30,11 @@ export class KernelWalletAllocator implements WalletAllocator { ) {} async createWallet( - userId: UserId, - email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary = false ): Promise { - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const key = await driver .createKey({ name: partyHint, @@ -43,7 +42,7 @@ export class KernelWalletAllocator implements WalletAllocator { .then(handleSigningError) const party = await this.partyAllocator.allocateParty( - userId, + authContext.userId, partyHint, key.publicKey, async (hash) => { @@ -84,11 +83,10 @@ export class KernelWalletAllocator implements WalletAllocator { } async allocateParty( - userId: UserId, - email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise { - const driver = this.signingDriver.controller(userId) + const driver = this.signingDriver.controller(authContext) const signingCallback = async (hash: string) => { const result = await driver .signTransaction({ @@ -105,7 +103,7 @@ export class KernelWalletAllocator implements WalletAllocator { } const party = await this.partyAllocator.allocateParty( - userId, + authContext.userId, existingWallet.hint, existingWallet.publicKey, signingCallback diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/participant-wallet-allocator.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/participant-wallet-allocator.ts index a623e7378..4518ea48f 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/participant-wallet-allocator.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/signing-providers/participant-wallet-allocator.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { UserId } from '@canton-network/core-wallet-auth' +import { AuthContext } from '@canton-network/core-wallet-auth' import { Store, Wallet } from '@canton-network/core-wallet-store' import { SigningProvider } from '@canton-network/core-signing-lib' import { Logger } from 'pino' @@ -17,12 +17,14 @@ export class ParticipantWalletAllocator implements WalletAllocator { ) {} async createWallet( - userId: UserId, - email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary = false ): Promise { - const party = await this.partyAllocator.allocateParty(userId, partyHint) + const party = await this.partyAllocator.allocateParty( + authContext.userId, + partyHint + ) const network = await this.store.getCurrentNetwork() const wallet: Wallet = { partyId: party.partyId, @@ -42,12 +44,11 @@ export class ParticipantWalletAllocator implements WalletAllocator { } async allocateParty( - userId: UserId, - email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise { const party = await this.partyAllocator.allocateParty( - userId, + authContext.userId, existingWallet.hint ) const network = await this.store.getCurrentNetwork() diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.test.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.test.ts index cc01495fe..ae6d2d692 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.test.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.test.ts @@ -20,6 +20,7 @@ import { SigningProvider } from '@canton-network/core-signing-lib' import type { SigningDriverInterface } from '@canton-network/core-signing-lib' import type { AllocatedParty } from '../party-allocation-service.js' import { WALLET_DISABLED_REASON } from '@canton-network/core-types' +import { AuthContext } from '@canton-network/core-wallet-auth' const createWallet = ( partyId: string, @@ -48,7 +49,7 @@ const createAllocatedParty = ( namespace, }) -const authContext = { +const authContext: AuthContext = { userId: 'user-1', accessToken: 'access-token', email: 'user-1@example.com', @@ -407,7 +408,7 @@ describe('WalletAllocationService', () => { controller: Mock } ).controller - ).toHaveBeenCalledWith(authContext.userId) + ).toHaveBeenCalledWith(authContext) expect(mockController.createKey).toHaveBeenCalledWith({ name: 'bob', }) diff --git a/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.ts b/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.ts index a24ed293d..657d093ce 100644 --- a/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.ts +++ b/wallet-gateway/remote/src/ledger/wallet-allocation/wallet-allocation-service.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { AuthContext, UserId } from '@canton-network/core-wallet-auth' +import { AuthContext } from '@canton-network/core-wallet-auth' import { Store, Wallet } from '@canton-network/core-wallet-store' import { SigningDriverInterface, @@ -18,14 +18,12 @@ import { DfnsWalletAllocator } from './signing-providers/dfns-wallet-allocator.j export interface WalletAllocator { createWallet( - userId: UserId, - email: string | undefined, + authContext: AuthContext, partyHint: PartyHint, primary: Primary ): Promise allocateParty( - userId: UserId, - email: string | undefined, + authContext: AuthContext, existingWallet: Wallet ): Promise } @@ -101,8 +99,7 @@ export class WalletAllocationService { switch (signingProviderId) { case SigningProvider.PARTICIPANT: return this.participantAllocator.createWallet( - authContext.userId, - authContext.email, + authContext, partyHint, primary ) @@ -113,8 +110,7 @@ export class WalletAllocationService { ) } return this.kernelAllocator.createWallet( - authContext.userId, - authContext.email, + authContext, partyHint, primary ) @@ -123,8 +119,7 @@ export class WalletAllocationService { throw new Error('Fireblocks signing driver not available') } return this.fireblocksAllocator.createWallet( - authContext.userId, - authContext.email, + authContext, partyHint, primary ) @@ -138,8 +133,7 @@ export class WalletAllocationService { ) } return this.blockdaemonAllocator.createWallet( - authContext.userId, - authContext.email, + authContext, partyHint, primary ) @@ -148,8 +142,7 @@ export class WalletAllocationService { throw new Error('Dfns signing driver not available') } return this.dfnsAllocator.createWallet( - authContext.userId, - authContext.email, + authContext, partyHint, primary ) @@ -168,8 +161,7 @@ export class WalletAllocationService { switch (signingProviderId) { case SigningProvider.PARTICIPANT: return this.participantAllocator.allocateParty( - authContext.userId, - authContext.email, + authContext, existingWallet ) case SigningProvider.WALLET_KERNEL: @@ -179,8 +171,7 @@ export class WalletAllocationService { ) } return this.kernelAllocator.allocateParty( - authContext.userId, - authContext.email, + authContext, existingWallet ) case SigningProvider.FIREBLOCKS: @@ -188,8 +179,7 @@ export class WalletAllocationService { throw new Error('Fireblocks signing driver not available') } return this.fireblocksAllocator.allocateParty( - authContext.userId, - authContext.email, + authContext, existingWallet ) case SigningProvider.BLOCKDAEMON: @@ -202,8 +192,7 @@ export class WalletAllocationService { ) } return this.blockdaemonAllocator.allocateParty( - authContext.userId, - authContext.email, + authContext, existingWallet ) case SigningProvider.DFNS: @@ -211,8 +200,7 @@ export class WalletAllocationService { throw new Error('Dfns signing driver not available') } return this.dfnsAllocator.allocateParty( - authContext.userId, - authContext.email, + authContext, existingWallet ) default: diff --git a/wallet-gateway/remote/src/ledger/wallet-sync-service.test.ts b/wallet-gateway/remote/src/ledger/wallet-sync-service.test.ts index f4de6658e..b069e72da 100644 --- a/wallet-gateway/remote/src/ledger/wallet-sync-service.test.ts +++ b/wallet-gateway/remote/src/ledger/wallet-sync-service.test.ts @@ -161,7 +161,7 @@ describe('WalletSyncService - resolveSigningProvider', () => { const internalDriver = service['signingDrivers'][ SigningProvider.WALLET_KERNEL ] as InternalSigningDriver - const controller = internalDriver.controller(authContext.userId) + const controller = internalDriver.controller(authContext) const key = await controller.createKey({ name: 'test-key' }) if ('error' in key) { diff --git a/wallet-gateway/remote/src/ledger/wallet-sync-service.ts b/wallet-gateway/remote/src/ledger/wallet-sync-service.ts index 988b57732..b3eec1d46 100644 --- a/wallet-gateway/remote/src/ledger/wallet-sync-service.ts +++ b/wallet-gateway/remote/src/ledger/wallet-sync-service.ts @@ -102,7 +102,6 @@ export class WalletSyncService { } // Get keys from signing providers try to match - const userId = this.authContext?.userId for (const [providerId, driver] of Object.entries( this.signingDrivers )) { @@ -114,7 +113,7 @@ export class WalletSyncService { } try { - const controller = driver.controller(userId) + const controller = driver.controller(this.authContext) const result = await controller.getKeys() // In case of error getKeys resolve Promise but with error object diff --git a/wallet-gateway/remote/src/user-api/controller.ts b/wallet-gateway/remote/src/user-api/controller.ts index 20204de70..4607e4eab 100644 --- a/wallet-gateway/remote/src/user-api/controller.ts +++ b/wallet-gateway/remote/src/user-api/controller.ts @@ -421,9 +421,9 @@ export const userController = ( } const connectedContext = assertConnected(authContext) - const userId = connectedContext.userId - const notifier = notificationService.getNotifier(userId) - + const notifier = notificationService.getNotifier( + connectedContext.userId + ) const transactionService = new TransactionService( store, logger, @@ -494,8 +494,11 @@ export const userController = ( ) } + const connectedContext = assertConnected(authContext) const driver = - drivers[SigningProvider.WALLET_KERNEL]?.controller(userId) + drivers[SigningProvider.WALLET_KERNEL]?.controller( + connectedContext + ) if (!driver) { return await emitFailedAndPersist( 'Wallet Kernel signing driver not available'