Cách đọc Smart Contract để hiểu mục đích giao dịch trên ví
37 mins read

Cách đọc Smart Contract để hiểu mục đích giao dịch trên ví

Trong bài viết hôm nay mình chủ yếu hướng dẫn cách đọc code trong một địa chỉ contract bất kỳ từ đó anh em có thể rút ra được insight và tìm hiểu xem liệu địa chỉ contract này có thể làm những gì với tài sản của chúng ta khi được cấp quyền (xác nhận giao dịch trên ví metamask).

Ở cuối của bài viết này mình sẽ giới thiệu đến anh em trong group 3 công cụ (extension trên Chrome) hỗ trợ đọc smart contract để hiểu thông tin giao dịch và cảnh báo cho anh em. Đây là 3 công cụ giúp mình giảm thiểu tối đa thời gian ngồi check thủ công, đặc biệt vì mình săn retroactive nên đa số các tương tác với ví đều là các giao dịch với smart contract của dự án mới nên thật sự mình thấy chúng rất hữu dụng. Tuy nhiên cần lưu ý rằng còn khá nhiều nền tảng mà các công cụ này chưa hoạt động được. Dù sao anh em vẫn cần hiểu bản chất và cách đọc smart contract, sau đó dùng thêm các công cụ hỗ trợ sẽ là tốt nhất.

  • Mình cũng xin lưu ý rằng bản thân mình không hề có nền tảng về kỹ thuật từ trước. Tất cả chỉ là những thông tin mà mình tự nghiên cứu tìm hiểu ở các nguồn tham khảo khác nhau nên có thể có nhiều điểm chưa hiểu đúng hoặc chưa sâu. Mình hi vọng anh em đọc với tâm thế tham khảo, nếu anh em nào chuyên môn có thể giúp mình để lại bình luận góp ý ở bên dưới phần comment.
  • Bài viết này sử dụng rất nhiều hình ảnh vì mình không tiện chép code ra. Anh em chịu khó đọc kết hợp xem hình để có thể dễ hình dung hơn, trong ảnh mình đã có chú thích đầy đủ.
I. LỢI ÍCH

Với một vài thuật ngữ trong solidity kết hợp với công cụ hỗ trợ là anh em hoàn toàn có thể hiểu được ý đồ lập trình của đội dev dự án, điều này có thể mang lại các lợi ích dưới đây:

  • Hiểu được cách vận hành và ý nghĩa của hàm đã được lập trình trong smart contract.
  • Xác định được các lỗ hổng bảo mật & khả năng phát hiện sớm các dự án scam thông qua các hàm lệnh mang ý đồ xấu —> bảo vệ tài sản cá nhân.
  • Có lợi thế trong đầu tư (khả năng đọc các hợp đồng mới được triển khai có thể mang lại kết quả đầu tư tốt hơn).

Trong bài này mình sẽ hướng dẫn anh em cách sử dụng một số công cụ để hỗ trợ quá trình đọc smart contract, đa số các công cụ này đều rất phổ biến:

  • Sử dụng metamask để đọc chi tiết về một giao dịch.
  • Sử dụng Blockscan (etherscan, bscscan,…) để đọc code trong smart contract.
  • Xác định một giao dịch mang lại gì? Phát hiện nguy cơ giao dịch muốn s.cam tiền của chúng ta?
  • Giới thiệu một số tools đọc smart contract mình thường dùng.

Bởi vì đây là kỹ năng thế nên mình sẽ không trình bày theo dạng lý thuyết mà sẽ đi vào ví dụ cụ thể. Anh em có thể rút ra các bài học về thao tác thực hiện và bản chất ý nghĩa của nó, từ đó áp dụng vào các dự án khác.

II. THỰC HÀNH

A. TƯƠNG TÁC VÍ VỚI DỰ ÁN OLYMPUS DAO

Truy cập vào trang web của Olympus DAO, tại đây chúng ta có thể thực hiện lệnh “Zap-Stake” để chuyển đổi ETH hoặc OHM thành gOHM. Màn UI của Olympus DAO trông khá giống với các DEX khác khiến chúng ta có khuynh hướng lầm tưởng rằng lệnh “Zap-Stake” này chỉ swap từ ETH sang gOHM. Nhưng thực sự, giao dịch này thực hiện mua OHM bằng ETH trong ví của anh em và sau đó stake số OHM vừa mua được rồi nhận về gOHM chỉ bằng đúng một lần giao dịch (một lần xác nhận trên ví).

