Cet article présente principalement le développement et le contenu associé des comptes abstraits (AA, comptes abstraits) dans la solution Layer 2 de zkSync. L’accent sera mis sur trois parties :
Contrat de compte : type de compte, point d'entrée important et points clés associés du contrat de compte
Transaction : méthode de vérification, méthode d'exécution et processus de transaction AA
Frais de traitement : frais de transaction, Paymaster
Table des matières
préface
Bref aperçu du contrat zkSync AA
Modèle de frais et Paymaster à l'ère de zkSync
Résumé et comparaison
Conclusion
arrière-plan
Familier avec le portefeuille de contrats intelligents et ses fonctionnalités communes
Obtenez un aperçu du fonctionnement des transactions Ethereum
Une compréhension générale du mode de fonctionnement de l'EIP-4337
Une compréhension générale du mode de fonctionnement de ZK (validité) Rollup
Aperçu rapide du zkSync
Ici, pour faciliter la lecture, il n'est pas nécessaire de comprendre zkSync en profondeur, mais de revoir brièvement les informations de base de zkSync. Il existe deux versions principales de zkSync, la version 1.0 (zkSync Lite) et la version 2.0 (zkSync Era).
La version 1.0 de zkSync ne prend en charge que l'EOA (compte externe) et ne prend pas en charge les contrats intelligents (prend uniquement en charge le transfert et l'échange de jetons), tandis que zkSync 2.0, à savoir zkSync Era, appartient à l'AA natif (compte abstrait) (tous les types de comptes sont des contrats, pas d'EOA). , qui est la différence entre EOA et compte de contrat dans Ethereum), est compatible avec EVM (Ethereum Virtual Machine) et prend en charge le développement de contrats intelligents utilisant Rust, Yul, Vyper, Solidity, etc.
Le zkSync mentionné ci-dessous fait référence à zkSync 2.0, à savoir zkSync Era, sauf indication contraire.
Dans zkSync Era, il existe plusieurs contrats, qui peuvent être compris car ils implémentent certaines fonctions importantes du système d'exploitation de zkSync dans les contrats intelligents. Ces contrats sont des contrats précompilés qui n'ont jamais été déployés (exécutés directement dans le nœud), mais ils ont tous une adresse formelle.
Lors de la mise en œuvre du protocole AA,zkSync effectuera des opérations et des jugements logiques via certains contrats.Par exemple, lors de la vérification du nonce, il est jugé par le NonceHolder, tandis que la mise en œuvre du mécanisme de compte abstrait et la collecte des frais sont jugées par le chargeur de démarrage. Ce qui suit les présentera un par un.
Récapitulatif de l'abstraction du compte
Le concept de base de l’abstraction des comptes peut être résumé en deux points clés : l’abstraction des signatures et l’abstraction des paiements.
L'objectif de l'abstraction de signature est de permettre à différents contrats de compte d'utiliser différents schémas de vérification. Cela signifie que les utilisateurs ne sont pas limités à un algorithme de signature numérique qui ne peut utiliser qu'une courbe spécifique, mais peuvent choisir le mécanisme de vérification de leur choix.
L'abstraction de paiement vise à fournir aux utilisateurs une variété d'options de paiement par transaction. Par exemple, les paiements pourraient être effectués à l'aide de jetons ERC-20 au lieu de jetons natifs, ou les transactions pourraient être sponsorisées par un tiers, ou même d'autres modèles de paiement plus ponctuels.
Les comptes dans zkSync 2.0 peuvent lancer des transactions comme EOA, mais peuvent également utiliser sa programmabilité pour implémenter une logique arbitraire, telle que des comptes de contrat. C'est ce que nous appelons l'abstraction de compte, qui combine les avantages des deux types de comptes dans Ethereum pour rendre l'expérience d'utilisation des comptes AA plus flexible, atteignant ainsi les deux objectifs ci-dessus : l'abstraction de signature et l'abstraction de paiement.
Mécanisme AA à l'ère zkSync
Dans zkSync Era, le rôle le plus important de zkSync AA est le chargeur de démarrage, qui est un contrat, principalement utilisé pour traiter les transactions et exécuter le mécanisme AA, correspondant au contrat EntryPoint d'EIP-4337. Le bootloader ne peut pas être appelé par l'utilisateur (il ne peut être déclenché que par l'opérateur), et il n'a jamais été déployé (s'exécute directement sur le nœud), mais il a une adresse officielle (peut être utilisée pour recevoir des paiements).
L'opérateur joue un rôle important dans ZK Rollup. Il s'agit d'un serveur hors chaîne centralisé. Semblable au séquenceur que vous avez peut-être vu, il est responsable du déclenchement de contrats tels que le chargeur de démarrage depuis l'extérieur.
Les protocoles d'abstraction de compte natifs (tels que StarkNet, zkSync) sont essentiellement conçus en référence à EIP-4337. Dans la mise en œuvre de zkSync, l'utilisateur enverra la transaction à l'opérateur, et l'opérateur enverra la transaction au chargeur de démarrage et démarrera un série de traitement.
D'un point de vue bloc :
Lorsque le chargeur de démarrage reçoit une entrée de l'opérateur, le chargeur de démarrage définira d'abord certaines variables d'environnement pour le bloc (telles que le prix de l'essence, le numéro de bloc, l'horodatage du bloc, etc.). Ensuite, le chargeur de démarrage lira séquentiellement la liste des transactions, demandera d'abord si le contrat de compte est d'accord avec la transaction (c'est-à-dire appellera la fonction de validation dans le mécanisme AA), puis les placera dans le bloc.
Une fois chaque transaction vérifiée, l'opérateur vérifie si le bloc est suffisamment grand pour être envoyé au vérificateur (ou s'il expire). S'il est suffisamment grand ou s'il expire, l'opérateur ferme le bloc, arrête d'ajouter de nouvelles transactions au chargeur de démarrage et termine l'exécution de la transaction.
Du point de vue des transactions, lorsque l'opérateur déclenche le chargeur de démarrage, celui-ci traitera chaque transaction de manière séquentielle :
Confirmez si le nonce correspondant à l'adresse contractuelle du compte utilisateur est légal
Appelez la fonction de validation sur le contrat du compte utilisateur pour vérification
Une fois la vérification réussie, le contrat de compte remettra les frais de gaz à l'adresse du chargeur de démarrage (ou via Paymaster, qui sera présenté plus tard), et le chargeur de démarrage vérifiera s'il a reçu suffisamment d'argent.
Appelez la fonction ute sur le contrat de compte utilisateur pour exécuter la transaction.
Les trois premières étapes ci-dessus correspondent à la boucle de vérification (Verification Loop) de l'EIP-4337, et la quatrième étape correspond à la boucle d'exécution (ution Loop) de l'EIP-4337.
Voici principalement une introduction générale, et les détails et les rôles de chaque étape seront élaborés un par un dans la description détaillée suivante.
Aperçu rapide du contrat de compte abstrait zkSync
Pas de fois
Le nom occasionnel de compte de zkSync est enregistré dans un contrat système nommé NonceHolder, qui se souvient si chaque paire (compte_adresse, nom occasionnel) est utilisée par mappage (mapping) pour juger si le nom occasionnel est légal.
Selon ce qui précède, la première étape après que l'opérateur a déclenché le chargeur de démarrage consiste à vérifier le nom occasionnel. Par conséquent, avant le début de chaque transaction, NonceHolder sera utilisé pour confirmer si l'ensemble de noms occasionnels actuellement utilisé est légal (actuellement, il vérifie uniquement s'ils ont été utilisés). Si le nonce est légal, il entrera dans la phase de vérification (Verification Phase), moment auquel le nonce sera marqué comme utilisé ; s'il n'est pas légal, la transaction (vérification) échouera.
Points importants concernant le nonce actuel de zkSync :
Bien qu'actuellement les utilisateurs puissent envoyer plusieurs transactions avec différents noms occasionnels au compte pour exécution en même temps, étant donné que zkSync ne prend pas en charge le traitement parallèle, les transactions avec différents noms occasionnels seront toujours traitées séquentiellement.
En théorie, les utilisateurs peuvent utiliser n'importe quel entier non nul de 256 bits comme nonce, mais zkSync recommande toujours d'utiliser incrémentNonceIfEquals comme moyen de gérer le nonce pour garantir qu'il est incrémenté dans l'ordre (actuellement, le mécanisme AA de zkSync ne confirme que le nonce inutilisé, mais le fonctionnaire (le document indique que l'incrément séquentiel pourrait être nécessaire à l'avenir).
Contrat de compte
Le contrat de compte dans zkSync comporte les quatre points d'entrée nécessaires suivants (Entry Point), qui sont :
validateTransaction : appelé pendant la phase de vérification pour confirmer si l'opération est autorisée par le propriétaire du compte, où les utilisateurs peuvent personnaliser leur propre logique de vérification (telle que divers algorithmes de signature, multi-signature, etc.).
payForTransaction : lorsque les frais de transaction sont payés par ce compte (au lieu d'utiliser paymaster), l'opérateur appellera cette fonction pour payer au moins tx.gasprice * tx.gaslimit d'ETH à l'adresse du chargeur de démarrage.
PrepareForPaymaster : lorsque les frais de transaction seront payés par Paymaster, l'opérateur appellera cette fonction pour terminer le travail de préparation avant d'interagir avec Paymaster. L'exemple fourni par zkSync est un jeton ERC-20 approuvé par Paymaster.
uteTransaction : une fois la phase de vérification réussie et les frais de transaction facturés avec succès, cette fonction sera utilisée pour effectuer l'opération que l'utilisateur souhaite réaliser (telle que l'interaction avec le contrat, le versement, etc.).
Concernant Paymaster, le montant des frais de traitement (tx.gasprice * tx.gaslimit), etc. sera expliqué dans les chapitres suivants.
Il existe également une fonction d'assurance non essentielle uteTransactionFromOutside dans le compte de zkSync. Les fonds peuvent être retirés vers L1 à l'aide du « mécanisme d'échappement » lorsque les opérations ne peuvent pas être effectuées (par exemple lorsque le générateur de séquence ne répond pas ou que zkSync s'avère être un risque réglementaire). Cette partie n'a pas grand-chose à voir avec le protocole AA, elle ne sera donc pas décrite en détail ici. Ceux qui sont intéressés peuvent consulter les documents officiels et la spécification de zkSync.
Points clés et limites des fonctions de validation
Dans la fonction validateTransaction, vous pouvez implémenter diverses logiques personnalisées. Par exemple, si le compte a implémenté la norme EIP-1271, vous pouvez appliquer directement la logique de vérification dans EIP-1271 à validateTransaction, ou vous référer à l'implémentation du contrat de compte multi-signature. dans le document officiel de zkSync.
Dans le même temps, afin d'éviter les menaces DoS lors de la phase de vérification d'EIP-4337, il existe certaines restrictions (ne peut pas impliquer des opcodes externes et une profondeur limitée, etc.), et il existe des restrictions similaires dans zkSync, par exemple :
1. La logique du contrat ne peut toucher que son propre emplacement (si l'adresse du contrat de compte est A) :
emplacement appartenant à l'adresse A
emplacement A à toute autre adresse
Le slot keccak256(A||X) de toute autre adresse, qui peut utiliser directement l'adresse comme clé du mappage (comme le mappage (adresse=>valeur)), équivaut également à autoriser l'accès au slot keccak256( A||X), pour réaliser l’expansion. Par exemple, les soldes de jetons sur ERC-20.
2. La logique contractuelle ne doit pas utiliser de variables globales, telles que block.number
Points clés et limites des fonctions d'exécution
Ce qu'il faut noter dans la fonction uteTransaction, c'est que si vous souhaitez effectuer un appel système (Call), vous devez vous assurer qu'il possède l'indicateur is. Parce que ces contrats système ont un impact important sur le système de compte. Par exemple, la seule façon d'augmenter le nombre nonce est d'interagir avec NonceHolder. Pour déployer un contrat, vous devez interagir avec ContractDeployer. L'utilisation de l'indicateur is peut garantir que les développeurs de comptes interagissent consciemment avec des contrats système.
Cependant, il est recommandé d'utiliser la bibliothèque ContractsCaller fournie par zkSync pour éviter de gérer vous-même l'indicateur is et d'utiliser CallWithPropagatedRevert pour terminer l'appel système.
L'exemple de code ci-dessus implique une interaction avec DEPLOYER__CONTRACT. La situation de contrat système la plus courante rencontrée par les développeurs de comptes est que nous souhaitons utiliser un compte pour déployer un contrat. À ce stade, nous devons interagir avec le contrat système ContractDeployer. Dans ce cas, le développeur du compte doit communiquer avec le contrat ContractDeployer pour s'assurer que le contrat est déployé avec succès et effectue les opérations requises.
Modèle de frais et Paymaster à l'ère de zkSync
Frais et limite de gaz
Le modèle de frais de zkSync est très similaire à celui d’Ethereum, le jeton de frais est toujours ETH. Cependant, comme d'autres solutions de couche 2 (telles que Arbitrum, Optimism), zkSync doit également prendre en compte le coût supplémentaire de publication sur L1 (frais de sécurité) en plus des coûts de calcul de base et d'emplacement d'écriture. Étant donné que le prix du gaz qui publie les données sur L1 est très instable, l'opérateur de zkSync définit les paramètres dynamiques suivants lorsque chaque bloc est ouvert (commence à enregistrer les transactions) :
gasPrice : prix du gaz en gwei, c'est-à-dire tx.gasprice dans l'objet de transaction mentionné ci-dessus
gasPerPubdata : La quantité de gaz nécessaire pour publier un octet de données sur Ethereum
De plus, contrairement à EIP-4337, zkSync n'a pas besoin de définir trois limites de gaz : vérificationGas, utionGas et preVerificationGas, mais nécessite uniquement une gasLimit pour couvrir tous les coûts ci-dessus, les utilisateurs doivent donc s'assurer que la gasLimit est suffisante pour couvrir le Étape de vérification, étape de mise en œuvre et téléchargement des données Toutes les dépenses telles que les frais de sécurité vers L1. Ce coût des frais est inclus dans le tx.gaslimit dans l'objet de transaction mentionné ci-dessus.
Multipliez les deux (tx.gasprice * tx.gaslimit) pour obtenir les frais de transaction payés au chargeur de démarrage.
Caissier
Paymaster paie principalement l'ETH au chargeur de démarrage au lieu du contrat de compte de l'utilisateur au stade des frais de paiement de la transaction utilisateur. Les utilisateurs peuvent choisir différents modes Paymaster et de paiement pour payer les frais de traitement, tels que (mais sans s'y limiter) :
Paiement des jetons ERC-20 à Paymaster avant le lancement de la transaction ou après l'exécution de la transaction
Recharger le contrat Paymaster avec une carte bancaire
Paymaster continuera à payer gratuitement une partie ou la totalité des frais des utilisateurs
La manière dont les utilisateurs interagissent avec Paymaster dépend de différents protocoles : elle peut être centralisée ou décentralisée ; elle peut être avant ou après la transaction ; elle peut utiliser des jetons ERC-20 ou de la monnaie légale, ou même gratuite.
Le contrat Paymaster de zkSync se compose principalement de deux fonctions, à savoir validateAndPayForPaymasterTransaction (obligatoire) et postTransaction (facultatif), qui ne peuvent toutes deux être appelées que par le chargeur de démarrage :
validateAndPayForPaymasterTransaction est la seule fonction qui doit être implémentée dans l'ensemble du contrat Paymaster. Lorsque l'opérateur reçoit une transaction avec un paramètre Paymaster, cela signifie que les frais de traitement ne sont pas payés par le contrat de compte de l'utilisateur, mais par Paymaster. À ce stade, l'opérateur appellera validateAndPayForPaymasterTransaction pour déterminer si le Paymaster est prêt à payer les frais de transaction. Si Paymaster est d'accord, cette fonction enverra au moins tx.gasprice * tx.gaslimit ETH au chargeur de démarrage.
postTransaction est une fonction facultative, généralement utilisée pour le remboursement (retourner le gaz non utilisé à l'expéditeur). Cependant, zkSync actuel ne prend pas encore en charge cette opération.
Le Paymaster dans zkSync exécutera postTransaction après l'implémentation de postTransaction, ce qui est différent de EIP-4337. EIP-4337 n'appellera pas postOp lorsque validatePaymasterUserOp ne renvoie pas le contexte, et vice versa.
Sur la base de ce qui précède, par exemple, l'utilisateur souhaite maintenant envoyer une transaction dont les frais de traitement sont payés par Paymaster, le processus est le suivant :
Utilisez NonceHolder pour confirmer si le nonce est légal
Appelez validateTransaction sur le contrat de compte de l'utilisateur pour vérifier que la transaction est autorisée par le propriétaire du compte.
Appelez prepareForPaymaster sur le contrat de compte de l'utilisateur, qui peut exécuter, par exemple, approuver un certain nombre de jetons ERC-20 à Paymaster ou ne rien faire.
Appelez validateAndPayForPaymasterTransaction sur le contrat Paymaster pour confirmer que Paymaster est prêt à payer et facturer les frais de traitement, et en même temps, Paymaster facturera à l'utilisateur un certain montant d'ERC-20 (approuvé précédemment)
Confirmez que le chargeur de démarrage reçoit le montant correct (au moins tx.gasprice * tx.gaslimit) de frais ETH
Appelez uteTransaction sur le contrat de compte de l'utilisateur pour exécuter la transaction souhaitée par l'utilisateur.
Si le contrat Paymaster implémente postTransaction et que le gaz est toujours suffisant (pas d'erreur de panne de gaz), exécutez postTransaction
Dans la dernière étape, même si postTransaction ne peut pas être exécuté en raison d'une erreur de manque de gaz, cette transaction AA est considérée comme réussie, mais l'action d'appeler postTransaction est omise.
Si vous approfondissez le Paymaster de zkSync, vous constaterez que ses règles de vérification sont légèrement différentes de celles de 4337 (zkSync Paymaster peut intervenir sur n'importe quel autre emplacement de contrat), et il en existe également différents types (tels que basés sur l'approbation). à la comparaison des détails. Ceux qui sont intéressés peuvent se référer aux documents officiels ou à ma mise en œuvre précédente.
Résumé et comparaison
Grâce aux explications précédentes, nous avons appris quels sont les points d'entrée importants du contrat de compte, ainsi que leurs fonctions et restrictions associées. Dans le même temps, nous avons également découvert les fonctions du contrat système. Ensuite, résumons le processus d'une transaction d'opération automatisée (AA) dans zkSync de la construction à l'achèvement, et je fournirai également des références plus détaillées pour ceux qui souhaitent en savoir plus :
L'utilisateur utilise le SDK ou le portefeuille localement pour construire des objets de transaction (par exemple : de, à, données, valeur, etc.).
L'utilisateur signe la transaction. La signature ici n'est pas nécessairement le format EIP-712 traditionnel et la signature de courbe ECDSA. zkSync prend également en charge EIP-2718 et EIP-1559. La clé pour choisir une méthode de signature et une méthode de vérification est de vérifier via la fonction de vérification dans le contrat de compte.
Envoyez la transaction signée à l'opérateur via l'API RPC. À ce stade, la transaction passe à l’état en attente. L'opérateur transmet la transaction au chargeur de démarrage (appelle la fonction processL2Tx sur le contrat du chargeur de démarrage) et démarre une série de processus de protocole AA.
Bootloader vérifiera si le Nonce est légal et utilisera NonceHolder pour vérifier.
Le Bootloader appellera la fonction validateTransaction sur le contrat du compte utilisateur pour confirmer que la transaction a été autorisée par le propriétaire du compte.
Bootloader dispose de deux manières de facturer des frais, et la méthode de facturation spécifique dépend des paramètres de transaction (si le paramètre paymaster est attaché lors de la construction de l'objet de transaction) :
a. Appelez la fonction payForTransaction et le contrat de compte pour facturer les frais de transaction ;
b. Appelez les fonctions prepareForPaymaster et validateAndPayForPaymasterTransaction pour collecter les frais de transaction avec le contrat Paymaster.
"Appelez payForTransaction pour contracter les frais avec le compte" ou "appelez PrepareForPaymaster et validateAndPayForPaymasterTransaction pour contracter les frais avec Paymaster"
Vérifiez si le chargeur de démarrage a reçu au moins les frais de transaction tx.gasprice * tx.gaslimit.
Bootloader appellera la fonction uteTransaction sur le contrat du compte utilisateur pour exécuter la transaction.
(Facultatif) Si vous utilisez Paymaster pour payer les frais de transaction, le chargeur de démarrage appellera la fonction postTransaction. Si Paymaster n'implémente pas postTransaction ou si le gaz est épuisé, cette étape sera ignorée.
Les étapes 4 à 7 ci-dessus sont la phase de vérification (définie dans la l2TxValidation du chargeur de démarrage) et la phase d'exécution des étapes 8 à 9 (définie dans la l2Txution du chargeur de démarrage).
Comparaison d'EIP-4337, StarkNet et zkSync Era
Fondamentalement, les processus du mécanisme AA des trois sont similaires, qui sont tous une étape de vérification → un mécanisme de frais de traitement (payés par contrat de compte ou Paymaster) → une étape d'exécution. Les principales différences sont :
Le rôle de la mise en œuvre du mécanisme AA est le suivant : la différence entre l'ouverture à l'ère zkSync et les deux autres AA est que l'opérateur doit coopérer avec le chargeur de démarrage (contrat système), par exemple, le chargeur de démarrage ouvrira un nouveau bloc et définira les paramètres pertinents du bloc, et recevoir l'opération Le trader envoyée par le membre et vérifiée. En 4337, cette partie est coordonnée par Bundler et EntryPoint, tandis que dans StarkNet, cette partie est entièrement en charge du Sequencer.
Le coût du gaz doit-il prendre en compte les frais de sécurité L1 : L2 AA doit prendre en compte le coût de téléchargement des données vers L1, pas seulement les cumuls ZK (validité) AA natifs mentionnés dans le push, mais doit également être inclus dans L1 lorsqu'il est optimiste. Les rollups implémentent des frais de sécurité 4337 (calculés dans preVerificationGas, voir les documents relatifs à l'alchimie pour plus de détails).
S'il est possible d'envoyer des transactions avant le déploiement du contrat de compte : à l'ère de StarkNet et de zkSync, il n'y a pas d'EntryPoint comme 4337 qui a le champ initCode pour permettre à l'utilisateur de déployer le contrat de compte, donc il n'envoie pas de transactions avant que le compte puisse être configuré.
Par rapport
Étant donné que StarkNet n'a pas encore réalisé le mécanisme Paymaster et que zkSync n'a pas encore terminé la conception du mécanisme de remboursement de gaz, certaines comparaisons plus détaillées ne sont pas répertoriées ici.
De plus, nous avons complété le pool de mémoire P2P pour le bundler 4337 actuel, et le séquenceur et l'opérateur de zkRollups sont également les seuls serveurs officiels, il existe donc certains composants centralisés.
Dans le processus de développement, puisque zkSync n'a pas de problème de connexion avec divers bundlers (il suffit d'interagir avec l'API de l'opérateur), il est facile d'utiliser 4337 et l'expérience de développement de contrats de compte (SDK) est également meilleure ; en même temps, zkSync peut utiliser Solidity comme langage de développement contractuel, il n'est donc pas nécessaire de franchir le seuil du Caire dans le développement de StarkNet.
Conclusion
Étant donné que StarkNet et zkSync appartiennent tous deux à la catégorie des AA locaux (AA natif), vous pouvez également vous référer à ma précédente introduction à StarkNet AA, intitulée « Introduction de l'abstraction de compte StarkNet » (Introduction de l'abstraction de compte StarkNet). Vous pouvez également lire d'autres articles liés à EIP-4337 pour plus d'informations.
Voir l'original
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
Introduction à l'abstraction de compte native dans zkSync
Auteur : Écrit par ChiHaoLu, imToken Labs
Cet article présente principalement le développement et le contenu associé des comptes abstraits (AA, comptes abstraits) dans la solution Layer 2 de zkSync. L’accent sera mis sur trois parties :
Table des matières
arrière-plan
Ici, pour faciliter la lecture, il n'est pas nécessaire de comprendre zkSync en profondeur, mais de revoir brièvement les informations de base de zkSync. Il existe deux versions principales de zkSync, la version 1.0 (zkSync Lite) et la version 2.0 (zkSync Era).
La version 1.0 de zkSync ne prend en charge que l'EOA (compte externe) et ne prend pas en charge les contrats intelligents (prend uniquement en charge le transfert et l'échange de jetons), tandis que zkSync 2.0, à savoir zkSync Era, appartient à l'AA natif (compte abstrait) (tous les types de comptes sont des contrats, pas d'EOA). , qui est la différence entre EOA et compte de contrat dans Ethereum), est compatible avec EVM (Ethereum Virtual Machine) et prend en charge le développement de contrats intelligents utilisant Rust, Yul, Vyper, Solidity, etc.
Le zkSync mentionné ci-dessous fait référence à zkSync 2.0, à savoir zkSync Era, sauf indication contraire.
Dans zkSync Era, il existe plusieurs contrats, qui peuvent être compris car ils implémentent certaines fonctions importantes du système d'exploitation de zkSync dans les contrats intelligents. Ces contrats sont des contrats précompilés qui n'ont jamais été déployés (exécutés directement dans le nœud), mais ils ont tous une adresse formelle.
Lors de la mise en œuvre du protocole AA,zkSync effectuera des opérations et des jugements logiques via certains contrats.Par exemple, lors de la vérification du nonce, il est jugé par le NonceHolder, tandis que la mise en œuvre du mécanisme de compte abstrait et la collecte des frais sont jugées par le chargeur de démarrage. Ce qui suit les présentera un par un.
Récapitulatif de l'abstraction du compte
Le concept de base de l’abstraction des comptes peut être résumé en deux points clés : l’abstraction des signatures et l’abstraction des paiements.
L'objectif de l'abstraction de signature est de permettre à différents contrats de compte d'utiliser différents schémas de vérification. Cela signifie que les utilisateurs ne sont pas limités à un algorithme de signature numérique qui ne peut utiliser qu'une courbe spécifique, mais peuvent choisir le mécanisme de vérification de leur choix.
L'abstraction de paiement vise à fournir aux utilisateurs une variété d'options de paiement par transaction. Par exemple, les paiements pourraient être effectués à l'aide de jetons ERC-20 au lieu de jetons natifs, ou les transactions pourraient être sponsorisées par un tiers, ou même d'autres modèles de paiement plus ponctuels.
Les comptes dans zkSync 2.0 peuvent lancer des transactions comme EOA, mais peuvent également utiliser sa programmabilité pour implémenter une logique arbitraire, telle que des comptes de contrat. C'est ce que nous appelons l'abstraction de compte, qui combine les avantages des deux types de comptes dans Ethereum pour rendre l'expérience d'utilisation des comptes AA plus flexible, atteignant ainsi les deux objectifs ci-dessus : l'abstraction de signature et l'abstraction de paiement.
Mécanisme AA à l'ère zkSync
Dans zkSync Era, le rôle le plus important de zkSync AA est le chargeur de démarrage, qui est un contrat, principalement utilisé pour traiter les transactions et exécuter le mécanisme AA, correspondant au contrat EntryPoint d'EIP-4337. Le bootloader ne peut pas être appelé par l'utilisateur (il ne peut être déclenché que par l'opérateur), et il n'a jamais été déployé (s'exécute directement sur le nœud), mais il a une adresse officielle (peut être utilisée pour recevoir des paiements).
L'opérateur joue un rôle important dans ZK Rollup. Il s'agit d'un serveur hors chaîne centralisé. Semblable au séquenceur que vous avez peut-être vu, il est responsable du déclenchement de contrats tels que le chargeur de démarrage depuis l'extérieur.
Les protocoles d'abstraction de compte natifs (tels que StarkNet, zkSync) sont essentiellement conçus en référence à EIP-4337. Dans la mise en œuvre de zkSync, l'utilisateur enverra la transaction à l'opérateur, et l'opérateur enverra la transaction au chargeur de démarrage et démarrera un série de traitement.
D'un point de vue bloc :
Lorsque le chargeur de démarrage reçoit une entrée de l'opérateur, le chargeur de démarrage définira d'abord certaines variables d'environnement pour le bloc (telles que le prix de l'essence, le numéro de bloc, l'horodatage du bloc, etc.). Ensuite, le chargeur de démarrage lira séquentiellement la liste des transactions, demandera d'abord si le contrat de compte est d'accord avec la transaction (c'est-à-dire appellera la fonction de validation dans le mécanisme AA), puis les placera dans le bloc.
Une fois chaque transaction vérifiée, l'opérateur vérifie si le bloc est suffisamment grand pour être envoyé au vérificateur (ou s'il expire). S'il est suffisamment grand ou s'il expire, l'opérateur ferme le bloc, arrête d'ajouter de nouvelles transactions au chargeur de démarrage et termine l'exécution de la transaction.
Du point de vue des transactions, lorsque l'opérateur déclenche le chargeur de démarrage, celui-ci traitera chaque transaction de manière séquentielle :
Les trois premières étapes ci-dessus correspondent à la boucle de vérification (Verification Loop) de l'EIP-4337, et la quatrième étape correspond à la boucle d'exécution (ution Loop) de l'EIP-4337.
Voici principalement une introduction générale, et les détails et les rôles de chaque étape seront élaborés un par un dans la description détaillée suivante.
Aperçu rapide du contrat de compte abstrait zkSync
Pas de fois
Le nom occasionnel de compte de zkSync est enregistré dans un contrat système nommé NonceHolder, qui se souvient si chaque paire (compte_adresse, nom occasionnel) est utilisée par mappage (mapping) pour juger si le nom occasionnel est légal.
Selon ce qui précède, la première étape après que l'opérateur a déclenché le chargeur de démarrage consiste à vérifier le nom occasionnel. Par conséquent, avant le début de chaque transaction, NonceHolder sera utilisé pour confirmer si l'ensemble de noms occasionnels actuellement utilisé est légal (actuellement, il vérifie uniquement s'ils ont été utilisés). Si le nonce est légal, il entrera dans la phase de vérification (Verification Phase), moment auquel le nonce sera marqué comme utilisé ; s'il n'est pas légal, la transaction (vérification) échouera.
Points importants concernant le nonce actuel de zkSync :
Bien qu'actuellement les utilisateurs puissent envoyer plusieurs transactions avec différents noms occasionnels au compte pour exécution en même temps, étant donné que zkSync ne prend pas en charge le traitement parallèle, les transactions avec différents noms occasionnels seront toujours traitées séquentiellement.
En théorie, les utilisateurs peuvent utiliser n'importe quel entier non nul de 256 bits comme nonce, mais zkSync recommande toujours d'utiliser incrémentNonceIfEquals comme moyen de gérer le nonce pour garantir qu'il est incrémenté dans l'ordre (actuellement, le mécanisme AA de zkSync ne confirme que le nonce inutilisé, mais le fonctionnaire (le document indique que l'incrément séquentiel pourrait être nécessaire à l'avenir).
Contrat de compte
Le contrat de compte dans zkSync comporte les quatre points d'entrée nécessaires suivants (Entry Point), qui sont :
Concernant Paymaster, le montant des frais de traitement (tx.gasprice * tx.gaslimit), etc. sera expliqué dans les chapitres suivants.
Il existe également une fonction d'assurance non essentielle uteTransactionFromOutside dans le compte de zkSync. Les fonds peuvent être retirés vers L1 à l'aide du « mécanisme d'échappement » lorsque les opérations ne peuvent pas être effectuées (par exemple lorsque le générateur de séquence ne répond pas ou que zkSync s'avère être un risque réglementaire). Cette partie n'a pas grand-chose à voir avec le protocole AA, elle ne sera donc pas décrite en détail ici. Ceux qui sont intéressés peuvent consulter les documents officiels et la spécification de zkSync.
Points clés et limites des fonctions de validation
Dans la fonction validateTransaction, vous pouvez implémenter diverses logiques personnalisées. Par exemple, si le compte a implémenté la norme EIP-1271, vous pouvez appliquer directement la logique de vérification dans EIP-1271 à validateTransaction, ou vous référer à l'implémentation du contrat de compte multi-signature. dans le document officiel de zkSync.
Dans le même temps, afin d'éviter les menaces DoS lors de la phase de vérification d'EIP-4337, il existe certaines restrictions (ne peut pas impliquer des opcodes externes et une profondeur limitée, etc.), et il existe des restrictions similaires dans zkSync, par exemple :
1. La logique du contrat ne peut toucher que son propre emplacement (si l'adresse du contrat de compte est A) :
emplacement appartenant à l'adresse A
emplacement A à toute autre adresse
Le slot keccak256(A||X) de toute autre adresse, qui peut utiliser directement l'adresse comme clé du mappage (comme le mappage (adresse=>valeur)), équivaut également à autoriser l'accès au slot keccak256( A||X), pour réaliser l’expansion. Par exemple, les soldes de jetons sur ERC-20.
2. La logique contractuelle ne doit pas utiliser de variables globales, telles que block.number
Points clés et limites des fonctions d'exécution
Ce qu'il faut noter dans la fonction uteTransaction, c'est que si vous souhaitez effectuer un appel système (Call), vous devez vous assurer qu'il possède l'indicateur is. Parce que ces contrats système ont un impact important sur le système de compte. Par exemple, la seule façon d'augmenter le nombre nonce est d'interagir avec NonceHolder. Pour déployer un contrat, vous devez interagir avec ContractDeployer. L'utilisation de l'indicateur is peut garantir que les développeurs de comptes interagissent consciemment avec des contrats système.
Cependant, il est recommandé d'utiliser la bibliothèque ContractsCaller fournie par zkSync pour éviter de gérer vous-même l'indicateur is et d'utiliser CallWithPropagatedRevert pour terminer l'appel système.
L'exemple de code ci-dessus implique une interaction avec DEPLOYER__CONTRACT. La situation de contrat système la plus courante rencontrée par les développeurs de comptes est que nous souhaitons utiliser un compte pour déployer un contrat. À ce stade, nous devons interagir avec le contrat système ContractDeployer. Dans ce cas, le développeur du compte doit communiquer avec le contrat ContractDeployer pour s'assurer que le contrat est déployé avec succès et effectue les opérations requises.
Modèle de frais et Paymaster à l'ère de zkSync
Frais et limite de gaz
Le modèle de frais de zkSync est très similaire à celui d’Ethereum, le jeton de frais est toujours ETH. Cependant, comme d'autres solutions de couche 2 (telles que Arbitrum, Optimism), zkSync doit également prendre en compte le coût supplémentaire de publication sur L1 (frais de sécurité) en plus des coûts de calcul de base et d'emplacement d'écriture. Étant donné que le prix du gaz qui publie les données sur L1 est très instable, l'opérateur de zkSync définit les paramètres dynamiques suivants lorsque chaque bloc est ouvert (commence à enregistrer les transactions) :
gasPrice : prix du gaz en gwei, c'est-à-dire tx.gasprice dans l'objet de transaction mentionné ci-dessus
gasPerPubdata : La quantité de gaz nécessaire pour publier un octet de données sur Ethereum
De plus, contrairement à EIP-4337, zkSync n'a pas besoin de définir trois limites de gaz : vérificationGas, utionGas et preVerificationGas, mais nécessite uniquement une gasLimit pour couvrir tous les coûts ci-dessus, les utilisateurs doivent donc s'assurer que la gasLimit est suffisante pour couvrir le Étape de vérification, étape de mise en œuvre et téléchargement des données Toutes les dépenses telles que les frais de sécurité vers L1. Ce coût des frais est inclus dans le tx.gaslimit dans l'objet de transaction mentionné ci-dessus.
Multipliez les deux (tx.gasprice * tx.gaslimit) pour obtenir les frais de transaction payés au chargeur de démarrage.
Caissier
Paymaster paie principalement l'ETH au chargeur de démarrage au lieu du contrat de compte de l'utilisateur au stade des frais de paiement de la transaction utilisateur. Les utilisateurs peuvent choisir différents modes Paymaster et de paiement pour payer les frais de traitement, tels que (mais sans s'y limiter) :
Paiement des jetons ERC-20 à Paymaster avant le lancement de la transaction ou après l'exécution de la transaction
Recharger le contrat Paymaster avec une carte bancaire
Paymaster continuera à payer gratuitement une partie ou la totalité des frais des utilisateurs
La manière dont les utilisateurs interagissent avec Paymaster dépend de différents protocoles : elle peut être centralisée ou décentralisée ; elle peut être avant ou après la transaction ; elle peut utiliser des jetons ERC-20 ou de la monnaie légale, ou même gratuite.
Le contrat Paymaster de zkSync se compose principalement de deux fonctions, à savoir validateAndPayForPaymasterTransaction (obligatoire) et postTransaction (facultatif), qui ne peuvent toutes deux être appelées que par le chargeur de démarrage :
validateAndPayForPaymasterTransaction est la seule fonction qui doit être implémentée dans l'ensemble du contrat Paymaster. Lorsque l'opérateur reçoit une transaction avec un paramètre Paymaster, cela signifie que les frais de traitement ne sont pas payés par le contrat de compte de l'utilisateur, mais par Paymaster. À ce stade, l'opérateur appellera validateAndPayForPaymasterTransaction pour déterminer si le Paymaster est prêt à payer les frais de transaction. Si Paymaster est d'accord, cette fonction enverra au moins tx.gasprice * tx.gaslimit ETH au chargeur de démarrage.
postTransaction est une fonction facultative, généralement utilisée pour le remboursement (retourner le gaz non utilisé à l'expéditeur). Cependant, zkSync actuel ne prend pas encore en charge cette opération.
Le Paymaster dans zkSync exécutera postTransaction après l'implémentation de postTransaction, ce qui est différent de EIP-4337. EIP-4337 n'appellera pas postOp lorsque validatePaymasterUserOp ne renvoie pas le contexte, et vice versa.
Sur la base de ce qui précède, par exemple, l'utilisateur souhaite maintenant envoyer une transaction dont les frais de traitement sont payés par Paymaster, le processus est le suivant :
Dans la dernière étape, même si postTransaction ne peut pas être exécuté en raison d'une erreur de manque de gaz, cette transaction AA est considérée comme réussie, mais l'action d'appeler postTransaction est omise.
Si vous approfondissez le Paymaster de zkSync, vous constaterez que ses règles de vérification sont légèrement différentes de celles de 4337 (zkSync Paymaster peut intervenir sur n'importe quel autre emplacement de contrat), et il en existe également différents types (tels que basés sur l'approbation). à la comparaison des détails. Ceux qui sont intéressés peuvent se référer aux documents officiels ou à ma mise en œuvre précédente.
Résumé et comparaison
Grâce aux explications précédentes, nous avons appris quels sont les points d'entrée importants du contrat de compte, ainsi que leurs fonctions et restrictions associées. Dans le même temps, nous avons également découvert les fonctions du contrat système. Ensuite, résumons le processus d'une transaction d'opération automatisée (AA) dans zkSync de la construction à l'achèvement, et je fournirai également des références plus détaillées pour ceux qui souhaitent en savoir plus :
L'utilisateur utilise le SDK ou le portefeuille localement pour construire des objets de transaction (par exemple : de, à, données, valeur, etc.).
L'utilisateur signe la transaction. La signature ici n'est pas nécessairement le format EIP-712 traditionnel et la signature de courbe ECDSA. zkSync prend également en charge EIP-2718 et EIP-1559. La clé pour choisir une méthode de signature et une méthode de vérification est de vérifier via la fonction de vérification dans le contrat de compte.
Envoyez la transaction signée à l'opérateur via l'API RPC. À ce stade, la transaction passe à l’état en attente. L'opérateur transmet la transaction au chargeur de démarrage (appelle la fonction processL2Tx sur le contrat du chargeur de démarrage) et démarre une série de processus de protocole AA.
Bootloader vérifiera si le Nonce est légal et utilisera NonceHolder pour vérifier.
Le Bootloader appellera la fonction validateTransaction sur le contrat du compte utilisateur pour confirmer que la transaction a été autorisée par le propriétaire du compte.
Bootloader dispose de deux manières de facturer des frais, et la méthode de facturation spécifique dépend des paramètres de transaction (si le paramètre paymaster est attaché lors de la construction de l'objet de transaction) :
a. Appelez la fonction payForTransaction et le contrat de compte pour facturer les frais de transaction ;
b. Appelez les fonctions prepareForPaymaster et validateAndPayForPaymasterTransaction pour collecter les frais de transaction avec le contrat Paymaster.
"Appelez payForTransaction pour contracter les frais avec le compte" ou "appelez PrepareForPaymaster et validateAndPayForPaymasterTransaction pour contracter les frais avec Paymaster"
Vérifiez si le chargeur de démarrage a reçu au moins les frais de transaction tx.gasprice * tx.gaslimit.
Bootloader appellera la fonction uteTransaction sur le contrat du compte utilisateur pour exécuter la transaction.
(Facultatif) Si vous utilisez Paymaster pour payer les frais de transaction, le chargeur de démarrage appellera la fonction postTransaction. Si Paymaster n'implémente pas postTransaction ou si le gaz est épuisé, cette étape sera ignorée.
Les étapes 4 à 7 ci-dessus sont la phase de vérification (définie dans la l2TxValidation du chargeur de démarrage) et la phase d'exécution des étapes 8 à 9 (définie dans la l2Txution du chargeur de démarrage).
Comparaison d'EIP-4337, StarkNet et zkSync Era
Fondamentalement, les processus du mécanisme AA des trois sont similaires, qui sont tous une étape de vérification → un mécanisme de frais de traitement (payés par contrat de compte ou Paymaster) → une étape d'exécution. Les principales différences sont :
Par rapport
De plus, nous avons complété le pool de mémoire P2P pour le bundler 4337 actuel, et le séquenceur et l'opérateur de zkRollups sont également les seuls serveurs officiels, il existe donc certains composants centralisés.
Dans le processus de développement, puisque zkSync n'a pas de problème de connexion avec divers bundlers (il suffit d'interagir avec l'API de l'opérateur), il est facile d'utiliser 4337 et l'expérience de développement de contrats de compte (SDK) est également meilleure ; en même temps, zkSync peut utiliser Solidity comme langage de développement contractuel, il n'est donc pas nécessaire de franchir le seuil du Caire dans le développement de StarkNet.
Conclusion
Étant donné que StarkNet et zkSync appartiennent tous deux à la catégorie des AA locaux (AA natif), vous pouvez également vous référer à ma précédente introduction à StarkNet AA, intitulée « Introduction de l'abstraction de compte StarkNet » (Introduction de l'abstraction de compte StarkNet). Vous pouvez également lire d'autres articles liés à EIP-4337 pour plus d'informations.