|
| 1 | +import type { Client, Address, Hex } from 'viem'; |
| 2 | +import { getCode } from 'viem/actions'; |
| 3 | + |
| 4 | +import type { DeleGatorEnvironment } from '../types'; |
| 5 | + |
| 6 | +// EIP-7702 delegation prefix (0xef0100) |
| 7 | +const DELEGATION_PREFIX = '0xef0100' as const; |
| 8 | + |
| 9 | +/** |
| 10 | + * Parameters for checking if an account is delegated to the EIP-7702 implementation. |
| 11 | + */ |
| 12 | +export type IsValid7702ImplementationParameters = { |
| 13 | + /** The client to use for the query. */ |
| 14 | + client: Client; |
| 15 | + /** The address to check for proper delegation. */ |
| 16 | + accountAddress: Address; |
| 17 | + /** The DeleGator environment containing contract addresses. */ |
| 18 | + environment: DeleGatorEnvironment; |
| 19 | +}; |
| 20 | + |
| 21 | +/** |
| 22 | + * Extracts the delegated contract address from EIP-7702 delegation code. |
| 23 | + * |
| 24 | + * @param code - The code returned from getCode for a delegated account. |
| 25 | + * @returns The delegated contract address or null if not a valid delegation. |
| 26 | + */ |
| 27 | +function extractDelegatedAddress(code: Hex | undefined): Address | null { |
| 28 | + if (!code || code.length !== 48) { |
| 29 | + // 0x (2 chars) + ef0100 (6 chars) + address (40 chars) = 48 chars |
| 30 | + return null; |
| 31 | + } |
| 32 | + |
| 33 | + if (!code.startsWith(DELEGATION_PREFIX)) { |
| 34 | + return null; |
| 35 | + } |
| 36 | + |
| 37 | + // Extract the 20-byte address after the delegation prefix |
| 38 | + const addressHex = code.slice(8); // Remove '0xef0100' prefix (8 chars) |
| 39 | + return `0x${addressHex}`; |
| 40 | +} |
| 41 | + |
| 42 | +/** |
| 43 | + * Checks if an account is properly delegated to the EIP-7702 implementation. |
| 44 | + * |
| 45 | + * This function validates EIP-7702 delegations by checking if the EOA has a 7702 |
| 46 | + * contract assigned to it and comparing the delegated address against the 7702 |
| 47 | + * implementation found in the environment. |
| 48 | + * |
| 49 | + * @param params - The parameters for checking the delegation. |
| 50 | + * @param params.client - The client to use for the query. |
| 51 | + * @param params.accountAddress - The address to check for proper delegation. |
| 52 | + * @param params.environment - The DeleGator environment containing contract addresses. |
| 53 | + * @returns A promise that resolves to true if the account is properly delegated to the 7702 implementation, false otherwise. |
| 54 | + * @example |
| 55 | + * ```typescript |
| 56 | + * const isValid = await isValid7702Implementation({ |
| 57 | + * client: publicClient, |
| 58 | + * accountAddress: '0x...', |
| 59 | + * environment: delegatorEnvironment, |
| 60 | + * }); |
| 61 | + * |
| 62 | + * if (isValid) { |
| 63 | + * console.log('Account is properly delegated to EIP-7702 implementation'); |
| 64 | + * } else { |
| 65 | + * console.log('Account is not properly delegated'); |
| 66 | + * } |
| 67 | + * ``` |
| 68 | + */ |
| 69 | +export async function isValid7702Implementation({ |
| 70 | + client, |
| 71 | + accountAddress, |
| 72 | + environment, |
| 73 | +}: IsValid7702ImplementationParameters): Promise<boolean> { |
| 74 | + try { |
| 75 | + // Get the code at the account address |
| 76 | + const code = await getCode(client, { |
| 77 | + address: accountAddress, |
| 78 | + }); |
| 79 | + |
| 80 | + // Extract the delegated contract address from the EIP-7702 delegation code |
| 81 | + const delegatedAddress = extractDelegatedAddress(code); |
| 82 | + |
| 83 | + // If no valid delegation found, return false |
| 84 | + if (!delegatedAddress) { |
| 85 | + return false; |
| 86 | + } |
| 87 | + |
| 88 | + // Compare the delegated address with the 7702 implementation in the environment |
| 89 | + const expectedImplementation = |
| 90 | + environment.implementations.EIP7702StatelessDeleGatorImpl; |
| 91 | + if (!expectedImplementation) { |
| 92 | + return false; |
| 93 | + } |
| 94 | + |
| 95 | + return ( |
| 96 | + delegatedAddress.toLowerCase() === expectedImplementation.toLowerCase() |
| 97 | + ); |
| 98 | + } catch (error) { |
| 99 | + // If the call fails (e.g., no code at address, network error), |
| 100 | + // then it's not properly delegated to our implementation |
| 101 | + return false; |
| 102 | + } |
| 103 | +} |
0 commit comments