คำเตือนความเสี่ยง: ระวังความเสี่ยงจากการระดมทุนที่ผิดกฎหมายในนาม 'สกุลเงินเสมือน' 'บล็อกเชน' — จากห้าหน่วยงานรวมถึงคณะกรรมการกำกับดูแลการธนาคารและการประกันภัย
ข่าวสาร
ค้นพบ
ค้นหา
เข้าสู่ระบบ
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt
BTC
ETH
HTX
SOL
BNB
ดูตลาด
ซีรี่ส์ Web3 Newbie: เคล็ดลับการพัฒนาสัญญาที่ฉันเรียนรู้จากโค้ด Uniswap
ZAN Team
特邀专栏作者
2024-11-02 02:00
บทความนี้มีประมาณ 2303 คำ การอ่านทั้งหมดใช้เวลาประมาณ 4 นาที
ไม่คิดว่าสัญญาจะเขียนแบบนี้ได้เหรอ? นี่คืออารมณ์ที่ฉันแสดงออกมาล่าสุด~

เมื่อเร็วๆ นี้ ฉันกำลังเขียนบทช่วยสอนเกี่ยวกับการพัฒนาการแลกเปลี่ยนแบบกระจายอำนาจ https://github.com/WTFAcademy/WTF-Dapp ฉันอ้างถึงการใช้โค้ดของ Uniswap V3 และได้เรียนรู้ประเด็นความรู้มากมาย ผู้เขียนเคยพัฒนาสัญญา NFT แบบง่ายๆ มาก่อน แต่นี่เป็นครั้งแรกที่ฉันพยายามพัฒนาสัญญา Defi ฉันเชื่อว่าเคล็ดลับเหล่านี้จะเป็นประโยชน์สำหรับผู้มาใหม่ที่ต้องการเรียนรู้การพัฒนาสัญญา

ผู้เชี่ยวชาญด้านการพัฒนาสัญญาสามารถไปที่ https://github.com/WTFAcademy/WTF-Dapp ได้โดยตรงเพื่อสนับสนุนโค้ดและสนับสนุน Web3~

ต่อไป เรามาดูกลเม็ดเล็กๆ น้อยๆ เหล่านี้กัน ซึ่งบางส่วนอาจเรียกได้ว่าเป็นกลเม็ดอัศจรรย์ก็ได้

มีวิธีที่จะทำให้ที่อยู่สัญญาของการปรับใช้สัญญาสามารถคาดการณ์ได้

เมื่อเราปรับใช้สัญญา เรามักจะได้รับที่อยู่แบบสุ่มที่ดูเหมือน เนื่องจากเกี่ยวข้องกับ "nonce" ที่อยู่ของสัญญาจึงคาดเดาได้ยาก แต่ใน Uniswap เรามีข้อกำหนดดังกล่าว: เราจำเป็นต้องอนุมานที่อยู่ของสัญญาผ่านคู่ธุรกรรมและข้อมูลที่เกี่ยวข้อง สิ่งนี้มีประโยชน์ในหลาย ๆ สถานการณ์ เช่น การกำหนดสิทธิ์ในการทำธุรกรรม หรือการได้รับที่อยู่ของพูล เป็นต้น

