Skip to content

Commit

Permalink
ledger clear signing upgrades (#5966)
Browse files Browse the repository at this point in the history
* fix build

* chore: upgrade ledgerhq depens, remove patch

chore: upgrade ledgerhq depens, remove patch

The upstream issue that required the patch was corrected. These upgrades will allow for Clear Signing with new Ledger firmware versions

chore: upgrade @ledgerhq/hw-app-eth

chore: upgrade to new versions

* ledger working again

* set default provider as mainnet

* clean console logs

---------

Co-authored-by: Bruno Barbieri <brunobar79@gmail.com>
  • Loading branch information
DanielSinclair and brunobar79 authored Oct 15, 2024
1 parent 7d75535 commit b191fef
Show file tree
Hide file tree
Showing 12 changed files with 725 additions and 362 deletions.
29 changes: 24 additions & 5 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ PODS:
- mobile-wallet-protocol-host (0.1.7):
- CoinbaseWalletSDK/Host
- React-Core
- MultiplatformBleAdapter (0.1.9)
- MultiplatformBleAdapter (0.2.0)
- nanopb (2.30910.0):
- nanopb/decode (= 2.30910.0)
- nanopb/encode (= 2.30910.0)
Expand Down Expand Up @@ -1160,9 +1160,28 @@ PODS:
- React-Core
- react-native-animateable-text (0.12.1):
- React-Core
- react-native-ble-plx (2.0.3):
- MultiplatformBleAdapter (= 0.1.9)
- react-native-ble-plx (3.2.1):
- DoubleConversion
- glog
- hermes-engine
- MultiplatformBleAdapter (= 0.2.0)
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Codegen
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-blur (4.4.0):
- DoubleConversion
- glog
Expand Down Expand Up @@ -2375,7 +2394,7 @@ SPEC CHECKSUMS:
MMKV: 817ba1eea17421547e01e087285606eb270a8dcb
MMKVCore: af055b00e27d88cd92fad301c5fecd1ff9b26dd9
mobile-wallet-protocol-host: 8ed897dcf4f846d39b35767540e6a695631cab73
MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d
nanopb: 438bc412db1928dac798aa6fd75726007be04262
PanModal: 421fe72d4af5b7e9016aaa3b4db94a2fb71756d3
Permission-Camera: 9b70902f34a83c10e198d2d01f0e453e58842776
Expand Down Expand Up @@ -2409,7 +2428,7 @@ SPEC CHECKSUMS:
React-Mapbuffer: 9f68550e7c6839d01411ac8896aea5c868eff63a
react-native-aes-crypto: d7e87fd02cee7285983c00957a34063dfc4c94b3
react-native-animateable-text: c95b74a78a13e416e6c4e8b012eea29e14913207
react-native-ble-plx: f10240444452dfb2d2a13a0e4f58d7783e92d76e
react-native-ble-plx: 08539040709361221aa9f8cada60dc730b9168c5
react-native-blur: a2acf22fd7bd13621df5e0b1c130b81adea7009c
react-native-branch: 960c897d57b9f4912b08b9d06a25284b6e9879da
react-native-cameraroll: b5ce04a1ee4081d7eea921918de979f0b41d8e22
Expand Down
368 changes: 184 additions & 184 deletions ios/Rainbow.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,50 @@ if (process.env.CI) {
const rainbowConfig = {
resolver: {
blacklistRE,
resolveRequest: (context, moduleName, platform) => {
try {
return context.resolveRequest(context, moduleName, platform);
} catch (error) {
console.warn('\n1️⃣ context.resolveRequest cannot resolve: ', moduleName);
}

try {
const resolution = require.resolve(moduleName, {
paths: [path.dirname(context.originModulePath), ...config.resolver.nodeModulesPaths],
});

if (path.isAbsolute(resolution)) {
return {
filePath: resolution,
type: 'sourceFile',
};
}
} catch (error) {
console.warn('\n2️⃣ require.resolve cannot resolve: ', moduleName);
}

try {
return defaultModuleResolver(context, moduleName, platform);
} catch (error) {
console.warn('\n3️⃣ defaultModuleResolver cannot resolve: ', moduleName);
}

try {
return {
filePath: require.resolve(moduleName),
type: 'sourceFile',
};
} catch (error) {
console.warn('\n4️⃣ require.resolve cannot resolve: ', moduleName);
}

try {
const resolution = getDefaultConfig(require.resolve(moduleName)).resolver?.resolveRequest;
return resolution(context, moduleName, platform);
} catch (error) {
console.warn('\n5️⃣ getDefaultConfig cannot resolve: ', moduleName);
}
},
},
transformer,
};
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@
"@gorhom/bottom-sheet": "4.6.1",
"@json-rpc-tools/utils": "1.7.6",
"@lavamoat/preinstall-always-fail": "2.0.0",
"@ledgerhq/hw-app-eth": "6.29.9",
"@ledgerhq/react-native-hw-transport-ble": "6.27.7",
"@ledgerhq/hw-app-eth": "6.39.0",
"@ledgerhq/react-native-hw-transport-ble": "6.33.4",
"@metamask/eth-sig-util": "7.0.2",
"@notifee/react-native": "7.8.2",
"@rainbow-me/provider": "0.1.1",
Expand Down Expand Up @@ -219,7 +219,7 @@
"react-native-actionsheet": "2.4.2",
"react-native-aes-crypto": "rainbow-me/react-native-aes#65c49f7e70266615b2999eaa7db654d3fe4f2e3b",
"react-native-animateable-text": "0.12.1",
"react-native-ble-plx": "2.0.3",
"react-native-ble-plx": "3.2.1",
"react-native-bootsplash": "5.5.3",
"react-native-branch": "5.3.1",
"react-native-change-icon": "4.0.0",
Expand Down
15 changes: 0 additions & 15 deletions patches/@ledgerhq+react-native-hw-transport-ble+6.27.7.patch

This file was deleted.

9 changes: 4 additions & 5 deletions src/handlers/LedgerSigner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

import AppEth, { ledgerService } from '@ledgerhq/hw-app-eth';
import TransportBLE from '@ledgerhq/react-native-hw-transport-ble';
import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util';
import { Signer } from '@ethersproject/abstract-signer';
import { Bytes, hexlify, joinSignature } from '@ethersproject/bytes';
Expand All @@ -14,6 +13,7 @@ import { logger, RainbowError } from '@/logger';
import { Navigation } from '@/navigation';
import Routes from '@/navigation/routesNames';
import { getAddress } from '@ethersproject/address';
import { getEthApp } from '@/utils/ledger';

function waiter(duration: number): Promise<void> {
return new Promise(resolve => {
Expand All @@ -40,10 +40,9 @@ export class LedgerSigner extends Signer {
defineReadOnly(
this,
'_eth',
TransportBLE.open(deviceId).then(
transport => {
const eth = new AppEth(transport);
return eth;
getEthApp(deviceId).then(
ethApp => {
return ethApp;
},
error => {
return Promise.reject(error);
Expand Down
120 changes: 66 additions & 54 deletions src/hooks/useLedgerImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function useLedgerImport({
*/
const handlePairSuccess = useCallback(
(deviceId: string) => {
logger.debug('[useLedgerImport]: Pairing Success', {}, DebugContext.ledger);
logger.debug('[useLedgerImport]: Pairing Success', {});
successCallback?.(deviceId);
handleCleanUp();
},
Expand All @@ -54,61 +54,73 @@ export function useLedgerImport({
*/
const searchAndPair = useCallback(() => {
let currentDeviceId = '';

const newObserver = TransportBLE.observeState({
// havnt seen complete or error fire yet but its in the docs so keeping for reporting purposes
complete: (e: any) => {
logger.debug('[useLedgerImport]: Observer complete', { e }, DebugContext.ledger);
},
error: (e: any) => {
logger.debug('[useLedgerImport]: Observer error ', { e }, DebugContext.ledger);
},
next: async (e: any) => {
// App is not authorized to use Bluetooth
if (e.type === 'Unauthorized') {
logger.debug('[useLedgerImport]: Bluetooth Unauthorized', {}, DebugContext.ledger);
if (IS_IOS) {
await showBluetoothPermissionsAlert();
} else {
await checkAndRequestAndroidBluetooth();
logger.debug('[useLedgerImport]: searchAndPair', {});
try {
const newObserver = TransportBLE.observeState({
// havnt seen complete or error fire yet but its in the docs so keeping for reporting purposes
complete: () => {
logger.debug('[useLedgerImport]: Observer complete', {});
},
error: (e: any) => {
logger.debug('[useLedgerImport]: Observer error ', { e });
},
next: async (e: any) => {
// App is not authorized to use Bluetooth
if (e.type === 'Unauthorized') {
logger.debug('[useLedgerImport]: Bluetooth Unauthorized', {});
if (IS_IOS) {
await showBluetoothPermissionsAlert();
return;
} else {
await checkAndRequestAndroidBluetooth();
return;
}
}
}
// Bluetooth is turned off
if (e.type === 'PoweredOff') {
logger.debug('[useLedgerImport]: Bluetooth Powered Off', {}, DebugContext.ledger);
await showBluetoothPoweredOffAlert();
}
if (e.available) {
const newListener = TransportBLE.listen({
complete: () => {},
error: error => {
logger.error(new RainbowError('[useLedgerImport]: Error Pairing'), { errorMessage: (error as Error).message });
},
next: async e => {
if (e.type === 'add') {
const device = e.descriptor;
// prevent duplicate alerts
if (currentDeviceId === device.id) {
return;
}
// set the current device id to prevent duplicate alerts
currentDeviceId = device.id;
// Bluetooth is turned off
if (e.type === 'PoweredOff') {
logger.debug('[useLedgerImport]: Bluetooth Powered Off', {});
await showBluetoothPoweredOffAlert();
return;
}
if (e.available) {
const newListener = TransportBLE.listen({
complete: () => {
logger.debug('[useLedgerImport]: TransportBLE.listen complete', {});
},
error: error => {
logger.error(new RainbowError('[useLedgerImport]: Error Pairing'), { errorMessage: (error as Error).message });
handlePairError(e);
},
next: async e => {
logger.debug('[useLedgerImport]: TransportBLE.listen next', { e });

try {
const transport = await TransportBLE.open(device.id);
if (e.type === 'add') {
const device = e.descriptor;
// prevent duplicate alerts
if (currentDeviceId === device.id) {
logger.debug('[useLedgerImport]: TransportBLE.listen next dupe', { deviceId: device.id });
return;
}
// set the current device id to prevent duplicate alerts
currentDeviceId = device.id;

logger.debug('[useLedgerImport]: TransportBLE.listen next paired successfully', { deviceId: device.id });
handlePairSuccess(device.id);
} catch (e) {
handlePairError(e as Error);
currentDeviceId === '';
} else {
logger.debug('[useLedgerImport]: TransportBLE.listen next not paired', { e });
handlePairError(e);
}
}
},
});
listener.current = newListener;
}
},
});
observer.current = newObserver;
},
});
listener.current = newListener;
}
},
});
observer.current = newObserver;
} catch (e) {
logger.error(new RainbowError('[useLedgerImport]: Error Pairing'), { errorMessage: (e as Error).message });
handlePairError(e as Error);
}
}, [handlePairError, handlePairSuccess]);

/**
Expand All @@ -118,10 +130,10 @@ export function useLedgerImport({

useEffect(() => {
const asyncFn = async () => {
logger.debug('[useLedgerImport]: init device polling', {}, DebugContext.ledger);
logger.debug('[useLedgerImport]: init device polling', {});

const isBluetoothEnabled = IS_ANDROID ? await checkAndRequestAndroidBluetooth() : true;
logger.debug('[useLedgerImport]: bluetooth enabled? ', { isBluetoothEnabled }, DebugContext.ledger);
logger.debug('[useLedgerImport]: bluetooth enabled? ', { isBluetoothEnabled });

if (isBluetoothEnabled) {
searchAndPair();
Expand Down
13 changes: 3 additions & 10 deletions src/model/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,7 @@ import { findWalletWithAccount } from '@/helpers/findWalletWithAccount';
import { EthereumAddress } from '@/entities';
import { authenticateWithPIN, authenticateWithPINAndCreateIfNeeded } from '@/handlers/authentication';
import { saveAccountEmptyState } from '@/handlers/localstorage/accountLocal';
import {
addHexPrefix,
isHexString,
isHexStringIgnorePrefix,
isValidBluetoothDeviceId,
isValidMnemonic,
web3Provider,
} from '@/handlers/web3';
import { addHexPrefix, isHexString, isHexStringIgnorePrefix, isValidBluetoothDeviceId, isValidMnemonic } from '@/handlers/web3';
import { createSignature } from '@/helpers/signingWallet';
import showWalletErrorAlert from '@/helpers/support';
import walletTypes, { EthereumWalletType } from '@/helpers/walletTypes';
Expand Down Expand Up @@ -300,11 +293,11 @@ export const loadWallet = async <S extends Screen>({
if (isHardwareWalletKey(privateKey)) {
const index = privateKey?.split('/')[1];
const deviceId = privateKey?.split('/')[0];
if (typeof index !== undefined && provider && deviceId) {
if (typeof index !== undefined && deviceId && provider) {
return new LedgerSigner(provider, getHdPath({ type: WalletLibraryType.ledger, index: Number(index) }), deviceId);
}
} else if (privateKey) {
return new Wallet(privateKey, provider || web3Provider);
return new Wallet(privateKey, provider);
}
if (ios && showErrorIfNotLoaded) {
showWalletErrorAlert();
Expand Down
4 changes: 2 additions & 2 deletions src/navigation/HardwareWalletTxNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ export const HardwareWalletTxNavigator = () => {
);

const successCallback = useCallback(() => {
logger.debug('[HardwareWalletTxNavigator]: submitting tx', {}, DebugContext.ledger);
logger.debug('[HardwareWalletTxNavigator]: submitting tx', {});
if (!isReady) {
setReadyForPolling(false);
setIsReady(true);
setHardwareTXError(false);
submit();
} else {
logger.debug('[HardwareWalletTxNavigator]: already submitted', {}, DebugContext.ledger);
logger.debug('[HardwareWalletTxNavigator]: already submitted', {});
}
}, [isReady, setIsReady, setReadyForPolling, submit]);

Expand Down
3 changes: 1 addition & 2 deletions src/screens/SendSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export default function SendSheet() {
const [debouncedRecipient] = useDebounce(recipient, 500);

const [isValidAddress, setIsValidAddress] = useState(!!recipientOverride);
const [currentProvider, setCurrentProvider] = useState<StaticJsonRpcProvider | undefined>();
const [currentProvider, setCurrentProvider] = useState<StaticJsonRpcProvider | undefined>(getProvider({ chainId: ChainId.mainnet }));
const theme = useTheme();
const { colors, isDarkMode } = theme;

Expand Down Expand Up @@ -403,7 +403,6 @@ export default function SendSheet() {
const onSubmit = useCallback(
async ({ ens }: OnSubmitProps = {}) => {
if (!selected) return;

const wallet = await performanceTracking.getState().executeFn({
fn: loadWallet,
operation: TimeToSignOperation.KeychainRead,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ export function PairHardwareWalletSigningSheet() {
const importHardwareWallet = useCallback(
async (deviceId: string) => {
if (busy) {
logger.debug('[PairHardwareWalletSigningSheet]: busy, already trying to import', { deviceId }, DebugContext.ledger);
logger.debug('[PairHardwareWalletSigningSheet]: busy, already trying to import', { deviceId });
return;
}
logger.debug('[PairHardwareWalletSigningSheet]: importing Hardware Wallet', { deviceId }, DebugContext.ledger);
logger.debug('[PairHardwareWalletSigningSheet]: importing Hardware Wallet', { deviceId });
handleSetSeedPhrase(deviceId);
handlePressImportButton({
forceAddress: deviceId,
Expand Down
Loading

0 comments on commit b191fef

Please sign in to comment.