Add support for wallet_getCapabilities from WalletConnect #39

Merged
nabarun merged 6 commits from pj-add-base-network into nym-vpn-app 2025-07-15 16:05:02 +00:00
10 changed files with 109 additions and 61 deletions

View File

@ -146,6 +146,23 @@ const App = (): React.JSX.Element => {
requestSessionData,
});
break;
case EIP155_SIGNING_METHODS.WALLET_GET_CAPABILITIES:
const supportedNetworks = networksData
.filter(network => network.namespace === EIP155)
.map(network => `${network.namespace}:${network.chainId}`);
const capabilitiesResponse = formatJsonRpcResult(id, {
accountManagement: true,
sessionManagement: true,
supportedAuthMethods: ['personal_sign', 'eth_sendTransaction'],
supportedNetworks: supportedNetworks,
});
await web3wallet!.respondSessionRequest({
topic,
response: capabilitiesResponse,
});
break;
case COSMOS_METHODS.COSMOS_SIGN_DIRECT:
const message = {
@ -347,6 +364,7 @@ const App = (): React.JSX.Element => {
// eslint-disable-next-line react/no-unstable-nested-components
headerRight: () => (
<Button
testID="pair-button"
onPress={() => {
navigation.navigate("AddSession");
}}

View File

@ -104,7 +104,7 @@ export const Header: React.FC<{
</Stack>
{showWalletConnect && (
<Button onClick={() => navigation.navigate("WalletConnect")}>
<Button data-webviewId="wallet-connect-button" onClick={() => navigation.navigate("WalletConnect")}>
{<WCLogo />}
</Button>
)}

View File

@ -282,20 +282,24 @@ const PairingModal = ({
)}
</View>
</ScrollView>
<View style={styles.flexRow}>
<Button
mode="contained"
onPress={handleAccept}
loading={isLoading}
disabled={isLoading}>
{isLoading ? 'Connecting' : 'Yes'}
</Button>
<View style={styles.space} />
<Button mode="outlined" onPress={handleReject}>
No
</Button>
</View>
{currentProposal && namespaces && (
<View style={styles.flexRow}>
<Button
mode="contained"
testID="accept-pair-request-button"
onPress={handleAccept}
loading={isLoading}
disabled={isLoading}>
{isLoading ? 'Connecting' : 'Yes'}
</Button>
<View style={styles.space} />
<Button mode="outlined" onPress={handleReject}>
No
</Button>
</View>
)}
</View>
</View>
</Modal>

View File

@ -44,7 +44,7 @@ const AddSession = () => {
/>
<Box sx={{ mt: 2 }}>
<Button variant="contained" onClick={pair}>
<Button variant="contained" data-webviewId="pair-session-button" onClick={pair}>
Pair Session
</Button>
</Box>

View File

@ -82,23 +82,27 @@ const ApproveTransfer = ({ route }: ApproveTransferProps) => {
useState<BigNumber | null>();
const isSufficientFunds = useMemo(() => {
if (!transaction.value) {
return;
}
if (!balance) {
return;
}
const amountBigNum = BigNumber.from(String(transaction.value));
const balanceBigNum = BigNumber.from(balance);
if (amountBigNum.gte(balanceBigNum)) {
return false;
} else {
return true;
if (!fees) {
return;
}
}, [balance, transaction]);
const balanceBigNum = BigNumber.from(balance);
const feesBigNum = BigNumber.from(fees);
let totalRequiredBigNum = feesBigNum;
if (transaction.value) {
const amountBigNum = BigNumber.from(String(transaction.value));
totalRequiredBigNum = amountBigNum.add(feesBigNum);
}
// Compare the user's balance with the total required amount
const isSufficient = balanceBigNum.gte(totalRequiredBigNum);
return isSufficient;
}, [balance, transaction.value, fees]);
const requestedNetwork = networksData.find(
networkData =>
@ -273,8 +277,12 @@ const ApproveTransfer = ({ route }: ApproveTransferProps) => {
useEffect(() => {
if (namespace === EIP155) {
const ethFees = BigNumber.from(ethGasLimit ?? 0)
.mul(BigNumber.from(ethMaxFee ?? ethGasPrice ?? 0))
if (!ethGasLimit || !(ethMaxFee || ethGasPrice)){
return;
}
const ethFees = BigNumber.from(ethGasLimit)
.mul(BigNumber.from(ethMaxFee ?? ethGasPrice))
.toString();
setFees(ethFees);
} else {
@ -495,7 +503,7 @@ const ApproveTransfer = ({ route }: ApproveTransferProps) => {
useEffect(() => {
const getEthGas = async () => {
try {
if (!isSufficientFunds || !provider) {
if (!provider) {
return;
}
@ -568,11 +576,11 @@ const ApproveTransfer = ({ route }: ApproveTransferProps) => {
}, [cosmosStargateClient, isSufficientFunds, sendMsg, transaction,txMemo]);
useEffect(() => {
if (balance && !isSufficientFunds) {
if (balance && !isSufficientFunds && !fees) {
setTxError('Insufficient funds');
setIsTxErrorDialogOpen(true);
}
}, [isSufficientFunds, balance]);
}, [isSufficientFunds, balance, fees]);
return (
<>
@ -614,14 +622,16 @@ const ApproveTransfer = ({ route }: ApproveTransferProps) => {
{transaction && (
<View style={styles.approveTransfer}>
<DataBox label="To" data={transaction.to!} />
<DataBox
label={`Amount (${
namespace === EIP155 ? 'wei' : requestedNetwork!.nativeDenom
})`}
data={BigNumber.from(
transaction.value?.toString(),
).toString()}
/>
{transaction.value !== undefined && transaction.value !== null && (
<DataBox
label={`Amount (${
namespace === EIP155 ? 'wei' : requestedNetwork!.nativeDenom
})`}
data={BigNumber.from(
transaction.value?.toString(),
).toString()}
/>
)}
{namespace === COSMOS && (
<DataBox
label="Memo"

View File

@ -116,7 +116,8 @@ const SignRequest = ({ route }: SignRequestProps) => {
);
useEffect(() => {
if (route.path) {
const requestEvent = route.params.requestEvent;
if (route.path && !requestEvent) {
const sanitizedRoute = sanitizePath(route.path);
sanitizedRoute &&
retrieveData(
@ -127,7 +128,6 @@ const SignRequest = ({ route }: SignRequestProps) => {
);
return;
}
const requestEvent = route.params.requestEvent;
const requestChainId = requestEvent?.params.chainId;
const requestedChain = networksData.find(
@ -310,6 +310,7 @@ const SignRequest = ({ route }: SignRequestProps) => {
<View style={styles.buttonContainer}>
<Button
mode="contained"
testID="accept-sign-request-button"
onPress={signMessageHandler}
loading={isApproving}
disabled={isApproving}>

View File

@ -43,15 +43,20 @@ export default function WalletConnect() {
// eslint-disable-next-line react/no-unstable-nested-components
left={() => (
<>
{session.peer.metadata.icons[0].endsWith(".svg") ? (
<View style={styles.dappLogo}>
<Text>SvgURI peerMetaDataIcon</Text>
</View>
{session.peer.metadata.icons && session.peer.metadata.icons.length > 0 ? (
session.peer.metadata.icons[0].endsWith(".svg") ? (
<View style={styles.dappLogo}>
<Text>SvgURI peerMetaDataIcon</Text>
</View>
) : (
<Image
style={styles.dappLogo}
source={{ uri: session.peer.metadata.icons[0] }}
/>
)
) : (
<Image
style={styles.dappLogo}
source={{ uri: session.peer.metadata.icons[0] }}
/>
// Render nothing if no icon is available
<View style={styles.dappLogo} /> // Or simply null
)}
</>
)}

View File

@ -344,7 +344,7 @@ const retrieveSingleAccount = async (
throw new Error('Accounts for given chain not found');
}
return loadedAccounts.find(account => account.address === address);
return loadedAccounts.find(account => account.address.toLowerCase() === address.toLowerCase());
};
const resetWallet = async () => {

View File

@ -40,6 +40,18 @@ export const DEFAULT_NETWORKS: NetworksFormData[] = [
coinType: '60',
isDefault: true,
},
// Base Chain Network
{
chainId: '8453',
networkName: EIP155_CHAINS['eip155:8453'].name,
namespace: EIP155,
rpcUrl: EIP155_CHAINS['eip155:8453'].rpc,
blockExplorerUrl: '',
currencySymbol: 'ETH',
coinType: '60',
isDefault: true,
},
{
chainId: 'provider',
networkName: COSMOS_TESTNET_CHAINS['cosmos:provider'].name,

View File

@ -11,13 +11,8 @@
export type TEIP155Chain = keyof typeof EIP155_CHAINS;
export type EIP155Chain = {
chainId: number;
name: string;
logo: string;
rgb: string;
rpc: string;
namespace: string;
smartAccountEnabled?: boolean;
};
/**
@ -25,12 +20,14 @@ export type EIP155Chain = {
*/
export const EIP155_CHAINS: Record<string, EIP155Chain> = {
'eip155:1': {
chainId: 1,
name: 'Ethereum',
logo: '/chain-logos/eip155-1.png',
rgb: '99, 125, 234',
rpc: 'https://cloudflare-eth.com/',
namespace: 'eip155',
},
// Ref: https://docs.base.org/base-chain/quickstart/connecting-to-base#base-mainnet
'eip155:8453': {
name: 'Base',
rpc: 'https://mainnet.base.org',
},
};
@ -40,4 +37,5 @@ export const EIP155_CHAINS: Record<string, EIP155Chain> = {
export const EIP155_SIGNING_METHODS = {
PERSONAL_SIGN: 'personal_sign',
ETH_SEND_TRANSACTION: 'eth_sendTransaction',
WALLET_GET_CAPABILITIES: 'wallet_getCapabilities'
};