Skip to content

Commit 0389e54

Browse files
committed
feat(web-extension): support wallet-specific trezorConfig in SigningCoordinator
- Add optional trezorConfig property to HardwareWallet type - Refactor #getTrezorConfig to merge wallet-specific config with global hwOptions - Update Trezor key agent creation to use merged configuration - Add test for trezorConfig merging behavior - Ensure derivationType and other wallet-specific settings are properly applied
1 parent e96ddb1 commit 0389e54

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

packages/web-extension/src/walletManager/SigningCoordinator/SigningCoordinator.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { AnyBip32Wallet, InMemoryWallet, WalletType } from '../types';
12
import { Cardano, Serialization } from '@cardano-sdk/core';
23
import { Cip30DataSignature } from '@cardano-sdk/dapp-connector';
34
import { CustomError } from 'ts-custom-error';
4-
import { InMemoryWallet, WalletType } from '../types';
55
import { KeyAgent, KeyPurpose, SignDataContext, TrezorConfig, errors } from '@cardano-sdk/key-management';
66
import { KeyAgentFactory } from './KeyAgentFactory';
77
import { Logger } from 'ts-log';
@@ -83,6 +83,21 @@ export class SigningCoordinator<WalletMetadata extends {}, AccountMetadata exten
8383
this.#logger = contextLogger(logger, 'SigningCoordinator');
8484
}
8585

86+
/**
87+
* Gets the appropriate TrezorConfig for the given wallet.
88+
*
89+
* This allows wallets to specify only the properties they want to override
90+
* (e.g., derivationType) while inheriting global settings (e.g., communicationType, manifest)
91+
*/
92+
#getTrezorConfig(wallet: AnyBip32Wallet<WalletMetadata, AccountMetadata>): TrezorConfig {
93+
return {
94+
...this.#hwOptions, // Global defaults (communicationType, manifest, etc.)
95+
...(wallet.type === WalletType.Trezor && 'trezorConfig' in wallet && wallet.trezorConfig
96+
? wallet.trezorConfig
97+
: {}) // Wallet-specific overrides (derivationType, etc.)
98+
};
99+
}
100+
86101
async signTransaction(
87102
{ tx, signContext, options }: SignTransactionProps,
88103
requestContext: RequestContext<WalletMetadata, AccountMetadata>
@@ -196,7 +211,7 @@ export class SigningCoordinator<WalletMetadata extends {}, AccountMetadata exten
196211
chainId: request.requestContext.chainId,
197212
extendedAccountPublicKey: account.extendedAccountPublicKey,
198213
purpose: account.purpose || KeyPurpose.STANDARD,
199-
trezorConfig: this.#hwOptions
214+
trezorConfig: this.#getTrezorConfig(request.requestContext.wallet)
200215
})
201216
).catch((error) => throwMaybeWrappedWithNoRejectError(error, options)),
202217
resolve,

packages/web-extension/src/walletManager/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AccountKeyDerivationPath, KeyPurpose } from '@cardano-sdk/key-management';
1+
import { AccountKeyDerivationPath, KeyPurpose, TrezorConfig } from '@cardano-sdk/key-management';
22
import { Bip32PublicKeyHex } from '@cardano-sdk/crypto';
33
import { Cardano } from '@cardano-sdk/core';
44
import { HexBlob } from '@cardano-sdk/util';
@@ -34,6 +34,7 @@ export type HardwareWallet<WalletMetadata extends {}, AccountMetadata extends {}
3434
AccountMetadata
3535
> & {
3636
type: WalletType.Ledger | WalletType.Trezor;
37+
trezorConfig?: Partial<TrezorConfig>;
3738
};
3839

3940
export type InMemoryWallet<WalletMetadata extends {}, AccountMetadata extends {}> = Bip32Wallet<

packages/web-extension/test/walletManager/SigningCoordinator.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ import {
1010
errors
1111
} from '@cardano-sdk/key-management';
1212
import { Ed25519PublicKeyHex, Ed25519SignatureHex, Hash28ByteBase16 } from '@cardano-sdk/crypto';
13-
import { HexBlob } from '@cardano-sdk/util';
1413
import {
14+
HardwareWallet,
1515
InMemoryWallet,
1616
KeyAgentFactory,
1717
RequestContext,
1818
SigningCoordinator,
1919
WalletType,
2020
WrongTargetError
2121
} from '../../src';
22+
import { HexBlob } from '@cardano-sdk/util';
2223
import { createAccount } from './util';
2324
import { dummyLogger } from 'ts-log';
2425
import { firstValueFrom } from 'rxjs';
@@ -53,6 +54,8 @@ describe('SigningCoordinator', () => {
5354
Ledger: jest.fn(),
5455
Trezor: jest.fn()
5556
};
57+
keyAgentFactory.InMemory.mockResolvedValue(keyAgent);
58+
keyAgentFactory.Trezor.mockResolvedValue(keyAgent as unknown as Awaited<ReturnType<KeyAgentFactory['Trezor']>>);
5659
signingCoordinator = new SigningCoordinator(
5760
{
5861
hwOptions: {
@@ -171,6 +174,47 @@ describe('SigningCoordinator', () => {
171174
expect(passphrase).toEqual(new Uint8Array([0, 0, 0]));
172175
});
173176
});
177+
178+
it('should pass wallet trezorConfig to Trezor key agent factory', async () => {
179+
const trezorWallet: HardwareWallet<{}, {}> = {
180+
accounts: [createAccount(0, 0)],
181+
metadata: {},
182+
trezorConfig: {
183+
communicationType: CommunicationType.Web,
184+
derivationType: 'ICARUS_TREZOR'
185+
},
186+
type: WalletType.Trezor,
187+
walletId: Hash28ByteBase16('ad63f855e831d937457afc52a21a7f351137e4a9fff26c217817335a')
188+
};
189+
190+
const trezorRequestContext: RequestContext<{}, {}> = {
191+
accountIndex: 0,
192+
chainId: Cardano.ChainIds.Preprod,
193+
purpose: KeyPurpose.STANDARD,
194+
wallet: trezorWallet
195+
};
196+
197+
// Test that the Trezor factory is called with merged config
198+
const reqEmitted = firstValueFrom(signingCoordinator.transactionWitnessRequest$);
199+
void signingCoordinator.signTransaction({ signContext, tx }, trezorRequestContext);
200+
const req = await reqEmitted;
201+
202+
// Call the sign method to trigger key agent creation
203+
await req.sign(passphrase);
204+
205+
expect(keyAgentFactory.Trezor).toHaveBeenCalledWith(
206+
expect.objectContaining({
207+
trezorConfig: expect.objectContaining({
208+
communicationType: CommunicationType.Web,
209+
derivationType: 'ICARUS_TREZOR',
210+
manifest: expect.objectContaining({
211+
appUrl: 'https://test.app',
212+
213+
})
214+
})
215+
})
216+
);
217+
});
174218
});
175219

176220
describe('signData', () => {

0 commit comments

Comments
 (0)