Gần đây, tôi đang viết một bài hướng dẫn về phát triển sàn giao dịch phi tập trung https://github.com/WTFAcademy/WTF-Dapp . Tôi đã đề cập đến việc triển khai mã của Uniswap V3 và học được rất nhiều điểm kiến thức. Tác giả đã phát triển các hợp đồng NFT đơn giản trước đây, nhưng đây là lần đầu tiên tôi thử phát triển hợp đồng Defi. Tôi tin rằng những lời khuyên này sẽ hữu ích cho những người mới muốn tìm hiểu cách phát triển hợp đồng.
Các chuyên gia phát triển hợp đồng có thể truy cập trực tiếp https://github.com/WTFAcademy/WTF-Dapp để đóng góp mã và đóng góp cho Web3~
Tiếp theo, chúng ta hãy xem những thủ thuật nhỏ này, một số trong đó thậm chí có thể được gọi là những thủ thuật thần kỳ.
Có một cách để làm cho địa chỉ hợp đồng triển khai hợp đồng có thể dự đoán được.
Khi chúng tôi triển khai một hợp đồng, chúng tôi thường nhận được một địa chỉ dường như ngẫu nhiên. Bởi vì nó liên quan đến nonce, địa chỉ hợp đồng rất khó dự đoán. Nhưng trong Uniswap, chúng ta có một yêu cầu như vậy: cần suy ra địa chỉ của hợp đồng thông qua cặp giao dịch và các thông tin liên quan. Điều này hữu ích trong nhiều trường hợp, chẳng hạn như xác định quyền giao dịch hoặc lấy địa chỉ của một nhóm, v.v.
Trong Uniswap, việc tạo hợp đồng được tạo thông qua mã như pool = address(new Uniswap V3 Pool{salt: keccak 256(abi.encode(token 0, token 1, charge))}());. Bằng cách thêm muối để sử dụng CREATE 2 ( https://github.com/AmazingAng/WTF-Solidity/blob/main/25_Create2/readme.md ) để tạo hợp đồng, ưu điểm là địa chỉ hợp đồng được tạo có thể dự đoán được và logic tạo địa chỉ là địa chỉ mới = hàm băm (0x FF, địa chỉ người tạo, muối, initcode).
Bạn có thể xem phần này của khóa học WTF-DApp tại https://github.com/WTFAcademy/WTF-Dapp/blob/main/P103_Factory/readme.md để tìm hiểu thêm.
Tận dụng tốt các chức năng gọi lại
Trong Solidity, các hợp đồng có thể gọi cho nhau. Có một tình huống trong đó A gọi B theo một phương thức nhất định và B gọi lại A theo phương thức được gọi. Điều này cũng hoạt động tốt trong một số trường hợp.
Trong Uniswap, khi bạn gọi phương thức hoán đổi của hợp đồng Uniswap V3 Pool để giao dịch, nó sẽ gọi lại swapCallback. Lệnh gọi lại sẽ chuyển vào Mã thông báo được tính toán thực sự cần thiết cho giao dịch này. Token cần thiết cho giao dịch được chuyển sang Uniswap V3 Pool thay vì chia phương thức hoán đổi thành hai phần để người gọi gọi. Điều này đảm bảo tính bảo mật của phương thức hoán đổi và đảm bảo rằng toàn bộ logic được thực thi đầy đủ. . mà không cần ghi nhật ký biến rườm rà để đảm bảo an ninh.
Đoạn mã như sau:
Bạn có thể tìm hiểu thêm về phần giao dịch của khóa học https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md .
Sử dụng các ngoại lệ để truyền thông tin và sử dụng tính năng thử bắt để ước tính các giao dịch.
Khi tham khảo code của Uniswap, chúng tôi nhận thấy trong hợp đồng của nó https://github.com/Uniswap/v3-periphery/blob/main/contracts/lens/Quoter.sol , phương thức hoán đổi của Uniswap V3 Pool được gói bằng try Catch và được thực thi:
Tại sao lại thế này? Bởi vì chúng ta cần mô phỏng phương pháp hoán đổi để ước tính số Token cần thiết cho giao dịch, nhưng do việc trao đổi Token sẽ không thực sự xảy ra trong quá trình ước tính nên sẽ xảy ra lỗi. Trong Uniswap, nó đưa ra một lỗi đặc biệt trong chức năng gọi lại giao dịch, sau đó ghi lại lỗi và phân tích thông tin cần thiết từ thông báo lỗi.
Nó trông khá hacky, nhưng nó cũng rất thực tế. Bằng cách này, không cần phải sửa đổi phương thức hoán đổi để đáp ứng nhu cầu của các giao dịch ước tính và logic đơn giản hơn. Trong khóa học của mình, chúng tôi cũng đã triển khai hợp đồng https://github.com/WTFAcademy/WTF-Dapp/blob/main/demo-contract/contracts/wtfswap/SwapRouter.sol có tham chiếu đến logic này.
Sử dụng số lớn để giải các bài toán chính xác
Trong mã của Uniswap, có rất nhiều logic tính toán, chẳng hạn như tính toán số token được trao đổi dựa trên giá hiện tại và tính thanh khoản, trong quá trình này, chúng ta phải tránh mất đi độ chính xác trong các hoạt động phân chia. Trong Uniswap, quá trình tính toán thường sử dụng thao tác << FixedPoint 96.RESOLUTION, biểu thị độ lệch trái 96 bit, tương đương với việc nhân với 2^96. Thực hiện phép chia sau khi dịch trái để đảm bảo độ chính xác không bị tràn trong các giao dịch thông thường (thường dùng uint 256 để tính toán là đủ).
Mã như sau (tính số lượng Token cần thiết cho một giao dịch thông qua giá cả và tính thanh khoản):
Như bạn có thể thấy, đầu tiên trong Uniswap, giá được nhân với căn bậc hai với 2^96 (tương ứng với sqrtRatioAX 96 và sqrtRatioBX 96 trong đoạn mã trên), sau đó thanh khoản sẽ là chuyển sang trái để tính tử số 1. Trong phép tính bên dưới, 2^96 sẽ bị trừ đi trong quá trình tính toán để có được kết quả cuối cùng.
Tất nhiên, dù thế nào đi chăng nữa thì vẫn sẽ có sự mất đi độ chính xác về mặt lý thuyết, nhưng trong trường hợp này đó là sự mất đi đơn vị nhỏ nhất thì có thể chấp nhận được.
Để biết thêm thông tin, bạn có thể tìm hiểu thêm về khóa học này tại https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md .
Tính thu nhập bằng phương pháp Chia sẻ
Trong Uniswap, chúng tôi cần ghi lại thu nhập từ phí của LP (nhà cung cấp thanh khoản). Rõ ràng, chúng tôi không thể ghi lại phí xử lý riêng cho từng LP trong mỗi giao dịch, vì điều này sẽ tiêu tốn rất nhiều Gas. Vậy làm thế nào để đối phó với nó?
Trong Uniswap, chúng ta có thể thấy cấu trúc sau được xác định trong Vị trí:
Nó bao gồm chargeGrowthInside0LastX128 và chargeGrowthInside1LastX128 , ghi lại phí xử lý mà mỗi thanh khoản sẽ nhận được khi phí xử lý được rút lần cuối cho mỗi vị trí (Vị trí).
Nói một cách đơn giản, tôi chỉ cần ghi lại tổng phí xử lý và mức phí xử lý sẽ được phân bổ cho mỗi thanh khoản là bao nhiêu, để khi LP rút phí xử lý, anh ta có thể tính toán được bao nhiêu phí xử lý có thể rút dựa trên tính thanh khoản trong đó. tay. Giống như nếu bạn nắm giữ cổ phiếu của một công ty nhất định, khi bạn muốn rút thu nhập từ cổ phiếu, bạn chỉ cần biết thu nhập lịch sử trên mỗi cổ phiếu của công ty và thu nhập khi bạn rút tiền lần cuối.
Trước đây, chúng ta đang ở phần Thiết kế hợp đồng khéo léo, hãy xem stETH tự động phân phối thu nhập hàng ngày như thế nào? Hãy để ETH của bạn tham gia cầm cố để nhận được lãi suất ổn định. Bài viết này cũng giới thiệu cách tính thu nhập của stETH cũng tương tự.
Không phải tất cả thông tin đều cần được lấy từ chuỗi
Lưu trữ trên chuỗi tương đối đắt tiền, vì vậy không phải tất cả thông tin của chúng tôi đều cần được tải lên hoặc lấy từ chuỗi. Ví dụ: nhiều giao diện được trang web giao diện người dùng Uniswap gọi là giao diện Web2 truyền thống.
Danh sách nhóm giao dịch, thông tin nhóm giao dịch, v.v. có thể được lưu trữ trong cơ sở dữ liệu thông thường và một số có thể cần được đồng bộ hóa thường xuyên từ chuỗi, nhưng chúng ta không cần gọi giao diện PRC do chuỗi hoặc dịch vụ nút cung cấp trong thực tế thời gian để có được dữ liệu liên quan.
Tất nhiên, nhiều nhà cung cấp blockchain của PRC hiện cung cấp một số giao diện nâng cao và bạn có thể lấy một số dữ liệu theo cách nhanh hơn và rẻ hơn. Đây là một lý do tương tự. Ví dụ: ZAN cung cấp giao diện tương tự như lấy tất cả NFT theo một người dùng nhất định. Thông tin này rõ ràng có thể được lưu vào bộ nhớ đệm để cải thiện hiệu suất và hiệu quả. Bạn có thể truy cập https://zan.top/service/advance-api để biết thêm.
Tất nhiên, các giao dịch quan trọng phải được thực hiện trên chuỗi.
Tìm hiểu cách phân chia hợp đồng và cũng học cách sử dụng các hợp đồng tiêu chuẩn hiện có như ERC 721
Một dự án có thể chứa nhiều hợp đồng được triển khai thực sự, ngay cả khi chỉ có một hợp đồng được triển khai thực sự, mã của chúng tôi có thể chia hợp đồng thành nhiều hợp đồng để bảo trì thông qua tính kế thừa.
Ví dụ: trong Uniswap, hợp đồng https://github.com/Uniswap/v3-periphery/blob/main/contracts/NonfungiblePositionManager.sol kế thừa nhiều hợp đồng. Mã như sau:
Và khi bạn xem xét việc thực hiện hợp đồng Giấy phép ERC 721, bạn sẽ thấy rằng nó trực tiếp sử dụng hợp đồng @openzeppelin/contracts/token/ERC 721/ERC 721.sol, giúp thuận tiện cho việc quản lý các vị thế thông qua Mặt khác, NFT. Các hợp đồng tiêu chuẩn hiện có cũng có thể được sử dụng để nâng cao hiệu quả phát triển hợp đồng.
Trong khóa học của chúng tôi, bạn có thể tìm hiểu https://github.com/WTFAcademy/WTF-Dapp/blob/main/ P 108 _PositionManager /readme.md và cố gắng phát triển một hợp đồng ERC 721 đơn giản để quản lý các vị thế.
Tóm tắt
Cho dù bạn có đọc bao nhiêu bài viết thì cũng không thực tế bằng việc bắt đầu tự phát triển nó. Trong quá trình cố gắng tự mình triển khai một phiên bản đơn giản của sàn giao dịch phi tập trung, bạn có thể hiểu sâu hơn về cách triển khai mã của Uniswap và bạn có thể. cũng như tìm hiểu thêm về các dự án thực tế.
Khóa học WTF-DApp là khóa học nguồn mở được hoàn thành bởi cộng đồng nhà phát triển của ZAN và sinh viên cộng đồng nhà phát triển của Học viện WTF. Nếu bạn cũng quan tâm đến việc phát triển dự án Web3 và Defi, bạn có thể tham khảo khóa học thực tế của chúng tôi https://github.com/WTFAcademy/WTF-Dapp để hoàn thành phiên bản trao đổi đơn giản từng bước. Tôi tin rằng nó sẽ hữu ích. Đã giúp ích cho bạn.
Bài viết này được viết bởi Fisher (tài khoản X @yudao 1024 ) của ZAN Team (tài khoản X @zan_team ).