Hình 1: Trang UI của dự án Olympus DAO

Sau khi click vào “zap-stake” thì một cửa sổ pop-up của ví metamask sẽ hiện lên (với điều kiện anh em đã cài sẵn metamask) yêu cầu xác nhận giao dịch. Tại thời điểm này bởi vì không có lệnh xác nhận chữ ký ví (lệnh approve) nên nếu không đọc kỹ giao dịch chúng ta sẽ không biết smart contract có thể làm gì với tài sản trong ví của chúng ta. Câu hỏi cần đặt ra là tài sản của chúng ta sẽ đi đâu? Và chúng ta nhận lại cái gì sau khi thực thi lệnh giao dịch? Giao dịch này có thực sự an toàn?

Hình 2: Pop-up trên ví metamask yêu cầu xác nhận giao dịch khi nhấn nút “Zap-Stake”

Ở bước này chúng ta tin tưởng vào OHM vì đây là một dự án có danh tiếng và uy tín. Nhưng điều gì sẽ xảy ra nếu đây không phải là smart contract từ một Dapp uy tín mà là smart contract của một dự án mới? Nếu chỉ nhìn vào cửa sổ pop-up này thì làm sao chúng ta có thể đảm bảo rằng dự án không có ý đồ đánh cắp tài sản của mình.

Hình 3: Thông tin CONTRACT INTERACTION trên cửa sổ ví metamask

Vậy thì bây giờ, bước đầu tiên là anh em sẽ chuyển hướng sang etherscan để kiểm tra giao dịch này. Ngay trên cửa sổ pop-up của ví metamask, anh em click vào dòng địa chỉ contract màu xanh dương trong hộp cạnh dòng chữ “CONTRACT INTERACTION”.

Hình 4: Thông tin CONTRACT INTERACTION

Một hộp thông tin về mã contract mà chúng ta sắp tương tác hiển thị, tiếp tục click vào dòng chữ “view on block explorer” để chuyển hướng sang etherscan hoặc có thể copy dòng contract này và dán vào thanh tìm kiếm trên etherscan cũng được.

Trên etherscan chúng ta cần thực hiện bước kiểm tra cơ bản xem liệu contract đã được verified hay chưa. Nếu đã được verified thì tiếp tục các bước tiếp theo, nếu chưa thì hãy huỷ lệnh giao dịch ngay lập tức. Đừng bao giờ tương tác với địa chỉ contract chưa được xác minh!

Nếu địa chỉ contract mà chúng ta chuẩn bị tương tác (xác nhận giao dịch trên ví) chưa được xác minh, chúng ta cần có ABI để truy cập vào thì mới xem được mã code của contract đó. Cần lưu ý rằng ABI sẽ không có sẵn nếu người triển khai hợp đồng không cung cấp nó ngay từ đầu. Tức là chúng ta sẽ không thể xem được mã code của địa chỉ contract này thế nên nếu tiếp tục xác nhận giao dịch, rất có thể chúng ta sẽ phải chịu hậu quả bị đánh cắp tài sản trong ví.

Hình 5: Check xem contract có được xác minh hay chưa

Để biết một contract đã được verified hay chưa chúng ta chỉ cần quan sát ngay trong etherscan tại mục “contract” đã có dấu tick xanh hay chưa. Nếu có tick xanh tức là địa chỉ contract đã được verified và bước đầu vượt qua vòng kiểm duyệt đầu tiên, lúc này chúng ta cũng có thể soi được code trong contract này trên etherscan.

Kéo xuống ngay bên dưới phần source code là một phần hiển thị toàn bộ mã code trong contract mà chúng ta chuẩn bị tương tác. Dễ dàng nhận thấy rằng contract này bao gồm rất nhiều tệp “.sol”, một trong số chúng có chứa chức năng “zap-stake” dựa vào nút zap-stake thể hiện ở trên UI của Olympus. Bởi vì chúng ta vừa tương tác với contract của Olympus thông qua chức năng “zap-stake” này nên đây sẽ là phần cần kiểm tra trước khi thực hiện xác nhận giao dịch trên ví metamask.

