Поради з розробки контрактів: досвід, отриманий з коду Uniswap
Нещодавно, коли я писав посібник по децентралізованій біржі, я звертався до реалізації Uniswap V3 і дізнався багато цікавих моментів. Як новачок, який тільки починає займатися розробкою Defi контрактів, ці техніки були для мене дуже надихаючими, і я впевнений, що вони також допоможуть іншим, хто хоче вивчати розробку смарт-контрактів.
Прогнозована адреса контракту
Зазвичай адреси розгортання контрактів виглядають випадковими через зв'язок з nonce. Але в певних ситуаціях нам потрібно вивести адресу контракту через інформацію про угоду, наприклад, визначити права на угоду або отримати адресу пулу.
Uniswap створює контракти, використовуючи CREATE2, додавши параметр salt. Таким чином, згенерована адреса контракту є передбачуваною і слідує логіці "нова адреса = hash('0xFF', адреса творця, salt, initcode)".
Розумне використання функцій зворотного виклику
У Solidity контракти можуть викликати один одного. Іноді контракт A викликає метод контракту B, а B потім викликає метод A, що є корисним у деяких сценаріях.
Наприклад, у процесі торгівлі Uniswap, коли викликається метод swap контракту UniswapV3Pool, він викликає swapCallback, передаючи фактичну кількість токенів, які потрібно. Викликаюча сторона повинна передати необхідні токени у зворотному виклику, що забезпечує цілісність і безпеку всієї торгової логіки.
Використовуйте винятки для передачі інформації, реалізуйте оцінку угоди за допомогою try catch
У контракті Quoter Uniswap метод swap UniswapV3Pool обгорнутий у try catch. Це зроблено для моделювання необхідних токенів для оцінки угоди, але під час оцінки токени фактично не обмінюються, тому виникає помилка.
Uniswap викидає спеціальну помилку у функції зворотного виклику торгівлі, а потім перехоплює цю помилку та розбирає інформацію. Цей підхід, хоча і виглядає як обхід, є дуже практичним, оскільки не потрібно спеціально модифікувати метод swap для оцінки попиту.
Проблема точності обробки великих чисел
У коді Uniswap є багато обчислень, таких як розрахунок кількості токенів для обміну на основі поточної ціни та ліквідності. Щоб уникнути втрати точності при діленні, в процесі обчислення часто використовується операція "<< FixedPoint96.RESOLUTION", що еквівалентно множенню на 2^96.
Цей метод забезпечує точність, гарантуючи при цьому, що нормальні транзакції не перевищують межі (зазвичай обчислюються за допомогою uint256). Хоча теоретично може бути невтрачене точності на мінімальному рівні, це вже прийнятно.
Розрахунок прибутку за допомогою Share
Uniswap потрібно фіксувати прибуток від комісій для постачальників ліквідності (LP). Щоб уникнути фіксації комісій для кожного LP під час кожної транзакції (що споживає велику кількість газу), Uniswap використовує хитрий метод.
У структурі Position визначено feeGrowthInside0LastX128 та feeGrowthInside1LastX128, які фіксують комісійні збори, що належать кожному позиції за одиницю ліквідності під час останнього їх виведення. Таким чином, потрібно лише зафіксувати загальні комісійні збори та частку на одиницю ліквідності, а LP під час виведення отримуватиме комісійні збори відповідно до утримуваної ліквідності.
Баланс отримання інформації в мережі та поза нею
Зберігання на ланцюгу є відносно дорогим, і не вся інформація повинна бути на ланцюзі або отримуватися з ланцюга. Багато інтерфейсів, які викликаються фронтендом Uniswap, є традиційними веб-інтерфейсами Web2.
Список торгових пулів, інформація про торгові пули тощо можуть зберігатися в звичайній базі даних, регулярно синхронізуючись з блокчейном. Не потрібно в реальному часі викликати RPC інтерфейси блокчейну чи сервісів вузлів для отримання відповідних даних.
Деякі постачальники RPC блокчейнів надають розширені інтерфейси, які дозволяють швидше та дешевше отримувати дані. Ці інтерфейси зазвичай підвищують продуктивність і ефективність за рахунок кешування.
Розділення контракту та використання стандартного контракту
Проект може містити кілька фактично розгорнених контрактів. Навіть якщо розгорнуто лише один контракт, код може бути розділений на кілька контрактів за допомогою успадкування.
Наприклад, контракт NonfungiblePositionManager Uniswap успадковує кілька контрактів. Контракт ERC721Permit безпосередньо використовує стандартний контракт ERC721 від OpenZeppelin, що полегшує управління позиціями за допомогою NFT і підвищує ефективність розробки.
Висновок
Практика є найкращим методом навчання. Спробувавши реалізувати просту версію децентралізованої біржі, можна глибше зрозуміти код Uniswap, а також дізнатися більше про важливі аспекти реальних проектів. Сподіваюся, ці досвіди стануть у нагоді друзям, які прагнуть розвивати проекти в Web3 та DeFi.
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
7 лайків
Нагородити
7
6
Поділіться
Прокоментувати
0/400
StableNomad
· 16год тому
статистично кажучи, uniswap все ще має найчистіший код...просто кажу
Переглянути оригіналвідповісти на0
StablecoinAnxiety
· 16год тому
Адреса може передбачити це дуже критично!
Переглянути оригіналвідповісти на0
PumpStrategist
· 17год тому
Захоплююче, DEX також займається оракул-машиною, що підвищує привабливість для великих інвестицій.
7 основних порад для розробки контрактів Uniswap: від передбачуваних адрес до балансу у блокчейні та поза блокчейном
Поради з розробки контрактів: досвід, отриманий з коду Uniswap
Нещодавно, коли я писав посібник по децентралізованій біржі, я звертався до реалізації Uniswap V3 і дізнався багато цікавих моментів. Як новачок, який тільки починає займатися розробкою Defi контрактів, ці техніки були для мене дуже надихаючими, і я впевнений, що вони також допоможуть іншим, хто хоче вивчати розробку смарт-контрактів.
Прогнозована адреса контракту
Зазвичай адреси розгортання контрактів виглядають випадковими через зв'язок з nonce. Але в певних ситуаціях нам потрібно вивести адресу контракту через інформацію про угоду, наприклад, визначити права на угоду або отримати адресу пулу.
Uniswap створює контракти, використовуючи CREATE2, додавши параметр salt. Таким чином, згенерована адреса контракту є передбачуваною і слідує логіці "нова адреса = hash('0xFF', адреса творця, salt, initcode)".
Розумне використання функцій зворотного виклику
У Solidity контракти можуть викликати один одного. Іноді контракт A викликає метод контракту B, а B потім викликає метод A, що є корисним у деяких сценаріях.
Наприклад, у процесі торгівлі Uniswap, коли викликається метод swap контракту UniswapV3Pool, він викликає swapCallback, передаючи фактичну кількість токенів, які потрібно. Викликаюча сторона повинна передати необхідні токени у зворотному виклику, що забезпечує цілісність і безпеку всієї торгової логіки.
Використовуйте винятки для передачі інформації, реалізуйте оцінку угоди за допомогою try catch
У контракті Quoter Uniswap метод swap UniswapV3Pool обгорнутий у try catch. Це зроблено для моделювання необхідних токенів для оцінки угоди, але під час оцінки токени фактично не обмінюються, тому виникає помилка.
Uniswap викидає спеціальну помилку у функції зворотного виклику торгівлі, а потім перехоплює цю помилку та розбирає інформацію. Цей підхід, хоча і виглядає як обхід, є дуже практичним, оскільки не потрібно спеціально модифікувати метод swap для оцінки попиту.
Проблема точності обробки великих чисел
У коді Uniswap є багато обчислень, таких як розрахунок кількості токенів для обміну на основі поточної ціни та ліквідності. Щоб уникнути втрати точності при діленні, в процесі обчислення часто використовується операція "<< FixedPoint96.RESOLUTION", що еквівалентно множенню на 2^96.
Цей метод забезпечує точність, гарантуючи при цьому, що нормальні транзакції не перевищують межі (зазвичай обчислюються за допомогою uint256). Хоча теоретично може бути невтрачене точності на мінімальному рівні, це вже прийнятно.
Розрахунок прибутку за допомогою Share
Uniswap потрібно фіксувати прибуток від комісій для постачальників ліквідності (LP). Щоб уникнути фіксації комісій для кожного LP під час кожної транзакції (що споживає велику кількість газу), Uniswap використовує хитрий метод.
У структурі Position визначено feeGrowthInside0LastX128 та feeGrowthInside1LastX128, які фіксують комісійні збори, що належать кожному позиції за одиницю ліквідності під час останнього їх виведення. Таким чином, потрібно лише зафіксувати загальні комісійні збори та частку на одиницю ліквідності, а LP під час виведення отримуватиме комісійні збори відповідно до утримуваної ліквідності.
Баланс отримання інформації в мережі та поза нею
Зберігання на ланцюгу є відносно дорогим, і не вся інформація повинна бути на ланцюзі або отримуватися з ланцюга. Багато інтерфейсів, які викликаються фронтендом Uniswap, є традиційними веб-інтерфейсами Web2.
Список торгових пулів, інформація про торгові пули тощо можуть зберігатися в звичайній базі даних, регулярно синхронізуючись з блокчейном. Не потрібно в реальному часі викликати RPC інтерфейси блокчейну чи сервісів вузлів для отримання відповідних даних.
Деякі постачальники RPC блокчейнів надають розширені інтерфейси, які дозволяють швидше та дешевше отримувати дані. Ці інтерфейси зазвичай підвищують продуктивність і ефективність за рахунок кешування.
Розділення контракту та використання стандартного контракту
Проект може містити кілька фактично розгорнених контрактів. Навіть якщо розгорнуто лише один контракт, код може бути розділений на кілька контрактів за допомогою успадкування.
Наприклад, контракт NonfungiblePositionManager Uniswap успадковує кілька контрактів. Контракт ERC721Permit безпосередньо використовує стандартний контракт ERC721 від OpenZeppelin, що полегшує управління позиціями за допомогою NFT і підвищує ефективність розробки.
Висновок
Практика є найкращим методом навчання. Спробувавши реалізувати просту версію децентралізованої біржі, можна глибше зрозуміти код Uniswap, а також дізнатися більше про важливі аспекти реальних проектів. Сподіваюся, ці досвіди стануть у нагоді друзям, які прагнуть розвивати проекти в Web3 та DeFi.