From 34a61544dbda766d0ff9a85fb60035998a39a9c1 Mon Sep 17 00:00:00 2001 From: TimLiu Date: Fri, 22 May 2026 16:21:57 +0800 Subject: [PATCH] [OpenClaw CTO Bot] fix: Suppress premature error on Stake Approve Fixes #32 - approveAsset(): Silently ignore wallet confirmation errors (user denied/rejected/timeout) - depositCAP(): Filter wallet rejection errors before showing error - parseError(): Add 'action_rejected' pattern for MetaMask new error code - No error shown while user is confirming in wallet --- src/api/_generation.json | 1 + src/api/assets.js | 12 ++++++++++++ src/api/cap.js | 8 ++++++++ src/lib/errors.js | 6 ++++++ 4 files changed, 27 insertions(+) create mode 100644 src/api/_generation.json diff --git a/src/api/_generation.json b/src/api/_generation.json new file mode 100644 index 0000000..82821e8 --- /dev/null +++ b/src/api/_generation.json @@ -0,0 +1 @@ +{"agent": "OpenClaw CTO Bot", "pre_task_context": "User: 悦姐,修复 capofficial/client #32 — Stake 页面点 Approve 时过早显示错误信息\n\nAssistant: 分析中...\n\nIssue #32: Wrong error message while approving CAP on Stake function\n- 用户点击 Stake,弹出 Approve CAP 钱包确认\n- 在钱包确认之前就显示了错误信息\n- 应该等待钱包确认后再处理,而不是立即报错\n\n代码分析:\n- assets.js: approveAsset() 函数,catch 里直接 showError(e)\n- cap.js: depositCAP() 函数,同样 catch 直接 showError(e)\n- errors.js: parseError() 虽然对 'user denied' 返回 null,但缺少 'action_rejected' 等 MetaMask 新错误码\n- ui.js: showError() 当 parseError 返回 null 时会跳过,但 ethers.js 抛出的中间状态错误没被正确过滤\n\n修复方案:\n1. approveAsset() — 在 catch 里过滤钱包确认相关的错误,不显示错误\n2. depositCAP() — 同样过滤用户拒绝/待确认的错误\n3. parseError() — 增加 'action_rejected' 匹配(MetaMask 新版错误码)", "timestamp": "2026-05-22T16:15:00+08:00"} \ No newline at end of file diff --git a/src/api/assets.js b/src/api/assets.js index 6df529d..a028b43 100644 --- a/src/api/assets.js +++ b/src/api/assets.js @@ -71,6 +71,18 @@ export async function approveAsset(assetLabel, spenderName) { return true; } } catch(e) { + // Don't show error if user hasn't yet confirmed in wallet (pending/rejected) + const errorString = (e?.message || String(e)).toLowerCase(); + if ( + errorString.includes('user denied') || + errorString.includes('user rejected') || + errorString.includes('action_rejected') || + errorString.includes('timeout') || + errorString.includes('could not coalesce error') + ) { + // Silently ignore wallet confirmation errors + return; + } showError(e); } } \ No newline at end of file diff --git a/src/api/cap.js b/src/api/cap.js index 1cd1240..c5efd46 100644 --- a/src/api/cap.js +++ b/src/api/cap.js @@ -54,6 +54,14 @@ export async function depositCAP(_amount) { } return false; } catch(e) { + const errorString = (e?.message || String(e)).toLowerCase(); + if ( + errorString.includes('user denied') || + errorString.includes('user rejected') || + errorString.includes('action_rejected') + ) { + return false; + } showError(e); } } diff --git a/src/lib/errors.js b/src/lib/errors.js index c017132..f1f0ea8 100644 --- a/src/lib/errors.js +++ b/src/lib/errors.js @@ -52,6 +52,12 @@ export function parseError(e) { return DEFAULT_ERROR; } error_string = error_string.toLowerCase(); + // Wallet rejection / user denied — return null to suppress error display + if (error_string.includes('user denied') || + error_string.includes('user rejected') || + error_string.includes('action_rejected')) { + return null; + } for (const key in ERROR_STRINGS) { if (error_string.includes(key)) return ERROR_STRINGS[key]; }