Tuy nhiên đối với nhiều trường hợp dự án khi chúng ta tương tác thì chức năng không rõ ràng, trong khi đó nếu mò hết cả mớ tệp “.sol” và các chức năng trong code thì thật sự là ác mộng. Thế thì chúng ta cần một cách để tìm ra chức năng đó, ở đây mình sử dụng ví metamask và soi code trong etherscan (mình đã đề cập sơ qua cách tìm function trong bộ code của smart contract trong bài check hành vi mint/burn token rồi).

Cách thực hiện cụ thể như sau:

Hình 6: Quay lại cửa sổ giao dịch của ví metamask, chọn tab “DATA” để xem thông tin các tham số giao dịch cơ bản. Chúng ta có thể hiểu được những từ khoá (từ khoá bằng Tiếng Anh nên anh em nào không biết chỉ cần google dịch ra là được) có ý nghĩa gì với giả định rằng chúng được đặt tên dựa theo mục đích.

Hình 7: Tất nhiên việc giả định là chưa thoả mãn thế nên chúng ta cần quay lại trang etherscan để kiểm tra kỹ hơn. Sử dụng các từ khoá trong mục DATA và nhập vào thanh tìm kiếm trong etherscan để tìm hàm chức năng trong code.

Ở đây mình quan tâm từ khoá “swapTarget” nên mình sẽ tìm bằng từ khoá này. Chúng ta nhận thấy rằng ở tệp “File 3 of 21: OlympusZapV2.sol” chứa một hàm có tên “_ZapStake ()” với các tham số thể hiện theo cùng một thứ tự giống hệt với thông tin trong mục “DATA” trên cửa sổ ví vừa xem.

—> Đây khả năng cao là hàm chức năng khi chúng ta nhấn nút “Zap-Stake” trên Olympus mà khi xác nhận trên ví thì nó sẽ được thực hiện.

Hình 8: Cách đọc một số thông tin chi tiết trong hàm chức năng:

  • external” tức là chức năng này chỉ được thực hiện bởi một tài khoản bên ngoài contract
  • payable” tức là chức năng này có thể nhận ETH/OHM (đúng với giao diện trên OHM chỉ có 2 loại tài sản này)
  • Khi chức năng này được thực thi, nó sẽ gọi các chức năng nội bộ (internal functions-chức năng chỉ có thể được gọi từ trong contract) khác đi sau
  • returns” tức là trả về một giá trị bằng số lượng được gọi là OHMrec (số lượng gOHM mà chúng ta nhận lại sau khi thực hiện chức năng zap-stake)
  • Và các dòng bắt đầu bằng “//” là bình luận của Dev giúp chúng ta hiểu mục đích của mã code bên dưới khi thực thi.

Các lệnh gọi hàm chức năng trong Solidity được thực hiện theo thứ tự. Do đó, để hiểu hàm “_zapstake ()” làm gì, chúng ta nên mổ xẻ nội dung của nó bắt đầu từ hàm đầu tiên.

Dòng đầu tiên gọi một hàm bên trong có tên “_pulltokens ()” với các inputs như sau “(fromToken, amountIn, referral, true)”. Có một vấn đề đó là không thể truy cập hàm chức năng “_pulltokens ()” trong trong tệp “OlympusZapV2.sol”. Điều này có nghĩa là hàm được gọi không bắt nguồn từ tệp .sol này mà được nhập (import) từ một tệp khác.

Hình 9: Kéo lên trên cùng của tệp “OlympusZapV2.sol” chúng ta sẽ tìm thấy một loạt các chức năng được import từ tệp .sol khác.

Bởi vì chúng ta không thể tìm thấy chức năng của hàm “-pulltokens ()” trong tệp “OlympusZapV2.sol”, vì vậy nó phải đến từ một trong các tệp được nhập (import) ở đây.

babyyoda_by_renanralts_ddnw5kw-pre.png

