Xây Dựng Aavegotchi DApp Bằng React + Web3
Xin chào mấy fen! Trong bài hướng dẫn, @Coyote sẽ hướng dẫn các bạn về quá trình xây dựng DApp (ứng dụng phi tập trung) có thể kết nối với blockchain của Aavegotchi. Bài hướng dẫn này sẽ sử dụng ngôn ngữ React và Typescript, tuy nhiên, đừng lo lắng nếu bạn không có kinh nghiệm lập trình React bởi bài hướng dẫn này sẽ sử dụng Web3 và Subgraph của Aavegotchi.
Bạn có thể xem đoạn code hoàn chỉnh ở đây: https://github.com/cgcbrown/aavegotchi-dex-tutorial
Bài gốc: https://dev.to/ccoyotedev/building-an-aavegotchi-dapp-using-react-web3-2noe
Web3 là gì?
Khi bạn lập trình ứng dụng trên blockchain, sẽ có hai hướng.
- Lập trình hợp đồng thông minh — viết code để có thể triển khai trên blockchain bằng ngôn ngữ lập trình Solidity.
- Phát triển website hoặc client có thể tương tác với blockchain thông qua hợp đồng thông minh.
Bởi hợp đồng thông minh của Aavegotchi đã sẵn sàng để được triển khai trên Matic Network nên điều duy cần bạn cần phải quan tâm là hoàn thành nhiệm vụ thứ hai. Thật sự thì bạn có thể xem Web3 là API của blockchain, trong đó bạn cần phải có địa chỉ hợp đồng thông minh, ABI và Provider.
Aavegotchi Subgraph là gì?
Subgraph là một GraphQL API được xây dựng bởi Pixelcraft trên The Graph, cho phép bạn lấy dữ liệu một các hiệu quả hơn từ blockchain của Aavegotchi mà không cần phải lo lắng về việc thiết lập Web3. Việc xem dữ liệu từ hợp đồng thông minh là rất cần thiết, tuy nhiên, việc này cũng có giới hạn. Bạn không thể gọi các hàm cần gas (như pet Aavegotchi của bạn) và một số dữ liệu mà bạn muốn vẫn chưa được tích hợp trên subgraph.
Xây Dựng Ứng Dụng
Trong bài hướng dẫn này, chúng ta sẽ xây dựng chương trình Aavegotchi Pokédẽ cho phép người dùng tìm kiếm và xem tất cả những Aavegotchi đã được triệu hồi. Kết quả sẽ nhìn giống thế này:
Cài đặt ban đầu
Trước khi bắt đầu, bạn cần phải đảm bảo rằng bạn đã cài đặt node≥10.16 và npm ≥5.6 trên máy của mình. Bạn cũng sẽ cần trình duyệt tương tích với Ethereum (nếu bạn đang dùng Chrome hoặc Firefox thì bạn sẽ cần cài đặt MetaMask trên ứng dụng mở rộng MetaMask) có kết nối với Matic Network.
Nếu đã hoàn thành thì hãy cùng nhau xây dựng ứng dụng React nhé. Để làm được điều này, hãy mở ứng dụng và chạy dòng code sau:
Những dòng code này sẽ tạo ra ứng dụng react cho bạn với tên gọi là aavegotchi-dex bên trong một đường dẫn vừa mới tạo ra gọi là tutorials. Hãy dùng --template typescript
để cấu hình React app nhằm sử dụng Typescript.
Sau khi hoàn tất việc cài đặt, trên màn hình của bạn hãy cho chạy:
Việc này sẽ khiến trình duyệt của bạn tự động mở lên và bạn sẽ nhìn thấy ứng dụng của mình chạy trên localhost:3000/. Nếu trình duyệt không mở thì hãy tự tay nhập http://localhost:3000/ vào thanh địa chỉ.
Giờ trên ứng dụng viết code mà bạn muốn (mình dùng Visual Studio code), hãy mở aavegotchi-dex
Trong src/App.tsx hãy thay thế tất cả các code bằng dòng code dưới đây và lưu lại:
Mình hình của bạn trên trình duyệt giờ sẽ trống. Tuy nhiên, nếu bạn mở công cụ lập trình trên trình duyệt, bạn nên thấy dòng chữ Hello fren trên console.
Đây không phải bài hướng dẫn lập trình React nên bạn đừng lo nếu bạn không hiểu mình đang làm gì. Tất cả những gì bạn cần biết là khi nào thì các thành phần được render, hook useEffect() được kích rồi lần lượt kích hoạt hàm fetchGotchi(). Đây là thời điểm mà chúng ta sẽ dùng logic để fetch logic của Aavegotchi từ trên blockchain.
Sử dụng Aavegotchi Subgraph
Giờ thì chúng ta đã kết thúc đoạn hướng dẫn nhàm chán, hãy cùng bắt đầu nhận data từ blockchain nhé!
Subgraph
Để khiến cuộc sống của chúng ta dễ dàng hơn, ta có thể dùng Aavegotchi Subgraph để kéo về danh sách dữ liệu của Aavegotchi. Một điểm thú vị về subgraph đó là bạn có thể mở playground lên để nhận query graphQL trước khi viết bất kỳ dòng code nào.
Ở bên phải có một Schema cho phép bạn nhìn thấy dữ liệu có thể fetch.
Subgraph có một giới hạn cứng vào khoảng 1000 đối với lượng dữ liệu mà bạn có thể fetch trong mỗi truy vấn. Đây không phải là vấn đề bởi với những ký do về vận hành chúng ta sẽ fetch 100, và sau đó, bạn có thể tăng mức độ fetch thêm nhiều dữ kiệu hơn khi bạn kéo xuống.
Giờ ta đã có thể chọn những dữ liệu mà ta sẽ nhận lại từ truy vấn. Với Aavegotchidex, ta biết ta muốn:
- name
- id
- collateral
- numeric traits
Chúng ta đang yêu cầu dữ liệu từ gotchiId thay vì id bởi gotchiId là một con số. Hãy thử yêu cầu bằng id và bạn sẽ thấy lý do tại sao việc này lại quan trọng.
Vậy tại sao ta cũng không thể lấy dữ liệu SVG? Ừ thì nếu bạn nhìn vào Aavegotchi Schema, bạn sẽ thấy rằng không hề có dữ liệu trả về dành cho SVG (vào lúc tác giả viết bài này). Đây là một ví dụ về nơi mà chúng ta sẽ sử dụng Web3 sau này.
Dùng truy vấn trong React
Giờ chúng ta đã có truy vấn nên ta sẽ dùng nó trong ứng dụng. Để được điều này, chúng ta cần cài đặt 2 gói, graphQL
vàgraphql-request
như trong ứng dụng khách graphQL của chúng ta. Vậy nên mở lên một cửa sổ mới và trong đường dẫn aavegotchi-dex, hãy chạy:
Một khi chúng đã được cài đặt, trong App.tsx hãy thêm những dòng code này vào:
Nếu bạn đang gặp lỗi runtime từ Typescript, hãy chạy npm install @types/react --dev
.
Nế bạn đã hoàn thành tất cả một cách chính xác, bạn sẽ thấy dữ liệu của aavegotchi được đang nhập vào console của bạn một cách chính xác khi bạn yêu cầu. Vật điều gì đang xảy ra.
Chuyện là khi hàm nhập vào yên cầu 2 arguments, hướng vào URL và query.Chúng ta sẽ nhận được URL từ thegraph.com dưới Queries (HTTP), việc này sẽ cho GraphQL yêu cầu nơi cần hướng tới.
Truy vấn là thứ mà chúng ta đã nhắc đến phía trên và giờ đã được chuyển thành một xâu. Sau đó chúng ta sẽ đợi chờ phản hồi trả về một cách không đồng bộ và đăng nhập nó vào console.
Giờ chúng ta đã biết yêu cầu của mình có thể hoạt động, chúng ta cần lưu nó ở dạng Apps để chúng ta có thể cho nó hiển thị lên UI. Để làm được điều này, chúng ta sẽ sự dụng hook React có tên useState(). Tuy nhiên, bởi vì chúng ta đang sử dụng Typscript nên chúng ta sẽ cài đặt lại nền tảng của mình trước.
Hãy tạo một folder mới dưới src gọi là types và bên trong nó tại ra một file index.ts. Giờ trên src/types/index.ts hãy điền vào những dòng code sau:
Mình xin nhắc lại là mình sẽ không đi sâu vào định nghĩa syntax của Typescript. Bạn chỉ cần hiểu rằng chúng ta đang copy những thứ mà chúng ta muốn phản hồi từ truy vấn của Subgraph sẽ hiện ra y như vậy.
Giờ bên cạnh App.tsx hãy nhập vào loại của chúng ta và dùng hook useState từ React, và chỉnh sử hàm fetchGotchis để lưu trữ phản hồi ỏ dạng:
Giờ ta đã lưu trữ dữ liệu xong, ta sẽ map chúng vào màn hình. Nếu bạn gọi ra bằng tay bên trong những thành phần của app trả lại hàm thì bạn sẽ thấy Typescript xuất hiện và đề nghị nội dung cho bạn. Nó cũng sẽ thông báo những đoạn gõ nhầm (thời gian bạn tiết kiệm được từ việc fix bug sẽ rất đang kể.
Chúng ta nên nhìn vào danh sách những cái tên trên màn hình.
Tuy nhiên, nhìn sẽ không hấp dẫn lắm. Vậy nên điều chúng ta cần làm tạo nên tổ hợp mới cho dành sách Aavegotchi, cho phép bạn chọn Aavegotchi.
Sắp xếp dữ liệu
Trong App.tsx, hãy thay thế JSX được trả về bằng những dòng code sau:
và bên trong App.css, hãy thay thế CSS bằng:
Bây giờ ta sẽ muốn tạo một danh sách thành phần của mỗi bài đăng về Aavegotchi cũng như những Aavegotchi đã được chọn.
Vậy nên trong src, hãy tạo một thư mục mới gọi là thành phần và bên trong tạo ra thêm hai thư mục nữa gọi là GotchiListing và SelectedGotchi và cả hai đều chứa một file index.tsx và một file styles.css
Folder của bạn sẽ có cấu trúc tương tự như bên dưới:
Render hình ảnh danh sách Aavegotchi
Bên trong GotchiListing/index.tsx hãy copy và paste nội dung sau đây:
Giao diện sẽ bảo người chỉnh sửa rằng thành phần của GotchiListing sẽ có những nội dung sau đây:
name — tên của Aavegotchi
Id — Id của Aavegotchi
collateralColor — Màu sắc chủ đạo của tài sản thế chấp (sẽ nói thêm)
selected — hàm boolean về việc gotchi có được chọn hay chưa
selectGotchi — hàm chuyển sự kiện click sang cho parent
Trong GotchiListing/styles.css điền vào:
Giờ bên trong App.tsx, hãy nhập in và render thành phần mới!
Ở trên những nội dung nhập khác hãy điền:
Và bên trong hàm div với className của gotchi-list, chúng ta sẽ map các thành phần của <GotchiListing /> cho mỗi Aavegotchi được chứa bên trong:
Nếu bạn gặp lỗi run time, bên trong SelectedGotchi/index.tsx
hãy gõ và lưu để sử tạm thời.
Khi làm như vậy, bạn sẽ có thể kéo thả để xem danh sách Aavegotchi.
Có thể bạn sẽ thấy rằng chúng ta không chuyển gotchi.collateral sang cho collateralColor
. Đó là do tài sản thế chấp và chúng ta trả lại không phải là hex code, mà là một ID độc nhất dành cho collecteral. Chúng ta sẽ phải dùng Web3 để gọi hợp đồng của Aavegotchi nhằm nhận lại màu sắc chính xác.
Chọn Aavegotchi
Giờ là là lúc để bạn điền vào hàm selection logic. Đầu tiên, hãy tạo ra câu lệnh khác trong App.tsx
dành cho bản dữ liệu Aavegotchi đã chọn:
Giờ đây, khi nhấp vào một bài đăng, chúng ta muốn đặt vị trí dữ liệu của gotchi được chọn vào trong câu lệnh. Và sau đó chúng ta có thể sử dụng thông tin đó để kiểm tra xem liệu gotchi được đăng có được chọn hay không:
Hay lắm! Khi bạn nhấp vào bài đăng bạn bạn sẽ thấy bài đăng nổi bật lên.
Giờ chúng ta sẽ thể hiện lựa chọn trên một tổ hợp mới gọi là SelectedGotchi. Bên trong SelectedGotchi/index.tsx hãy paste lại dòng code sau đây:
Trong mục SelectedGotchi/styles.css
:
Giờ chúng ta sẽ render thành phần mới trong App.tsx như sau:
Việc chúng ta đang làm là để kiểm tra xem có gotchi nào tồn tại trong mảng hay không, sau đó chúng ta sẽ render thành phần <SelectedGotchi />. Sau đó chúng ta sẽ dùng dữ liệu selectedGotchi để nhận được tên gotchi và đặt tính muốn hướng đến từ mảng gotchis.
Giờ bạn đã có thể chọn một gotchi và xem tên cũng như thuộc tính trong một thành phần mới!
Sử dụng Web3
Để xem thông tin trên blockchain, bạn cần 3 thứ:
- Provider
Provider là node mà bạn lựa chọn để giao tiếp với mạng Matic. Nếu bạn đã cài đặt MetaMask hoặc bạn đang dùng một trình duyệt tương thích với Ethereum thì nó sẽ giúp bạn trong việc giao tiếp
2. Địa chỉ hợp đồng thông minh
Đây chính là URL của hợp đồng thông minh được nhắm tới, bạn có thể tìm hiểu về nó bằng cách truy cập vào Aavegotchi Contract Github để tìm những hợp đồng này.
Chúng ta muốn hợp đồng kim cương của Aavegotchi có thể truy cập vào mọi khía cạnh khi cần.
3. ABI (giao diện nhị phân ứng dụng)
Đây là file JSON với nhiệm vụ mã hoá và giải hoá việc gọi hàm và từ hợp đồng Solidity. Chúng ta cũng có thể tải/copy từ Aavegotchi Github tại đây.
Một khi bạn đã xác định được tất cả công cụ bạn bần, chúng ta có thể bắt đầu ngay trong ứng dụng của mình.
Cài đặt hợp đồng
Ta bắt đầu bằng cách cài đặt web3:
Giờ trong folder src của ứng dụng, ta sẽ tạo ra một folder mới gọi là abi và trong đó ta sẽ tạo ra một file JSON gọi là diamondABI.json. Trong file này, chúng ta sẽ copy and paste cả vật thể JSON từ trang Github.
Trong App.tsx, ta có thể nhập vào:
Contract và AbiItem chỉ được dùng cho mục đích Typescript.
Chúng ta cũng sẽ set diamondAddress thành hằng số const bằng cách dùng địa chỉ mà chúng ta tìm thấy trong Aavegotchi Contract Github.
Giờ chúng ta đã có mọi thứ cần thiết để xem dữ liệu từ Aavegotchi Blockchain. Trong App() hãy tạo ra một hàm mới gọi là connectToWeb3() mà sẽ tạo ra hợp đồng của chúng ta và lưu nó trong câu lệnh.
Chúng ta muốn gọi hàm này khi trang web render lần đầu, do đó chúng ta để hàm useEffect()
sau hàmfetchGotchis()
.
Với provider chúng ta đã dùng Web3.givenProvider, nó sẽ tự động có sẵn nếu ta dùng trình duyệt tương thích với Ethereum. Nếu bạn không có những loại trình duyệt này, bạn có thể cài đặt node địa phương hoặc ở xa và dùng chúng như provider.
Gọi method từ hợp đồng
Giờ hợp đồng của đã được cài đặt nên chúng ta có thể bắt đầu gọi method từ đó. Bạn có thể chú ý rằng việc gọi method trên hợp đồng có thể yêu cầu gas. Tuy nhiên, việc này chỉ áp dụng cho những method phải thêm, xoá, hoặc thay đổi thông tin từ hợp đồng. Việc chỉ xem thông thin không yêu cầu việc thao túng hợp đồng và do đó sẽ hoàn toàn không tốn gas.
Method đầu ta mà ta muốn gọi chính là method có thể fetch từ màu sắc chủ đạo của tài sản thế chấp vậy nne chúng ta có thể chuyển màu chắc chính xác qua <GotchiListing />. Hãy ghé qua trang Aavegotchi Developer Documentation để tìm tên các method cho nhiều hợp đồng khác nhau. Chúng ta muốn hàm getCollateralInfo() như được đặt tại đây.
Bạn cũng sẽ tìm thấy tất cả các hàm hợp đồng cũng như output và input với ABI.
Chúng ta muốn fetch tất cả thông tin tài sản thế chấp chỉ từ một lần request , tuy nhiên, chúng ta cần đảm bảo rằng contract đã được cài đặt sẵn.
Để làm được điều này, hãy tạo một hook useEffect() trong App.tsx, với contract là một phần phụ thuộc.
Như bạn đã thấy, hàm fetchAavegotiCollaterals() sẽ chỉ được kích hoạt nếu contract đáng tin. Do đó khi mới lần đầu render, nó sẽ không được kích hoạt do contract chưa được cài đặt. Do đó bằng cách thêm contract thành một phần phụ thuộc, useEffect() giờ đây sẽ kích hoạt một hiệu ứng phụ với việc thay đổi contract.
Nếu mọi thứ được điền một cách chính xác, bạn sẽ thấy những tài sản thế chấp khác nhau đăng nhập trên console của trình duyệt.
Chúng ta có thể dùng output đã được đăng nhập tạo ra định nghĩa loại riêng của mình từ đó chương trình viết code của chúng ta sẽ biết chúng ta đang muốn gì. Vậy nên bên trong src/types/index.ts, hãy tạo ra một giao diện mới cho Collecteral như sau:
Trong App.tsx, hãy nhập giao diện mới của bạn và tạo ra câu lệnh mới giúp suy ra mảng tài sản thế chấp và trong hàm fetchAavegotchiCollaterals(), bạn có thể set câu lệnh:
Giờ chúng ta sẽ thấy tất cả tài sản thế chấp được lưu trữ trong câu lệnh, vậy hãy tạo ra một hàm với gotchi.collectera, tìm nó trong collecterals và trả lại primaryColor
.
Quá trình được thay thế đã định dạng một cách chính xác giá trị primaryColor thành mã hex mà CSS có thể dịch được.
Bài đăng gotchi giờ sẽ có màu thể hiện tài sản thế chấp của gotchi (nếu bạn muốn thực hiện một bước nữa, bạn có thể nhập vào hàm logic để hiện lên ico của tài sản thế chấp chính xác.
Thể hiện Aavegotchi SVG
Tất cả những việc còn lại ta cần làm là thể hiện hình ảnh Aavegotchi đã được lựa chọn. Đây chắc chắn là điều mình rất thích về Aavegotchi do tất cả những file SVG cả Aavegotchi đều được lưu trữ trên blockchain.
Nếu bạn trở lại trang Aavegotchi developer wiki, bạn có thể tìm method mong muốn, chính là getAavegotchiSvg(tokenId)
. Method này yêu cầu thông qua Aavegotchi như một công cụ đo lường.
Mỗi lần chúng ta chọn một gotchi chúng ta sẽ muốn render fie SVG trong thành phần SelectedGtochi. Do đó chúng ta cần một hook useEffect() mới, được kích hoạt mỗi khi selectedGotchi
, gotchis
hoặc contract
thay đổi:
Nếu bạn đi đến console.log(gotchiSVG), bạn sẽ thấy output là code HTML. Đây là dữ liệu SBG mà chúng ta muốn để vào code của mình.
Sau đó chúng ta sẽ chuyển dữ liệu SVG vào thành phần <SelectedGotchi /> như sau:
Trong thành phần SelectedGotchi, chúng ta cần thêm svg vào giao diện để có thể dùng chúng như một prop.
Vậy nên hãy vào src/components/SelectedGotchi/index.tsx, và thêm vào những thay đổi sau:
Nếu mọi thứ được thực hiện chính xác, bạn sẽ có thể thấy những Aavegotchi mà bạn chọn!
Do dữ liệu SVG được render trong DOM, nên bạn có thể dùng element inspector của trình duyệt để tìm ra tên lớp của những layer khác nhau trong SVG. Việc này rất hữu dụng nếu bạn muốn tạo hoạt ảnh hoặc giấu đi những lớp nhất định của Aavegotchi SVG.
Để những vật này hiện lên, chúng ta sẽ giấu đi SVG trong nền bằng cách paste SelectedGotchi/styles.css
:
Kết luận
Tốt lắm! Trong bài hướng dẫn này, bạn đã học được cách dùng Subgraph và Web3 để tạo ra một ứng dụng React phi tập trung!
Giờ bạn đã được trang bị kiến thức cần thiết để phát triển thâm cho ứng dụng. Bạn có thể thêm chức năng lăn vô tận để có thể tập hợp nhiều ứng dụng Aavegotchi hơn.. Hoặc một vài chức năng lọc hoặc sắp xếp giúp gửi truy vấn để subgraph nhằm fetch nhiều dữ liệu hơn chẳng hạn?
Nếu bạn có bất kỳ câu hỏi nào hoặc muốn xây dựng thêm nhiều DApps hơn nữa, hãy tham gia vào Aavegotchi discord community để được hỗ trợ tận tình!
Bạn có thể tìm bộ code đầy đủ ở đây:
https://github.com/cgcbrown/aavegotchi-dex-tutorial