#442 复审时 Codex 独立挖出的发现,直接打在该 PR 自己的核心目标上,按建议尽快跟进。
问题
#442 给 AccountService 加了 assertChainMatchesRpc(),接在两个入口:
prepareGuardianSetup(guardian acceptance hash)
submitCreateWithPasskey(部署广播)
漏了第三个:prepareCreateWithPasskey(aastar/src/account/account.service.ts ~352 行)。它调 this.client.accounts.prepareCreateAccountWithPasskey(...),产出 challenge / challengeId / publicKeyOptions / predictedAddress —— 也就是用户设备实际要签的那个 CREATE_ACCOUNT digest,同样是链绑定的产物,却没有任何前置校验。
为什么这比 submitCreateWithPasskey 上那个更重要
#442 的 PR 描述里明确写了修复目标是「在一次性 WebAuthn 仪式被消耗之前失败」。但 submitCreateWithPasskey 已经是仪式之后了 —— 到那一步用户早就把脸/指纹按过了。真正能兑现那个目标的位置恰恰是 prepareCreateWithPasskey,而它没加。
也就是说:CHAIN_ID/ETH_RPC_URL 不一致时,当前行为仍然是「用户白做一次仪式,在 submit 阶段才被拒」。#442 修好了「不会广播一笔签名对不上的部署」,但没修好「不会浪费用户一次仪式」。
修法
在 prepareCreateWithPasskey 的 try 之前加:
await this.assertChainMatchesRpc(
"The CREATE_ACCOUNT digest would be signed for a chain the account is not created on."
);
helper 已经在(#442 引入),一行的事。
配套单测参照 account.service.spec.ts 里现成的 mismatch 用例:不一致时 prepareCreateAccountWithPasskey 必须未被调用(不发 challenge),一致时正常返回。
关联
#442 复审时 Codex 独立挖出的发现,直接打在该 PR 自己的核心目标上,按建议尽快跟进。
问题
#442 给
AccountService加了assertChainMatchesRpc(),接在两个入口:prepareGuardianSetup(guardian acceptance hash)submitCreateWithPasskey(部署广播)漏了第三个:
prepareCreateWithPasskey(aastar/src/account/account.service.ts~352 行)。它调this.client.accounts.prepareCreateAccountWithPasskey(...),产出challenge/challengeId/publicKeyOptions/predictedAddress—— 也就是用户设备实际要签的那个 CREATE_ACCOUNT digest,同样是链绑定的产物,却没有任何前置校验。为什么这比 submitCreateWithPasskey 上那个更重要
#442 的 PR 描述里明确写了修复目标是「在一次性 WebAuthn 仪式被消耗之前失败」。但
submitCreateWithPasskey已经是仪式之后了 —— 到那一步用户早就把脸/指纹按过了。真正能兑现那个目标的位置恰恰是prepareCreateWithPasskey,而它没加。也就是说:CHAIN_ID/ETH_RPC_URL 不一致时,当前行为仍然是「用户白做一次仪式,在 submit 阶段才被拒」。#442 修好了「不会广播一笔签名对不上的部署」,但没修好「不会浪费用户一次仪式」。
修法
在
prepareCreateWithPasskey的try之前加:helper 已经在(#442 引入),一行的事。
配套单测参照
account.service.spec.ts里现成的 mismatch 用例:不一致时prepareCreateAccountWithPasskey必须未被调用(不发 challenge),一致时正常返回。关联