Chúng ta tìm hiểu thêm về “interfaces” là gì như giải thích mình tham khảo dưới đây (source: howkteam):

  • Interface (nhiều tài liệu gọi là giao diện hoặc lớp giao tiếp) là 1 tập các thành phần chỉ có khai báo mà không có phần định nghĩa.
  • Một interface được hiểu như là 1 khuôn mẫu mà mọi lớp thực thi nó đều phải tuân theo. Interface sẽ định nghĩa phần “làm gì” (khai báo) và những lớp thực thi interface này sẽ định nghĩa phần “làm như thế nào” (định nghĩa nội dung) tương ứng.

—> Hiểu đơn giản thì interfaces giống như một giao diện và việc tương tác với giao diện chỉ là thực hiện hành vi khai báo “làm gì” chứ nó không thực hiện chức năng “làm như thế nào” —> Vì vậy, khi đã hiểu cách thức hoạt động của interfaces, chúng ta nhận ra rằng từ cách gọi tên thì “_pullTokens ()” không phải một giao diện tương tác mà là một chức năng, tức là thuộc phần “làm như thế nào”. Do đó, nó phải đến từ “libraries” (thư viện) thuộc tệp “zapbasev3.sol” như dòng cuối cùng trong khoanh đổ của hình 9.

Hình 10: Chúng ta tìm từ khoá “pulltokens” trên thanh tìm kiếm và đến tệp “zapbasev3.sol”. Một hàm chức năng gốc của “_pullTokens()” hiển thị.

Quan sát mục mô tả hàm chức năng trong hình 10 chúng ta thấy rằng khi thực thi, hàm “_pulltokens ()” sẽ chuyển token của chúng ta đến một địa chỉ contract nào đó. Chúng ta sẽ kiểm chứng logic này.

Hình 11: Nếu chúng ta quyết định gửi ETH (token==address(0)), thì đối tượng “msg.value” sẽ lớn hơn 0. Và nếu chúng ta swap sang các token khác thì hàm sẽ chuyển một số lượng token cụ thể từ tài khoản ví của chúng ta tới địa chỉ contract này.

Ở hình 11 có 2 từ khoá quan trọng của hàm mà chúng ta cần lưu ý đó là “msg.value” và “safeTransferFrom” bởi vì chúng ám chỉ một giao dịch tiền/tài sản liên quan tới chức năng hàm.

  • msg.value” có nghĩa là chức năng gửi ETH tới contract theo một kịch bản cụ thể
  • safeTransferFrom” có nghĩa là có một giao dịch chuyển ERC20 giữa 2 đối tượng (đối tượng gửi và nhận). Trong trường hợp này là từ “msg.sender” tới “address(this)” hay hiểu đơn giản là từ tài khoản của chúng ta tới địa chỉ contract của dự án.

Những dòng code có từ khoá “Goodwill” không mang ý nghĩa gì quan trọng ở đây. Về cơ bản, Goodwill gọi một hàm nội bộ để tính toán số tiền chuyển đến địa chỉ giới thiệu (affiliate). Tuy nhiên, vì Goodwill được đặt bằng 0 bởi Olympus nên chức năng này hiện không ảnh hưởng đến kết quả giao dịch.

Hình 12: Tới đây thì anh em đã hiểu được khi xác nhận trên ví thì token của chúng ta sẽ được chuyển ra khỏi ví tới một địa chỉ contract của dự án Olumpus.

Bây giờ mình quay trở lại với hàm “_ZapStake ()”. Chúng ta tìm hiểu hàm thứ 2 là hàm “_fillQuote” cũng được import vào tệp “OlympusZapV2.sol” giống với “_pullTokens ()”.

Hình 13: Như vậy thì tương tự chúng ta tìm ra hàm chức năng này trong tệp “ZapBaseV3.sol”.

Hình 14: Hàm này gọi một contract bên ngoài để swap tài sản mà chúng ta gửi vào contract đó sang token OHM. Anh em quan sát thấy dòng code bắt đầu với “(bool success, )” đúng chứ? đây chính là nơi thực thi hàm.

Những đoạn code bên trên dòng (bool success, ) nhằm thực hiện swap ETH sang WETH và chuẩn bị token trong ví cho lệnh swap (thông tin phê duyệt “approval” và số dư “balance” trên tài khoản ví).

