web3.js là gì

Hẳn những lập trình viên Dapp lâu năm lẫn cả những bạn beginer sẽ không quá xa lạ với thư viện web3.js dùng để tương tác với Ethereum blockchain. Còn với ethers.js thì hẳn chưa có quá nhiều người biết [mình cũng mới được biết và sử dụng trong thời gian gần đây]. Sau một thời gian sử dụng và làm việc với ethers.js, mình thấy nó có 1 ưu điểm muốn chia sẻ với mọi người qua bài viết ngày hôm nay.

1. Giới thiệu

Nói một cách đơn giản, ethers.js là một thư viện được viết bằng Javascript giúp Dapp tương tác với mạng Ethereum Blockchain.

Các tính năng nổi bật ethers.js gồm có

  • Giữ private key ở client một cách an toàn
  • Import và export JSON wallets
  • Import và export ví theo chuẩn BIP 39
  • Hỗ trợ ABI, ABIv2 và Human-Readable ABI
  • Kết nối với Ethereum nodes thông qua nhiều provider như JSON-RPC, INFURA, Etherscan, Alchemy, Cloudflare, MetaMask ...
  • Hỗ trợ ENS
  • Nhẹ [88kb khi nén và 284kb khi không nén]
  • Hỗ trợ TypeScript

Cài đặt và import

npm install --save ethers // Node.js const { ethers } = require["ethers"]; // ES6 hoặc TypeScript import { ethers } from "ethers"; // ES6 trên trình duyệt import { ethers } from "//cdn.ethers.io/lib/ethers-5.0.esm.min.js"; // Your code here...

2. Sử dụng

Kết nối

// Với Metamask const provider = new ethers.providers.Web3Provider[window.ethereum] // Kết nối qua JSON-RPC, mặc định là //localhost:8545 const provider = new ethers.providers.JsonRpcProvider['URL RPC'];

Query

// Truy vấn block number hiện tại provider.getBlockNumber[] // { Promise: 11792922 } // Truy vấn số dư ETH balance = await provider.getBalance["ethers.eth"] // { BigNumber: "2337132817842795605" } ethers.utils.formatEther[balance] // '2.337132817842795605' // If a user enters a string in an input field, you may need // to convert it from ether [as a string] to wei [as a BigNumber] ethers.utils.parseEther["1.0"] // { BigNumber: "1000000000000000000" }

Thao tác ghi dữ liệu vào blockchain

Để thực hiện các giao dịch làm thay đổi trạng thái của blockchain, giao dịch gửi đi phải được ký bằng private của 1 account. Cơ bản chúng ta sẽ có 2 cách là lấy tài khoản mặc định từ provider và import account vào bằng private key

Cách 1:

Mình chạy ganache-cli lên ở cổng 8545, ganache-cli sẽ tạo cho chúng ta 10 tài khoản.

