Привет сообществу Stack Overflow!
Я разработал два отдельных приложения, используя Next.js и Web3: одно для MetaMask, а другое для TrustWallet. Однако я столкнулся с проблемой, когда попытка подключения к MetaMask приводит к запуску TrustWallet. Кроме того, после установки TrustWallet в мое локальное хранилище сохраняется много ненужных данных, чего не было, когда TrustWallet не был установлен.
Подробности выпуска:
Среда:
Поведение локального хранилища:
Странное поведение
Пример кода MetaMask и TrustWallet
import { useEffect, useState } from "react";
import Web3 from 'web3';
import { useLocalStorage } from "@/hooks/auth/useLocalStorage";
const TrustWalletOnlyApp = () => {
const [account, setAccount] = useLocalStorage("eth_trustwallet_account", null);
const [trustConnected, setTrustConnected] = useLocalStorage("eth_trustwallet_connected", false);
const [walletInstalled, setWalletInstalled] = useState(false);
const [balance, setBalance] = useState(null);
const [isClient, setIsClient] = useState(false);
console.info(walletInstalled, trustConnected, account, balance);
useEffect(() => {
setIsClient(true); // Marcar que estamos no cliente
const checkWalletAvailability = async () => {
if (typeof window.ethereum !== "undefined" && window.ethereum.isTrust) {
setWalletInstalled(true);
const accounts = await window.ethereum.request({ method: 'eth_accounts' });
if (accounts.length > 0) {
setAccount(accounts[0]);
getBalance(accounts[0]);
setTrustConnected(true);
} else {
setTrustConnected(false);
}
} else {
setWalletInstalled(false);
setTrustConnected(false);
}
};
checkWalletAvailability();
}, []);
const onWalletDisconnect = () => {
setAccount(null);
setBalance(null);
setTrustConnected(false);
window.localStorage.removeItem("eth_trustwallet_account");
};
const onConnectClick = async () => {
if (window.ethereum && window.ethereum.isTrust) {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
if (accounts.length > 0) {
setAccount(accounts[0]);
getBalance(accounts[0]);
setTrustConnected(true);
window.localStorage.setItem("eth_trustwallet_account", accounts[0]);
}
} else {
console.info("Trust Wallet is not installed");
}
};
const getBalance = async (account) => {
const web3 = new Web3(window.ethereum);
const balance = await web3.eth.getBalance(account);
setBalance(web3.utils.fromWei(balance, 'ether'));
};
if (!isClient) {
return null;
}
return (
<div style = {{ padding: 30 }}>
<h1>Trust Wallet Connect Test App</h1>
<div>
{trustConnected ? (
<div>
<h3>Trust Wallet Account</h3>
<div>Address: {account}</div>
<div>Balance: {balance} ETH</div>
</div>
) : (
<div>
<h3>No account connected</h3>
</div>
)}
</div>
<div style = {{ background: "lightgray", padding: 30, marginTop: 10 }}>
<button style = {{ height: 30, width: 180, marginLeft: 10 }} onClick = {onConnectClick}>
Connect Trust Wallet
</button>
</div>
<div>
<button onClick = {onWalletDisconnect}>Disconnect</button>
</div>
</div>
);
};
export default TrustWalletOnlyApp;
import { useState, useEffect } from 'react';
import Web3 from 'web3';
import { useLocalStorage } from "@/hooks/auth/useLocalStorage";
const MetamaskOnlyApp = () => {
const [account, setAccount] = useLocalStorage("eth_metamask_account", null);
const [metamaskConnected, setMetamaskConnected] = useLocalStorage("eth_metamask_connected", false);
const [metamaskInstalled, setMetamaskInstalled] = useState(false);
const [balance, setBalance] = useState(null);
const [isClient, setIsClient] = useState(false);
console.info(metamaskInstalled, metamaskConnected, account, balance);
useEffect(() => {
setIsClient(true); // Marcar que estamos no cliente
const checkMetamaskAvailability = async () => {
if (typeof window !== "undefined" && window.ethereum && window.ethereum.isMetaMask) {
setMetamaskInstalled(true);
const accounts = await window.ethereum.request({ method: 'eth_accounts' });
if (accounts.length > 0) {
setAccount(accounts[0]);
getBalance(accounts[0]);
setMetamaskConnected(true);
} else {
setMetamaskConnected(false);
}
} else {
setMetamaskInstalled(false);
setMetamaskConnected(false);
}
};
checkMetamaskAvailability();
}, []);
const onWalletDisconnect = () => {
setAccount(null);
setBalance(null);
setMetamaskConnected(false);
window.localStorage.removeItem("eth_metamask_account");
};
const onConnectClick = async () => {
if (window.ethereum && window.ethereum.isMetaMask) {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
if (accounts.length > 0) {
setAccount(accounts[0]);
getBalance(accounts[0]);
setMetamaskConnected(true);
window.localStorage.setItem("eth_metamask_account", accounts[0]);
}
} else {
console.info("MetaMask is not installed");
}
};
const getBalance = async (account) => {
const web3 = new Web3(window.ethereum);
const balance = await web3.eth.getBalance(account);
setBalance(web3.utils.fromWei(balance, 'ether'));
};
if (!isClient) {
return null;
}
return (
<div style = {{ padding: 30 }}>
<h1>MetaMask Connect Test App</h1>
<div>
{metamaskConnected ? (
<div>
<h3>MetaMask Account</h3>
<div>Address: {account}</div>
<div>Balance: {balance} ETH</div>
</div>
) : (
<div>
<h3>No account connected</h3>
</div>
)}
</div>
<div style = {{ background: "lightgray", padding: 30, marginTop: 10 }}>
<button style = {{ height: 30, width: 180, marginLeft: 10 }} onClick = {onConnectClick}>
Connect MetaMask
</button>
</div>
<div>
<button onClick = {onWalletDisconnect}>Disconnect</button>
</div>
</div>
);
};
export default MetamaskOnlyApp;
Вывод локального хранилища:
Перед установкой TrustWallet:
{
"eth_metamask_account": "0xb5c6a848...6e49475d11",
"eth_metamask_connected": "true"
}
После установки TrustWallet (один и тот же адрес для обоих кошельков, адрес TrustWallet):
{
"binance-http://localhost:3000": "{}",
"eth_trustwallet_account": "0xb5c6a84.....A7cF6E49475d11",
"eth_metamask_account": "0xb5c6a84......A7cF6E49475d11",
"ethereum-http://localhost:3000": "{\"address\":\"0xb5c6a848f23d92d67e68b4fc1da7cf6e49475d11\",\"chainId\":\"0x1\",\"networkVersion\":1}",
"eth_trustwallet_connected": "true",
"trust:cache:timestamp": "{\"timestamp\":1717892710717}",
"eth_metamask_connected": "true",
"loglevel": "SILENT"
}
Вопросы:
Будем очень признательны за любые идеи или решения. Спасибо!
Обнаружение нескольких поставщиков может стать проблемой из-за конфликтов.
EIP-6963 призван решить эту проблему.
const [metaMaskProvider, setMetaMaskProvider] = useState(null)
const [trustWalletProvider, setTrustWalletProvider] = useState(null)
useEffect(() => {
window.addEventListener("eip6963:announceProvider", (event) => {
const provider = event.detail.provider
if (provider.isMetaMask) {
setMetaMaskProvider(provider)
}
if (provider.isTrust) {
setTrustWalletProvider(provider)
}
})
window.dispatchEvent(new Event("eip6963:requestProvider"))
}, [])
const isMetaMaskInstalled = !!metaMaskProvider
const isTrustWalletInstalled = !!trustWalletProvider