diff --git a/basic/78-wallet-connect/README.md b/basic/78-wallet-connect/README.md new file mode 100644 index 000000000..8f15b2dc0 --- /dev/null +++ b/basic/78-wallet-connect/README.md @@ -0,0 +1,136 @@ +# WalletConnect + +## 简介 + +**WalletConnect** 是一个开放协议,允许用户将加密钱包安全地连接到去中心化应用(DApps),并支持多区块链网络的交互。用户只需扫描二维码或使用深度链接,即可与 DApp 进行交互,而无需暴露私钥,提供了安全、便捷的体验。 + +WalletConnect 通过加密消息在钱包与 DApp 之间传递信息,确保安全性。此外,WalletConnect 还支持多链和多会话连接,已广泛应用于 DeFi 和 NFT 平台等 Web3 领域。 + +## 功能 + +- **多链支持**:WalletConnect v2 支持跨多个区块链网络的连接,用户可以在单一会话中管理多链资产。 +- **安全消息传递**:所有通信均加密,确保钱包和 DApp 之间的交互安全。 +- **灵活的会话管理**:支持多会话,用户可以轻松在不同 DApps 和区块链网络之间切换。 +- **简单的集成方式**:DApp 和钱包开发者可以使用 WalletConnect SDK 快速集成,并支持广泛的钱包连接。 +- **跨平台兼容**:支持 iOS、Android 和 Web,确保用户在各种设备上都能访问。 + +## 安装 + +在 DApp 中使用 WalletConnect 时,可以安装 WalletConnect JavaScript 客户端库: + +```bash +npm install @walletconnect/client +``` + +对于钱包提供方,需要集成 WalletConnect SDK(提供 iOS、Android 和 Web 版本)。 + +## 使用 + +### 步骤 1:初始化 WalletConnect 客户端 + +在 JavaScript/TypeScript 代码中,导入并初始化 WalletConnect 客户端: + +```javascript +import WalletConnect from "@walletconnect/client"; +import QRCodeModal from "@walletconnect/qrcode-modal"; + +// 创建 WalletConnect 客户端实例 +const connector = new WalletConnect({ + bridge: "https://bridge.walletconnect.org", // 必填项 + qrcodeModal: QRCodeModal, +}); +``` + +### 步骤 2:检查连接并创建会话 + +如果没有已建立的连接,则创建一个新会话,提示用户连接钱包。 + +```javascript +// 检查是否已连接 +if (!connector.connected) { + // 创建新会话 + await connector.createSession(); +} + +// 监听会话事件 +connector.on("connect", (error, payload) => { + if (error) { + throw error; + } + + // 连接成功 + const { accounts, chainId } = payload.params[0]; +}); + +connector.on("session_update", (error, payload) => { + if (error) { + throw error; + } + + // 更新的账户和链ID + const { accounts, chainId } = payload.params[0]; +}); + +connector.on("disconnect", (error, payload) => { + if (error) { + throw error; + } + + // 已断开连接 +}); +``` + +### 步骤 3:发送交易 + +连接成功后,即可与区块链进行交互。例如,发送一笔交易: + +```javascript +// 设置交易详情 +const tx = { + from: accounts[0], // 用户地址 + to: "0xRecipientAddress", + value: "0xAmountInWei", // 金额,单位为 wei + data: "0x", // 可选数据 +}; + +// 发送交易请求 +const result = await connector.sendTransaction(tx); +``` + +## 从 WalletConnect v1 迁移到 v2 + +随着 WalletConnect v2 的发布,应用现已支持多链、多会话功能,并提供了更高的安全性。如果您仍在使用 WalletConnect v1,建议尽快迁移到 v2,以享受这些新功能的优势。 + + +## WalletConnect V1 与 V2 对比 + +WalletConnect V2 引入了多链、多会话支持和改进的协议设计,提升了用户体验和开发灵活性。以下是 V1 和 V2 主要功能的对比: + +| 功能 | WalletConnect V1 | WalletConnect V2 | +|---------------------------|-----------------------------------------|------------------------------------------------| +| **多链支持** | 不支持 | 支持多个区块链网络,允许跨链操作 | +| **多会话管理** | 不支持 | 支持多个会话同时存在,简化用户切换 | +| **连接效率** | 单一桥接服务器,容易过载 | 分布式桥接,降低延迟,提升连接稳定性 | +| **消息加密方式** | 使用 AES-256-CBC 加密 | 使用 X25519 和 Noise 协议的混合加密方案 | +| **会话恢复** | 每次需重新连接,体验不佳 | 支持持久会话,用户无需频繁扫码 | +| **会话控制和管理** | 简单控制,功能有限 | 提供更细致的权限控制和管理接口 | +| **拓展性** | 限制较多 | 模块化设计,支持不同应用场景的灵活扩展 | +| **链选择** | 无法在会话中切换链 | 用户可在单一会话中选择并切换多个区块链 | +| **连接稳定性** | 依赖于中心化桥接服务器 | 支持分布式和多节点桥接,增强连接稳定性 | +| **事件监听** | 支持基础事件监听 | 提供丰富的事件 API,简化多链事件处理 | +| **开发难度** | 较低 | 功能更强大,集成更复杂,需要额外的配置 | + +## 常见问题 + +- **二维码未显示**:请确保 `QRCodeModal` 正确导入并配置。 +- **连接问题**:请检查桥接 URL,默认桥接为 `"https://bridge.walletconnect.org"`,也支持自托管桥接。 + +## 资源 + +- [WalletConnect 文档](https://docs.walletconnect.com/) +- [WalletConnect GitHub](https://github.com/WalletConnect) +- [WalletConnect 博客](https://walletconnect.com/blog) + +## 许可证 + +本项目采用 MIT 许可证。 diff --git a/basic/78-wallet-connect/v2/basic-dapp-example/README.md b/basic/78-wallet-connect/v2/basic-dapp-example/README.md index 13a2bb4a1..e4e5b2cdb 100644 --- a/basic/78-wallet-connect/v2/basic-dapp-example/README.md +++ b/basic/78-wallet-connect/v2/basic-dapp-example/README.md @@ -1,11 +1,29 @@ +# Wallet Connect Demo -# Run the demo -``` -yarn -yarn start -``` +This demo showcases how to set up Wallet Connect with React, using `wagmi` and `web3modal` for blockchain connection and user authentication. -# Reference -- https://wagmi.sh/react/getting-started -- https://wagmi.sh/examples/connect-wallet +## Setup Instructions +1. **Install Dependencies** + ```bash + yarn + ``` + +2. **Create `.env` File** + + Create a `.env` file in the root of your project and add your Wallet Connect Project ID. You can obtain a Project ID by signing up at [Wallet Connect Cloud](https://cloud.walletconnect.com). + + ```plaintext + REACT_APP_PROJECT_ID=your_project_id_here + ``` + +3. **Start the Demo** + ```bash + yarn start + ``` + +## References + +For more details, see the following resources: +- [Wagmi Getting Started](https://wagmi.sh/react/getting-started) +- [Wagmi Connect Wallet Example](https://wagmi.sh/examples/connect-wallet) diff --git a/basic/78-wallet-connect/v2/basic-dapp-example/src/App.js b/basic/78-wallet-connect/v2/basic-dapp-example/src/App.js index a0af17099..afc1b007b 100644 --- a/basic/78-wallet-connect/v2/basic-dapp-example/src/App.js +++ b/basic/78-wallet-connect/v2/basic-dapp-example/src/App.js @@ -1,74 +1,45 @@ -//Ignore this -import Button from '@material-ui/core/Button'; +// Import core components and styles import './App.css'; -//WalletConnect basic imports -import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum' +// WalletConnect and Wagmi imports +import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum'; +import { Web3Modal, Web3Button, Web3NetworkSwitch } from '@web3modal/react'; +import { configureChains, createConfig, WagmiConfig } from 'wagmi'; +import { mainnet, arbitrum, polygon, localhost } from 'wagmi/chains'; -//WalletConenct UI components -import { Web3Modal } from '@web3modal/react'; -import { Web3Button } from '@web3modal/react'; -import { Web3NetworkSwitch } from '@web3modal/react'; -import { W3mQrCode } from '@web3modal/react'; +// Define chains and project ID +const chains = [mainnet, arbitrum, polygon, localhost]; +const projectId = process.env.REACT_APP_PROJECT_ID || "453f2a8e1d89bc35b8bc49eb781167b9"; - -//WalletConnect Hooks to controll the UI status -import { useWeb3Modal } from '@web3modal/react'; - -//Wagami imports -import { configureChains, createConfig, WagmiConfig } from 'wagmi' -import { mainnet, arbitrum, polygon, localhost} from 'wagmi/chains' - - -//Define which blockchains you want to connect -const chains = [mainnet, arbitrum, polygon,localhost]; -//Your project id, apply one at https://cloud.walletconnect.com -const projectId = process.env.REACT_APP_PROJECT_ID; - -//Wagmi client -const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]) +// Configure Wagmi client and Ethereum client +const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]); const wagmiConfig = createConfig({ autoConnect: true, connectors: w3mConnectors({ projectId, chains }), publicClient -}) -const ethereumClient = new EthereumClient(wagmiConfig, chains) +}); +const ethereumClient = new EthereumClient(wagmiConfig, chains); function App() { return (
- +
- ) + ); } - - -function HomePageExample1() { - - return (
- - - +function HomePage() { + return ( +
+ +
); } -function HomePageExample2() { - const { open, close } = useWeb3Modal(); - - return (
- -
- ); -} -export default App; \ No newline at end of file +export default App; diff --git a/basic/78-wallet-connect/v2/sign-example/README.md b/basic/78-wallet-connect/v2/sign-example/README.md index b7f053c80..afa768191 100644 --- a/basic/78-wallet-connect/v2/sign-example/README.md +++ b/basic/78-wallet-connect/v2/sign-example/README.md @@ -1,3 +1,29 @@ +# Wallet Connect Sign Demo -# Reference -- https://github.com/WalletConnect/web3modal-examples/blob/main/walletconnect-modal-sign-react/src/pages/index.jsx \ No newline at end of file +This demo showcases how to set up Wallet Connect with React, using `wagmi` and `web3modal` for blockchain connection and user authentication. + +## Setup Instructions + +1. **Install Dependencies** + ```bash + yarn + ``` + +2. **Create `.env` File** + + Create a `.env` file in the root of your project and add your Wallet Connect Project ID. You can obtain a Project ID by signing up at [Wallet Connect Cloud](https://cloud.walletconnect.com). + + ```plaintext + REACT_APP_PROJECT_ID=your_project_id_here + ``` + +3. **Start the Demo** + ```bash + yarn start + ``` + +## References + +For more details, see the following resources: +- [Wagmi Getting Started](https://wagmi.sh/react/getting-started) +- [Wagmi Connect Wallet Example](https://wagmi.sh/examples/connect-wallet) diff --git a/basic/78-wallet-connect/v2/sign-example/src/App.js b/basic/78-wallet-connect/v2/sign-example/src/App.js index dc9cd9c27..c6674b816 100644 --- a/basic/78-wallet-connect/v2/sign-example/src/App.js +++ b/basic/78-wallet-connect/v2/sign-example/src/App.js @@ -1,43 +1,44 @@ import { Button } from "@material-ui/core"; -import "./App.css"; - import { useState, useEffect } from "react"; import Client from "@walletconnect/sign-client"; import { Web3Modal } from "@web3modal/standalone"; +import "./App.css"; - -const web3Modal = new Web3Modal({ - projectId: process.env.REACT_APP_PROJECT_ID, - walletConnectVersion: 2 -}); - +// Initialize Web3Modal with WalletConnect Project ID +const projectId = process.env.REACT_APP_PROJECT_ID || "453f2a8e1d89bc35b8bc49eb781167b9"; +const web3Modal = new Web3Modal({ projectId, walletConnectVersion: 2 }); function App() { - const [client, setClient] = useState(); - const [session, setSession] = useState([]); - const [account, setAccount] = useState([]); + const [client, setClient] = useState(null); + const [session, setSession] = useState(null); + const [account, setAccount] = useState(""); + + useEffect(() => { + if (!client) { + createClient(); + } + }, [client]); - /** - * 1. Initialize a basic signing client , which is used to send messages. - */ - async function createClient() { + // Initialize the WalletConnect client + const createClient = async () => { try { const newClient = await Client.init({ - projectId: process.env.REACT_APP_PROJECT_ID, + projectId, relayUrl: "wss://relay.walletconnect.com", }); setClient(newClient); - await subscribeToEvents(newClient); - } catch (e) { - console.log(e); + subscribeToEvents(newClient); + } catch (error) { + console.error("Failed to create client:", error); } - } + }; - async function handleConnect() { - /** - * 2. Request to create a new session via sign client. - */ - if (!client) throw Error("Client is not set"); + // Connect to Wallet and create a session + const handleConnect = async () => { + if (!client) { + console.error("Client not initialized"); + return; + } try { const proposalNamespace = { eip155: { @@ -48,43 +49,29 @@ function App() { }; const { uri, approval } = await client.connect({ - requiredNamespaces: proposalNamespace, }); - /** - * 3. The session is created, display the session url in QRcode format via Web3Modal. - */ if (uri) { web3Modal.openModal({ uri }); - - /** - * 4. Now wait for wallet side to confirm the connection. - */ const sessionNamespace = await approval(); - /** - * 5. After the wallet accept the session, it will returns the wallet address it chooses. - */ - console.log('wallet confirmed') - console.log(sessionNamespace); onSessionConnected(sessionNamespace); web3Modal.closeModal(); } - } catch (e) { - console.log(e); + } catch (error) { + console.error("Failed to connect:", error); } - } + }; - async function onSessionConnected(session) { - try { - setSession(session); - setAccount(session.namespaces.eip155.accounts[0].slice(9)); - } catch (e) { - console.log(e); - } - } + // Handle session confirmation + const onSessionConnected = (sessionNamespace) => { + setSession(sessionNamespace); + setAccount(sessionNamespace.namespaces.eip155.accounts[0].slice(9)); + }; - async function handleDisconnect() { + // Disconnect session + const handleDisconnect = async () => { + if (!client || !session) return; try { await client.disconnect({ topic: session.topic, @@ -92,94 +79,74 @@ function App() { code: 6000, }); reset(); - } catch (e) { - console.log(e); + } catch (error) { + console.error("Failed to disconnect:", error); } - } - - async function subscribeToEvents(client) { - if (!client) - throw Error("Unable to subscribe to events. Client does not exist."); - try { - client.on("session_ping", (args) => { - alert('ping received'); - }); - - client.on("session_event", (args) => { - console.log("EVENT", "session_event", args); - }); + }; - client.on("session_update", ({ topic, params }) => { - console.log("EVENT", "session_update", { topic, params }); - const { namespaces } = params; - const _session = client.session.get(topic); - const updatedSession = { ..._session, namespaces }; - onSessionConnected(updatedSession); - }); + // Subscribe to WalletConnect events + const subscribeToEvents = (client) => { + client.on("session_ping", () => alert("Ping received")); + client.on("session_event", (args) => console.log("Event received:", args)); + client.on("session_update", ({ topic, params }) => { + console.log("Session updated:", params); + const updatedSession = { ...client.session.get(topic), namespaces: params.namespaces }; + onSessionConnected(updatedSession); + }); + client.on("session_delete", () => { + console.log("Session deleted"); + reset(); + }); + }; - client.on("session_delete", () => { - console.log("The user has disconnected the session from their wallet."); - reset(); - }); - } catch (e) { - console.log(e); + // Sign a message + const handleSend = async () => { + if (!account || !session) { + console.error("No account or session found"); + return; } - } - - /** - * 6. Since the session is online, now you can send message to the wallet to sign. - */ - async function handleSend() { - if (!account.length) throw Error("No account found"); try { - //args of personal_sign:https://docs.metamask.io/wallet/reference/personal_sign/ - const signParams = ["0x4d7920656d61696c206973206a6f686e40646f652e636f6d202d2031363931383133383031323731",account]; - - console.log(signParams); - + const message = "My email is john@doe.com - 1691813801271"; const result = await client.request({ topic: session.topic, chainId: "eip155:1", request: { method: "personal_sign", - params: signParams, + params: [message, account], }, }); - console.log("result is "+ result); - alert('sign result '+ result); - } catch (e) { - console.log(e); + alert("Signature: " + result); + } catch (error) { + console.error("Failed to sign:", error); } - } + }; + // Reset session and account state const reset = () => { - setAccount([]); - setSession([]); + setAccount(""); + setSession(null); }; - useEffect(() => { - if (!client) { - createClient(); - } - }, [client]); - return (
-

Sign Demo

- {account.length ? ( +

WalletConnect Sign Demo

+ {account ? ( <> -

{account}

- - +

Connected Account: {account}

+ + ) : ( - + )}
); } - -export default App; \ No newline at end of file +export default App;