Hình 15: Tiếp tục trở lại với hàm chức năng “_zapstake ()”, chúng ta cùng kiểm tra dòng code thứ 3 được gọi là hàm “_stake”.

Hàm này thực hiện chuyển token OHM vào địa chỉ staking và trả lại cho chúng ta sOHM hoặc gOHM.

Hình 16: Cũng tương tự các hàm bên trên, hàm “_stake ()” được import vào “_zapstake ()”, chúng ta tìm từ khoá “stake” và thấy rằng hàm chức năng này nằm ngay trong tệp “OlympusZapV2.sol”.

Chúng ta quan tâm đến từ khoá “claimedTokens” trong hàm này, đi theo sau nó là biểu thức “IStaking(staking).stake(…)”.

  • ISTAKING là một giao diện (interfaces) được cung cấp bởi Olympus. Nó cho phép chúng ta tương tác với hợp đồng tại địa chỉ “staking” mà không thực hiện lệnh low-level call (tìm hiểu về low-level call trong solidity trên google nhé anh em)

Hình 17: Nếu kéo lên trên cùng của tệp “OlympusZapV2.sol” thì ta thấy địa chỉ staking được khai báo công khai (public), có nghĩa là ai cũng có thể truy cập để xem thông tin được.

Hình 18: Để tìm ra và kiểm tra địa chỉ ví staking, chúng ta chọn mục “Read Contract” như trong hình và chọn hàng thứ 11 trong bảng liệt kê. Đây là địa chỉ được gọi trong hàm chức năng khi chúng ta thực hiện staking OHM.

Hình 19: Click vào địa chỉ contract này để kiểm tra sâu hơn trên etherscan, chúng ta thấy rằng địa chỉ này thuộc về OlympusStaking. Tiếp tục chuyển sang tab “contract” của địa chỉ này, chúng ta tìm thấy hàm chức năng “stake ()” tại đây.

Dòng đầu tiên của hàm là “Ohm.safetransferfrom ()” thực hiện chuyển OHM của chúng ta sang địa chỉ contract của Olympusstaking. Sau đó là dòng code cập nhật số lượng token gửi staking trong trường hợp rebase (Rebasing là gì thực ra không quan trọng lắm, có thể tìm hiểu thêm trên google nhé anh em).

Tiếp đến là hàm “_send ()” sẽ thực hiện gửi sOHM đến hợp đồng “Olympus_v2_zap_in” nếu ”_Rebasing = true” và gửi gOHM nếu ”_Rebasing = false”. Và phần code còn lại của hàm “send ()” thực hiện cập nhật thông tin staking tương ứng với tài khoản của chúng ta khi được xác nhận ví.

Hình 20: Sau khi thực hiện stake OHM thì gOHM vẫn còn nằm trong contract “Olympus_V2_Zap_In”. Dòng code tiếp theo bắt đầu với “IERC20” thực hiện chuyển token gOHM trả lại vào địa chỉ ví của chúng ta.

Hình 21: Cuối cùng, chúng ta kiểm tra dòng code còn lại trong hàm chức năng “_zapstake ()” xem chúng có ý nghĩa gì.

  • Dòng code bắt đầu bằng “require ()” đảm bảo rằng chúng ta sẽ nhận được nhiều sOHM/gOHM hơn so với số lượng tối thiểu thể hiện ở dòng “OHMRec > minToToken”.
  • Dòng code bắt đầu bằng “emit” dùng cho việc truy cập vào thông tin về những gì đã được thực thi trong hàm chức năng “zapstake ()” của contract. Dòng code này không cần thiết cho mục đích của chức năng nên không ảnh hưởng.

⇒ Như vậy sau khi đọc một loạt các chức năng trong hàm “zap-stake” chúng ta hiểu rằng khi tương tác ví với nút Zap-Stake trên UI của Olympus là an toàn, nó thực hiện đúng với ý đồ chức năng ban đầu và không có dấu hiệu bất thường.

Thế là mình vừa kết thúc ví dụ hướng dẫn kiểm tra cách đọc code để hiểu giao dịch mà chúng ta chuẩn bị tương tác trên ví sử dụng ví metamask kết hợp với etherscan. Mặc dù đây là một ví dụ khá cụ thể nhưng mình tin chắc khi hiểu được nó anh em hoàn toàn có thể áp dụng kiểm tra cho các giao dịch khác.

