Skip to content

Commit e34ca09

Browse files
committed
Enhance error handling in LedgerKeyring tests
Added tests to handle specific TransportStatusError codes for user rejection and blind signing scenarios in transaction signing, personal message signing, and typed data signing. This improves the robustness of error handling in the LedgerKeyring class.
1 parent 87ad186 commit e34ca09

1 file changed

Lines changed: 143 additions & 0 deletions

File tree

packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Common, Chain, Hardfork } from '@ethereumjs/common';
22
import { RLP } from '@ethereumjs/rlp';
33
import { TransactionFactory } from '@ethereumjs/tx';
44
import * as ethUtil from '@ethereumjs/util';
5+
import { TransportStatusError } from '@ledgerhq/hw-transport';
56
import * as sigUtil from '@metamask/eth-sig-util';
67
import { bytesToHex, Hex, remove0x } from '@metamask/utils';
78
import EthereumTx from 'ethereumjs-tx';
@@ -784,6 +785,60 @@ describe('LedgerKeyring', function () {
784785
keyring.signTransaction(fakeAccounts[0], fakeTx),
785786
).rejects.toThrow('Ledger: The transaction signature is not valid');
786787
});
788+
789+
it('throws user rejection error when TransportStatusError with code 27013 is thrown', async function () {
790+
await basicSetupToUnlockOneAccount();
791+
const transportError = {
792+
statusCode: 27013,
793+
message: 'Ledger device: (denied by the user?) (0x6985)',
794+
name: 'TransportStatusError',
795+
};
796+
797+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
798+
jest
799+
.spyOn(keyring.bridge, 'deviceSignTransaction')
800+
.mockRejectedValue(transportError);
801+
802+
await expect(
803+
keyring.signTransaction(fakeAccounts[0], fakeTx),
804+
).rejects.toThrow('Ledger: User rejected the transaction');
805+
});
806+
807+
it('throws blind signing error when TransportStatusError with code 27264 is thrown', async function () {
808+
await basicSetupToUnlockOneAccount();
809+
const transportError = {
810+
statusCode: 27264,
811+
message: 'Ledger device: Invalid data received (0x6a80)',
812+
name: 'TransportStatusError',
813+
};
814+
815+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
816+
jest
817+
.spyOn(keyring.bridge, 'deviceSignTransaction')
818+
.mockRejectedValue(transportError);
819+
820+
await expect(
821+
keyring.signTransaction(fakeAccounts[0], fakeTx),
822+
).rejects.toThrow('Ledger: Blind signing must be enabled');
823+
});
824+
825+
it('re-throws TransportStatusError with unknown status code', async function () {
826+
await basicSetupToUnlockOneAccount();
827+
const transportError = {
828+
statusCode: 12345,
829+
message: 'Some other transport error',
830+
name: 'TransportStatusError',
831+
};
832+
833+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
834+
jest
835+
.spyOn(keyring.bridge, 'deviceSignTransaction')
836+
.mockRejectedValue(transportError);
837+
838+
await expect(
839+
keyring.signTransaction(fakeAccounts[0], fakeTx),
840+
).rejects.toThrow(transportError);
841+
});
787842
});
788843

789844
describe('signPersonalMessage', function () {
@@ -858,6 +913,40 @@ describe('LedgerKeyring', function () {
858913
'Ledger: The signature doesnt match the right address',
859914
);
860915
});
916+
917+
it('throws user rejection error when TransportStatusError with code 27013 is thrown in signPersonalMessage', async function () {
918+
await basicSetupToUnlockOneAccount();
919+
const transportError = {
920+
statusCode: 27013,
921+
message: 'Ledger device: (denied by the user?) (0x6985)',
922+
name: 'TransportStatusError',
923+
};
924+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
925+
jest
926+
.spyOn(keyring.bridge, 'deviceSignMessage')
927+
.mockRejectedValue(transportError);
928+
929+
await expect(
930+
keyring.signPersonalMessage(fakeAccounts[0], 'some message'),
931+
).rejects.toThrow('Ledger: User rejected the transaction');
932+
});
933+
934+
it('re-throws TransportStatusError with unknown status code in signPersonalMessage', async function () {
935+
await basicSetupToUnlockOneAccount();
936+
const transportError = {
937+
statusCode: 12345,
938+
message: 'Some other transport error',
939+
name: 'TransportStatusError',
940+
};
941+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
942+
jest
943+
.spyOn(keyring.bridge, 'deviceSignMessage')
944+
.mockRejectedValue(transportError);
945+
946+
await expect(
947+
keyring.signPersonalMessage(fakeAccounts[0], 'some message'),
948+
).rejects.toThrow(transportError);
949+
});
861950
});
862951

863952
describe('signMessage', function () {
@@ -1207,6 +1296,60 @@ describe('LedgerKeyring', function () {
12071296
'0x72d4e38a0e582e09a620fd38e236fe687a1ec782206b56d576f579c026a7e5b946759735981cd0c3efb02d36df28bb2feedfec3d90e408efc93f45b894946e3200',
12081297
);
12091298
});
1299+
1300+
it('throws user rejection error when TransportStatusError with code 27013 is thrown in signTypedData', async function () {
1301+
const transportError = {
1302+
statusCode: 27013,
1303+
message: 'Ledger device: (denied by the user?) (0x6985)',
1304+
name: 'TransportStatusError',
1305+
};
1306+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
1307+
jest
1308+
.spyOn(keyring.bridge, 'deviceSignTypedData')
1309+
.mockRejectedValue(transportError);
1310+
1311+
await expect(
1312+
keyring.signTypedData(fakeAccounts[15], fixtureData, {
1313+
version: sigUtil.SignTypedDataVersion.V4,
1314+
}),
1315+
).rejects.toThrow('Ledger: User rejected the transaction');
1316+
});
1317+
1318+
it('throws blind signing error when TransportStatusError with code 27264 is thrown in signTypedData', async function () {
1319+
const transportError = {
1320+
statusCode: 27264,
1321+
message: 'Ledger device: Invalid data received (0x6a80)',
1322+
name: 'TransportStatusError',
1323+
};
1324+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
1325+
jest
1326+
.spyOn(keyring.bridge, 'deviceSignTypedData')
1327+
.mockRejectedValue(transportError);
1328+
1329+
await expect(
1330+
keyring.signTypedData(fakeAccounts[15], fixtureData, {
1331+
version: sigUtil.SignTypedDataVersion.V4,
1332+
}),
1333+
).rejects.toThrow('Ledger: Blind signing must be enabled');
1334+
});
1335+
1336+
it('re-throws TransportStatusError with unknown status code in signTypedData', async function () {
1337+
const transportError = {
1338+
statusCode: 12345,
1339+
message: 'Some other transport error',
1340+
name: 'TransportStatusError',
1341+
};
1342+
Object.setPrototypeOf(transportError, TransportStatusError.prototype);
1343+
jest
1344+
.spyOn(keyring.bridge, 'deviceSignTypedData')
1345+
.mockRejectedValue(transportError);
1346+
1347+
await expect(
1348+
keyring.signTypedData(fakeAccounts[15], fixtureData, {
1349+
version: sigUtil.SignTypedDataVersion.V4,
1350+
}),
1351+
).rejects.toThrow(transportError);
1352+
});
12101353
});
12111354

12121355
describe('destroy', function () {

0 commit comments

Comments
 (0)