Tous les articles

Comprendre et implémenter l'EIP-7702

·
27 sept. 2025
·
6 min de lecture
·
••• vues
·
••• j'aime

Traduit de l'article original en anglais. Lire en anglais

Comprendre et implémenter l'EIP-7702

Imaginons que vous essayez d'exécuter une transaction atomique complexe tout-en-un qui nécessite d'échanger des tokens, d'ajouter de la liquidité et de staker des récompenses. Mais voilà, votre wallet Ethereum classique, un EOA, ne sait pas faire de transactions groupées. Vous allez donc devoir signer trois transactions séparées, payer le gas trois fois, ce qui est hors de question, puis prier pour que les bots MEV ne vous prennent pas en sandwich entre les étapes.

C'est l'un des débats les plus animés de l'écosystème EVM ces derniers temps, comment exactement donner des superpouvoirs aux wallets classiques sans tout casser d'un coup ?

Deux EIPs sont nées de ce défi, EIP-3074 puis EIP-7702. Les deux cherchent à combler l'écart entre un simple EOA et les smart contract accounts, mais elles abordent la délégation d'autorité de manière différente. L'une offre un pouvoir persistant avec lequel les choses peuvent très mal tourner et vos wallets se faire vider. L'autre peut vous donner à la fois une délégation persistante et une délégation temporaire qui peut disparaître dès que votre transaction est exécutée on-chain.

Voyons pourquoi cette différence compte et comment la proposition de Vitalik a peut-être évité à Ethereum un cauchemar potentiel en matière de sécurité.

EIP-2718 - Enveloppe de transaction typée

Avant d'entrer dans le sujet de la délégation, il y a une brique d'infra importante qui rend tout cela possible, EIP-2718. Voyez-la comme le système de conteneurs maritimes d'Ethereum pour les transactions.

// before eip-2718 all transactions looked the same
const legacyTx = rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]);
 
// after eip-2718 transactions can now be typed
const typedTx = TransactionType || TransactionPayload;

EIP-2718 introduit les Typed Transaction Envelopes, où TransactionType || TransactionPayload est une transaction valide. TransactionType identifie le format de la transaction tandis que Payload contient le contenu de la transaction. Ce système d'enveloppe signifie que l'on peut introduire des comportements de transaction entièrement nouveaux sans casser les fonctionnalités existantes.

En introduisant un type de transaction enveloppe, il suffit d'assurer la rétrocompatibilité avec les transactions existantes, et à partir de là, il ne reste qu'à résoudre le problème bien plus simple de garantir qu'il n'y a pas de conflit de numérotation entre les TransactionTypes. Donc quand EIP-7702 a eu besoin d'introduire son mécanisme de délégation temporaire, elle a pu simplement définir un nouveau type de transaction, par exemple 0x04, sans exiger le moindre changement dans l'EVM elle-même.

EIP-3074 - L'approche de la délégation persistante

EIP-3074 a adopté une approche audacieuse de la délégation, en donnant aux EOAs la possibilité de déléguer de façon permanente leur autorité à des smart contracts grâce à deux nouveaux opcodes de l'EVM - AUTH et AUTHCALL.

Comment fonctionnent AUTH et AUTHCALL

Le mécanisme est simple

// user signs an auth message
bytes32 commit = keccak256(abi.encode(invokerAddress, batchActions));
bytes memory signature = signMessage(userPrivateKey, commit);
 
// invoker contract calls AUTH opcode
AUTH(commit, signature.v, signature.r, signature.s);
// This sets the 'authorized' context variable to user's address
 
// now invoker can make calls as the user
AUTHCALL(gasLimit, targetContract, 0, 0, calldata, calldataLength, 0, 0);

AUTH prend quatre paramètres, commit et les valeurs yParity, r et s de la signature, et si la signature est valide et que l'adresse du signataire est égale à l'autorité, la variable de contexte authorized prend la valeur de cette autorité. AUTHCALL permet ensuite au contrat invoker autorisé d'envoyer des transactions, avec CALLER défini sur l'adresse autorisée plutôt que sur l'invoker.

Maintenant, imaginez un contrat invoker capable de gérer des transactions groupées