Mình hiểu rằng đối với một giao dịch anh em thường càng muốn thật nhanh gọn càng tốt, việc đọc code quá phức tạp và mất thời gian. Thế nhưng việc bảo vệ tài sản an toàn là trên hết, trước khi tương tác với bất kỳ một dự án mới nào đó mà yêu cầu phải kết nối hay phải xác nhận giao dịch lần đầu tiên với một địa chỉ contract lạ. Anh em hãy bỏ ra một chút thời gian kiểm tra để hiểu địa chỉ contract mà chúng ta chuẩn bị tương tác có thể làm gì với tài sản trong ví của anh em. Sau khi đảm bảo an toàn thì từ lần sau tương tác với dự án đó chúng ta có thể bỏ qua bước check này.

B. 2 CÔNG CỤ HỖ TRỢ ĐỌC GIAO DỊCH

1) Join Fire (joinfire .xyz)

Công cụ hỗ trợ đọc smart contract mà mình thích nhất cho tới thời điểm hiện tại. Trong đa số trường hợp, joinfire đều có thể đọc nhanh các giao dịch và trình bày thông tin một cách dễ hiểu cho chúng ta.

Hình 22: Website của Joinfire

Đối với joinfire thì anh em chỉ cần cài đặt extension trên chrome, sau đó mint một NFT fire miễn phí từ dự án. Anh em sẽ cần chọn đúng NFT fire trong 4 thẻ mà dự án cung cấp để mint và dùng sản phẩm. Có một mẹo để tiết kiệm phí gas đó là anh em chọn vào NFT và chờ joinfire thông báo thông tin giao dịch, trên cửa sổ thông tin anh em có thể nhìn thấy hình thu nhỏ của thẻ NFT đó là thẻ chuẩn hay thẻ “REKT”. Nếu là thẻ chuẩn thì xác nhận mint, nếu là thẻ “REKT” thì huỷ giao dịch rồi chọn lại cho đến khi chuẩn thì thôi.

Hình 23: Ví dụ trước khi xác nhận một giao dịch trên ví và Joinfire phân tích giao dịch cho chúng ta. Mục đích (purpose) của giao dịch là chính xác và an toàn. Nếu không an toàn joinfire sẽ gắn redflag cho giao dịch đó.

2) Sunrise: NFT Scam Protector (sunrise .wtf)

Đây là công cụ hỗ trợ anh em chống scam hiệu quả khi mint NFT. Sunrise có 2 lớp bảo vệ chúng ta, lớp thứ nhất đó là sunrise sẽ quét địa chỉ trang web mà chúng ta truy cập và đưa ra cảnh báo an toàn/không an toàn và lớp thứ 2 tương tự như joinfire thì sunrise cũng sẽ phân tích giao dịch xem có an toàn hay không trước khi chúng ta ký xác nhận trên ví.

Hình 24: Ví dụ truy cập một trang web về NFT thì sunrise sẽ quét tên miền và đưa ra cảnh báo

Sunrise chỉ hạn chế dùng cho các kênh về NFT nhưng tuy nhiên mình thất rất hữu ích vì các kênh mint NFT thường khá nguy hiểm khi tương tác ví. Sunrise giúp mình né rất nhiều dự án mint NFT miễn phí nhưng là trang scam. Những anh em nào mà hay chơi flip NFT chắc chắn sẽ rất ưng em này.

3) Web3 Antivirus (web3antivirus .io)

Tool này mới và đang ở phiên bản beta nên còn nhiều hạn chế, về tính năng thì tương tự Sunrise tuy nhiên mình thấy nó đầy đủ hơn. Khi bản chính thức hoạt động ổn định có thể mình sẽ chuyển hẳn sang dùng kênh này thay vì Sunrise để check NFT và website.

Hình 25: Ví dụ sử dụng Web3 Antivirus trên mint .fun

Oke đến đây thôi, hy vọng anh em học được chút gì đó từ hướng dẫn của mình trong bài này. Mình cũng khuyến khích anh em sử dụng các công cụ mình giới thiệu trên đây để tiết kiệm thời gian cũng như an toàn hơn khi thực hiện giao dịch.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *