Tuyệt vời! Bạn đã đến phần cuối cùng trong loạt hướng dẫn của tôi. Tôi hứa rằng đây là một chủ đề vô cùng thú vị: tạo một ứng dụng phi tập trung (dApp) full-stack bằng cách kết nối hợp đồng thông minh Hello World của bạn với một dự án frontend và tương tác với nó.
Khi đọc xong hướng dẫn này, bạn sẽ biết cách:
- Kết nối ví Metamask với dự án dApp của bạn
- Đọc dữ liệu từ hợp đồng thông minh của bạn bằng API Alchemy Web3
- Ký các giao dịch Ethereum bằng Metamask
Đối với dApp này, chúng ta sẽ sử dụng React làm framework frontend; tuy nhiên, điều quan trọng cần lưu ý là chúng ta sẽ không dành nhiều thời gian để phân tích các nguyên tắc cơ bản của nó, vì chúng ta chủ yếu tập trung vào việc mang chức năng Web3 vào dự án của mình.
Là một điều kiện tiên quyết, bạn nên có kiến thức cấp độ cơ bản về React — biết cách các component, props, useState/useEffect và gọi hàm cơ bản hoạt động. Nếu bạn chưa từng nghe nói về bất kỳ thuật ngữ nào trong số đó, tôi khuyên bạn nên xem hướng dẫn Giới thiệu về React này. Đối với những người học trực quan hơn, tôi đặc biệt khuyên bạn nên học bằng loạt video Hướng dẫn React Hiện đại Toàn diện của Net Ninja tuyệt vời này.
Nào hãy bắt đầu nội dung chính! 😎
Kết Hợp Web2 & Web3: Kết Nối Hợp Đồng Thông Minh với Dự Án Frontend
Bước 1: Sao chép các tệp khởi đầu
Đầu tiên, hãy truy cập kho lưu trữ github hello-world-part-four để lấy các tệp khởi đầu cho dự án này. Sao chép kho lưu trữ này vào môi trường cục bộ của bạn.
Bạn không biết cách sao chép kho lưu trữ? Hãy xem hướng dẫn này từ Github.
Khi bạn mở kho lưu trữ hello-world-part-four đã sao chép này, bạn sẽ nhận thấy rằng nó chứa hai thư mục: starter-files và completed.
- starter files chứa các tệp khởi đầu (về cơ bản là giao diện người dùng React) cho dự án này. Trong hướng dẫn này, chúng ta sẽ làm việc trong thư mục này, khi bạn tìm hiểu cách đưa giao diện người dùng này vào thực tế bằng cách kết nối nó với ví Ethereum của bạn và hợp đồng thông minh Hello World mà bạn đã phát hành trên Etherscan ở Phần 3.
- completed chứa toàn bộ hướng dẫn đã hoàn thành và có sẵn cho bạn như một tài liệu tham khảo nếu bạn gặp khó khăn.
Tiếp theo, hãy mở bản sao starter-files của bạn với trình soạn thảo mã nguồn yêu thích của bạn (tôi là người hâm mộ lớn của VScode) và sau đó điều hướng vào thư mục src của bạn:
Tất cả mã chúng ta sẽ viết sẽ nằm trong thư mục src. Chúng ta sẽ chỉnh sửa component HelloWorld.js và các tệp javascript util/interact.js để cung cấp chức năng Web3 cho dự án của chúng ta.
Bước 2: Kiểm tra các tệp khởi đầu
Trước khi chúng ta bắt đầu viết mã, điều cực kỳ quan trọng là chúng ta phải tìm hiểu những gì đã có trong các tệp khởi đầu.
Chạy dự án React của bạn
Hãy bắt đầu bằng cách chạy dự án React trong trình duyệt của chúng ta. Vẻ đẹp của React là khi chúng ta chạy dự án trong trình duyệt, bất kỳ thay đổi nào chúng ta lưu sẽ được cập nhật trực tiếp trong trình duyệt của chúng ta.
Để chạy dự án, hãy điều hướng đến thư mục gốc của thư mục starter files và sau đó chạy npm install trong thiết bị đầu cuối của bạn để cài đặt các phụ thuộc của dự án:
Sau khi cài đặt xong, hãy chạy npm start trong thiết bị đầu cuối của bạn:
Thao tác này sẽ mở http://localhost:3000/ trong trình duyệt của bạn, nơi bạn sẽ thấy giao diện frontend cho dự án của chúng ta. Nó sẽ bao gồm một trường (nơi để cập nhật thông báo được lưu trữ trong hợp đồng thông minh của bạn), nút “Connect Wallet” và nút “Update”.
Giao diện người dùng của bạn sẽ trông như thế nào
Nếu bạn thử nhấp vào nút “Connect Wallet” hoặc “Update”, bạn sẽ nhận thấy rằng chúng không hoạt động—đó là vì ta vẫn cần lập trình thêm chức năng của chúng! 🙂
Component HelloWorld.js
LƯU Ý: Hãy đảm bảo bạn đang ở trong thư mục starter-files và không phải thư mục completed!
Hãy quay lại thư mục src trong trình soạn thảo của chúng ta và mở tệp HelloWorld.js. Điều cực kỳ quan trọng là chúng ta phải hiểu mọi thứ trong tệp này, vì đây là component React chính mà chúng ta sẽ làm việc.
Ở đầu tệp này, bạn sẽ nhận thấy chúng ta có một số câu lệnh nhập cần thiết để chạy dự án của chúng ta, bao gồm thư viện React, các hook useEffect và useState, một số mục từ ./util/interact.js (tôi sẽ mô tả chúng chi tiết hơn ở đoạn sau!) và logo Alchemy.🧙
Tiếp theo, chúng ta có các biến trạng thái mà chúng ta sẽ cập nhật sau các sự kiện cụ thể.
Nếu bạn chưa bao giờ nghe nói về các biến trạng thái React hoặc các hook trạng thái? Tôi khuyên bạn hãy xem các tài liệu này.
Đây là ý nghĩa của mỗi biến:
- walletAddress- một chuỗi lưu trữ địa chỉ ví của người dùng
- status- một chuỗi lưu trữ một thông báo hữu ích hướng dẫn người dùng cách tương tác với dApp
- message- một chuỗi lưu trữ thông báo hiện tại trong hợp đồng thông minh
- new message- một chuỗi lưu trữ thông báo mới sẽ được ghi vào hợp đồng thông minh
Sau các biến trạng thái, bạn sẽ thấy năm hàm chưa được triển khai: useEffect, addSmartContractListener, connectWalletPressed và onUpdatePressed. Tôi sẽ giải thích những gì chúng làm bên dưới:
- useEffect: Đây là một hook React được gọi sau khi component của bạn được render. Vì nó có một prop mảng trống [] được truyền vào (xem dòng 4), nó sẽ chỉ được gọi khi component được render lần đầu tiên. Ở đây, tôi sẽ tải thông báo hiện tại được lưu trữ trong hợp đồng thông minh của mình, gọi các listener hợp đồng thông minh và ví của mình và cập nhật giao diện người dùng để phản ánh xem ví đã được kết nối hay chưa.
- addSmartContractListener: Hàm này thiết lập một listener để theo dõi sự kiện UpdatedMessages của hợp đồng HelloWorld của tôi và cập nhật giao diện người dùng khi thông báo được thay đổi trong hợp đồng thông minh của tôi.
- addWalletListener: Hàm này thiết lập một listener phát hiện các thay đổi trong trạng thái ví Metamask của người dùng, chẳng hạn như khi người dùng ngắt kết nối ví của họ hoặc chuyển đổi địa chỉ.
- connectWalletPressed: Hàm này sẽ được gọi để kết nối ví Metamask của người dùng với dApp của tôi.
- onUpdatePressed: Hàm này sẽ được gọi khi người dùng muốn cập nhật thông báo được lưu trữ trong hợp đồng thông minh.
Gần cuối tệp này, bạn sẽ thấy giao diện người dùng của component mà tôi đã làm.
Nếu bạn quét mã này cẩn thận, bạn sẽ nhận thấy nơi tôi sử dụng các biến trạng thái khác nhau của mình trong giao diện người dùng:
- Trên các dòng 6-12, nếu ví của người dùng được kết nối (tức là walletAddress.length > 0) thì nó sẽ hiển thị phiên bản rút gọn của walletAddress của người dùng trong nút có ID “walletButton;” nếu không, nó chỉ đơn giản nói “Connect Wallet.”
- Trên dòng 17, hiển thị thông báo hiện tại được lưu trữ trong hợp đồng thông minh, được ghi lại trong chuỗi message.
- Trên các dòng 23-26, tôi sử dụng một component được kiểm soát để cập nhật biến trạng thái newMessage khi đầu vào trong trường văn bản thay đổi.
Ngoài các biến trạng thái, bạn cũng sẽ thấy rằng các hàm connectWalletPressed và onUpdatePressed được gọi khi các nút có ID publishButton và walletButton được nhấp tương ứng.
Cuối cùng, hãy giải quyết component HelloWorld.js này.
Nếu bạn truy cập App.js, là component chính trong React đóng vai trò là container cho tất cả các component khác, bạn sẽ thấy component HelloWorld.js của chúng ta được chèn vào dòng 7.
Cuối cùng nhưng không kém phần quan trọng, hãy kiểm tra một tệp khác được cung cấp cho bạn, tệp interact.js.
Tệp interact.js
Vì chúng ta muốn tuân theo mô hình M-V-C, chúng ta sẽ muốn một tệp riêng biệt chứa tất cả các hàm của chúng ta để quản lý logic, dữ liệu và quy tắc của dApp của chúng ta, và sau đó có thể xuất các hàm đó sang frontend của chúng ta (component HelloWorld.js của chúng ta).
👆🏽Đây chính xác là mục đích của tệp interact.js của chúng ta!
Điều hướng đến thư mục util trong thư mục src của bạn và bạn sẽ nhận thấy tôi đã bao gồm một tệp có tên interact.js sẽ chứa tất cả các hàm và biến tương tác với hợp đồng thông minh và ví của tôi.
Bạn sẽ nhận thấy ở đầu tệp rằng tôi đã nhận xét đối tượng helloWorldContract. Ở bước sau trong bài hướng dẫn này, tôi sẽ bỏ nhận xét đối tượng này và khởi tạo hợp đồng thông minh trong biến này, sau đó tôi sẽ đưa nó vào component HelloWorld.js.
Tôi sẽ cho bốn hàm chưa được triển khai sau đối tượng helloWorldContract thực hiện những điều sau:
- loadCurrentMessage: Hàm này xử lý logic tải thông báo hiện tại được lưu trữ trong hợp đồng thông minh. Nó sẽ thực hiện một lệnh gọi đọc đến hợp đồng thông minh Hello World bằng API Alchemy Web3.
- connectWallet: Hàm này sẽ kết nối ví Metamask của người dùng với dApp của tôi.
- getCurrentWalletConnected: Hàm này sẽ kiểm tra xem tài khoản Ethereum đã được kết nối với dApp của tôi khi tải trang hay chưa và cập nhật giao diện người dùng của tôi cho phù hợp.
- updateMessage: Hàm này sẽ cập nhật thông báo được lưu trữ trong hợp đồng thông minh. Nó sẽ thực hiện một lệnh gọi ghi đến hợp đồng thông minh Hello World, vì vậy ví Metamask của người dùng sẽ phải ký một giao dịch Ethereum để cập nhật thông báo.
Nếu bạn đã hiểu tất cả những gì tôi nói phía trên, tiếp theo hãy tìm hiểu cách đọc từ hợp đồng thông minh!
Bước 3: Đọc từ hợp đồng thông minh của bạn
Để đọc từ hợp đồng thông minh của bạn, bạn cần thiết lập thành công:
- Kết nối API với chuỗi Ethereum
- Một phiên bản đã tải của hợp đồng thông minh của bạn
- Một hàm để gọi đến hàm hợp đồng thông minh của bạn
- Một listener để theo dõi các bản cập nhật khi dữ liệu bạn đang đọc những thay đổi của hợp đồng thông minh
Điều này có vẻ như rất nhiều bước, nhưng đừng lo lắng! Tôi sẽ hướng dẫn bạn cách thực hiện từng bước! 🙂
Thiết lập kết nối API với chuỗi Ethereum
Vậy bạn có nhớ ở Phần 2 của hướng dẫn này, tôi đã sử dụng khóa Alchemy Web3 để đọc từ hợp đồng thông minh của chúng ta không? Bạn cũng sẽ cần một khóa Alchemy Web3 trong dApp của mình để đọc từ chuỗi.
Nếu bạn chưa có, trước tiên hãy cài đặt Alchemy Web3 bằng cách điều hướng đến thư mục gốc của starter-files của bạn và chạy lệnh sau trong thiết bị đầu cuối của bạn:
Alchemy Web3 là một trình bao bọc xung quanh Web3.js, cung cấp các phương thức API nâng cao và các lợi ích quan trọng khác để giúp bạn phát triển web3 dễ dàng hơn. Nó được thiết kế để yêu cầu cấu hình tối thiểu để bạn có thể bắt đầu sử dụng nó trong ứng dụng của mình ngay lập tức!
Sau đó, cài đặt gói dotenv trong thư mục dự án của bạn, để chúng ta có một nơi an toàn để lưu trữ khóa API của mình sau khi chúng ta có được nó.
Đối với dApp của chúng ta, chúng ta sẽ sử dụng khóa API Websockets của mình thay vì khóa API HTTP của chúng ta, vì nó sẽ cho phép chúng ta thiết lập một listener dùng để phát hiện khi thông báo được lưu trữ trong hợp đồng thông minh thay đổi.
Sao chép url websockets
Khi bạn có khóa API của mình, hãy tạo tệp .env trong thư mục gốc của bạn và thêm url Alchemy Websockets của bạn vào đó. Sau đó, tệp .env của bạn sẽ trông như sau:
Bây giờ, chúng ta đã sẵn sàng thiết lập điểm cuối Alchemy Web3 của mình trong dApp của chúng ta! Hãy quay lại interact.js của chúng ta được lồng bên trong thư mục util của chúng ta và thêm mã sau vào đầu tệp:
Ở trên, trước tiên chúng ta đã nhập khóa Alchemy từ tệp .env của chúng ta và sau đó truyền alchemyKey của chúng ta cho createAlchemyWeb3 để thiết lập điểm cuối Alchemy Web3 của chúng ta.
Với điểm cuối này đã sẵn sàng, đã đến lúc tải hợp đồng thông minh của chúng ta!
Tải hợp đồng thông minh Hello World của bạn
Để tải hợp đồng thông minh Hello World của bạn, bạn sẽ cần địa chỉ hợp đồng và ABI của nó, cả hai đều có thể được tìm thấy trên Etherscan nếu bạn đã hoàn thành Phần 3 của hướng dẫn này.
Cách lấy ABI hợp đồng của bạn từ Etherscan
Nếu bạn đã bỏ qua Phần 3 của hướng dẫn này, bạn có thể sử dụng hợp đồng HelloWorld với địa chỉ 0x6f3f635A9762B47954229Ea479b4541eAF402A6A. ABI của nó có thể được tìm thấy tại đây.
Tệp contract-abi.json của bạn nên được lưu trữ trong thư mục src của bạn
Sau khi đã có địa chỉ hợp đồng, ABI và điểm cuối Alchemy Web3, chúng ta có thể sử dụng phương thức contract để tải một phiên bản của hợp đồng thông minh của chúng ta. Nhập ABI hợp đồng của bạn vào tệp interact.js và thêm địa chỉ hợp đồng của bạn.
Bây giờ chúng ta cuối cùng có thể bỏ bình luận biến helloWorldContract và tải hợp đồng thông minh bằng cách sử dụng điểm cuối AlchemyWeb3 của chúng ta:
Tóm lại, 12 dòng đầu tiên của interact.js của bạn bây giờ sẽ trông như thế này:
Bây giờ chúng ta đã tải hợp đồng của mình, chúng ta có thể triển khai hàm loadCurrentMessage!
Triển khai loadCurrentMessage trong tệp interact.js của bạn
Hàm này rất đơn giản. Giống như chúng ta đã làm trong Phần 2 của loạt bài hướng dẫn này, ở đây chúng ta sẽ thực hiện một lệnh gọi web3 async đơn giản để đọc từ hợp đồng của chúng ta. Hàm của chúng ta sẽ trả về thông báo được lưu trữ trong hợp đồng thông minh:
Cập nhật loadCurrentMessage trong tệp interact.js của bạn thành như sau:
Vì chúng ta muốn hiển thị hợp đồng thông minh này trong giao diện người dùng của chúng ta, hãy cập nhật hàm useEffect trong thành phần HelloWorld.js của chúng ta thành như sau:
Lưu ý, chúng ta muốn loadCurrentMessage của chúng ta được gọi một lần trong lần hiển thị đầu tiên của thành phần. Chúng ta sẽ sớm triển khai addSmartContractListener để tự động cập nhật giao diện người dùng sau khi thông báo trong hợp đồng thông minh thay đổi.
Trước khi chúng ta đi sâu vào trình nghe của chúng ta, hãy xem những gì chúng ta có cho đến hiện tại! Lưu các tệp HelloWorld.js và interact.js của bạn, sau đó truy cập http://localhost:3000/
Bạn sẽ nhận thấy rằng thông báo hiện tại không còn hiển thị “No connection to the network.” Thay vào đó, nó hiển thị thông báo được lưu trữ trong hợp đồng thông minh. Tuyệt vời!
Giao diện người dùng của bạn bây giờ sẽ phản ánh thông báo được lưu trữ trong hợp đồng thông minh.
Triển khai addSmartContractListener
Nếu bạn nhớ lại tệp HelloWorld.sol mà chúng ta đã viết trong Phần 1 của loạt bài hướng dẫn này, bạn sẽ nhớ rằng có một sự kiện hợp đồng thông minh gọi là UpdatedMessages được phát hành sau khi hàm update của hợp đồng thông minh của chúng ta được gọi (xem dòng 9 và 27):
Sự kiện hợp đồng thông minh là một cách để hợp đồng của bạn thông báo rằng một cái gì đó đã xảy ra (ví dụ là có một sự kiện) trên blockchain đến ứng dụng front-end của bạn, ứng dụng này có thể ‘lắng nghe’ các sự kiện cụ thể và thực hiện hành động khi chúng xảy ra.
Hàm addSmartContractListener sẽ đặc biệt lắng nghe sự kiện UpdatedMessages của hợp đồng thông minh Hello World của chúng ta và cập nhật giao diện người dùng để hiển thị thông báo mới.
Sửa đổi addSmartContractListener thành như sau:
Hãy phân tích những gì xảy ra khi trình nghe phát hiện một sự kiện:
Nếu xảy ra lỗi khi sự kiện được phát hành, chúng ta sẽ cập nhật giao diện người dùng thông qua biến trạng thái status của chúng ta.
Ngược lại, chúng ta sẽ sử dụng đối tượng data được trả về. data.returnValues là một mảng được lập tại 0, trong đó phần tử đầu tiên trong mảng lưu trữ thông báo trước đó và phần tử thứ hai lưu trữ thông báo được cập nhật. Tổng thể, khi một sự kiện thành công, chúng ta sẽ đặt chuỗi message của chúng ta thành thông báo được cập nhật, xóa chuỗi newMessage và cập nhật biến trạng thái status để phản ánh rằng một thông báo mới đã được xuất bản trên hợp đồng thông minh của chúng ta.
Cuối cùng, hãy gọi trình nghe của chúng ta trong hàm useEffect để nó được khởi tạo trong lần hiển thị đầu tiên của thành phần HelloWorld.js. Tổng thể, hàm useEffect của bạn sẽ trông như thế này:
Bây giờ chúng ta đã có thể đọc từ hợp đồng thông minh của mình, thật tuyệt nếu chúng ta có thể tìm hiểu cách ghi vào nó! Tuy nhiên, để ghi vào dApp của chúng ta, trước tiên chúng ta phải có một ví Ethereum được kết nối với nó.
Vì vậy, tiếp theo chúng ta sẽ giải quyết việc thiết lập ví Ethereum (Metamask) và sau đó kết nối nó với dApp của chúng ta!
Bước 4: Thiết lập ví Ethereum của bạn
Để ghi bất cứ điều gì vào chuỗi Ethereum, người dùng phải ký các giao dịch bằng khóa riêng của ví ảo của họ. Đối với hướng dẫn này, chúng ta sẽ sử dụng Metamask, một ví ảo trong trình duyệt được sử dụng để quản lý địa chỉ tài khoản Ethereum của bạn, vì nó làm cho quá trình giao dịch này dễ dàng cho người dùng cuối.
Nếu bạn muốn hiểu thêm về cách các giao dịch trên Ethereum hoạt động, hãy xem trang này từ Ethereum foundation.
Tải xuống Metamask
Bạn có thể tải xuống và tạo tài khoản Metamask miễn phí tại đây. Khi bạn đang tạo tài khoản, hoặc nếu bạn đã có tài khoản, hãy đảm bảo chuyển sang “Ropsten Test Network” ở phía trên bên phải (để chúng ta không phải giao dịch bằng tiền thật).
Thêm Ether từ Faucet
Để ký một giao dịch trên blockchain Ethereum, chúng ta sẽ cần một số Eth giả. Để nhận Eth, bạn có thể truy cập Ropsten faucet và nhập địa chỉ tài khoản Ropsten của bạn, sau đó nhấp vào “Send Ropsten Eth.” Bạn sẽ sớm thấy Eth trong tài khoản Metamask của mình!
Kiểm tra số dư của bạn
Để kiểm tra kỹ số dư của chúng ta có ở đó không, hãy thực hiện yêu cầu eth_getBalance bằng cách sử dụng công cụ soạn thảo của Alchemy. Hàm này sẽ trả về số lượng Eth trong ví của chúng ta. Sau khi bạn nhập địa chỉ tài khoản Metamask của bạn và nhấp vào “Send Request”, bạn sẽ thấy phản hồi như thế này:
LƯU Ý: Kết quả này là trong wei chứ không phải eth. Wei được sử dụng làm đơn vị nhỏ nhất của ether. Chuyển đổi từ wei sang eth là: \( 1 \, \text{eth} = 10^{18} \, \text{wei} \). Vì vậy, nếu chúng ta chuyển đổi 0xde0b6b3a7640000 sang thập phân, chúng ta nhận được \( 1^*10^{18} \) tương đương với \( 1 \, \text{eth} \).
- Phù!* Tiền giả của chúng ta đã có đủ!
Bước 5: Kết nối Metamask với giao diện người dùng
Bây giờ ví Metamask của chúng ta đã được thiết lập, hãy kết nối dApp của chúng ta với nó!
Hàm connectWallet
Trong tệp interact.js của chúng ta, hãy triển khai hàm connectWallet, sau đó chúng ta có thể gọi nó trong thành phần HelloWorld.js của chúng ta.
Hãy sửa đổi connectWallet thành như sau:
{” “} 🦊{” “} Bạn cần phải cài đặt ví Metamask vào trình duyệt, bản chất là một ví ảo trên mạng Ethereum.
Vậy chính xác thì đoạn mã nguồn dài ngoằng này dùng để làm gì?
Đầu tiên, nó kiểm tra xem window.ethereum có được kích hoạt trong trình duyệt của bạn không.
- window.ethereum* là một API toàn cầu được sử dụng bởi Metamask và các nhà cung cấp ví khác cho phép các trang web cần thông tin tài khoản Ethereum của người dùng. Nếu được chấp thuận, nó có thể đọc dữ liệu từ các blockchain mà người dùng đã kết nối và đề nghị người dùng ký các thông báo và giao dịch. Kiểm tra tài liệu Metamask để biết thêm thông tin!
Nếu window.ethereum không hiển thị, điều đó có nghĩa là Metamask chưa được cài đặt. Điều này dẫn đến việc một đối tượng JSON được trả về, trong đó địa chỉ trả về là một chuỗi rỗng và đối tượng JSX status thông báo rằng người dùng phải cài đặt Metamask.
Bây giờ nếu window.ethereum hiển thị, đó là khi mọi thứ trở nên thú vị.
Sử dụng vòng lặp try/catch, chúng ta sẽ thử kết nối với Metamask bằng cách gọi window.ethereum.request({ method: “eth_requestAccounts” }); Gọi hàm này sẽ mở Metamask trong trình duyệt, nơi người dùng sẽ được nhắc kết nối ví của họ với dApp của bạn.
Nếu người dùng chọn kết nối, method: “eth_requestAccounts” sẽ trả về một mảng chứa tất cả các địa chỉ tài khoản của người dùng đã kết nối với dApp. Tổng thể, hàm connectWallet của chúng ta sẽ trả về một đối tượng JSON chứa địa chỉ đầu tiên trong mảng này (xem dòng 9) và một thông báo trạng thái nhắc người dùng viết một thông báo vào hợp đồng thông minh.
Nếu người dùng từ chối kết nối, thì đối tượng JSON sẽ chứa một chuỗi rỗng cho địa chỉ trả về và một thông báo trạng thái phản ánh rằng người dùng đã từ chối kết nối.
Bây giờ chúng ta đã viết hàm connectWallet này, bước tiếp theo là gọi nó vào thành phần HelloWorld.js của chúng ta.
Thêm hàm connectWallet vào thành phần giao diện người dùng HelloWorld.js
Điều hướng đến hàm connectWalletPressed trong HelloWorld.js và cập nhật nó thành như sau:
Lưu ý cách hầu hết chức năng của chúng ta được trừu tượng hóa khỏi thành phần HelloWorld.js từ tệp interact.js? Điều này là để chúng ta tuân thủ mô hình M-V-C!
Trong connectWalletPressed, chúng ta chỉ đơn giản thực hiện một lệnh gọi await đến hàm connectWallet đã nhập và sử dụng phản hồi của nó, chúng ta cập nhật các biến status và walletAddress thông qua các hook trạng thái của chúng.
Bây giờ, hãy lưu cả hai tệp (HelloWorld.js và interact.js) và kiểm tra giao diện người dùng của chúng ta cho đến nay.
Mở trình duyệt của bạn trên trang **http://localhost:3000/**, và nhấn nút “Connect Wallet” ở phía trên bên phải của trang.
Nếu bạn đã cài đặt Metamask, bạn sẽ nhận được thông báo nhắc nhở kết nối ví của bạn với dApp của bạn. Chấp nhận lời mời để kết nối.
Bạn sẽ thấy rằng nút ví bây giờ cho thấy rằng địa chỉ của bạn đã được kết nối! Yasssss 💡
Tiếp theo, hãy thử làm mới trang… điều này thật kỳ lạ. Nút ví của chúng ta đang nhắc chúng ta kết nối Metamask, mặc dù nó đã được kết nối…
Vấn đề khi tải lại trang
Tuy nhiên, đừng lo lắng! Chúng ta có thể dễ dàng giải quyết điều đó (hiểu ý tôi chứ? 😊) bằng cách triển khai getCurrentWalletConnected, hàm này sẽ kiểm tra xem một địa chỉ đã được kết nối với dApp của chúng ta hay chưa và cập nhật giao diện người dùng tương ứng!
Hàm getCurrentWalletConnected
Cập nhật hàm getCurrentWalletConnected trong tệp interact.js thành như sau:
Mã này rất giống với hàm connectWallet mà chúng ta vừa viết trong bước trước.
Sự khác biệt chính là thay vì gọi phương thức eth_requestAccounts, phương thức này mở Metamask để người dùng kết nối ví của họ, ở đây chúng ta gọi phương thức eth_accounts, phương thức này chỉ đơn giản trả về một mảng chứa các địa chỉ Metamask hiện đang kết nối với dApp của chúng ta.
Sự khác biệt chính là thay vì gọi phương thức eth_requestAccounts, phương thức này mở Metamask và các thực thể khác, có hai loại thực thể khác nhau:
Sự khác biệt chính là thay vì gọi phương thức eth_requestAccounts (phương thức này sẽ mở Metamask để người dùng kết nối ví của họ), ở đây chúng ta gọi phương thức eth_accounts, phương thức này chỉ đơn giản trả về một mảng chứa các địa chỉ Metamask hiện đang được kết nối với dApp của chúng ta.
Lưu ý chúng ta sử dụng phản hồi của lệnh gọi getCurrentWalletConnected để cập nhật các biến trạng thái walletAddress và status.
Bây giờ bạn đã thêm mã này, hãy thử làm mới cửa sổ trình duyệt của chúng ta.
Nó đang hoạt động!!!!!
Tuyệt vời! Nút sẽ hiển thị rằng bạn đã kết nối và hiển thị bản xem trước địa chỉ ví được kết nối của bạn.
Triển khai addWalletListener
Bước cuối cùng trong thiết lập ví dApp của chúng ta là triển khai trình nghe ví để giao diện người dùng của chúng ta cập nhật khi trạng thái ví của chúng ta thay đổi, chẳng hạn như khi người dùng ngắt kết nối hoặc chuyển đổi tài khoản.
Trong tệp HelloWorld.js của bạn, hãy sửa đổi hàm addWalletListener như sau:
function addWalletListener() {
if (window.ethereum) {
window.ethereum.on("accountsChanged", (accounts) => {
if (accounts.length > 0) {
setWallet(accounts[0]);
setStatus(" Write a message in the text-field above.");
} else {
setWallet("");
setStatus(" Connect to Metamask using the top right button.");
}
});
} else {
setStatus(
<span>
{" "}
🌧 {" "}
You must install Metamask, a virtual Ethereum wallet, in your browser.
</span>
);
}
}
Tôi cá là bạn thậm chí không cần sự trợ giúp của chúng tôi để hiểu những gì đang xảy ra ở đây vào lúc này 😊, nhưng để đảm bảo đầy đủ, hãy nhanh chóng phân tích nó:
Đầu tiên, hàm của chúng ta kiểm tra xem window.ethereum có được kích hoạt không (tức là Metamask đã được cài đặt).
Nếu không, chúng ta chỉ cần đặt biến trạng thái status của chúng ta thành một chuỗi JSX nhắc người dùng cài đặt Metamask.
Nếu có, chúng ta thiết lập trình nghe window.ethereum.on(“accountsChanged”) trên dòng 3, trình nghe này lắng nghe các thay đổi trạng thái trong ví Metamask, bao gồm khi người dùng kết nối thêm tài khoản với dApp, chuyển đổi tài khoản hoặc ngắt kết nối tài khoản. Nếu có ít nhất một tài khoản được kết nối, biến trạng thái walletAddress sẽ được cập nhật thành tài khoản đầu tiên trong mảng accounts được trả về bởi trình nghe. Nếu không, walletAddress sẽ được đặt thành một chuỗi rỗng.
Cuối cùng nhưng không kém phần quan trọng, chúng ta phải gọi nó trong hàm useEffect của chúng ta:
Và đó là tất cả! Chúng ta đã hoàn thành việc lập trình tất cả các chức năng ví của chúng ta! Bây giờ hãy chuyển sang nhiệm vụ cuối cùng: cập nhật thông báo được lưu trữ trong hợp đồng thông minh của chúng ta!
Bước 6: Triển khai hàm updateMessage
Được rồi các bạn, chúng ta đã đến phần cuối cùng! Trong hàm updateMessage của tệp interact.js, chúng ta sẽ thực hiện các bước sau:
- Đảm bảo rằng thông báo chúng ta muốn phát hành hợp đồng thông minh của chúng ta là hợp lệ
- Ký giao dịch của chúng ta bằng Metamask
- Gọi hàm này từ thành phần frontend HelloWorld.js của chúng ta
Xử lý lỗi đầu vào
Thông thường, việc có một số xử lý lỗi đầu vào ở đầu hàm là hợp lý.
Chúng ta sẽ muốn hàm của chúng ta trả về sớm nếu không có tiện ích mở rộng Metamask được cài đặt, không có ví nào được kết nối (tức là địa chỉ được truyền vào là một chuỗi rỗng), hoặc thông báo là một chuỗi rỗng. Hãy thêm xử lý lỗi sau vào updateMessage:
Bây giờ chúng ta đã có xử lý lỗi đầu vào thích hợp, đã đến lúc ký giao dịch qua Metamask!
Ký giao dịch
Nếu bạn đã quen thuộc với các giao dịch Ethereum web3 truyền thống, mã chúng ta viết tiếp theo sẽ rất quen thuộc. Dưới mã xử lý lỗi đầu vào của bạn, hãy thêm mã sau vào updateMessage:
Hãy phân tích những gì đang xảy ra. Đầu tiên, chúng ta thiết lập các tham số giao dịch, trong đó:
- to chỉ định địa chỉ người nhận (hợp đồng thông minh của chúng ta)
- from chỉ định người ký giao dịch, biến address mà chúng ta đã truyền vào hàm của chúng ta
- data chứa lệnh gọi đến phương thức update của hợp đồng thông minh Hello World của chúng ta, nhận biến chuỗi message của chúng ta làm đầu vào
Sau đó, chúng ta thực hiện một lệnh await gọi window.ethereum.request, nơi chúng ta yêu cầu Metamask ký giao dịch. Lưu ý, ở dòng 11 và 12, chúng ta chỉ định phương thức eth của mình là eth_sendTransaction và truyền vào các tham số giao dịch (transactionParameters) của chúng ta.
Tại thời điểm này, Metamask sẽ mở trong trình duyệt và nhắc người dùng ký hoặc từ chối giao dịch.
- Nếu giao dịch thành công, hàm sẽ trả về một đối tượng JSON trong đó chuỗi JSX status nhắc người dùng kiểm tra Etherscan để biết thêm thông tin về giao dịch của họ.
- Nếu giao dịch thất bại, hàm sẽ trả về một đối tượng JSON trong đó chuỗi status thông báo thông điệp lỗi.
Tổng thể, hàm updateMessage của chúng ta sẽ trông như thế này:
Cuối cùng nhưng không kém phần quan trọng, chúng ta cần kết nối hàm updateMessage của chúng ta với thành phần HelloWorld.js.
Kết nối updateMessage với frontend HelloWorld.js
Hàm onUpdatePressed của chúng ta nên thực hiện một lệnh gọi await đến hàm updateMessage đã nhập và sửa đổi biến trạng thái status để phản ánh xem giao dịch của chúng ta có thành công hay không:
Nó rất gọn gàng và đơn giản. Và đoán xem… DAPP CỦA BẠN ĐÃ HOÀN THÀNH!!!
Hãy thử nghiệm nút “Update”!
Bước 7: Tạo dApp tùy chỉnh của riêng bạn
Wooooo, bạn đã đến bước cuối của hướng dẫn! Tóm tắt lại, tôi đã hướng dẫn bạn cách:
- Kết nối ví Metamask với dự án dApp của bạn
- Đọc dữ liệu từ hợp đồng thông minh bằng cách sử dụng API Alchemy Web3
- Ký các giao dịch Ethereum bằng Metamask
Bây giờ bạn đã được trang bị đầy đủ để áp dụng các kỹ năng từ hướng dẫn này để xây dựng dự án dApp tùy chỉnh của riêng bạn! Nếu bạn có bất kỳ câu hỏi nào, đừng ngần ngại liên hệ với tôi để được giúp đỡ.