contract BatchInvoker {
    struct BatchCall {
        address target;
        bytes data;
        uint256 value;
    }
    
    function executeBatch(
        BatchCall[] calldata calls,
        bytes32 commit,
        uint8 v, bytes32 r, bytes32 s
    ) external {
        // authorize the user
        AUTH(commit, v, r, s);
        
        // Execute all calls as the user
        for (uint i = 0; i < calls.length; i++) {
            AUTHCALL(
                gasleft(),
                calls[i].target,
                calls[i].value,
                0, // valueExt (must be 0 for now)
                // ... calldata parameters
            );
        }
    }
}

Aussi enthousiasmant que ce soit, ces deux opcodes ont soulevé un certain nombre de problèmes de sécurité dans la communauté EVM. La variable de contexte authorized persiste pendant toute une frame d'exécution du contrat, mais n'est transmise à aucun appel, y compris DELEGATECALL. En gros, cela veut dire que l'autorisation est active sur toute la portée de la transaction.

Le vrai problème n'est pas le caractère temporaire au sein d'une transaction, c'est ce qui se passe quand des contrats invoker sont très largement utilisés. Si tout le monde finit par utiliser des smart accounts, les opcodes AUTH et AUTHCALL peuvent devenir un énorme fardeau technique et ajouter de la complexité à l'EVM elle-même.

Que se passe-t-il quand un contrat invoker populaire comme celui ci-dessus a un bug ? Tout à coup, chaque utilisateur qui a un jour autorisé ce contrat peut se retrouver en danger. Une mise à jour malveillante, un cas limite oublié, un dépassement d'entier, et c'est tout, un vidage massif commence.

L'écosystème EVM a compris que cela créait une dynamique étrange. Le modèle de sécurité d'EIP-3074 repose fortement sur le contrat invoker. Comme plusieurs utilisateurs peuvent dépendre de la même logique d'invoker, une vulnérabilité ou un exploit dans un seul invoker pourrait compromettre les actifs ou les permissions de nombreux utilisateurs en même temps, et c'est pour ça qu'EIP-3074 a été retirée.

EIP-7702 - La solution de délégation flexible

Maintenant, EIP-7702, proposée par Vitalik en mai 2024, est arrivée sur le mainnet via le pectra upgrade en mai 2025 et introduit une nouvelle approche simplifiée, qui permet aux EOAs de fonctionner temporairement comme des smart contracts le temps d'une seule transaction, et c'est énorme !

Au lieu de nouveaux opcodes, EIP-7702 s'appuie sur le système d'enveloppe de transaction de EIP-2718's pour introduire un nouveau type de transaction

interface EIP7702Transaction {
    chainId: number;
    nonce: number;
    maxPriorityFeePerGas: bigint;
    maxFeePerGas: bigint;
    gasLimit: bigint;
    to: string;
    value: bigint;
    data: Uint8Array;
    accessList: AccessList;
    authorizationList: Authorization[];
}
 
interface Authorization {
    chainId: number;
    address: string;  // the address of the contract code to delegate to
    nonce: number;
    yParity: 0 | 1;
    r: Uint8Array;
    s: Uint8Array;
}

Pour chaque objet d'autorisation, un indicateur de délégation (0xef0100 || address) est écrit dans le code du compte qui donne l'autorisation. Toutes les opérations qui exécutent du code doivent charger et exécuter le code pointé par la délégation.

Comment fonctionne vraiment la persistance de la délégation

C'est là que beaucoup de gens s'embrouillent. EIP-7702 a évolué depuis son brouillon initial. Au départ, la proposition était conçue pour rendre les EOAs temporairement smart le temps d'une seule transaction. Mais la version finale vous laisse contrôler la durée de la délégation.

function processEIP7702Transaction(tx) {
    // verify all auth signatures
    for (const auth of tx.authorizationList) {
        const signer = recoverSigner(auth);
        if (signer !== getAddressFromAuth(auth)) {
            throw new Error("Invalid authorization");
        }
    }
    
    // set delegation pointers (these persist after transaction)
    for (const auth of tx.authorizationList) {
        const eoaAddress = getAddressFromAuth(auth);
        
        // set delegation pointer - 0xef0100 || contract_address
        const delegationPointer = concat(['0xef0100', auth.address]);
        setCode(eoaAddress, delegationPointer);
        
        // nowm this delegation PERSISTS unless explicitly cleared
    }
    
    // execute the transaction normally
    executeTransaction(tx);
    
    // no auto cleanup, delegation stays active
}

