Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion wallets/rn_cli_wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"postinstall": "./scripts/copy-sample-files.sh",
"prebuild": "expo prebuild",
"postprebuild": "node scripts/setup-secrets.js",
"android": "expo run:android",
"android": "expo run:android --app-id com.walletconnect.web3wallet.rnsample.debug",
"android:debug": "expo run:android --app-id com.walletconnect.web3wallet.rnsample.debug",
"android:internal": "expo run:android --variant internal --app-id com.walletconnect.web3wallet.rnsample.internal",
"android:prod": "expo run:android --variant release --app-id com.walletconnect.web3wallet.rnsample",
Expand All @@ -31,6 +31,7 @@
"permit2:revoke": "node ./scripts/revoke-permit2-approval.js"
},
"dependencies": {
"@bitcoinerlab/secp256k1": "1.2.0",
"@bottom-tabs/react-navigation": "1.3.1",
"@craftzdog/react-native-buffer": "6.1.1",
"@expo/metro-runtime": "~56.0.15",
Expand All @@ -39,6 +40,7 @@
"@mhpdev/react-native-haptics": "1.1.0",
"@mysten/sui": "1.45.2",
"@noble/hashes": "1.8.0",
"@noble/secp256k1": "3.0.0",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-native-community/netinfo": "12.0.1",
"@react-navigation/bottom-tabs": "7.18.3",
Expand All @@ -53,10 +55,14 @@
"@ton/crypto": "3.3.0",
"@ton/ton": "15.4.0",
"@walletconnect/react-native-compat": "2.23.10",
"bip32": "4.0.0",
"bip39": "3.1.0",
"bitcoinjs-lib": "6.1.7",
"bitcoinjs-message": "2.2.0",
"bs58": "6.0.0",
"crc-32": "1.2.2",
"dayjs": "1.11.21",
"ecpair": "2.1.0",
"ed25519-hd-key": "1.3.0",
"ethers": "6.13.5",
"expo": "56.0.12",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions wallets/rn_cli_wallet/src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import SessionSignTronModal from '@/modals/SessionSignTronModal';
import SessionSignCantonModal from '@/modals/SessionSignCantonModal';
import SessionSolanaSignMessageModal from '@/modals/SessionSolanaSignMessageModal';
import SessionSolanaSignTransactionModal from '@/modals/SessionSolanaSignTransactionModal';
import SessionBitcoinSignMessageModal from '@/modals/SessionBitcoinSignMessageModal';
import SessionBitcoinSendTransactionModal from '@/modals/SessionBitcoinSendTransactionModal';
import SessionBitcoinGetAddressesModal from '@/modals/SessionBitcoinGetAddressesModal';
import PaymentOptionsModal from '@/modals/PaymentOptionsModal';
import ImportWalletModal from '@/modals/ImportWalletModal';
import SessionDetailModal from '@/modals/SessionDetailModal';
Expand Down Expand Up @@ -79,6 +82,12 @@ export default function Modal() {
return <SessionSolanaSignMessageModal />;
case 'SessionSolanaSignTransactionModal':
return <SessionSolanaSignTransactionModal />;
case 'SessionBitcoinSignMessageModal':
return <SessionBitcoinSignMessageModal />;
case 'SessionBitcoinSendTransactionModal':
return <SessionBitcoinSendTransactionModal />;
case 'SessionBitcoinGetAddressesModal':
return <SessionBitcoinGetAddressesModal />;
case 'PaymentOptionsModal':
return <PaymentOptionsModal />;
case 'ImportWalletModal':
Expand Down
176 changes: 176 additions & 0 deletions wallets/rn_cli_wallet/src/components/NetworkDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { useState } from 'react';
import { Image, ScrollView, StyleSheet, View } from 'react-native';

import { useTheme } from '@/hooks/useTheme';
import { PresetsUtil } from '@/utils/PresetsUtil';
import { Spacing, BorderRadius } from '@/utils/ThemeUtil';
import { Text } from '@/components/Text';
import { Button } from '@/components/Button';
import CaretUpDown from '@/assets/CaretUpDown';
import Checkmark from '@/assets/Checkmark';

export interface NetworkDropdownOption<T extends string> {
label: T;
chainId: string;
}

interface NetworkDropdownProps<T extends string> {
options: readonly NetworkDropdownOption<T>[];
selected: T;
onSelect: (label: T) => void;
// Optional controlled open state. When provided, the parent owns whether the
// list is expanded (e.g. to close it when another field gains focus).
isOpen?: boolean;
onOpenChange?: (open: boolean) => void;
}

export function NetworkDropdown<T extends string>({
options,
selected,
onSelect,
isOpen,
onOpenChange,
}: NetworkDropdownProps<T>) {
const Theme = useTheme();
const [internalOpen, setInternalOpen] = useState(false);

const expanded = isOpen ?? internalOpen;
const setExpanded = (open: boolean) => {
if (onOpenChange) {
onOpenChange(open);
} else {
setInternalOpen(open);
}
};

const selectedOption =
options.find(option => option.label === selected) ?? options[0];

const handleSelect = (label: T) => {
onSelect(label);
setExpanded(false);
};

return (
<View style={styles.wrapper}>
<Button
style={[
styles.control,
{
backgroundColor: Theme['bg-primary'],
borderColor: Theme['foreground-tertiary'],
},
]}
onPress={() => setExpanded(!expanded)}
>
<View style={styles.chainInfo}>
<Image
source={PresetsUtil.getChainIconById(selectedOption.chainId)}
style={[
styles.chainLogo,
{ backgroundColor: Theme['foreground-tertiary'] },
]}
/>
<Text variant="md-400" color="text-primary">
{selectedOption.label}
</Text>
</View>
<CaretUpDown width={20} height={20} fill={Theme['text-secondary']} />
</Button>

{expanded && (
<View
style={[
styles.list,
{
backgroundColor: Theme['bg-primary'],
borderColor: Theme['foreground-tertiary'],
},
]}
>
<ScrollView
style={styles.scroll}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.listContent}
nestedScrollEnabled
>
{options.map(option => {
const isSelected = option.label === selected;
return (
<Button
key={option.label}
style={styles.row}
onPress={() => handleSelect(option.label)}
>
<View style={styles.chainInfo}>
<Image
source={PresetsUtil.getChainIconById(option.chainId)}
style={[
styles.chainLogo,
{ backgroundColor: Theme['foreground-tertiary'] },
]}
/>
<Text variant="md-400" color="text-primary">
{option.label}
</Text>
</View>
{isSelected && (
<Checkmark
width={16}
height={16}
fill={Theme['icon-accent-primary']}
/>
)}
</Button>
);
})}
</ScrollView>
</View>
)}
</View>
);
}

const styles = StyleSheet.create({
wrapper: {
width: '100%',
},
control: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderWidth: 1,
borderRadius: BorderRadius[3],
paddingVertical: Spacing[3],
paddingHorizontal: Spacing[4],
},
list: {
borderWidth: 1,
borderRadius: BorderRadius[3],
marginTop: Spacing[2],
paddingHorizontal: Spacing[4],
paddingVertical: Spacing[2],
},
scroll: {
maxHeight: 240,
},
listContent: {
gap: Spacing[1],
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: Spacing[2],
},
chainInfo: {
flexDirection: 'row',
alignItems: 'center',
gap: Spacing[2],
},
chainLogo: {
width: 24,
height: 24,
borderRadius: BorderRadius.full,
},
});
50 changes: 50 additions & 0 deletions wallets/rn_cli_wallet/src/constants/Bitcoin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Bitcoin (bip122)
import Bitcoin from '@/assets/chains/bitcoin.png';
import { Chain } from '@/utils/TypesUtil';

