fix(ops): send net recipient amount as burn_amount in withdraw request#9
Conversation
The withdraw proof's circuit Amount (c.Amount) equals the total UTXO deduction: net_recipient + relayerFee + protocolFee. The contract computes amountWithFee = inp.amount + contractProtocolFee + inp.relayerFee and uses it as ZKP public input[6]. For the proof to verify, inp.amount must be the net recipient amount so that: amountWithFee = net + protocolFee + relayerFee = burnAmount = c.Amount Previously, withdraw_amount (used as burn_amount / inp.amount in the relayer request) was set to burnAmount (total UTXO deduction including fees). The contract would then add fees on top again, making amountWithFee > c.Amount and failing ZKP verification with "Transaction validation failed. The note may have been spent or is invalid." Fix: use typedPlan.requestedAmount (the net amount the user asked to receive) as withdraw_amount in the proof context so the relayer sends the correct inp.amount to the contract. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求解决了一个关键错误,该错误导致提款操作因智能合约内零知识证明(ZKP)计算不匹配而失败。修复方案确保在证明上下文中使用了正确的净收款人金额,从而使合约能够准确验证交易并成功处理提款。 Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
| relayer: typedPlan.relayer, | ||
| recipient: input.recipient, | ||
| withdraw_amount: burnAmount, | ||
| withdraw_amount: BigInt(typedPlan.requestedAmount), |
…urn_amount The test expected withdraw_amount = burnAmount (total UTXO deduction), but the correct value is requestedAmount (net recipient amount). Update assertions to reflect the fix in ops.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
问题
Withdraw 始终失败,relayer 返回:「Transaction validation failed. The note may have been spent or is invalid.」
实际是合约 ZKP 验证失败(
estimate_gas报错),不是 nullifier 问题。根因分析
合约
withdraw()构造 ZKP 验证的input[6]:电路的平衡约束:
因此
c.Amount = burnAmount = net_recipient + relayerFee + protocolFee(总 UTXO 扣减量)。ZKP 验证要求
circuit c.Amount == contract input[6],即:只有当
inp.amount = net_recipient(净到账金额)时,两边才相等(因为双方用同一公式计算protocolFee)。Bug:原代码将
withdraw_amount设为burnAmount(= net + relayerFee + protocolFee,总扣减量),relayer 直接用它作为inp.amount传给合约,合约再次叠加手续费,导致amountWithFee > c.Amount,ZKP 验证失败。修复
将 proof context 中的
withdraw_amount从burnAmount改为typedPlan.requestedAmount(用户请求的净到账金额),使合约能正确还原出与电路一致的amountWithFee。验证
在 Sepolia testnet 上运行 automation(
withdrawFeeBPS = 25),三个实例均在 cycle 8 成功 withdraw,链上 tx 已确认:0x0368d4afc36e59c4fb00730e79d3beb4aaf4fea9a78adc423d6fa6a9ac5574bc0x46b11ac7028767c936fe8ac2d4826ef54336f64d7e56902cd0f6bc396c0ece6b0x3f1172565024b3ff4468209d8fbbb262c4ddb5cf98ed4886cdfcf070c02744ed修复前在
withdrawFeeBPS = 0时可能碰巧通过(relayerFee 极小时误差也极小),设为 25 BPS 后问题必现。🤖 Generated with Claude Code