REMARQUE : si l'exécution d'une transaction 7702 échoue, les indicateurs de délégation déjà traités ne sont pas annulés et persistent, à moins d'être explicitement effacés en définissant l'adresse de délégation à 0x0 dans une transaction 7702 ultérieure.

Cela veut dire que vous avez trois modèles de délégation :

Options temporaire ET persistante

Ce qui est bien avec EIP-7702, c'est qu'elle vous laisse le choix. Vous voulez une délégation temporaire pour une transaction complexe ponctuelle ? C'est possible. Vous voulez faire évoluer durablement votre EOA pour qu'il se comporte comme un smart contract wallet ? C'est possible aussi.

Pour la délégation temporaire, voici un exemple

// one off delegation
const tempDelegationTx = {
    type: 0x04,
    authorizationList: [{
        address: batchExecutorContract,
        // ... auth details
    }],
    to: userAddress,
    data: encodeBatchCall([
        // execute your complex operation
        swapTokens(),
        addLiquidity(), 
        stakeRewards(),
    ])
};

Et pour la délégation persistante, voici un exemple

// upgrade EOA to smart wallet
const persistentDelegationTx = {
    type: 0x04,
    authorizationList: [{
        address: smartWalletImplementation,
        // ... auth details  
    }],
    to: userAddress,
    data: encodeCall("initializeSmartFeatures", [])
    // this delegation persists for future txns
};
 
// later txns can now use smart wallet features
const futureTransaction = {
    to: userAddress, // your EOA will now execute smart wallet code
    data: encodeCall("batchExecute", [multipleOperations])
    // no new auth needed
};

Pourquoi 7702 est plus sûre

La différence clé entre EIP-3074 et EIP-7702 n'est pas seulement temporaire contre persistant, c'est une question de répartition du risque et de contrôle. EIP-3074 crée un point de défaillance partagé où le problème d'un seul contrat populaire peut affecter des milliers d'utilisateurs. EIP-7702 isole chaque transaction, donc les bugs ne peuvent affecter que cette transaction précise. EIP-7702 est entièrement compatible avec l'ERC-4337 existant, sans nécessiter de nouveaux opcodes. Concrètement, les wallets peuvent l'adopter progressivement sans casser aucun système existant.

L'idée essentielle, c'est que ce sont les wallets, et non les dApps, qui gèrent les délégations. Le consensus général est donc de ne permettre qu'aux wallets de gérer les délégations, ce qui veut dire :

Ce que les devs doivent savoir

Si vous construisez une application qui va supporter EIP-7702, voici quelques points techniques à noter

  1. Changements dans la construction des transactions Votre logique de construction de transactions doit gérer les listes d'autorisations
// old: simple EOA transaction
const tx = {
    to: contractAddress,
    data: encodedCall,
    // ... standard fields
};
 
// new way with eip-7702 delegation
const tx = {
    type: 0x04,
    to: userAddress, // calling user's own address
    data: encodeBatchCall([
        contract.interface.encodeFunctionData("swap", [tokenA, tokenB, amount]),
        contract.interface.encodeFunctionData("addLiquidity", [lpTokens]),
        contract.interface.encodeFunctionData("stake", [lpAmount])
    ]),
    authorizationList: [{
        address: batchExecutorImplementation,
        // ... authorization signature
    }],
    // ... standard fields
};
  1. Complexité de l'estimation du gas Si l'EOA décide de révoquer le contrôle du smart contract, une autre transaction 7702 doit être envoyée pour remettre la délégation à 0x0. Cela veut dire que votre estimation du gas doit prendre en compte
  1. Support des signatures de smart contract EIP-7702 permet la vérification de signature EIP-1271 pour les EOAs. Cela veut dire que votre EOA mis à niveau peut signer des messages avec d'autres méthodes comme les passkeys, tout en restant rétrocompatible.
// your EOA can now implement smart signature verification
function isValidSignature(bytes32 hash, bytes signature) external view returns (bytes4) {
    // can verify passkey signatures, multisig, etc.
    if (verifyPasskeySignature(hash, signature)) {
        return 0x1626ba7e; // EIP-1271 magic value
    }
    return 0xffffffff;
}

Liens essentiels

•••
Partager cet article :

Restez informé

Recevez les derniers articles dans votre boîte mail.