Автор: Автор ChiHaoLu, imToken Labs
Ця стаття головним чином представляє розробку та відповідний вміст абстрактних облікових записів (AA, абстрактні облікові записи) у рішенні рівня 2 zkSync. Основна увага буде зосереджена на трьох частинах:
Зміст
фон
Тут, для зручності читання, немає необхідності глибоко розбиратися в zkSync, а коротко розглянемо основну інформацію про zkSync. Існує дві основні версії zkSync: версія 1.0 (zkSync Lite) і версія 2.0 (zkSync Era).
zkSync версії 1.0 підтримує лише EOA (зовнішній обліковий запис) і не підтримує смарт-контракти (підтримує лише передачу та обмін токенів), тоді як zkSync 2.0, а саме zkSync Era, належить до рідного AA (абстрактного облікового запису) (усі типи облікових записів є контрактами, без EOA) , що є різницею між EOA та контрактним обліковим записом в Ethereum), сумісний з EVM (Ethereum Virtual Machine) і підтримує розробку смарт-контрактів за допомогою Rust, Yul, Vyper, Solidity тощо.
ZkSync, згаданий нижче, стосується zkSync 2.0, а саме zkSync Era, якщо не вказано інше.
В zkSync Era є кілька контрактів, які можна зрозуміти, оскільки вони реалізують деякі важливі функції операційної системи zkSync у смарт-контрактах. Ці контракти є попередньо скомпільованими контрактами, які ніколи не розгорталися (запускаються безпосередньо у вузлі), але всі вони мають офіційну адресу.
Під час реалізації протоколу AA zkSync виконуватиме логічні операції та судження через деякі контракти. Наприклад, під час перевірки nonce це оцінюється NonceHolder, тоді як реалізація механізму абстрактного облікового запису та збору комісії оцінюється завантажувачем. Нижче буде представлено їх один за одним.
Резюме облікового запису
Основну концепцію абстракції облікового запису можна звести до двох ключових моментів: абстракція підпису та абстракція платежу.
Мета абстракції підпису — дозволити різним контрактам облікових записів використовувати різні схеми перевірки. Це означає, що користувачі не обмежені алгоритмом цифрового підпису, який може використовувати лише певну криву, а можуть вибрати будь-який механізм перевірки, який їм подобається.
Абстракція платежів має на меті надати користувачам різноманітні варіанти оплати транзакцій. Наприклад, платежі можуть здійснюватися за допомогою токенів ERC-20 замість власних токенів, або трансакції можуть спонсоруватися третьою стороною, або навіть інші більш спеціальні моделі оплати.
Облікові записи в zkSync 2.0 можуть ініціювати транзакції, як EOA, але також можуть використовувати його можливість програмування для реалізації довільної логіки, наприклад облікові записи контрактів. Це те, що ми називаємо абстракцією облікового запису, яка поєднує в собі переваги двох типів облікових записів в Ethereum, щоб зробити досвід використання облікових записів AA більш гнучким, таким чином досягаючи двох вищезазначених цілей: абстракції підпису та абстракції платежу.
Механізм AA в епоху zkSync
В zkSync Era найважливішою роллю zkSync AA є завантажувач, який є контрактом, який в основному використовується для обробки транзакцій і виконання механізму AA, що відповідає контракту EntryPoint EIP-4337. Завантажувач не може бути викликаний користувачем (його може запустити лише Оператор), і він ніколи не розгортався (запускається безпосередньо на вузлі), але має офіційну адресу (може використовуватися для отримання платежів).
Оператор відіграє важливу роль у ZK Rollup. Це централізований сервер поза ланцюгом. Подібно до Sequencer, який ви, можливо, бачили, він відповідає за ініціювання контрактів, таких як завантажувач іззовні.
Власні протоколи абстрагування облікових записів (такі як StarkNet, zkSync) в основному розроблені з посиланням на EIP-4337. У реалізації zkSync користувач надсилає транзакцію оператору, а оператор надсилає транзакцію завантажувачу та запускає ряд обробки.
З точки зору блоку:
Коли завантажувач отримує вхідні дані від оператора, завантажувач спочатку визначає деякі змінні середовища для блоку (такі як ціна на газ, номер блоку, мітка часу блоку тощо). Потім завантажувач послідовно прочитає список транзакцій, спочатку запитає, чи договір облікового запису узгоджується з транзакцією (тобто викличе функцію перевірки в механізмі AA), а потім помістить їх у блок.
Після перевірки кожної транзакції Оператор перевіряє, чи достатньо великий блок, щоб його було надіслано верифікатору (чи минув час очікування). Якщо він достатньо великий або минув час очікування, Оператор закриває блок, припиняє додавати нові транзакції до завантажувача та завершує виконання транзакції.
З точки зору транзакцій, коли Оператор запускає завантажувач, завантажувач оброблятиме кожну транзакцію послідовно:
Перші три кроки вище відповідають циклу перевірки (Verification Loop) EIP-4337, а четвертий крок відповідає циклу виконання (ution Loop) EIP-4337.
Тут наведено в основному оглядовий вступ, а деталі та ролі кожного кроку будуть детально описані один за одним у наступному детальному описі.
Швидкий огляд договору абстрактного облікового запису zkSync
Один раз
Обліковий запис nonce для zkSync записується в системному контракті під назвою NonceHolder, який запам’ятовує, чи використовується кожна пара (account_address, nonce) шляхом зіставлення (відображення), щоб визначити, чи є nonce законним.
Відповідно до вищезазначеного, першим кроком після запуску завантажувача оператором є перевірка nonce. Таким чином, перед початком кожної транзакції NonceHolder використовуватиметься для підтвердження того, чи набір nonces, який зараз використовується, є законним (наразі лише перевіряє, чи вони були використані). Якщо nonce є законним, він увійде у фазу перевірки (Verification Phase), під час якої nonce буде позначено як використаний; якщо він не є законним, транзакція (перевірка) не вдасться.
Важливі моменти щодо поточного nonce zkSync:
Хоча наразі користувачі можуть надсилати кілька транзакцій з різними одноразовими номерами в обліковий запис для виконання одночасно, оскільки zkSync не підтримує паралельну обробку, транзакції з різними одноразовими номерами все одно оброблятимуться послідовно.
Теоретично користувачі можуть використовувати будь-яке 256-розрядне ненульове ціле число як nonce, але zkSync все одно рекомендує використовувати incrementNonceIfEquals як спосіб керування nonce, щоб гарантувати, що він збільшується в порядку (наразі механізм AA zkSync лише підтверджує невикористані nonce, але офіційно документ вказує на те, що послідовне збільшення може знадобитися в майбутньому).
Договір про обліковий запис
Договір облікового запису в zkSync має наступні чотири необхідні точки входу (точка входу), а саме:
Про Paymaster, розмір комісії за обробку (tx.gasprice * tx.gaslimit) тощо буде пояснено в наступних розділах.
В обліковому записі zkSync також є необов’язкова функція страхування uteTransactionFromOutside. Кошти можна вивести на L1 за допомогою «механізму виходу», якщо операції не можуть бути виконані (наприклад, коли генератор послідовностей не відповідає або zkSync вважається регуляторним ризиком). Ця частина має мало спільного з протоколом AA, тому детально описувати її тут не буде, кому цікаво, можете ознайомитися з офіційними документами та специфікацією zkSync.
Ключові моменти та обмеження функцій перевірки
У функції validateTransaction можна реалізовувати різні спеціальні логіки. Наприклад, якщо в обліковому записі реалізовано стандарт EIP-1271, логіку перевірки в EIP-1271 можна застосувати безпосередньо до validateTransaction або звернутися до контракту облікового запису з кількома підписами реалізація в офіційному документі zkSync.
У той же час, щоб уникнути загроз DoS на етапі перевірки EIP-4337, існують деякі обмеження (не можна використовувати зовнішні коди операції та обмежена глибина тощо), а також є подібні обмеження в zkSync, наприклад:
1. Логіка контракту може торкатися лише свого власного слота (якщо адреса контракту облікового запису A):
слот, що належить до адреси А
слот А за будь-якою іншою адресою
Слот keccak256(A||X) будь-якої іншої адреси, яка може безпосередньо використовувати адресу як ключ відображення (наприклад, відображення (адреса=>значення)), також еквівалентно дозволу доступу до слота keccak256( A||X), щоб досягти розширення. Наприклад, баланс токенів на ERC-20.
2. Логіка контракту не повинна використовувати глобальні змінні, такі як block.number
Ключові моменти та обмеження виконання функцій
У функції uteTransaction слід звернути увагу на те, що якщо ви хочете виконати системний виклик (Call), вам потрібно переконатися, що він має прапор is. Оскільки ці системні контракти мають великий вплив на систему облікових записів. Наприклад, єдиний спосіб збільшити nonce – це взаємодіяти з NonceHolder. Щоб розгорнути контракт, ви повинні взаємодіяти з ContractDeployer. Використання прапорця is може гарантувати, що розробники облікових записів свідомо взаємодіють з системними контрактами.
Однак рекомендується використовувати бібліотеку ContractsCaller, надану zkSync, щоб уникнути самостійної обробки прапора is, і використовувати CallWithPropagatedRevert для завершення системного виклику.
Зразок коду вище передбачає взаємодію з DEPLOYER__CONTRACT. Найпоширенішою ситуацією системного контракту, з якою стикаються розробники облікових записів, є те, що ми хочемо використовувати обліковий запис для розгортання контракту. У цей час ми повинні взаємодіяти з системним контрактом ContractDeployer. У цьому випадку розробник облікового запису має зв’язатися з контрактом ContractDeployer, щоб переконатися, що контракт успішно розгорнуто та виконує необхідні операції.
Комісійна модель і Paymaster в епоху zkSync
Збори та ліміт газу
Комісійна модель zkSync дуже схожа на Ethereum, платіжним токеном залишається ETH. Однак, як і інші рішення рівня 2 (такі як Arbitrum, Optimism), zkSync також потребує врахування додаткових витрат на публікацію в L1 (комісія за безпеку) на додаток до основних витрат на обчислення та запис. Оскільки ціна на газ, який публікує дані в L1, дуже нестабільна, Оператор zkSync визначає такі динамічні параметри, коли кожен блок відкривається (починає записувати транзакції):
gasPrice: ціна газу в gwei, тобто tx.gasprice у згаданому вище об’єкті транзакції
gasPerPubdata: кількість газу, необхідна для публікації байта даних в Ethereum.
Крім того, на відміну від EIP-4337, zkSync не потрібно визначати три ліміти газу: verificationGas, utionGas і preVerificationGas, але вимагає лише gasLimit для покриття всіх вищезазначених витрат, тому користувачі повинні переконатися, що gasLimit достатньо для покриття Етап перевірки, етап оновлення та завантаження даних Усі витрати, такі як плата за безпеку, на L1. Ця комісія включена в tx.gaslimit у згаданому вище об’єкті транзакції.
Помножте два (tx.gasprice * tx.gaslimit), щоб отримати комісію за транзакцію, сплачену завантажувачу.
Оплата праці
Paymaster переважно сплачує ETH завантажувачу замість контракту облікового запису користувача на етапі комісії за транзакцію користувача. Користувачі можуть вибрати різні платіжні системи та способи оплати, щоб сплатити комісію за обробку, наприклад (але не обмежуючись цим):
Оплата токенів ERC-20 Paymaster до початку транзакції або після її виконання
Поповнити контракт Paymaster кредитною карткою
Paymaster продовжуватиме сплачувати частину або всі збори для користувачів безкоштовно
Спосіб взаємодії користувачів із Paymaster залежить від різних протоколів, він може бути централізованим або децентралізованим; він може бути до або після транзакції; він може використовувати токени ERC-20 або законний платіжний засіб або навіть безкоштовний.
Контракт Paymaster для zkSync в основному складається з двох функцій, а саме validateAndPayForPaymasterTransaction (обов’язково) і postTransaction (необов’язково), обидві з яких може викликати лише завантажувач:
validateAndPayForPaymasterTransaction — це єдина функція, яка має бути реалізована в усьому контракті Paymaster. Коли оператор отримує транзакцію з параметром Paymaster, це означає, що комісія за обробку оплачується не договором облікового запису користувача, а Paymaster. У цей момент оператор викличе validateAndPayForPaymasterTransaction, щоб визначити, чи готовий Paymaster сплатити комісію за транзакцію. Якщо Paymaster погодиться, ця функція надішле принаймні tx.gasprice * tx.gaslimit ETH до завантажувача.
postTransaction є додатковою функцією, яка зазвичай використовується для відшкодування (повернення невикористаного газу відправнику). Однак поточний zkSync ще не підтримує цю операцію.
Paymaster у zkSync виконає postTransaction після впровадження postTransaction, що відрізняється від EIP-4337. EIP-4337 не викличе postOp, якщо validatePaymasterUserOp не повертає контекст, і навпаки.
Виходячи з вищезазначеного, наприклад, користувач тепер хоче надіслати транзакцію, комісія за обробку якої оплачується Paymaster, процес виглядає наступним чином:
На останньому кроці, навіть якщо postTransaction неможливо виконати через помилку браку газу, ця транзакція AA вважається успішною, але дія виклику postTransaction пропускається.
Якщо ви глибше заглибитесь у Paymaster zkSync, то побачите, що його Правила перевірки дещо відрізняються від 4337 (zkSync Paymaster може наступати на будь-який інший контрактний слот), а також існують різні типи (наприклад, на основі схвалення). до порівняння деталей.Кого цікавить може звернутися до офіційних документів або моєї попередньої реалізації.
Підсумок і порівняння
Завдяки попереднім поясненням ми дізналися, які важливі точки входу має договір облікового запису, а також їхні функції та відповідні обмеження. Одночасно ми також дізналися про функції системного контракту. Далі, давайте підсумуємо процес транзакції автоматизованих операцій (AA) у zkSync від будівництва до завершення, і я також надам більш докладні посилання для тих, хто хоче дізнатися більше:
Користувач використовує SDK або гаманець локально для створення об’єктів транзакції (наприклад: від, до, дані, значення тощо).
Користувач підписує транзакцію. Підписом тут не обов’язково є традиційний формат EIP-712 і підпис кривої ECDSA. zkSync також підтримує EIP-2718 і EIP-1559. Ключем до вибору методу підпису та методу перевірки є перевірка за допомогою функції перевірки в договорі облікового запису.
Надішліть підписану транзакцію оператору через RPC API. У цей момент транзакція переходить у стан очікування. Оператор передає транзакцію завантажувачу (викликає функцію processL2Tx у контракті завантажувача) і запускає серію процесів протоколу AA.
Завантажувач перевірить, чи Nonce є законним, і використає NonceHolder для перевірки.
Завантажувач викличе функцію validateTransaction у контракті облікового запису користувача, щоб підтвердити, що транзакцію авторизовано власником облікового запису.
Bootloader може стягувати комісію двома способами, і конкретний спосіб стягнення плати залежить від параметрів транзакції (чи додається параметр paymaster під час створення об’єкта транзакції):
a. Виклик функції payForTransaction і договір рахунку, щоб стягнути комісію за транзакцію;
b. Викличте функції pripravForPaymaster і validateAndPayForPaymasterTransaction, щоб стягнути комісію за транзакцію за контрактом Paymaster.
«Зателефонуйте payForTransaction, щоб укласти комісію з обліковим записом» або «зателефонуйте, щоб підготуватиPaymaster і validateAndPayForPaymasterTransaction, щоб укласти комісію з Paymaster»
Перевірте, чи отримав завантажувач принаймні комісію за транзакцію tx.gasprice * tx.gaslimit.
Завантажувач викличе функцію uteTransaction у контракті облікового запису користувача, щоб виконати транзакцію.
(Необов’язково) Якщо для оплати комісії за транзакцію використовується Paymaster, завантажувач викличе функцію postTransaction. Якщо Paymaster не реалізує postTransaction або газ вичерпано, цей крок буде пропущено.
Наведені вище 4.~7. кроки — це фаза перевірки (визначена в l2TxValidation завантажувача) і фаза виконання 8.~9. кроків (визначена в l2Txution завантажувача).
Порівняння EIP-4337, StarkNet і zkSync Era
В основному процеси механізму АА у трьох подібні, усі вони включають стадію перевірки→механізм комісії за обробку (оплачується за договором рахунку або Paymaster)→етап виконання.Основні відмінності:
Порівняно
Оскільки StarkNet ще не реалізував механізм Paymaster, а zkSync ще не завершив розробку механізму відшкодування газу, деякі більш детальні порівняння тут не наведено.
Крім того, ми завершили створення P2P mempool для поточного об’єднувача 4337, а Sequencer і Operator zkRollups також є єдиними офіційними серверами, тому є певні централізовані компоненти.
У процесі розробки, оскільки zkSync не має проблеми підключення до різних групувальників (потрібно лише взаємодіяти з Operator API), він простий у використанні 4337, і досвід розробки контрактів облікових записів (SDK) також кращий; на водночас zkSync може використовувати Solidity як контрактну мову розробки, тому немає потреби перетинати поріг Cairo у розробці StarkNet.
Висновок
Оскільки і StarkNet, і zkSync належать до категорії локальних AA (Native AA), ви також можете звернутися до мого попереднього вступу до StarkNet AA під назвою «Вступ до абстракції облікового запису StarkNet» (Вступ до абстракції облікового запису StarkNet). Крім того, ви можете прочитати інші статті, пов’язані з EIP-4337, щоб отримати додаткові відомості.