Skip to content

feat: allow to alter signing provider for wallets - #2333

Open
mateuszpiatkowski-da wants to merge 16 commits into
mainfrom
mateuszpiatkowski-da/allow-to-alter-signing-provider-for-wallets
Open

feat: allow to alter signing provider for wallets#2333
mateuszpiatkowski-da wants to merge 16 commits into
mainfrom
mateuszpiatkowski-da/allow-to-alter-signing-provider-for-wallets

Conversation

@mateuszpiatkowski-da

@mateuszpiatkowski-da mateuszpiatkowski-da commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

.

…dd `changeSigningProvider` endpoint

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
…form

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
…it wallet form

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
@mateuszpiatkowski-da mateuszpiatkowski-da self-assigned this Aug 20, 2026
@mateuszpiatkowski-da mateuszpiatkowski-da linked an issue Aug 20, 2026 that may be closed by this pull request
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
@mateuszpiatkowski-da
mateuszpiatkowski-da marked this pull request as ready for review August 21, 2026 14:10
@mateuszpiatkowski-da
mateuszpiatkowski-da requested a review from a team as a code owner August 21, 2026 14:10
…allow-to-alter-signing-provider-for-wallets

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>

@mjuchli-da mjuchli-da left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You nailed it conceptually! Left a few tweaks

{
"name": "listSigningProviderVaults",
"description": "Lists available vaults of a signing provider",
"name": "listSigningProviderKeys",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does that replace listSigningProviderVaults instead of it being an addition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK this method returns a set of keys assigned to a signing provider. "Vaults" is a reserved keyword for Fireblocks, but it doesn't make sense to keep this naming convention when extending the functionality to other SP, hence the change in naming :)

}
},
{
"name": "changeSigningProvider",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use a more generalized updateWallet for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little reluctant about this - updateWallet would suggest the ability to edit any/all properties of a specified wallet, whereas here we're only interested in updating the portion of the data associated with the SP. If you want I could create a generic method called like that and enable the user to update any property and use it to update the SP data where required

Comment thread core/wallet-store-inmemory/src/store-internal.ts Outdated
'/api-keys/add',
'/api-keys',
'/login',
'/parties/edit',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a follow-up but I suggest changing routes that involve /parties with /wallets

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't this change Wallets -> Parties in what is visible in UI a product decision?

Comment thread mock-oauth2/src/index.ts
protected signingDriver: SigningDriverInterface
) {}

private handleSigningError<T extends object>(result: SigningError | T): T {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is misleading. I initially thought it's related to signing, but it's related to a signing driver api call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the method is repetitive; perhaps something to extract to a central location

return this.store.updateWallet(walletUpdate)
}

async getVaults(userId: UserId): Promise<{ vaults: string[] }> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I start to understand that vaults and keys are the same here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus vaults listing was redundant; correct me if i'm wrong

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, Fireblocks vaults are equal to keys. Fireblocks had it earlier, because unlike other drivers it doesn't allow creating keys, you have to select pre-existing vault when creating a party.

protected signingDriver: SigningDriverInterface
) {}

private handleSigningError<T extends object>(result: SigningError | T): T {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate

protected signingDriver: SigningDriverInterface
) {}

private handleSigningError<T extends object>(result: SigningError | T): T {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate

protected signingDriver: SigningDriverInterface
) {}

private handleSigningError<T extends object>(result: SigningError | T): T {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate

signingProviderId:
resolvedSigningProvider.signingProviderId,
disabled: !isMatched,
userId: '',

@pawelstepien-da pawelstepien-da Aug 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why empty userId? You can get current user ID by this.authContext.userId, but store.addWallet doesn't need it anyway, because it also extracts userId from authContext.

Comment thread core/wallet-store-sql/src/store-sql.ts Outdated
})
}

async getWallet(constraint: WalletUniqueConstraint) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about manually passing userId to store. Other methods take userId from authContext (assertConnected). User Alice shouldn't be able to get Wallet that belongs to Bob and it's good to have this constraint on store level. Unless you need to be able to get Wallet of any user from some service, I would adhere to convention that store gets userId from authContext, not from a param.

Comment thread api-specs/openrpc-user-api.json Outdated
"additionalProperties": false,
"properties": {
"userId": {
"title": "userId",

@pawelstepien-da pawelstepien-da Aug 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows a user to log in as user Bob to Network1 and get Wallet of user Alice for Network2. Even if UI constrains it, one could execute a request manually.

changeSigningProvider: async (
params: ChangeSigningProviderParams
): Promise<null> => {
const { signingProviderId, partyId, publicKey } = params

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we should trust that request payload contains singingProviderId that exists and a publicKey that belongs to that signing provider. Perhaps we should try to do listSigningProviderKeys (or extract a subset of that method this one) and compare request params against result before changing wallet record?

Comment on lines +1221 to +1228
const keys = await walletAllocationService.getKeys(
assertConnected(authContext),
params.signingProviderId as SigningProvider
)
if (
!drivers[params.signingProviderId as SigningProvider] ||
!keys
) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would switch order - first check that driver is registered, act on it (getKeys) afterwards.

.publicKeys=${this.publicKeys}
.selectedSigningProvider=${this.selectedSigningProvider}
.partyId=${this.walletConstraint.partyId}
.selectedPublicKeyId=${this.selectedPublicKey}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that work? Inside edit-form we compare wallet.publicKey against key.id. I assumed those are not (or not always) equal.

Comment thread wallet-gateway/remote/src/web/frontend/parties/index.ts
): Promise<void> {
// For dApp-triggered approvals the popup is opened with
// `closeafteraction`, so success is signalled by the popup closing.
// dApp-triggered approvals often close the popup, but newer flows can

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I preferred previous comment.
It's not like it happens "often" or "rarely", nor there are "newer" and "older" flows. It is deterministic based on whether approve screen is triggereed via dapp-sdk, or by going to WG transaction list, you will get query param closeafteraction or not.

.getByRole('button', { name: 'Create' })
.click()
const submitButton = (await this.page()).getByRole('button', {
name: /^(Add|Create)$/,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is more than one button text?


private _onWalletEdit(e: WalletCardEditEvent) {
setLocationHref(
`/parties/edit?partyId=${e.wallet.partyId}&networkId=${e.wallet.networkId}&userId=${e.wallet.userId}`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use toRelPath also here? It could work on with dev but fail with build without that.

try {
await this.userClient.request({
method: 'changeSigningProvider',
params: event,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't pass DOM Event directly to API, better extract specific properties from it.

if (network === undefined) {
throw new Error('No network session found')
}
if (!network.adminAuth) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't really need adminAuth, but I understand that we need it for PartyAllocationService constructor, even tho we only need it to create a fingerprint which doesn't require adminAuth.
I created a separate tech debt issue to address those unnecessary adminAuth dependencies #2360

return this.securosysAllocator
case SigningProvider.WALLET_KERNEL:
return this.kernelAllocator
case SigningProvider.PARTICIPANT:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have BitGo driver merged, you will need to sync your branch with main and add case for it here and make sure getKeys is available in it's allocator.

pawelstepien-da and others added 3 commits August 26, 2026 16:14
Signed-off-by: Pawel Stepien <pawel.stepien@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow to alter Signing Provider for Wallets

3 participants