/**
* Methods
*/
export const BIP122_SIGNING_METHODS = {
BIP122_SIGN_MESSAGE: 'signMessage',
BIP122_GET_ACCOUNT_ADDRESSES: 'getAccountAddresses',
BIP122_SEND_TRANSACTION: 'sendTransfer',
BIP122_SIGN_PSBT: 'signPsbt',
};

/**
* Events
*/
export const BIP122_EVENTS = {
BIP122_ADDRESSES_CHANGED: 'bip122_addressesChanged',
};

export const BIP122_NAMESPACE = 'bip122';

// Mainnet genesis block hash (CAIP-2 reference). Testnet is intentionally not
// supported here — the RN wallet exposes only mainnet chains.
export const BIP122_MAINNET_ID = '000000000019d6689c085ae165831e93';
export const BIP122_MAINNET_CAIP2 = `${BIP122_NAMESPACE}:${BIP122_MAINNET_ID}`;

export type IBip122ChainId = typeof BIP122_MAINNET_CAIP2;

// BIP44 coin type for Bitcoin mainnet (used for HD derivation).
export const BIP122_MAINNET_COIN_TYPE = '0';
export const BIP122_MAINNET_RPC = 'https://mempool.space/api';

export const BIP122_MAINNET = {
[BIP122_MAINNET_CAIP2]: {
chainId: BIP122_MAINNET_ID,
namespace: BIP122_NAMESPACE,
name: 'Bitcoin',
rpcUrl: BIP122_MAINNET_RPC,
},
};

