Texte original : "Vanity Addresses" par foobar
Compilation : Porridge du jour au lendemain, à la manière de la DeFi
160 millions de dollars américains ont disparu et Wintermute a perdu les fonds. Wintermute est l'un des fonds de tenue de marché les plus astucieux du secteur. Un matin de septembre, lorsque le responsable de Wintermute s'est réveillé, il a découvert qu'il s'agissait de l'un de leurs portefeuilles importants. avait perdu 9 chiffres. Alors, qu’est-ce qui a conduit au vol de Wintermute ? Cela est dû à un mauvais caractère aléatoire dans un générateur d'adresses personnalisées. Les pirates au chapeau noir forcent brutalement la paire clé privée et adresse publique à partir de zéro, puis une grande quantité d'actifs cryptographiques est transférée.
Il y a aussi une histoire de piratage d'Indexed Finance, où 16 millions de dollars ont été volés en octobre 2021, et les fonds volés ont ensuite été déplacés vers des adresses commençant par 0xba5ed… . Ce qu’ils ne savaient pas, c’est que l’adresse personnalisée était également affectée par la mauvaise vulnérabilité aléatoire qui affectait Wintermute, et en septembre 2022, tout l’argent a de nouveau été volé, allant vers une autre adresse de portefeuille piratée. Les voleurs sont impitoyables.
Alors, quels problèmes ces développeurs talentueux ont-ils rencontrés et que pouvons-nous en apprendre ?
Sur la gauche se trouve l'adresse normale utilisée pour le contrat WETH. A droite se trouve une jolie adresse avec 14 zéros non significatifs pour l'optimisation du robot MEV. Le type d’adresse personnalisée le plus courant est celui comportant de nombreux zéros non significatifs.
Tout d’abord, qu’est-ce qu’une adresse personnalisée (également appelée adresse personnalisée) ? Une adresse personnalisée fait référence à une adresse publique qu'un utilisateur crée délibérément pour l'associer à son portefeuille ou à son contrat intelligent. Peut-être qu'elle commence par 0x0000000, peut-être qu'elle commence par 0xdeadbeef, peut-être qu'il s'agit d'une autre adresse standard. Plusieurs raisons expliquent leur popularité :
1. Optimisation du gaz : Wintermute a économisé 15 000 $ en utilisant une adresse EOA avec plusieurs zéros non significatifs. Cela semble idiot ? Beaucoup de gens sont d’accord, mais c’est ainsi que fonctionne l’EVM. Si vous avez beaucoup de zéros dans votre adresse, les frais de transaction peuvent diminuer ! Ainsi, si vous utilisez une adresse de contrat intelligent avec de nombreux zéros non significatifs, les utilisateurs seront heureux lorsqu'ils interagiront avec elle, car cela leur permettra d'économiser de l'argent.
Le livre jaune d'Ethereum décrit comment les adresses zéro principales peuvent permettre d'obtenir du gaz moins cher
2. Marque d'accord. Savez-vous que le contrat 1inch Token commence par 0x111111111... ?
Contrat de jeton de 1 pouce
3. Répétabilité multibrins. À mon avis, c'est une priorité absolue et c'est pourquoi chaque protocole devrait utiliser une adresse personnalisée pour son déploiement. Votre application peut exister sur 15 chaînes EVM différentes et avoir la même adresse partout ! Ne serait-ce pas plus facile pour les développeurs et les utilisateurs ?
Alors, quand une jolie adresse est-elle sûre ?
Il existe deux types d’adresses Ethereum : les comptes externes (EOA) et les comptes de contrats intelligents. Si vous avez utilisé un portefeuille comme MetaMask, chaque adresse qu'il contient est un EOA, qui est utilisé pour signer des messages et traiter des transactions. Comparez cela à un compte de contrat intelligent tel que le contrat Uniswap, avec lequel les gens peuvent interagir mais il ne peut pas entreprendre ses propres actions sans être déclenché. Pour résumer, c'est très simple. Les adresses en bon nombre ne sont pas sûres pour les comptes EOA, mais elles le sont pour les comptes de contrats intelligents.
Alors pourquoi est-ce ainsi ? Nous expliquerons cela plus en détail ci-dessous, mais cela dépend de la manière dont l'adresse personnalisée est générée. Pour les comptes EOA, vous parcourez des millions de clés privées jusqu'à ce que vous en trouviez une qui correspond à une belle adresse publique. Cependant, la clé privée contrôle les fonds d'un compte EOA, donc si le caractère aléatoire que vous utilisez pour parcourir la clé privée est compromis, l'intégralité de votre compte est ruinée. D'un autre côté, la création d'adresses personnalisées de contrat intelligent nécessite uniquement de parcourir des graines publiques, qui n'accordent aucun droit administratif sur le contrat intelligent.
C'est pourquoi Wintermute échoue et OpenSea réussit : générer des clés privées dans une mémoire non sécurisée avec un logiciel non sécurisé est une mauvaise chose. Mais générer des graines publiques de cette façon est plutôt sympa ! Par conséquent, une bonne adresse EOA est une voie vers la faillite, tandis qu’une bonne adresse de contrat intelligent est une voie vers le succès.
Pourquoi le protocole exige-t-il une jolie adresse ?
Documentation plus simple ! Vous pouvez pointer vers une adresse contractuelle sur toutes les chaînes ;
Vérifiable par l'utilisateur ! La même adresse de contrat n'apparaîtra que si et seulement si le bytecode correspond octet par octet ;
Les développeurs peuvent vérifier ! Étant donné que des adresses de contrat identiques n'apparaissent que dans le cas d'une correspondance exacte, vous pouvez détecter de petites modifications délicates dans votre script de déploiement ;
Une intégration plus facile ! D'autres protocoles peuvent coder en dur votre adresse de contrat dans leur code multi-chaîne sans avoir à utiliser des instructions if basées sur chainId.
REMARQUE : Nous sommes sur le point de nous plonger dans un manuel d’instructions détaillé. En rassemblant toutes les pièces pour la première fois, nous plongeons profondément dans l'espace technique et ciblons les développeurs de contrats intelligents ayant une expérience dans le déploiement de contrats intelligents en chaîne. Si vous êtes intéressé, continuez à lire, mais si ce n'est pas pour vous, ne vous inquiétez pas, il y a un défi technique supplémentaire à la fin (avec des récompenses).
Smart contract belle adresse
Il existe un moyen de générer des adresses personnalisées de contrats intelligents 100 % sécurisées, quel que soit le logiciel que vous utilisez, peu importe si la technologie itérative est divulguée publiquement. C'est ce qu'on appelle la « méthode d'usine CREATE2 » et non seulement elle fournit une jolie adresse, mais c'est également un moyen infaillible de garantir que vous avez la même adresse de déploiement de contrat sur plusieurs chaînes. Il permet également à d'autres de déployer du code en toute confiance en votre nom, sans partage de clé privée ni hypothèses occasionnelles.
Tout d’abord, un bref aperçu de la façon de choisir une adresse de contrat intelligent. Il existe deux options de déploiement, CREATE et CREATE2. Lorsque vous déployez un contrat intelligent directement depuis EOA, le processus par défaut est CREATE. L'adresse est déterminée en hachant l'adresse du créateur du contrat avec le nom occasionnel du créateur du contrat. Ce nom occasionnel fait référence au nombre de transactions qu'une adresse a envoyées, donc un nouveau portefeuille commence à 0 et est incrémenté de 1 à chaque fois qu'une nouvelle transaction est envoyée. Voici la formule magique de l’adresse de smart contract déployée par CREATE :
new_address = hash (expéditeur, nonce)
Moins courante, mais plus intéressante, est l’adresse de contrat intelligent déployée à l’aide de CREATE2, et voici sa formule :
new_address = hash (0xFF, expéditeur, sel, bytecode)
Le premier semble plus simple, non ? Cependant, donnons un exemple où cette simplicité peut être préjudiciable par rapport au processus CREATE2, plus robuste.
Airy Alice : Il y a un problème avec le multi-chaîne
Imaginez qu'un développeur de crypto nommé Alice crée deux contrats intelligents : un fork d'Uniswap appelé GriddleSwap et un projet NFT appelé ph00ts. Ce sont toutes des primitives indépendantes immuables, ce qui signifie qu’il n’y a pas de dépendances externes ni de risques de pont entre chaînes. Alice déploie GriddleSwap sur Ethereum en utilisant le nonce 0, puis déploie ph00ts sur Ethereum en utilisant le nonce 1. Malheureusement, Alice a une capacité d'attention limitée et a été distraite sur Twitter crypto pendant quelques minutes avant de déployer son travail sur Binance Smart Chain (BSC), la deuxième plus grande plateforme de contrats intelligents.
Oups, j'ai foiré l'ordre de déploiement !
Mais attendez ! Elle a gâché l’ordre de déploiement et déployé ph00ts avant GriddleSwap. Étant donné que l'adresse du contrat intelligent repose uniquement sur l'adresse du créateur et que dans la blockchain déployée, Ethereum Gridleswap a exactement la même adresse que BSC ph00ts ! Pour aggraver les choses, l'adresse d'Ethereum ph00ts est la même que celle de BSC GriddleSwap. Penser que les utilisateurs finaux seront confus est un euphémisme. En fait, des déployeurs malveillants peuvent en abuser pour faire croire aux gens que le comportement du contrat sur la chaîne est le même - ce qui est une hypothèse juste, étant donné la même adresse !
Attention Alice : Il y aura encore des problèmes
Même si Alice est prudente lors du déploiement et ne mélange jamais l'ordre de ses occasionnels, il existe d'autres problèmes. Si Alice se déploie correctement sur Ethereum et BSC, mais effectue ensuite une transaction sans rapport sur Polygon, une fois 0 a été utilisé. Elle ne pourra jamais y déployer GriddleSwap car son occasionnel a été incrémenté. Par conséquent, les clés privées des déployeurs doivent être protégées à tout prix. Si Alice le divulgue, un saboteur malveillant peut effectuer des transactions sans rapport. Si Alice le perd, elle perdra également la possibilité de se déployer à nouveau à cette adresse sur une nouvelle chaîne. Il s’agit d’une vulnérabilité permanente qui repose sur une personne honnête pour protéger la clé privée. Si même les principaux développeurs de Bitcoin ne peuvent pas le faire, comment pouvons-nous le faire ?
Solution : CRÉER2
Heureusement, il existe un meilleur moyen d’obtenir des adresses cohérentes à travers les chaînes : un moyen qui ne s’appuie pas sur des clés privées secrètes, qui ne s’appuie pas sur un seul déployeur et qui résiste aux erreurs du déployeur en cours de route. Rappelez-vous la formule pour trouver l'adresse d'un contrat intelligent déployé avec CREATE2 :
new_address = hash (0xFF, expéditeur, sel, bytecode)
Le premier paramètre 0xFF est une valeur constante qui peut être ignorée. Le deuxième paramètre (adresse de l'expéditeur) peut être rendu cohérent en sélectionnant le déploiement CREATE2Factory de z0age 0x0000000000FFe8B47B3e2130213B802212439497 dans la plupart des chaînes EVM. Le troisième paramètre est un sel sélectionné par l'utilisateur, que nous pouvons utiliser pour trouver une bonne adresse et la conserver inchangée sur la chaîne. Le quatrième est le bytecode du contrat, qui sert de contrôle de cohérence utile pour garantir que nous déployons exactement la même fonctionnalité sur la chaîne. Les quatre paramètres peuvent rester les mêmes, quelles que soient les actions d'un seul déployeur.
Pourquoi est-ce préférable ? Contrairement à la clé privée, le sel sélectionné par le déployeur peut être rendu public. Connaître le sel vous permet de déployer le contrat, mais vous n'avez aucun contrôle sur les actifs ou les fonctionnalités du contrat ! Parce qu'il ne lie aucune information secrète, n'importe qui peut déployer le contrat sur la nouvelle chaîne sans révéler ni partager la clé privée. Le paramètre bytecode garantit également que ces nouveaux déploiements sans autorisation auront la même adresse si et seulement si le bytecode est le même. Par conséquent, les utilisateurs finaux bénéficient de garanties plus solides sans avoir à faire de différences détaillées dans le code.
Pour un aperçu plus approfondi, consultez l’article de vulgarisation scientifique d’OpenZeppelin.
Créez votre propre belle adresse
Vous pensez que la Proof of Work (PoW) sera inutile après la fusion Ethereum ? Détrompez-vous ! Les mêmes capacités GPU qui aident à trouver des préimages de hachage avec un grand nombre de zéros non significatifs pour les blocs Bitcoin sont également excellentes pour trouver des préimages de hachage avec un grand nombre de zéros non significatifs pour les contrats intelligents EVM. z0age d'OpenSea (grâce à son explication pour ce post) a trouvé une configuration simple pour créer votre propre adresse personnalisée.
1. Utilisezvast.ai pour lancer un exemple d'instance de GPU, qui tente environ 2 milliards de fois par seconde et coûte environ 25 cents/heure :
Image:nvidia / opencl
GPU : 1x RTX 3090
Espace disque requis à allouer : 1,83 Go
2. SSH et installez rust + create2crunch
sudo apt install build-essential -y ; curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; source "$HOME/.cargo/env" ; git clone https://github.com/0age/create2crunch && cd create2crunch; sed -i 's/0x4/0x40/g' src/lib.rs
3. Exécutez une recherche de graines. Pour les variables d'environnement, INIT_CODE_HASH est le keccak256 du code de création du contrat. Un imprimé d'un exemple de test de fonderie peut être trouvé ici - assurez-vous de le vérifier avant de consommer de grandes quantités de ressources informatiques ! LEADING doit être le nombre d'octets zéro en tête souhaité et TOTAL doit être le nombre total d'octets zéro souhaité dans l'adresse du contrat.
exporter FACTORY="0x0000000000ffe8b47b3e2130213b802212439497"; exporter APPELANT="0x00000000000000000000000000000000000000000" ; exporter INIT_CODE_HASH="0xabc...def"; exporter LEADING=5 ; exportation TOTAL=7 ; cargo run --release $FACTORY $CALLER $INIT_CODE_HASH 0 $LEADING $TOTAL
Lorsque z0age a publié son dépôt pour la première fois, il était capable d'exécuter 1,9 milliard de tentatives par seconde sur le matériel VastAI susmentionné. Depuis, la vectorisation est devenue folle sur certains cœurs OpenGL, et j'ai observé 2,15 milliards de tentatives par seconde. Cela signifie que trouver une adresse avec 5 octets zéro en tête prendrait 256^5/(2150000000 * 60) ~= 8 minutes et trouver une adresse avec 6 octets zéro en tête prendrait 256^6/(2150000000 * 3600) ~ = 36 heures . Une adresse de 7 octets zéro en tête prend 256^7/(2150000000 * 86400) ~= 387 jours. Notez qu'un octet est égal à deux caractères hexadécimaux, donc une adresse de 5 octets de début aura 10 zéros. Bien entendu, cette recherche peut être entièrement parallélisée et la probabilité réelle de succès dans le temps suivra une distribution de Poisson.
Déployer la fabrique CREATE2
Les lecteurs avisés ont peut-être remarqué que CREATE2 Factory existe déjà à 0x0000000000FFe8B47B3e2130213B802212439497 sur toutes les chaînes. C'est un peu le problème de la poule et de l'œuf. Comment un déploiement d'adresses cohérent dépend-il d'un déploiement d'adresses cohérent ?
Lorsque j'ai découvert cette approche pour la première fois, je pensais qu'il s'agissait simplement d'une clé privée détenue par quelqu'un de plus intelligent que moi (le scénario « Alice observatrice » ci-dessus). Mais c'est en réalité bien plus robuste que cela ! L'approche « transactions sans clé » du fondateur de l'ENS, Nick Johnson, exploite le fait que vous pouvez récupérer l'adresse publique de n'importe quelle signature de transaction sans connaître la clé privée correspondante qui l'a signée. Par conséquent, il est possible de créer une transaction (« déployer une usine create2 »), puis d'inventer une fausse signature pour celle-ci, par exemple une signature composée de seulement 2. La clé privée de cette fausse signature existe, mais personne ne sait de quoi il s’agit. Mais on peut récupérer l'adresse publique correspondant à la "signature sans clé", lui envoyer de l'ETH, puis soumettre la transaction signée au mempool. Malgré l'obscurité de cette méthode, il s'agit d'une transaction valide, et en fait la seule transaction valide pouvant être envoyée à partir de cette adresse publique.
Résultat : n’importe qui peut déployer une usine sur une nouvelle chaîne sans aucune information exclusive, tout en empêchant les acteurs malveillants de causer des dommages. Créer un EOA à usage unique capable de déployer une seule transaction est une technique très intelligente.
Adresses spécifiques et contrats créés lors de transactions sans clé
Ceci peut être accompli avec trois commandes simples « forge cast ». Le bytecode est trop long pour être copié ici, mais vous pouvez suivre les instructions sur https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md sans autorisation sur n'importe quelle chaîne de votre choix Déployez CREATE2 Factory facilement !
Bien entendu, s’il a déjà été déployé, il n’est pas nécessaire de le déployer à nouveau.
Remarque complémentaire : les exigences EIP-155 sont terribles
Une brève tentative pour soutenir mes aventures de gouvernance L1, n'hésitez pas à passer à autre chose. EIP-155 est une proposition avancée par Vitalik en 2016, qui introduit le concept de « chaîne d'identification » pour empêcher les attaques par rejeu. Chaque chaîne possède son propre identifiant unique - 1 pour Ethereum, 56 pour BSC et 137 pour Polygon - qui sera inclus dans les transactions signées pour empêcher les attaques par rejeu, ce qui a été rapidement adopté par Ethereum, et toutes les autres chaînes EVM ont suivi cette proposition. C'est génial, mais le problème survient lorsque quelques chaînes sont sélectionnées, comme Evmos qui a récemment décidé d'interdire explicitement les transactions avant EIP-155 , ce qui, pour des raisons étranges, évite une erreur opérationnelle où Optimism a envoyé 20 millions de jetons OP à un multisig (oui, encore eux) adresse que Wintermute n'existe pas, prétend posséder mais n'a jamais été initialisé. Cependant, la désactivation des transactions antérieures à 155 interromprait considérablement tout un ensemble de déploiements inter-chaînes, tels que l'usine CREATE2 et des projets phares comme Seaport. Ces propositions de gouvernance devraient être annulées immédiatement, et les détails de protection comme celui-ci devraient provenir du portefeuille plutôt que du niveau de consensus. Si le multi-chaîne est l’avenir, alors ces restrictions inutiles constitueront un énorme obstacle au déploiement des meilleurs projets sur votre blockchain.
Trucs amusants : déployer des primes
Aujourd'hui https://delegate.cash est déployé sur 7 chaînes EVM différentes (Ethereum, Polygon, Optimism, Celo, Avalanche, Fantom et Arbitrum) et 7 testnets correspondant à ces chaînes. L'adresse du contrat pour tous ces éléments est la même : 0x00000000000076A84feF008CDAbe6409d2FE638B.
Alors est-ce suffisant ? Non, nous avons besoin de plus de chaînes. Étant donné que déléguécash est une primitive indépendante sans dépendance, cela signifie que le risque de plusieurs chaînes est effectivement nul. C'est un pur avantage ! Par conséquent, pour les 5 premières personnes à déployer et vérifier le contrat intelligent déléguécash sur la nouvelle chaîne et le testnet correspondant, j'attribuerai un bonus de 100 USDC !
Vous devez utiliser le script de déploiement du référentiel open source ici. Cela peut nécessiter le déploiement de CREATE2 Factory si elle n'existe pas, et n'oubliez pas la vérification Etherscan ! Bon déploiement et bon apprentissage expérientiel !
