From 5cdee0932ec974862530ee571681a55093214280 Mon Sep 17 00:00:00 2001 From: Filip Date: Fri, 1 May 2026 10:26:08 +0200 Subject: [PATCH] fix: resolve eip712Domain on fresh 7702 EOAs in signQuote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In EIP-7702 mode the account address is the EOA itself, but the SDK still passes factoryAddress + factoryData to viem's getEip712Domain. When the EOA has no code yet, viem falls back to a deployless call that asserts the factory deploys at the expected address — which is impossible because the factory deploys at a CREATE2 address by definition different from the EOA — and reverts with CounterfactualDeploymentFailedError. This broke signQuote on V2_2_1+ for any 7702 user that called signQuote before delegation landed. Detect the 7702 case (account address == signer address) and read the EIP-712 domain directly from the implementation contract, substituting chainId and verifyingContract with the values the EOA will return post-delegation. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/sdk/account/toNexusAccount.ts | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/sdk/account/toNexusAccount.ts b/src/sdk/account/toNexusAccount.ts index 6535c7df..0b1cfed4 100644 --- a/src/sdk/account/toNexusAccount.ts +++ b/src/sdk/account/toNexusAccount.ts @@ -650,12 +650,38 @@ export const toNexusAccount = async ( } /** - * Use viem helper to obtain and cache the eip712 domain for the account + * Use viem helper to obtain and cache the eip712 domain for the account. + * + * In EIP-7702 mode the smart-account address is the EOA itself, but `factoryAddress` + + * `factoryData` would deploy a Nexus account at a CREATE2 address that is by definition + * not the EOA. viem's deployless fallback (used when the address has no code yet) asserts + * that the deployed address equals the target address and reverts when they don't match — + * breaking `signQuote` for a 7702 EOA that hasn't been delegated yet. Read the domain from + * the implementation contract directly instead, and substitute chainId + verifyingContract + * with the values the EOA will return after delegation. */ const getEip712Domain = async (): Promise => { if (!isNullOrUndefined(_eip712Domain)) return _eip712Domain + + const address = await getAddress() + + if (addressEquals(address, signer.address)) { + const implDomain = await getEip712DomainViemAction(publicClient, { + address: meeConfig.implementationAddress + }) + _eip712Domain = { + ...implDomain, + domain: { + ...implDomain.domain, + chainId: chain.id, + verifyingContract: address + } + } + return _eip712Domain + } + const eip712Domain = await getEip712DomainViemAction(publicClient, { - address: await getAddress(), + address, factory: meeConfig.factoryAddress, factoryData })