كل المقالات

فهم EIP-7702 وتطبيقه

·
27 سبتمبر 2025
·
وقت القراءة: 6 د
·
••• مشاهدة
·
••• إعجاب

مترجمة عن المقالة الأصلية باللغة الإنجليزية. اقرأها بالإنجليزية

فهم EIP-7702 وتطبيقه

لنفترض أنك تحاول تنفيذ معاملة ذرّية معقدة شاملة في خطوة واحدة تتطلب مبادلة الرموز، وإضافة السيولة، وتخزين المكافآت (staking). لكن محفظة Ethereum العادية لديك، أي حساب EOA، لا تستطيع تنفيذ معاملات مجمّعة. لذا ستحتاج إلى توقيع ثلاث معاملات منفصلة، ودفع الغاز ثلاث مرات، وهذا أمر مرفوض تمامًا، ثم الدعاء ألا تحاصرك روبوتات MEV بهجوم الساندويتش بين الخطوات.

هذا أحد النقاشات الساخنة في منظومة EVM مؤخرًا، كيف بالضبط نمنح المحافظ العادية قدرات خارقة دون أن نكسر كل شيء في الوقت نفسه؟

خرج من هذا التحدي اقتراحان من EIPs، هما EIP-3074 ثم EIP-7702 لاحقًا. يسعى كلاهما إلى سد الفجوة بين EOA البسيط و smart contract accounts، لكنهما يتبعان نهجين مختلفين في تفويض الصلاحية. أحدهما يقدم صلاحية دائمة قد تسوء فيها الأمور كثيرًا وتُستنزف محافظك. والآخر يمكن أن يمنحك التفويض الدائم والتفويض المؤقت معًا، وقد يختفي التفويض المؤقت لحظة تنفيذ معاملتك على السلسلة.

لنتحدث عن سبب أهمية هذا الفرق، وكيف ربما أنقذ اقتراح Vitalik شبكة Ethereum من كابوس أمني محتمل.

EIP-2718 - غلاف المعاملات ذات الأنواع

قبل أن ندخل في موضوع التفويض، هناك جزء مهم من البنية التحتية يجعل كل هذا ممكنًا، وهو EIP-2718. فكّر فيه على أنه نظام حاويات الشحن الخاص بالمعاملات في Ethereum.

// 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 مفهوم Typed Transaction Envelopes، حيث تكون TransactionType || TransactionPayload معاملة صالحة. يحدد TransactionType صيغة المعاملة، بينما يحتوي Payload على محتويات المعاملة. والآن، يعني نظام التغليف هذا أننا نستطيع تقديم سلوكيات جديدة كليًا للمعاملات دون كسر الوظائف الموجودة.

وبإدخال نوع معاملة مغلّف، لا نحتاج إلا إلى ضمان التوافق مع المعاملات الموجودة، ومن ثم لا يتبقى لنا إلا حل مشكلة أبسط بكثير، وهي ضمان عدم وجود تعارض في الترقيم بين TransactionTypes. لذا عندما احتاج EIP-7702 إلى تقديم آلية التفويض المؤقت الخاصة به، أمكنه ببساطة أن يعرّف نوع معاملة جديدًا، على سبيل المثال 0x04، دون أن يتطلب أي تغييرات في EVM نفسه.

EIP-3074 - نهج التفويض الدائم

اتخذ EIP-3074 نهجًا جريئًا في التفويض، إذ منح EOAs القدرة على تفويض الصلاحية بشكل دائم إلى العقود الذكية باستخدام اثنين من opcodes الجديدة في EVM - AUTH و AUTHCALL.

كيف يعمل AUTH و AUTHCALL

الآلية بسيطة ومباشرة

// 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 أربع وسائط، commit و yParity الخاص بالتوقيع و r و s، وإذا كان التوقيع صالحًا وكان عنوان الموقّع مساويًا لصاحب الصلاحية، تُضبط قيمة متغير السياق authorized على صاحب الصلاحية ذاك. ثم يسمح AUTHCALL لعقد الاستدعاء (invoker) المخوَّل بإرسال المعاملات، مع ضبط CALLER على العنوان المخوَّل بدلًا من عنوان عقد الاستدعاء.

والآن، تخيّل عقد استدعاء يستطيع التعامل مع المعاملات المجمّعة

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
            );
        }
    }
}

بقدر ما يبدو هذا مثيرًا، فقد أثار هذان الـ opcodes عددًا من المخاوف الأمنية لدى مجتمع EVM. فمتغير السياق authorized يستمر طوال إطار تنفيذ واحد للعقد، لكنه لا يُمرَّر عبر أي استدعاءات بما فيها DELEGATECALL. وهذا يعني في الأساس أن التخويل يبقى فعّالًا طوال نطاق المعاملة بأكملها.

المشكلة الحقيقية ليست في الطبيعة المؤقتة داخل المعاملة، بل فيما يحدث عندما تكون لديك عقود استدعاء واسعة الاستخدام. فإذا كان الجميع سيستخدمون الحسابات الذكية في النهاية، فقد يصبح AUTH و AUTHCALL من الـ opcodes عبئًا تقنيًا ضخمًا ويضيفان تعقيدًا إلى EVM نفسه.