ใน Uniswap การสร้างสัญญาจะถูกสร้างขึ้นผ่านโค้ด เช่น "pool = address(new Uniswap V3 Pool{salt: keccak 256(abi.encode(token 0, token 1, fee))}());" โดยเติม "เกลือ" เพื่อใช้ CREATE 2 ( https://github.com/AmazingAng/WTF-Solidity/blob/main/25_Create2/readme.md ) เพื่อสร้างสัญญา ข้อดีคือ ที่อยู่สัญญาที่สร้างขึ้น เป็นที่คาดเดาได้ และตรรกะของการสร้างที่อยู่คือ "ที่อยู่ใหม่ = hash("0x FF", ที่อยู่ของผู้สร้าง, Salt, รหัสเริ่มต้น)"

คุณสามารถดูบท https://github.com/WTFAcademy/WTF-Dapp/blob/main/P103_Factory/readme.md ของหลักสูตร WTF-DApp เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับส่วนนี้

ใช้ฟังก์ชันโทรกลับให้เกิดประโยชน์

ใน Solidity สัญญาสามารถเรียกหากันได้ มีสถานการณ์สมมติที่ A เรียก B ในวิธีการบางอย่าง และ B โทรกลับ A ในวิธีที่เรียก ซึ่งยังใช้ได้ดีในบางสถานการณ์

ใน Uniswap เมื่อคุณเรียกใช้วิธี "swap" ของสัญญา "Uniswap V3 Pool" เพื่อแลกเปลี่ยน มันจะโทรกลับ "swapCallback" การโทรกลับจะส่งผ่านใน "โทเค็น" ที่คำนวณได้จริงซึ่งจำเป็นสำหรับธุรกรรมนี้ โทเค็นที่จำเป็นสำหรับธุรกรรมจะถูกโอนไปยัง "Uniswap V3 Pool" แทนที่จะแยกวิธี "swap" ออกเป็นสองส่วนเพื่อให้ผู้โทรโทรได้ สิ่งนี้ทำให้มั่นใจได้ถึงความปลอดภัยของวิธี "swap" และรับรองว่าตรรกะทั้งหมดได้รับการดำเนินการอย่างสมบูรณ์ โดยไม่จำเป็นต้องบันทึกตัวแปรที่ยุ่งยากเพื่อความปลอดภัย

ข้อมูลโค้ดมีดังนี้:

คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับส่วนการซื้อขายของหลักสูตร https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md

ใช้ข้อยกเว้นในการถ่ายทอดข้อมูล และใช้ try catch เพื่อประมาณธุรกรรม

เมื่อพูดถึงโค้ดของ Uniswap เราพบว่าในสัญญา https://github.com/Uniswap/v3-periphery/blob/main/contracts/lens/Quoter.sol วิธีการ "swap" ของ "Uniswap V3 Pool" " ถูกห่อด้วย " try catch " และดำเนินการ:

ทำไมเป็นเช่นนี้? เนื่องจากเราจำเป็นต้องจำลองวิธีการ "สลับ" เพื่อประมาณโทเค็นที่จำเป็นสำหรับการทำธุรกรรม แต่เนื่องจากการแลกเปลี่ยนโทเค็นจะไม่เกิดขึ้นจริงในระหว่างการประมาณการ ข้อผิดพลาดจะถูกรายงาน ใน Uniswap จะแสดงข้อผิดพลาดพิเศษในฟังก์ชันการเรียกกลับของธุรกรรม จากนั้นจะจับข้อผิดพลาดและแยกวิเคราะห์ข้อมูลที่จำเป็นจากข้อความแสดงข้อผิดพลาด

มันดูค่อนข้างแฮ็ก แต่ก็ใช้งานได้จริงเช่นกัน ด้วยวิธีนี้ ไม่จำเป็นต้องแก้ไขวิธีการสลับเพื่อให้ตรงกับความต้องการของธุรกรรมโดยประมาณ และตรรกะก็ง่ายขึ้น ในหลักสูตรของเรา เรายังปรับใช้สัญญา https://github.com/WTFAcademy/WTF-Dapp/blob/main/demo-contract/contracts/wtfswap/SwapRouter.sol โดยอ้างอิงถึงตรรกะนี้

ใช้ตัวเลขจำนวนมากเพื่อแก้ปัญหาที่แม่นยำ

ในโค้ดของ Uniswap มีตรรกะในการคำนวณมากมาย เช่น การคำนวณโทเค็นที่แลกเปลี่ยนตามราคาปัจจุบันและสภาพคล่อง ในกระบวนการนี้ เราต้องหลีกเลี่ยงการสูญเสียความแม่นยำระหว่างการดำเนินการหาร ใน Uniswap กระบวนการคำนวณมักจะใช้การดำเนินการ "<< FixPoint 96.RESOLUTION" ซึ่งแสดงถึงการเลื่อนไปทางซ้าย 96 บิต ซึ่งเทียบเท่ากับการคูณด้วย "2^96" ดำเนินการแบ่งหลังกะซ้ายเพื่อรับประกันความแม่นยำไม่ล้นในธุรกรรมปกติ (ปกติจะใช้ "uint 256" ในการคำนวณซึ่งก็เพียงพอแล้ว)

รหัสมีดังนี้ (คำนวณจำนวนโทเค็นที่จำเป็นสำหรับการทำธุรกรรมผ่านราคาและสภาพคล่อง):

อย่างที่คุณเห็น อันดับแรกใน Uniswap ราคาจะถูกคูณด้วยรากที่สองด้วย "2^96" (ตรงกับ "sqrtRatioAX 96" และ "sqrtRatioBX 96" ในโค้ดด้านบน) จากนั้นสภาพคล่อง "สภาพคล่อง" จะเป็น เลื่อนไปทางซ้ายเพื่อคำนวณ "ตัวเศษ" 1" ในการคำนวณด้านล่าง "2^96" จะถูกลบออกในระหว่างขั้นตอนการคำนวณเพื่อให้ได้ผลลัพธ์สุดท้าย

แน่นอนว่าไม่ว่าจะเกิดอะไรขึ้น ในทางทฤษฎีก็ยังคงสูญเสียความแม่นยำ แต่ในกรณีนี้คือการสูญเสียหน่วยที่เล็กที่สุดซึ่งเป็นที่ยอมรับได้

สำหรับข้อมูลเพิ่มเติม คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับหลักสูตรนี้ ได้ที่ https://github.com/WTFAcademy/WTF-Dapp/blob/main/P106_PoolSwap/readme.md

คำนวณรายได้โดยใช้วิธีแบ่งปัน

ใน Uniswap เราจำเป็นต้องบันทึกรายได้ค่าธรรมเนียมของ LP (ผู้ให้บริการสภาพคล่อง) แน่นอนว่าเราไม่สามารถบันทึกค่าธรรมเนียมการจัดการของตนเองสำหรับแต่ละ LP ในทุกธุรกรรมได้ เนื่องจากจะทำให้ใช้ Gas จำนวนมาก แล้วจะจัดการกับมันอย่างไร?

ใน Uniswap เราจะเห็นว่าโครงสร้างต่อไปนี้ถูกกำหนดไว้ใน "ตำแหน่ง":

ประกอบด้วย " feeGrowthInside0LastX128 และ feeGrowthInside1LastX128 " ซึ่งบันทึกค่าธรรมเนียมการจัดการที่แต่ละสภาพคล่องควรได้รับเมื่อมีการถอนค่าธรรมเนียมการจัดการครั้งล่าสุดสำหรับแต่ละตำแหน่ง

พูดง่ายๆ ฉันต้องบันทึกค่าธรรมเนียมการจัดการทั้งหมดและค่าธรรมเนียมการจัดการที่ควรจัดสรรให้กับสภาพคล่องแต่ละรายการเป็นจำนวนเท่าใด เพื่อว่าเมื่อ LP ถอนค่าธรรมเนียมการจัดการ เขาสามารถคำนวณจำนวนค่าธรรมเนียมการจัดการที่เขาสามารถถอนออกได้ตามสภาพคล่องใน มือ. เช่นเดียวกับหากคุณถือหุ้นของบริษัทใดบริษัทหนึ่ง เมื่อคุณต้องการถอนกำไรจากหุ้น คุณเพียงแค่ต้องทราบกำไรต่อหุ้นในอดีตของบริษัทและรายได้เมื่อคุณถอนกำไรครั้งล่าสุด

ก่อนหน้านี้เราอยู่ใน "Ingenious Contract Design มาดูกันว่า stETH กระจายรายได้โดยอัตโนมัติในแต่ละวันอย่างไร" ให้ ETH ของคุณมีส่วนร่วมในการจำนำเพื่อรับดอกเบี้ยที่มั่นคง บทความนี้ยังแนะนำวิธีการคำนวณรายได้ของ stETH ซึ่งคล้ายกัน

ไม่จำเป็นต้องได้รับข้อมูลทั้งหมดจากห่วงโซ่

พื้นที่จัดเก็บข้อมูลออนไลน์มีราคาค่อนข้างแพง ดังนั้นจึงไม่จำเป็นต้องอัพโหลดหรือรับข้อมูลทั้งหมดของเราจากเครือข่ายดังกล่าว ตัวอย่างเช่น อินเทอร์เฟซจำนวนมากที่เรียกโดยเว็บไซต์ส่วนหน้าของ Uniswap นั้นเป็นอินเทอร์เฟซ Web2 แบบดั้งเดิม

รายการกลุ่มธุรกรรม ข้อมูลกลุ่มธุรกรรม ฯลฯ สามารถจัดเก็บไว้ในฐานข้อมูลทั่วไป และบางส่วนอาจจำเป็นต้องซิงโครไนซ์จากห่วงโซ่เป็นประจำ แต่เราไม่จำเป็นต้องเรียกใช้อินเทอร์เฟซ PRC ที่ห่วงโซ่หรือบริการโหนดให้บริการจริง เวลาที่จะได้รับข้อมูลที่เกี่ยวข้อง

แน่นอนว่าซัพพลายเออร์บล็อคเชน PRC จำนวนมากในขณะนี้มีอินเทอร์เฟซขั้นสูง และคุณสามารถรับข้อมูลบางอย่างได้รวดเร็วและถูกกว่า นี่เป็นเหตุผลที่คล้ายกัน ตัวอย่างเช่น ZAN มีอินเทอร์เฟซที่คล้ายกับการรับ NFT ทั้งหมดภายใต้ผู้ใช้บางราย สามารถแคชข้อมูลนี้ได้อย่างชัดเจนเพื่อปรับปรุงประสิทธิภาพและประสิทธิภาพ คุณสามารถไปที่ https://zan.top/service/advance-api เพื่อรับข้อมูลเพิ่มเติม

แน่นอนว่าธุรกรรมสำคัญจะต้องดำเนินการบนเครือข่าย

เรียนรู้วิธีแยกสัญญา และเรียนรู้การใช้สัญญามาตรฐานที่มีอยู่ เช่น ERC 721

โปรเจ็กต์อาจมีสัญญาหลายฉบับที่ใช้งานจริง แม้ว่าจะมีสัญญาเดียวที่ใช้งานจริง โค้ดของเราก็สามารถแบ่งสัญญาออกเป็นหลายสัญญาเพื่อการบำรุงรักษาผ่านการสืบทอดได้

ตัวอย่างเช่น ใน Uniswap สัญญา https://github.com/Uniswap/v3-periphery/blob/main/contracts/NonfungiblePositionManager.sol จะสืบทอดสัญญาจำนวนมาก โดยมีโค้ดดังนี้:

และเมื่อคุณดูการดำเนินการตามสัญญา "ERC 721 Permit" คุณจะพบว่ามีการใช้สัญญา "@openzeppelin/contracts/token/ERC 721/ERC 721.sol" โดยตรง ซึ่งทำให้สะดวกในการจัดการตำแหน่งผ่าน ในทางกลับกัน สัญญามาตรฐานที่มีอยู่ยังสามารถใช้เพื่อปรับปรุงประสิทธิภาพการพัฒนาสัญญาได้อีกด้วย

ในหลักสูตรของเรา คุณสามารถเรียนรู้ https://github.com/WTFAcademy/WTF-Dapp/blob/main/ P 108 _PositionManager /readme.md และพยายามพัฒนาสัญญา ERC 721 ง่ายๆ เพื่อจัดการตำแหน่ง

สรุป

ไม่ว่าคุณจะอ่านบทความจำนวนเท่าใด มันไม่มีประโยชน์เท่ากับการเริ่มพัฒนาด้วยตัวเอง ในกระบวนการพยายามปรับใช้การแลกเปลี่ยนแบบกระจายอำนาจเวอร์ชันง่ายๆ ด้วยตัวคุณเอง คุณจะมีความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับการนำโค้ดของ Uniswap ไปใช้ และคุณก็สามารถทำได้ เรียนรู้เพิ่มเติมเกี่ยวกับโครงการจริง สัมผัสประสบการณ์คะแนนความรู้

หลักสูตร WTF-DApp เป็นหลักสูตรโอเพ่นซอร์สที่เสร็จสมบูรณ์ร่วมกันโดยชุมชนนักพัฒนาของ ZAN และนักเรียนชุมชนนักพัฒนา WTF Academy หากคุณสนใจในการพัฒนาโครงการ Web3 และ Defi คุณสามารถดูหลักสูตรภาคปฏิบัติของเรา https://github.com/WTFAcademy/WTF-Dapp เพื่อทำการแลกเปลี่ยนเวอร์ชันง่ายๆ ทีละขั้นตอน ฉันเชื่อว่ามันจะมีประโยชน์ ถึงคุณ. ช่วยด้วย~

บทความนี้เขียนโดย Fisher (บัญชี X @yudao 1024 ) จากทีม ZAN (บัญชี X @zan_team )

Uniswap
เทคโนโลยี
ยินดีต้อนรับเข้าร่วมชุมชนทางการของ Odaily
กลุ่มสมาชิก
https://t.me/Odaily_News
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
บัญชีทางการ
https://twitter.com/OdailyChina
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
สรุปโดย AI
กลับไปด้านบน
ไม่คิดว่าสัญญาจะเขียนแบบนี้ได้เหรอ? นี่คืออารมณ์ที่ฉันแสดงออกมาล่าสุด~
คลังบทความของผู้เขียน
ZAN Team
ดาวน์โหลดแอพ Odaily พลาเน็ตเดลี่
ให้คนบางกลุ่มเข้าใจ Web3.0 ก่อน
IOS
Android