export const BIP122_NETWORKS_IMAGES = {
[BIP122_MAINNET_CAIP2]: Bitcoin,
};

export const BIP122_CHAINS: Record<string, Chain> = {
...BIP122_MAINNET,
};
5 changes: 5 additions & 0 deletions wallets/rn_cli_wallet/src/hooks/useInitializeWalletKit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { createOrRestoreTonWallet } from '@/utils/TonWalletUtil';
import { createOrRestoreTronWallet } from '@/utils/TronWalletUtil';
import { createOrRestoreCantonWallet } from '@/utils/CantonWalletUtil';
import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil';
import { createOrRestoreBitcoinWallet } from '@/utils/BitcoinWalletUtil';

export default function useInitializeWalletKit() {
const [initialized, setInitialized] = useState(false);
Expand All @@ -28,6 +29,8 @@ export default function useInitializeWalletKit() {
await createOrRestoreCantonWallet();
const { solanaAddress, solanaWallet } =
await createOrRestoreSolanaWallet();
const { bitcoinAddress, bitcoinWallet } =
await createOrRestoreBitcoinWallet();

SettingsStore.setEIP155Address(eip155Addresses[0]);
SettingsStore.setWallet(eip155Wallets[eip155Addresses[0]]);
Expand All @@ -41,6 +44,8 @@ export default function useInitializeWalletKit() {
SettingsStore.setCantonWallet(cantonWallet);
SettingsStore.setSolanaAddress(solanaAddress);
SettingsStore.setSolanaWallet(solanaWallet);
SettingsStore.setBitcoinAddress(bitcoinAddress);
SettingsStore.setBitcoinWallet(bitcoinWallet);
await createWalletKit(relayerRegionURL);
setInitialized(true);
SettingsStore.state.initPromiseResolver?.resolve(undefined);
Expand Down
17 changes: 17 additions & 0 deletions wallets/rn_cli_wallet/src/hooks/useWalletKitEventsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TRON_SIGNING_METHODS } from '@/constants/Tron';
import { CANTON_SIGNING_METHODS } from '@/constants/Canton';
import { approveCantonRequest } from '@/utils/CantonRequestHandlerUtil';
import { SOLANA_SIGNING_METHODS } from '@/constants/Solana';
import { BIP122_SIGNING_METHODS } from '@/constants/Bitcoin';

export default function useWalletKitEventsManager(initialized: boolean) {
/******************************************************************************
Expand Down Expand Up @@ -183,6 +184,22 @@ export default function useWalletKitEventsManager(initialized: boolean) {
requestEvent,
requestSession,
});
case BIP122_SIGNING_METHODS.BIP122_SIGN_MESSAGE:
return ModalStore.open('SessionBitcoinSignMessageModal', {
requestEvent,
requestSession,
});
case BIP122_SIGNING_METHODS.BIP122_GET_ACCOUNT_ADDRESSES:
return ModalStore.open('SessionBitcoinGetAddressesModal', {
requestEvent,
requestSession,
});
case BIP122_SIGNING_METHODS.BIP122_SEND_TRANSACTION:
case BIP122_SIGNING_METHODS.BIP122_SIGN_PSBT:
return ModalStore.open('SessionBitcoinSendTransactionModal', {
requestEvent,
requestSession,
});
default:
return ModalStore.open('SessionUnsuportedMethodModal', {
requestEvent,
Expand Down
Loading
Loading