ماذا يحدث عندما يحتوي عقد استدعاء شائع مثل العقد أعلاه على خلل؟ فجأة، يصبح كل مستخدم سبق أن خوّل ذلك العقد معرّضًا للخطر على الأرجح. تحديث خبيث واحد، أو حالة حدّية واحدة فاتتك، أو تجاوز عدد صحيح واحد، وانتهى الأمر، يبدأ استنزاف جماعي.

أدركت منظومة EVM أن هذا خلق ديناميكية غريبة. فنموذج الأمان في EIP-3074 يعتمد بشدة على عقد الاستدعاء. وبما أن مستخدمين كثيرين قد يعتمدون على منطق عقد الاستدعاء نفسه، فإن ثغرة أو استغلالًا في عقد استدعاء واحد قد يعرّض أصول أو صلاحيات كثير من المستخدمين للخطر دفعة واحدة، ولهذا سُحب EIP-3074.

EIP-7702 - حل التفويض المرن

والآن، فإن EIP-7702 الذي اقترحه Vitalik في مايو 2024 وصل إلى mainnet عبر pectra upgrade في مايو 2025، وهو يقدّم نهجًا جديدًا مبسّطًا يسمح لـ EOAs بأن تعمل مؤقتًا مثل العقود الذكية طوال مدة معاملة واحدة، وهذا أمر كبير!

بدلًا من opcodes جديدة، يستفيد EIP-7702 من نظام تغليف المعاملات في EIP-2718's لتقديم نوع معاملة جديد

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;
}

لكل كائن تخويل، يُكتب مؤشر تفويض (0xef0100 || address) في شيفرة الحساب المانح للتخويل. ويجب على جميع العمليات التي تنفّذ الشيفرة أن تحمّل الشيفرة التي يشير إليها التفويض وتنفذها.

كيف يعمل استمرار التفويض فعليًا

هذا هو الموضع الذي يرتبك فيه كثير من الناس. لقد تطوّر EIP-7702 منذ مسودته الأصلية. ففي البداية، صُمم الاقتراح ليجعل EOAs ذكية مؤقتًا لمعاملة واحدة فقط. لكن النسخة النهائية تمنحك التحكم في المدة التي يستمر فيها التفويض.

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
}

ملاحظة: إذا فشل تنفيذ معاملة 7702، فإن مؤشرات التفويض التي عولجت لا يُتراجع عنها، وتبقى قائمة ما لم تُمسح صراحةً بضبط عنوان التفويض على 0x0 في معاملة 7702 لاحقة.

هذا يعني أن لديك ثلاثة أنماط للتفويض:

الخياران المؤقت والدائم معًا

الجميل في EIP-7702 أنه يمنحك حرية الاختيار. هل تريد تفويضًا مؤقتًا لمعاملة معقدة لمرة واحدة؟ يمكنك ذلك. هل تريد ترقية EOA الخاص بك بشكل دائم ليعمل مثل محفظة عقد ذكي؟ يمكنك ذلك أيضًا.

للتفويض المؤقت، إليك مثالًا

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

وللتفويض الدائم، إليك مثالًا

// 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
};

لماذا يُعدّ 7702 أكثر أمانًا

الفرق الجوهري بين EIP-3074 و EIP-7702 ليس مجرد مؤقت مقابل دائم، بل يتعلق بتوزيع المخاطر والتحكم. يُنشئ EIP-3074 نقطة فشل مشتركة قد تؤثر فيها مشكلة عقد واحد شائع في آلاف المستخدمين. أما EIP-7702 فيعزل كل معاملة، لذا لا يمكن للأخطاء أن تؤثر إلا في تلك المعاملة بعينها. و EIP-7702 متوافق تمامًا مع ERC-4337 الموجود، ولا يتطلب أي opcodes جديدة. وهذا يعني في الأساس أن المحافظ تستطيع تبنّيه تدريجيًا دون كسر أي أنظمة قائمة.

الفكرة الحاسمة هي أن wallets، وليس dApps، هي التي تدير التفويضات. لذا فإن الاتفاق العام هو السماح للمحافظ وحدها بإدارة التفويضات، وهذا يعني:

ما يحتاج المطورون إلى معرفته

إذا كنت تبني تطبيقًا سيدعم EIP-7702، فهناك بعض الأمور التقنية التي يجب ملاحظتها

  1. تغييرات في بناء المعاملات يجب أن يتعامل منطق بناء المعاملات لديك مع قوائم التخويل
// 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. تعقيد تقدير الغاز إذا قرر حساب EOA إلغاء تحكم العقد الذكي، فيجب إرسال معاملة 7702 أخرى لإعادة ضبط التفويض على 0x0. وهذا يعني أن تقدير الغاز لديك يجب أن يأخذ في الحسبان
  1. دعم توقيعات العقود الذكية يتيح EIP-7702 التحقق من التوقيعات وفق EIP-1271 لحسابات EOAs. وهذا يعني أن EOA المُرقّى الخاص بك يستطيع توقيع الرسائل باستخدام طرق بديلة مثل passkeys، مع الحفاظ على التوافق مع الإصدارات السابقة.
// 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;
}

روابط أساسية

•••
شارك هذه المقالة:

ابقَ على اطلاع

احصل على أحدث المقالات في بريدك الوارد.