Những mẹo nhỏ trong phát triển hợp đồng học được từ mã Uniswap
Gần đây, khi viết hướng dẫn phát triển sàn giao dịch phi tập trung, tôi đã tham khảo mã nguồn của Uniswap V3 và học được nhiều điểm kiến thức quý giá. Là một nhà phát triển trước đây chỉ phát triển các hợp đồng NFT đơn giản, lần thử nghiệm phát triển hợp đồng Defi này đã mang lại cho tôi nhiều trải nghiệm mới. Tôi tin rằng những mẹo nhỏ này sẽ rất hữu ích cho những người mới muốn học phát triển hợp đồng.
Tiếp theo, hãy cùng nhau xem qua những mẹo phát triển hữu ích này, trong đó có một số mẹo thậm chí có thể được coi là những kỹ thuật đặc biệt.
Địa chỉ triển khai hợp đồng có thể dự đoán
Thông thường, địa chỉ mà hợp đồng triển khai nhận được là một địa chỉ có vẻ ngẫu nhiên, vì nó liên quan đến nonce, nên địa chỉ hợp đồng rất khó dự đoán. Nhưng trong một số trường hợp, chúng ta cần suy luận địa chỉ hợp đồng từ các giao dịch và thông tin liên quan, chẳng hạn như xác định quyền giao dịch hoặc lấy địa chỉ của pool.
Uniswap tạo hợp đồng bằng cách thêm tham số salt và sử dụng phương thức CREATE2, giúp địa chỉ của hợp đồng được tạo ra có thể dự đoán. Logic sinh địa chỉ là: địa chỉ mới = hash("0xFF", địa chỉ người tạo, salt, initcode).
Sử dụng hàm callback một cách hiệu quả
Trong Solidity, các hợp đồng có thể gọi lẫn nhau. Trong một số trường hợp, việc A gọi phương thức của B và B gọi lại A trong phương thức được gọi là rất hữu ích.
Trong Uniswap, khi gọi phương thức swap của hợp đồng UniswapV3Pool để giao dịch, nó sẽ gọi lại swapCallback, và callback sẽ truyền vào Token thực tế cần thiết cho giao dịch lần này. Bên gọi cần chuyển Token cần thiết cho giao dịch vào UniswapV3Pool trong callback, thay vì tách phương thức swap thành hai phần để bên gọi thực hiện. Điều này đảm bảo tính an toàn của phương thức swap, đảm bảo toàn bộ logic được thực hiện đầy đủ mà không cần ghi chép biến phức tạp để đảm bảo an toàn.
Sử dụng ngoại lệ để truyền thông tin, thực hiện ước lượng giao dịch bằng try catch
Trong một số hợp đồng của Uniswap, phương thức swap của UniswapV3Pool được bao quanh bởi try catch để thực hiện. Điều này nhằm mô phỏng phương thức swap để ước lượng Token cần thiết cho giao dịch. Do trong quá trình ước lượng không thực sự xảy ra việc trao đổi Token, nên sẽ có lỗi xảy ra. Uniswap ném ra một lỗi đặc biệt trong hàm callback giao dịch và sau đó bắt lỗi đó, từ thông tin lỗi để phân tích ra thông tin cần thiết.
Phương pháp này có vẻ hơi gian lận, nhưng rất thực tế. Không cần phải cải tiến phương pháp swap để ước tính nhu cầu giao dịch, logic cũng đơn giản hơn.
Sử dụng số lớn để giải quyết vấn đề độ chính xác
Trong mã Uniswap có rất nhiều logic tính toán, chẳng hạn như tính toán Token được trao đổi dựa trên giá hiện tại và tính thanh khoản. Để tránh mất độ chính xác do phép chia gây ra, trong quá trình tính toán thường sử dụng thao tác << FixedPoint96.RESOLUTION, tức là dịch trái 96 bit, tương đương với nhân với 2^96. Sau khi dịch trái, thực hiện phép chia, đảm bảo độ chính xác trong các giao dịch bình thường không bị tràn.
Mặc dù về lý thuyết vẫn sẽ có sự mất mát độ chính xác, nhưng thường chỉ là sự mất mát ở đơn vị tối thiểu, có thể chấp nhận.
Tính toán lợi nhuận bằng cách sử dụng Share
Uniswap cần ghi lại lợi nhuận phí giao dịch của LP (nhà cung cấp thanh khoản). Rõ ràng không thể ghi lại phí giao dịch của từng LP trong mỗi giao dịch, điều này sẽ tiêu tốn một lượng lớn Gas.
Giải pháp của Uniswap là định nghĩa feeGrowthInside0LastX128 và feeGrowthInside1LastX128 trong cấu trúc Position, ghi lại phí giao dịch mà mỗi vị trí nên nhận được khi rút phí giao dịch lần cuối.
Nói một cách đơn giản, chỉ cần ghi lại tổng phí giao dịch và phí giao dịch mà mỗi thanh khoản nên được phân phối. Khi LP rút phí giao dịch, phí giao dịch có thể rút được được tính dựa trên thanh khoản mà họ nắm giữ. Điều này giống như việc nắm giữ cổ phiếu của một công ty, khi rút lợi nhuận từ cổ phiếu chỉ cần biết lợi nhuận mỗi cổ phiếu trong lịch sử của công ty và lợi nhuận từ lần rút trước.
Không phải tất cả thông tin đều cần lấy từ chuỗi.
Lưu trữ trên chuỗi tương đối đắt đỏ, và không phải mọi thông tin đều cần phải được lưu trữ trên chuỗi hoặc lấy từ chuỗi. Ví dụ, nhiều giao diện mà trang web front-end của Uniswap gọi là các giao diện Web2 truyền thống.
Danh sách các bể giao dịch, thông tin bể giao dịch, v.v. có thể được lưu trữ trong cơ sở dữ liệu thông thường, một số có thể cần định kỳ đồng bộ từ chuỗi, nhưng không cần gọi giao diện RPC do chuỗi hoặc dịch vụ nút cung cấp để lấy dữ liệu liên quan theo thời gian thực.
Tất nhiên, giao dịch quan trọng phải được thực hiện trên chuỗi.
Học cách phân chia hợp đồng, sử dụng hợp đồng tiêu chuẩn có sẵn
Một dự án có thể bao gồm nhiều hợp đồng được triển khai thực tế. Ngay cả khi chỉ có một hợp đồng được triển khai thực tế, chúng ta cũng có thể chia hợp đồng thành nhiều hợp đồng khác nhau bằng cách kế thừa.
Ví dụ, một số hợp đồng trong Uniswap kế thừa từ nhiều hợp đồng khác. Trong quá trình thực hiện, hợp đồng @openzeppelin/contracts/token/ERC721/ERC721.sol đã được sử dụng trực tiếp, điều này không chỉ thuận tiện cho việc quản lý vị thế thông qua cách thức NFT mà còn có thể tận dụng các hợp đồng tiêu chuẩn đã có để tăng hiệu suất phát triển.
Tóm tắt
Tự tay phát triển sẽ giúp bạn hiểu sâu hơn so với việc đọc bài viết. Việc thử nghiệm quy trình xây dựng một sàn giao dịch phi tập trung đơn giản sẽ giúp bạn hiểu rõ hơn về mã nguồn của Uniswap và bạn cũng sẽ học được nhiều kiến thức thực tế hơn trong các dự án.
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
7 thích
Phần thưởng
7
4
Chia sẻ
Bình luận
0/400
BearMarketGardener
· 18giờ trước
Người mới, hãy bắt đầu từ việc luyện đan.
Xem bản gốcTrả lời0
MissedAirdropAgain
· 18giờ trước
Lại sắp phải mở cuốn rồi? Vừa mới cuộn xong NFT vẫn chưa đủ.
Xem bản gốcTrả lời0
Web3Educator
· 19giờ trước
ok sinh viên, để tôi giải thích nhanh chóng điều này...
Giải thích mã Uniswap V3: 7 mẹo phát triển hợp đồng hữu ích
Những mẹo nhỏ trong phát triển hợp đồng học được từ mã Uniswap
Gần đây, khi viết hướng dẫn phát triển sàn giao dịch phi tập trung, tôi đã tham khảo mã nguồn của Uniswap V3 và học được nhiều điểm kiến thức quý giá. Là một nhà phát triển trước đây chỉ phát triển các hợp đồng NFT đơn giản, lần thử nghiệm phát triển hợp đồng Defi này đã mang lại cho tôi nhiều trải nghiệm mới. Tôi tin rằng những mẹo nhỏ này sẽ rất hữu ích cho những người mới muốn học phát triển hợp đồng.
Tiếp theo, hãy cùng nhau xem qua những mẹo phát triển hữu ích này, trong đó có một số mẹo thậm chí có thể được coi là những kỹ thuật đặc biệt.
Địa chỉ triển khai hợp đồng có thể dự đoán
Thông thường, địa chỉ mà hợp đồng triển khai nhận được là một địa chỉ có vẻ ngẫu nhiên, vì nó liên quan đến nonce, nên địa chỉ hợp đồng rất khó dự đoán. Nhưng trong một số trường hợp, chúng ta cần suy luận địa chỉ hợp đồng từ các giao dịch và thông tin liên quan, chẳng hạn như xác định quyền giao dịch hoặc lấy địa chỉ của pool.
Uniswap tạo hợp đồng bằng cách thêm tham số salt và sử dụng phương thức CREATE2, giúp địa chỉ của hợp đồng được tạo ra có thể dự đoán. Logic sinh địa chỉ là: địa chỉ mới = hash("0xFF", địa chỉ người tạo, salt, initcode).
Sử dụng hàm callback một cách hiệu quả
Trong Solidity, các hợp đồng có thể gọi lẫn nhau. Trong một số trường hợp, việc A gọi phương thức của B và B gọi lại A trong phương thức được gọi là rất hữu ích.
Trong Uniswap, khi gọi phương thức swap của hợp đồng UniswapV3Pool để giao dịch, nó sẽ gọi lại swapCallback, và callback sẽ truyền vào Token thực tế cần thiết cho giao dịch lần này. Bên gọi cần chuyển Token cần thiết cho giao dịch vào UniswapV3Pool trong callback, thay vì tách phương thức swap thành hai phần để bên gọi thực hiện. Điều này đảm bảo tính an toàn của phương thức swap, đảm bảo toàn bộ logic được thực hiện đầy đủ mà không cần ghi chép biến phức tạp để đảm bảo an toàn.
Sử dụng ngoại lệ để truyền thông tin, thực hiện ước lượng giao dịch bằng try catch
Trong một số hợp đồng của Uniswap, phương thức swap của UniswapV3Pool được bao quanh bởi try catch để thực hiện. Điều này nhằm mô phỏng phương thức swap để ước lượng Token cần thiết cho giao dịch. Do trong quá trình ước lượng không thực sự xảy ra việc trao đổi Token, nên sẽ có lỗi xảy ra. Uniswap ném ra một lỗi đặc biệt trong hàm callback giao dịch và sau đó bắt lỗi đó, từ thông tin lỗi để phân tích ra thông tin cần thiết.
Phương pháp này có vẻ hơi gian lận, nhưng rất thực tế. Không cần phải cải tiến phương pháp swap để ước tính nhu cầu giao dịch, logic cũng đơn giản hơn.
Sử dụng số lớn để giải quyết vấn đề độ chính xác
Trong mã Uniswap có rất nhiều logic tính toán, chẳng hạn như tính toán Token được trao đổi dựa trên giá hiện tại và tính thanh khoản. Để tránh mất độ chính xác do phép chia gây ra, trong quá trình tính toán thường sử dụng thao tác << FixedPoint96.RESOLUTION, tức là dịch trái 96 bit, tương đương với nhân với 2^96. Sau khi dịch trái, thực hiện phép chia, đảm bảo độ chính xác trong các giao dịch bình thường không bị tràn.
Mặc dù về lý thuyết vẫn sẽ có sự mất mát độ chính xác, nhưng thường chỉ là sự mất mát ở đơn vị tối thiểu, có thể chấp nhận.
Tính toán lợi nhuận bằng cách sử dụng Share
Uniswap cần ghi lại lợi nhuận phí giao dịch của LP (nhà cung cấp thanh khoản). Rõ ràng không thể ghi lại phí giao dịch của từng LP trong mỗi giao dịch, điều này sẽ tiêu tốn một lượng lớn Gas.
Giải pháp của Uniswap là định nghĩa feeGrowthInside0LastX128 và feeGrowthInside1LastX128 trong cấu trúc Position, ghi lại phí giao dịch mà mỗi vị trí nên nhận được khi rút phí giao dịch lần cuối.
Nói một cách đơn giản, chỉ cần ghi lại tổng phí giao dịch và phí giao dịch mà mỗi thanh khoản nên được phân phối. Khi LP rút phí giao dịch, phí giao dịch có thể rút được được tính dựa trên thanh khoản mà họ nắm giữ. Điều này giống như việc nắm giữ cổ phiếu của một công ty, khi rút lợi nhuận từ cổ phiếu chỉ cần biết lợi nhuận mỗi cổ phiếu trong lịch sử của công ty và lợi nhuận từ lần rút trước.
Không phải tất cả thông tin đều cần lấy từ chuỗi.
Lưu trữ trên chuỗi tương đối đắt đỏ, và không phải mọi thông tin đều cần phải được lưu trữ trên chuỗi hoặc lấy từ chuỗi. Ví dụ, nhiều giao diện mà trang web front-end của Uniswap gọi là các giao diện Web2 truyền thống.
Danh sách các bể giao dịch, thông tin bể giao dịch, v.v. có thể được lưu trữ trong cơ sở dữ liệu thông thường, một số có thể cần định kỳ đồng bộ từ chuỗi, nhưng không cần gọi giao diện RPC do chuỗi hoặc dịch vụ nút cung cấp để lấy dữ liệu liên quan theo thời gian thực.
Tất nhiên, giao dịch quan trọng phải được thực hiện trên chuỗi.
Học cách phân chia hợp đồng, sử dụng hợp đồng tiêu chuẩn có sẵn
Một dự án có thể bao gồm nhiều hợp đồng được triển khai thực tế. Ngay cả khi chỉ có một hợp đồng được triển khai thực tế, chúng ta cũng có thể chia hợp đồng thành nhiều hợp đồng khác nhau bằng cách kế thừa.
Ví dụ, một số hợp đồng trong Uniswap kế thừa từ nhiều hợp đồng khác. Trong quá trình thực hiện, hợp đồng @openzeppelin/contracts/token/ERC721/ERC721.sol đã được sử dụng trực tiếp, điều này không chỉ thuận tiện cho việc quản lý vị thế thông qua cách thức NFT mà còn có thể tận dụng các hợp đồng tiêu chuẩn đã có để tăng hiệu suất phát triển.
Tóm tắt
Tự tay phát triển sẽ giúp bạn hiểu sâu hơn so với việc đọc bài viết. Việc thử nghiệm quy trình xây dựng một sàn giao dịch phi tập trung đơn giản sẽ giúp bạn hiểu rõ hơn về mã nguồn của Uniswap và bạn cũng sẽ học được nhiều kiến thức thực tế hơn trong các dự án.