const { ethers, Wallet } = require['ethers']; async function main[] { try { let provider = new ethers.providers.JsonRpcProvider[]; let signer = provider.getSigner[]; console.log[await signer.getAddress[]]; // Gửi 1 ETH const tx = await signer.sendTransaction[{ to: '0x999E01f04Bb155AbdFc4B2200D762800a758c469', value: ethers.utils.parseEther['1.0'] }]; console.log[parseInt[await signer.getBalance[]]]; } catch [err] { console.log[err]; } } main[];

Kết qủa in ra sẽ là tài khoản số 0 và balance của signer cũng giảm đi 1 ETH

0x58232B661A58112ab6e491918fddE2793D5Dd4Cc

Cách 2: Import tài khoản bên ngoài

const { ethers, Wallet } = require['ethers']; async function main[] { try { let provider = new ethers.providers.JsonRpcProvider[]; let signer = new Wallet['PRIVATE_KEY']; // Cách 1 thì signer đã được connect sẵn với provider, với cách này thì chúng ta cần connect tài khoản với provider để có thể thực thi giao dịch let wallet = signer.connect[provider]; } catch [err] { console.log[err]; } } main[];

Hoặc chúng ta có thể dùng thêm các phương thức khác như tạo random account, load từ mnemonic, ...

  • ethers.Wallet.createRandom[ [ options = {} ] ]
  • ethers.Wallet.fromEncryptedJson[ json , password [ , progress ] ]
  • ethers.Wallet.fromEncryptedJsonSync[ json , password ]
  • ethers.Wallet.fromMnemonic[ mnemonic [ , path , [ wordlist ] ] ]

Thao tác với contract

Để tương tác với bất kỳ contract nào trong Ethereum thì chúng ta đều cần 2 thông tin đó là địa chỉ contractABI

const { ethers, Wallet } = require['ethers']; async function main[] { try { let provider = new ethers.providers.JsonRpcProvider[]; let signer = new Wallet['PRIVATE_KEY']; let wallet = signer.connect[provider]; const contract = new ethers.Contract['ADDRESS', 'ABI', provider]; // Kết nối wallet với contract const withSigner = contract.connect[wallet]; } catch [err] { console.log[err]; } } main[];

1 ưu điểm của việc gọi hàm trong contract bằng ethers.js so với web3.js là không cần dài dòng thêm call[] hay send[] ở cuối.

const daiAddress = "dai.tokens.ethers.eth"; const daiAbi = [ // Some details about the token "function name[] view returns [string]", "function symbol[] view returns [string]", // Get the account balance "function balanceOf[address] view returns [uint]", // Send some of your tokens to someone else "function transfer[address to, uint amount]", // An event triggered whenever anyone transfers to someone else "event Transfer[address indexed from, address indexed to, uint amount]" ]; const daiContract = new ethers.Contract[daiAddress, daiAbi, provider]; daiContract.name[] // { Promise: 'Dai Stablecoin' } daiContract.symbol[] // { Promise: 'DAI' } balance = await daiContract.balanceOf["ricmoo.firefly.eth"] // { BigNumber: "198172622063578627973" } ethers.utils.formatUnits[balance, 18] // '198.172622063578627973'

Truy vấn lịch sử giao dịch [Query Historic Events]

Một tính năng khá hay ho của ethers.js mà mình chưa được mục kích sở thị trên web3.js đó là khả năng lọc, truy vấn lịch sử giao dịch. Chúng có thể dễ dàng tìm kiếm các giao dịch đầu vào, đầu ra theo điều kiện cho trước.

const { ethers, Wallet } = require['ethers']; async function main[] { try { let provider = new ethers.providers.JsonRpcProvider[]; let signer = new Wallet['PRIVATE_KEY']; let wallet = signer.connect[provider]; const myAddress = signer.getAddress[]; // ... const daiContract = new ethers.Contract[daiAddress, daiAbi, provider]; // Filter tất cả giao dịch gửi token DAI từ myAddress let filterFrom = await daiContract.filters.Transfer[myAddress, null]; // { // address: 'dai.tokens.ethers.eth', // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72' // ] // } // Filter tất cả giao dịch gửi token DAI cho myAddress let filterTo = await daiContract.filters.Transfer[null, myAddress]; // { // address: 'dai.tokens.ethers.eth', // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // null, // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72' // ] // } // Filter các giao dịch gửi DAI token từ myAddress trong khoảng block [9843470, 9843480] daiContract.queryFilter[filterFrom, 9843470, 9843480] // { Promise: [ // { // address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // args: [ // '0x8ba1f109551bD432803012645Ac136ddd64DBA72', // '0x8B3765eDA5207fB21690874B722ae276B96260E0', // { BigNumber: "4750000000000000000" } // ], // blockHash: '0x8462eb2fbcef5aa4861266f59ad5f47b9aa6525d767d713920fdbdfb6b0c0b78', // blockNumber: 9843476, // data: '0x00000000000000000000000000000000000000000000000041eb63d55b1b0000', // decode: [Function], // event: 'Transfer', // eventSignature: 'Transfer[address,address,uint256]', // getBlock: [Function], // getTransaction: [Function], // getTransactionReceipt: [Function], // logIndex: 69, // removeListener: [Function], // removed: false, // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', // '0x0000000000000000000000008b3765eda5207fb21690874b722ae276b96260e0' // ], // transactionHash: '0x1be23554545030e1ce47391a41098a46ff426382ed740db62d63d7676ff6fcf1', // transactionIndex: 81 // }, // { // address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // args: [ // '0x8ba1f109551bD432803012645Ac136ddd64DBA72', // '0x00De4B13153673BCAE2616b67bf822500d325Fc3', // { BigNumber: "250000000000000000" } // ], // blockHash: '0x8462eb2fbcef5aa4861266f59ad5f47b9aa6525d767d713920fdbdfb6b0c0b78', // blockNumber: 9843476, // data: '0x00000000000000000000000000000000000000000000000003782dace9d90000', // decode: [Function], // event: 'Transfer', // eventSignature: 'Transfer[address,address,uint256]', // getBlock: [Function], // getTransaction: [Function], // getTransactionReceipt: [Function], // logIndex: 70, // removeListener: [Function], // removed: false, // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', // '0x00000000000000000000000000de4b13153673bcae2616b67bf822500d325fc3' // ], // transactionHash: '0x1be23554545030e1ce47391a41098a46ff426382ed740db62d63d7676ff6fcf1', // transactionIndex: 81 // } // ] } } catch [err] { console.log[err]; } } main[];

Tổng kết

Trong giới hạn bài viết, mình đã cùng các bạn tìm hiểu cách sử dụng cơ bản ethers.js để tương tác với mạng Ethereum, chi tiết kỹ hơn và các hàm, tham số thì mọi người có thể dễ dàng tham khảo ở tài liệu chính thức từ ethers.js

Những gì web3.js làm được, gần như ethers.js cũng làm được và thậm chí có cú pháp gọn gàng hơn [gọi hàm trong contrat]. Ngoài trừ hàm web3.eth.net.isListening[] trên web3.js để kiếm tra kết nối đến provider có thành công hay không thì mình chưa tìm được hàm tương tự trên ethers.js

Combo Hardhat và ether.js đang được team mình sử dụng thay thế dần cho bộ đôi huyền thoại truffle và web3.js và hoạt động khá trơn tru. Các bạn có thể cân nhắc chuyển qua dùng thử bộ đôi trên

Tài liệu tham khảo

//docs.ethers.io/v5/

Blockchain và Web Development

HaDu Đặng
Follow
Oct 26, 2018 · 8 min read

Khi tôi bắt đầu học blockchain tôi đã rất bối rối về việc kết nối các trang web với blockchain. Ban đầu, để xây dựng một DAPP với blockchain, tôi đã sử dụng truffle, ganache, meta-mask và web3-js.

Bài viết này là về việc thiết lập một trang web để tương tác với blockchain [bao gồm cả code] và luồng kiến trúc của nó. Vì vậy, nếu bạn quan tâm đến việc tìm hiểu luồng kiến trúc khi blockchain tương tác với các trang web. Xin vui lòng tiếp tục :-]

Là người mới bắt đầu, tôi chỉ biết về phát triển web cơ bản như HTML, CSS, JS, NodeJS. Vì vậy, tôi không có nhiều lựa chọn khi chọn một truffle box để phát triển ứng dụng của mình.

Truffle là một công trình khung nổi tiếng với cách gọi con dao quân đội Thụy Sĩ của blockchain. Về cơ bản truffle là một template giúp chúng ta viết code solidity, test code, triển khai và tương tác code với front-end của web development.

Ví dụ: Nếu bạn đang làm việc trên một ứng dụng web bao gồm reactJs và blockchain. Truffle sẽ cung cấp một truffle box với một số mẫu tương tác của reactjs với blockchain, một thiết lập kiểm tra thích hợp cho code solidity của bạn và nhiều chức năng khác.

Ganache là một ứng dụng, thiết lập thử nghiệm kết nối mạng Ethereum với 10 tài khoản ban đầu, mỗi tài khoản có 100 ETH và được lập trình sẵn để chạy mining [đào] một cách tự động.

Dù Truffle box cung cấp các chức năng trực tiếp để bạn kết hợp Blockchain với web development, nhưng điều quan trọng là bạn phải hiểu được toàn bộ quy trình trong cách mà Blockchain tương tác với web development, vì sẽ không có nghĩa lý gì trong việc tạo ra một ứng dụng chỉ để tìm hiểu về Blockchain. Và bởi vì tất cả các công trình khung trong Truffle box làm cho mọi thứ dễ dàng hơn bằng việc cung cấp một sự khái quát để phát triển các ứng dụng blockchain. Nên tôi đã quyết định tìm ra cách mọi thứ hoạt động chính xác bằng cách tránh sử dụng các khung công cụ và công cụ này.

Chúng ta hãy xem cách chúng hoạt động.

Quan sát hình bên dưới. Toàn bộ lời giải thích của nằm trong hình này. Nó trình bày cách blockchain tương tác với các trang web.

Tôi sẽ giả thuyết rằng các bạn đã biết về những thứ sau đây trước khi bắt đầu bài tập phát triển này:

  • Sử dụng HTML, CSS, Java Script và nodeJS để phát triển các ứng dụng web cơ bản
  • Sử dụng Solidity để viết Smart Contract

Sử dụng Geth Console để tạo ra một vài tài khoản [cặp public và private key] và bắt đầu đào bằng cách tạo ra các Blockchain cục bộ. Nếu bạn muốn tìm hiểu cụ thể về vấn đề này, xem ở đây

  • web3Js được sử dụng để truy cập các chức năng và các biến trong code solidity từ trang web của tôi và thực hiện các giao dịch.

Lưu ý: Vui lòng xem qua blog ở trên. Vì toàn bộ blog này được dựa trên thiết lập geth từ blog ở trên.

Xem xét trường hợp ta có một trang web được lưu trữ trên máy chủ cục bộ và bây giờ ta cần phải thêm chức năng Blockchain vào trang web. Hãy tạo ra 1 trang web gọi hàm renderHelloWorld[] trong solidity và in kết quả trả về trên trang web.

Đây là Solidity Contract của helloWorld:

  • Bây giờ chúng ta đã có code solidity, và hãy biên dịch nó bằng cách dùng nodejs script tùy chỉnh sử dụng solcJS module
  • Biên dịch code solidity cho chúng ta ABI [giao diện nhị phân ứng dụng] và mã byte.

Giải thích về ABI và mã Byte:

Trong c ++ hoặc java, ta biên dịch mã và nhận mã nhị phân để thực thi . Mã byte cũng tương tự như vậy. Nó được sử dụng để triển khai smart contract trên Blockchain
ABI giúp web3Js trong việc giao tiếp với Blockchain. Vì code của chúng ta không biết cấu trúc chính xác của Blockchain. Cấu trúc ở đây là tên, input, output và loại hàm.

ABI nói với frontent code: bất cứ khi nào bạn nói chuyện với Blockchain, hãy sử dụng tôi để truy cập bất kỳ đối tượng cụ thể nào trong code solidity được triển khai trong Blockchain đó.

Nếu bạn muốn tìm hiểu thêm về ABI, hãy click vào đây

Giờ đã đủ lý thuyết, hãy tạo một vài ABI và mã Byte bằng cách sử dụng nodejs script. Vui lòng vào kho lưu trữ git-hub bên dưới và tải xuống mã.

abhilashreddyy/hello-world-webdev-with-blockchain

repo supporting my medium blog. Contribute to abhilashreddyy/hello-world-webdev-with-blockchain development by creating

github.com

Trong đó, bạn có thể thấy cấu trúc dữ liệu như sau:

compile.js biên dịch solidity code để tạo mã ABI và byte.

Biên dịch solidity code

Đoạn trích code trên nhập vào module solc [solidity compiler], được dùng để biên dịch code solidity. Đối số command line đầu tiên process.argv[2 diễn tả con đường của solidity code, đối số command line thứ 2 process.argv[3] diễn tả con đường của file output.

Đọc code solidity từ import và biên dịch:

Viết mã ABI và Byte được tạo ra vào files trong Hello_world folder

Hãy biên dịchcompile.js sử dụng commandnode .\compile.js hello_world.sol ..\hello_world .Giờ thì bạn sẽ có thể tìm thấy2 file helloWorld.abi & helloWorld.code trong hello_world folder.

Bây giờ chúng tôi đã biên dịch mã solidity của chúng tôi và có được mã ABI và Byte.

Để truy cập các chức năng và các biến trong solidity từ trang web, chúng ta sử dụng web3JS. Có 2 điều cần lưu ý:

  • Địa chỉ của Blockchain: Bởi vì chúng ta triển khai ứng dụng của mìnhtrong mạng chính cùng với smart contract khác. Vì vậy, về cơ bản chúng ta cần một cái gì đó để xác định duy nhất ứng dụng của chúng ta được triển khai, địa chỉ ở đây là một định danh duy nhất của contract được triển khai của chúng ta trên Blockchain
  • ABI [giao diện nhị phân ứng dụng] như được thảo luận trước đó

Tạo địa chỉ:

Bây giờ thì giao diện điều khiển của geth [go-ethereum] đã trở thành huyền thoại. Geth là một siêu anh hùng với nhiều sức mạnh siêu nhiên, và chúng ta sẽ sử dụng một số trong đó cho ứng dụng của mình:

  • Nó có thể tạo tài khoản, public key và private key với ETH giả
  • Nó có thể khởi tạo mạng blockchain thử nghiệm tại một cổng cụ thể trên máy chủ cục bộ dựa trên một khối genesis.
  • Nó có thể khai thác trên một mạng blockchain thể được triển khai trên một cổng cụ thể.
geth --identity LocalTestNode --rpc --rpcport 8080 --rpccorsdomain * --datadir ~/mychain/data/ --port 30303 --nodiscover --rpcapi db,eth,net,web3,personal --networkid 1999 --maxpeers 0 console

Đây là 1 node Ethereum cục bộ được thiết lập trên cổng 8080. Điều này có nghĩa là nhà cung cấp mạng ethereum của chúng ta đang chạy tại localhost: 8080.

Tạo một mạng Blockchain cục bộ được viết trong Blog này blog và bắt đầu mining sử dụng miner.start[]trong giao diện điều khiển geth. Hãy nhớ rằng blog này rất quan trọng trong việc hiểu những vấn đề về sau. Do đó, hãy đọc và thiết lập 1 blockchain với một vài ETH giả và bắt đầu giao diện điều khiển geth của bạn, bắt đầu mining như hướng dẫn trong blog này.

Giờ thì trở lại với phần địa chỉ, bây giờ hãy hiểu rõ compile_and_deploy/deploy.js để bắt đầu tạo ra địa chỉ bằng cách chạy đoạn code NodeJS này.

Nhập các mô-đun bắt buộc và đặt địa chỉ của nhà cung cấp. Hiện tại nhà cung cấp của chúng ta là giao diện điều khiển geth chạy trên localhost:8080

Đọc mã ABI và byte được tạo trong quá trình biên dịch và tạo một obbject để thực hiện một giao dịch mẫu và lấy địa chỉ.

Mở khóa tài khoản dùng để thực hiện giao dịch. Trong trường hợp này, ta sử dụng tài khoản đầu tiên của geth là:web3.eth.accounts[0].

Triển khai một smart contract mới , để triển khai, ta gửi biến code mã byte của smart contract, lượng gas tối đa và public key của tài khoản để thực hiện.

Trong mã bên dưới, chúng ta đang chờ nhận giao dịch và địa chỉ có thể được trả lại chỉ khi giao dịch của chúng ta được thêm thành công vào Blockchain.

Hãy xem tập tin deploy.js hoàn chỉnh

Biên dịch code trên trong terminalnode deploy.js. Bằng cách này, địa chỉ sẽ được hiển thị trên giao diện điều khiển.

Ở giai đoạn này, chúng ta có ABI, mã byte và địa chỉ nơi smart contract được triển khai. Cho phép thiết lập web3 để tương tác với smart contract.

Javascript code trong front-end

Đặt địa chỉ của nhà cung cấp web3, tạo đối tượng của lớp web3 và xác định tài khoản biến với public key

print_hello[] gọi hàm solidity renderHelloWorld, sử dụng tài khoản đã đề cập trước đó:

Đây là đoạn code cuối cùng, code này sử dụng ABI và địa chỉ của smart contract để gọi hàm hello world. Nếu tài khoản bị khóa thì nó sẽ nhắc mật khẩu, nếu không thì hàm hello world sẽ được gọi trực tiếp. Bảo toàn đoạn code ở hàm print_hello[] tương tác với solidity code.

Nếu mọi thứ ổn, bạn sẽ thấy hiển thị như sau trong trình duyệt web của bạn

Lưu ý: Bất kỳ lúc nào khi gọi 1 hàm hoặc thực hiện một giao dịch, hãy chắc chắn rằng node của bạn vẫn đang khai thác trên giao diện điều khiển Geth, bởi vì mọi giao dịch cần phải bao gồm trong đó Blockchain. Vì đó, mãi tới lúc ta bắt đầu khai thác, về cơ bản thì sẽ không có ai xác thực giao dịch của chúng ta và thêm vào Blockchain.

Xem lại bức ảnh dưới đây một lần nữa, sau khi đọc hết bài viết, bạn sẽ cảm thấy dễ tiếp thu hơn khi nhìn lại nó:

Kết luận: Với những người vừa mới học Blockchain, vui lòng đừng sử dụng toàn bộ công cụ, lối tắt, công trình khung để phát triển dự án của mình. Hãy học mọi thứ từ gốc rễ vì điều đó sẽ tốt cho sự phát triển lâu dài của bạn. Một nền móng tốt sẽ là cơ sở vững chắc cho một công trình đồ sộ!

Nguồn: abhilash reddy@Coinmock

Dịch: Lecle Việt Nam

ABOUT LECLE VIETNAM

LECLE is a global software blockchain technology house headquartered in South Korea with offices in the USA, Singapore, and Vietnam.

Founded in 2014, we received an initial investment from The Ventures and went through Plug and Plays accelerating program. Up to now, we have offered innovative solutions that are best suited to various customers in Korea. Since 2018, we have decided to shift our focus onto blockchain business while continuing to develop our outsourcing projects. Now we have been creating a blockchain platform for communities based EOS.

  • Website: //vn.lecle.co.kr/
  • Facebook: //www.facebook.com/LecleVietnam/
  • Twitter: //twitter.com/leclevn
  • Linkedin: //www.linkedin.com/company/lecle/

Video liên quan

Chủ Đề