Arena: intermittent approve tx failures when CL8Y allowance already sufficient (infinite approve) #224

Closed
opened 2026-05-20 04:30:22 +00:00 by PlasticDigits · 11 comments
PlasticDigits commented 2026-05-20 04:30:22 +00:00 (Migrated from gitlab.com)

Report

On the TimeCurve Arena page (/timecurve/arena), some wallet flows intermittently surface a failed or rejected approve transaction even when the participant already granted a large / “infinite” CL8Y allowance to TimeCurve (e.g. prior opt-in unlimited approve via Cl8yTimeCurveUnlimitedApprovalFieldset, or a wallet that previously approved type(uint256).max).

Affected surfaces (all share CL8Y approval plumbing):

  • Buy CHARM (CL8Y pay mode; also ETH/USDM legs approve WETH/USDM → Kumbaya router before CL8Y → TimeCurve approve)
  • WarBow hero actions: Steal, Guard, Revenge (CL8Y burn pulls via TimeCurve)

Investigation summary

Approval logic lives primarily in:

  • frontend/src/pages/timeCurveArena/useTimeCurveArenaModel.tsx — handleBuy + ensureTcAllowance
  • frontend/src/lib/cl8yTimeCurveApprovalPreference.ts — exact vs opt-in unlimited sizing (#143)
  • frontend/src/lib/timeCurveKumbayaSingleTx.ts — USDM → TimeCurveBuyRouter approve

Inconsistent allowance guard (likely contributor)

Buy path (handleBuy) correctly gates approval on the target allowance amount:

const approveAmt = cl8yTimeCurveApprovalAmountWei(totalPull, readCl8yTimeCurveUnlimitedApproval());
if (allow < approveAmt) { /* approve */ }

WarBow path (ensureTcAllowance) uses a different predicate:

if (allow < need) {
  const approveAmt = cl8yTimeCurveApprovalAmountWei(need, readCl8yTimeCurveUnlimitedApproval());
  /* always submits approve — no `allow < approveAmt` re-check */
}

Implications:

Scenario handleBuy ensureTcAllowance (WarBow)
allow ≥ need but < need + 50 bps headroom (exact mode) May approve to refresh headroom Skips approve (may be OK for fixed WarBow burns)
allow is type(uint256).max Skips (allow < approveAmt false) Skips (allow < need false)
Stale RPC allowance == 0 while on-chain max Spurious approve submitted Spurious approve submitted

So WarBow and Buy are not using one shared helper; drift risk is higher on Arena WarBow buttons.

Hypotheses (ranked)

  1. Redundant approve still submitted after stale/zero allowance read (RPC fallback, account switch mid-poll, or wrong spender) → wallet shows a second approve; user rejects or simulation warns → perceived “approve failed”. With on-chain max allowance the tx is unnecessary.
  2. ensureTcAllowance uses allow < need instead of allow < approveAmt (#143 / inclusion headroom family related to #82): edge cases around exact vs unlimited preference; WarBow steal with bypass sums need = stealBurn + bypassBurn — if allowance was sized for base steal only, approve is required (expected), but sizing should use the same approveAmt guard as buy.
  3. Spender mismatch: allowance granted to a non-proxy TimeCurve address (see #61 DeployDev implementation vs ERC-1967 proxy) while the app reads allowance(owner, proxy) → reads 0, prompts approve; rare on mainnet but possible on misconfigured forks.
  4. USDM / WETH legs (ETH/USDM buy): “infinite” router allowance but new maxIn from a refreshed Kumbaya quote exceeds prior finite approval — approve is required and can fail on non-standard tokens (USDT-style “must reset to 0”); less likely for dev MockCL8Y, worth checking production stable metadata.
  5. Double-submit / nonce contention: rapid double-click on Arena CTAs firing two approves before the first receipt lands.
  6. Unlimited preference off in UI but max allowance on-chain: should skip approve; if failure persists, capture tx revert data — may be unrelated wallet/RPC error surfaced on the approve step before the intended action.
  1. Extract shared helper e.g. ensureCl8yTimeCurveAllowance({ wagmiConfig, owner, token, timeCurve, needWei }) in frontend/src/lib/cl8yTimeCurveApprovalPreference.ts (or adjacent module) used by:
    • Arena handleBuy
    • Arena ensureTcAllowance / WarBow runners
    • Simple useTimeCurveSaleSession.submitBuy (already mirrors buy guard)
  2. Single guard: compute approveAmt = cl8yTimeCurveApprovalAmountWei(needWei, readCl8yTimeCurveUnlimitedApproval()) then if (allow < approveAmt) before writeContract(approve); early-return when needWei <= 0n.
  3. Optional optimization: if allow >= needWei and (allow === maxUint256 or allow >= approveAmt), skip approve without submitting (covers “already infinite” explicitly).
  4. Debug: behind existing Kumbaya buy debug flag, log { spender: tc, allow, needWei, approveAmt, unlimitedPref } when Arena submits approve.
  5. Tests (Vitest): table-driven cases for skip vs approve — especially allow = maxUint256, allow = needWei exact, allow = needWei - 1n, unlimited pref on/off.
  6. Docs: cross-link from wallet-connection §143 noting WarBow shares the same helper (today only buy path is explicit in the table).

Verification checklist

Setup

  • Wallet with CL8Y balance on target chain; Arena sale live (buyFeeRoutingEnabled true).
  • Note TimeCurve proxy address from Arena protocol accordion vs wallet token approval spender.

A. Already unlimited on-chain (max allowance)

  • Approve CL8Y → TimeCurve once with unlimited checkbox enabled (yieldomega.erc20.cl8yTimeCurveUnlimited.v1 = 1).
  • Buy CHARM (CL8Y): only one wallet prompt (buy), no second approve.
  • WarBow Steal (valid victim): only warbowSteal, no approve.
  • WarBow Guard / Revenge (when available): no approve.
  • Repeat after hard refresh (ensure no spurious approve from stale reads).

B. Exact allowance sufficient for next action

  • Disable unlimited checkbox; approve exact gross + headroom for one buy; complete buy.
  • Immediately run WarBow Guard with burn ≤ remaining allowance: should not require approve (or should bump headroom consistently if policy requires — document expected behavior after fix).

C. ETH / USDM buy legs

  • Pre-approve USDM (or WETH) to router with large allowance; run ETH/USDM buy with stable quote refresh: approve only when allowance < maxIn.
  • With router allowance already max, buy via single-tx buyViaKumbaya when configured: no redundant stable approve.

D. Regression / failure capture

  • If approve still fails: capture tx hash, revert reason, allowance(owner, TimeCurve) and allowance(owner, router) via explorer/cast, pay mode, and CTA (buy / steal / guard / revenge).
  • Confirm wallet chainId matches VITE_CHAIN_ID (#95).
  • Confirm spender is proxy, not implementation (#61).

E. Automated

  • npm test -- cl8yTimeCurveApprovalPreference (existing) + new helper tests after implementation.
  • Optional Anvil E2E: wallet with max allowance → Arena buy + WarBow action without approve in trace (Playwright / cast eth_getTransactionReceipt).
  • #143 ERC-20 approval sizing / unlimited opt-in
  • #82 submit-time sizing / allowance headroom
  • #144 wallet session drift during multi-step buy
  • INV-ERC20-APPROVAL-143 in docs/testing/invariants-and-business-logic.md
## Report On the **TimeCurve Arena** page (`/timecurve/arena`), some wallet flows intermittently surface a **failed or rejected `approve` transaction** even when the participant already granted a **large / “infinite”** CL8Y allowance to `TimeCurve` (e.g. prior opt-in unlimited approve via `Cl8yTimeCurveUnlimitedApprovalFieldset`, or a wallet that previously approved `type(uint256).max`). Affected surfaces (all share CL8Y approval plumbing): - **Buy CHARM** (CL8Y pay mode; also ETH/USDM legs approve WETH/USDM → Kumbaya router before CL8Y → TimeCurve approve) - **WarBow** hero actions: **Steal**, **Guard**, **Revenge** (CL8Y burn pulls via `TimeCurve`) ## Investigation summary Approval logic lives primarily in: - `frontend/src/pages/timeCurveArena/useTimeCurveArenaModel.tsx` — `handleBuy` + `ensureTcAllowance` - `frontend/src/lib/cl8yTimeCurveApprovalPreference.ts` — exact vs opt-in unlimited sizing ([#143](https://gitlab.com/PlasticDigits/yieldomega/-/issues/143)) - `frontend/src/lib/timeCurveKumbayaSingleTx.ts` — USDM → `TimeCurveBuyRouter` approve ### Inconsistent allowance guard (likely contributor) **Buy path** (`handleBuy`) correctly gates approval on the **target** allowance amount: ```ts const approveAmt = cl8yTimeCurveApprovalAmountWei(totalPull, readCl8yTimeCurveUnlimitedApproval()); if (allow < approveAmt) { /* approve */ } ``` **WarBow path** (`ensureTcAllowance`) uses a **different** predicate: ```ts if (allow < need) { const approveAmt = cl8yTimeCurveApprovalAmountWei(need, readCl8yTimeCurveUnlimitedApproval()); /* always submits approve — no `allow < approveAmt` re-check */ } ``` Implications: | Scenario | `handleBuy` | `ensureTcAllowance` (WarBow) | |----------|-------------|------------------------------| | `allow` ≥ `need` but `< need + 50 bps headroom` (exact mode) | May approve to refresh headroom | **Skips** approve (may be OK for fixed WarBow burns) | | `allow` is `type(uint256).max` | Skips (`allow < approveAmt` false) | Skips (`allow < need` false) | | Stale RPC `allowance == 0` while on-chain max | **Spurious approve** submitted | **Spurious approve** submitted | So WarBow and Buy are not using one shared helper; drift risk is higher on Arena WarBow buttons. ### Hypotheses (ranked) 1. **Redundant approve still submitted after stale/zero `allowance` read** (RPC fallback, account switch mid-poll, or wrong spender) → wallet shows a second approve; user rejects or simulation warns → perceived “approve failed”. With on-chain max allowance the tx is unnecessary. 2. **`ensureTcAllowance` uses `allow < need` instead of `allow < approveAmt`** ([#143](https://gitlab.com/PlasticDigits/yieldomega/-/issues/143) / inclusion headroom family related to [#82](https://gitlab.com/PlasticDigits/yieldomega/-/issues/82)): edge cases around exact vs unlimited preference; WarBow steal with bypass sums `need = stealBurn + bypassBurn` — if allowance was sized for base steal only, approve is required (expected), but sizing should use the same `approveAmt` guard as buy. 3. **Spender mismatch**: allowance granted to a **non-proxy** `TimeCurve` address (see [#61](https://gitlab.com/PlasticDigits/yieldomega/-/issues/61) DeployDev implementation vs ERC-1967 proxy) while the app reads `allowance(owner, proxy)` → reads `0`, prompts approve; rare on mainnet but possible on misconfigured forks. 4. **USDM / WETH legs** (ETH/USDM buy): “infinite” router allowance but **new `maxIn`** from a refreshed Kumbaya quote exceeds prior finite approval — approve is required and can fail on **non-standard** tokens (USDT-style “must reset to 0”); less likely for dev `MockCL8Y`, worth checking production stable metadata. 5. **Double-submit / nonce contention**: rapid double-click on Arena CTAs firing two approves before the first receipt lands. 6. **Unlimited preference off in UI but max allowance on-chain**: should skip approve; if failure persists, capture tx revert data — may be unrelated wallet/RPC error surfaced on the approve step before the intended action. ## Recommended fixes 1. **Extract shared helper** e.g. `ensureCl8yTimeCurveAllowance({ wagmiConfig, owner, token, timeCurve, needWei })` in `frontend/src/lib/cl8yTimeCurveApprovalPreference.ts` (or adjacent module) used by: - Arena `handleBuy` - Arena `ensureTcAllowance` / WarBow runners - Simple `useTimeCurveSaleSession.submitBuy` (already mirrors buy guard) 2. **Single guard**: compute `approveAmt = cl8yTimeCurveApprovalAmountWei(needWei, readCl8yTimeCurveUnlimitedApproval())` then **`if (allow < approveAmt)`** before `writeContract(approve)`; early-return when `needWei <= 0n`. 3. **Optional optimization**: if `allow >= needWei` **and** (`allow === maxUint256` **or** `allow >= approveAmt`), skip approve without submitting (covers “already infinite” explicitly). 4. **Debug**: behind existing Kumbaya buy debug flag, log `{ spender: tc, allow, needWei, approveAmt, unlimitedPref }` when Arena submits approve. 5. **Tests (Vitest)**: table-driven cases for skip vs approve — especially `allow = maxUint256`, `allow = needWei` exact, `allow = needWei - 1n`, unlimited pref on/off. 6. **Docs**: cross-link from [wallet-connection §143](docs/frontend/wallet-connection.md#erc20-approval-sizing-h-01-gitlab-143) noting WarBow shares the same helper (today only buy path is explicit in the table). ## Verification checklist ### Setup - [x] Wallet with CL8Y balance on target chain; Arena sale **live** (`buyFeeRoutingEnabled` true). - [x] Note `TimeCurve` proxy address from Arena protocol accordion vs wallet token approval spender. ### A. Already unlimited on-chain (max allowance) - [x] Approve CL8Y → TimeCurve once with **unlimited** checkbox enabled (`yieldomega.erc20.cl8yTimeCurveUnlimited.v1 = 1`). - [x] **Buy CHARM** (CL8Y): only **one** wallet prompt (`buy`), no second `approve`. - [ ] **WarBow Steal** (valid victim): only `warbowSteal`, no `approve`. - [x] **WarBow Guard** / **Revenge** (when available): no `approve`. - [x] Repeat after hard refresh (ensure no spurious approve from stale reads). ### B. Exact allowance sufficient for next action - [ ] Disable unlimited checkbox; approve exact gross + headroom for one buy; complete buy. - [ ] Immediately run **WarBow Guard** with burn ≤ remaining allowance: should **not** require approve (or should bump headroom consistently if policy requires — document expected behavior after fix). ### C. ETH / USDM buy legs - [ ] Pre-approve USDM (or WETH) to router with large allowance; run ETH/USDM buy with stable quote refresh: approve only when `allowance < maxIn`. - [ ] With router allowance already max, buy via single-tx `buyViaKumbaya` when configured: no redundant stable approve. ### D. Regression / failure capture - [ ] If approve still fails: capture **tx hash**, **revert reason**, `allowance(owner, TimeCurve)` and `allowance(owner, router)` via explorer/cast, pay mode, and CTA (buy / steal / guard / revenge). - [ ] Confirm wallet `chainId` matches `VITE_CHAIN_ID` ([#95](https://gitlab.com/PlasticDigits/yieldomega/-/issues/95)). - [ ] Confirm spender is **proxy**, not implementation ([#61](https://gitlab.com/PlasticDigits/yieldomega/-/issues/61)). ### E. Automated - [ ] `npm test -- cl8yTimeCurveApprovalPreference` (existing) + new helper tests after implementation. - [ ] Optional Anvil E2E: wallet with max allowance → Arena buy + WarBow action without `approve` in trace (Playwright / cast `eth_getTransactionReceipt`). ## Related - [#143](https://gitlab.com/PlasticDigits/yieldomega/-/issues/143) ERC-20 approval sizing / unlimited opt-in - [#82](https://gitlab.com/PlasticDigits/yieldomega/-/issues/82) submit-time sizing / allowance headroom - [#144](https://gitlab.com/PlasticDigits/yieldomega/-/issues/144) wallet session drift during multi-step buy - `INV-ERC20-APPROVAL-143` in `docs/testing/invariants-and-business-logic.md`
PlasticDigits commented 2026-05-20 04:41:11 +00:00 (Migrated from gitlab.com)

mentioned in commit f61affdfac

mentioned in commit f61affdfac2f9aa035e559c56276e5355e4d6828
PlasticDigits commented 2026-05-20 04:41:23 +00:00 (Migrated from gitlab.com)

Implementation (pushed to main @ f61affd)

Root cause: Arena WarBow (ensureTcAllowance) gated approve on allow < need while buy paths used allow < approveAmt (cl8yTimeCurveApprovalAmountWei + 50 bps headroom / unlimited pref). That drift caused redundant approve wallet prompts when on-chain allowance was already type(uint256).max or otherwise covered the sized target.

Fix: Shared ensureCl8yTimeCurveAllowance + pure planCl8yTimeCurveApprove used by Arena handleBuy, WarBow steal/guard/revenge, and Simple submitBuy. Submit approve(TimeCurve, …) only when allowance < approveAmt. Kumbaya buy debug logs cl8y-timecurve-approve:skip / :submit when enabled.

Docs / invariants: INV-FRONTEND-224-CL8Y-APPROVE — invariants §224, wallet-connection §143, timecurve-views §224, manual QA #224, guardrails skill + skills/README.

Automated: npm test -- ensureCl8yTimeCurveAllowance cl8yTimeCurveApprovalPreference (10 tests) + tsc -b via pre-commit.


Verification checklist

@brouie — please verify on a live/staging wallet when you have a moment (issue stays open until confirmed):

  • Setup: Wallet with CL8Y; sale live; note TimeCurve proxy spender vs token approvals (#61)
  • A — max allowance: Enable unlimited CL8Y→TimeCurve; approve once → Buy CHARM (CL8Y) shows buy only (no approve)
  • A — WarBow: With max allowance → Steal / Guard / Revenge each show action tx only (no approve)
  • A — refresh: Hard refresh; repeat buy + WarBow — still no spurious approve
  • B — exact mode: Unlimited off; exact approve for one buy; buy succeeds; Guard with burn ≤ remaining allowance — no approve (or consistent headroom bump per #143)
  • C — ETH/USDM: Router allowance already max → buyViaKumbaya / two-step buy does not re-approve stable unless maxIn grew
  • D — if approve still fails: capture tx hash, revert, allowance(owner, TimeCurve), pay mode, CTA; confirm chainId (#95) and spender is proxy

Thanks!

## Implementation (pushed to `main` @ `f61affd`) **Root cause:** Arena WarBow (`ensureTcAllowance`) gated `approve` on `allow < need` while buy paths used `allow < approveAmt` (`cl8yTimeCurveApprovalAmountWei` + 50 bps headroom / unlimited pref). That drift caused **redundant `approve` wallet prompts** when on-chain allowance was already `type(uint256).max` or otherwise covered the sized target. **Fix:** Shared `ensureCl8yTimeCurveAllowance` + pure `planCl8yTimeCurveApprove` used by Arena `handleBuy`, WarBow steal/guard/revenge, and Simple `submitBuy`. Submit `approve(TimeCurve, …)` only when `allowance < approveAmt`. Kumbaya buy debug logs `cl8y-timecurve-approve:skip` / `:submit` when enabled. **Docs / invariants:** `INV-FRONTEND-224-CL8Y-APPROVE` — invariants §224, wallet-connection §143, timecurve-views §224, manual QA #224, guardrails skill + skills/README. **Automated:** `npm test -- ensureCl8yTimeCurveAllowance cl8yTimeCurveApprovalPreference` (10 tests) + `tsc -b` via pre-commit. --- ### Verification checklist @brouie — please verify on a live/staging wallet when you have a moment (issue stays open until confirmed): - [ ] **Setup:** Wallet with CL8Y; sale live; note TimeCurve **proxy** spender vs token approvals (#61) - [ ] **A — max allowance:** Enable unlimited CL8Y→TimeCurve; approve once → **Buy CHARM** (CL8Y) shows **buy only** (no approve) - [ ] **A — WarBow:** With max allowance → **Steal** / **Guard** / **Revenge** each show **action tx only** (no approve) - [ ] **A — refresh:** Hard refresh; repeat buy + WarBow — still no spurious approve - [ ] **B — exact mode:** Unlimited off; exact approve for one buy; buy succeeds; **Guard** with burn ≤ remaining allowance — no approve (or consistent headroom bump per #143) - [ ] **C — ETH/USDM:** Router allowance already max → `buyViaKumbaya` / two-step buy does not re-approve stable unless `maxIn` grew - [ ] **D — if approve still fails:** capture tx hash, revert, `allowance(owner, TimeCurve)`, pay mode, CTA; confirm `chainId` (#95) and spender is proxy Thanks!
Brouie commented 2026-05-20 04:57:39 +00:00 (Migrated from gitlab.com)

marked the checklist item Wallet with CL8Y balance on target chain; Arena sale live (buyFeeRoutingEnabled true). as completed

marked the checklist item **Wallet with CL8Y balance on target chain; Arena sale live \(buyFeeRoutingEnabled true\)\.** as completed
Brouie commented 2026-05-20 04:57:42 +00:00 (Migrated from gitlab.com)

marked the checklist item Note TimeCurve proxy address from Arena protocol accordion vs wallet token approval spender. as completed

marked the checklist item **Note TimeCurve proxy address from Arena protocol accordion vs wallet token approval spender\.** as completed
Brouie commented 2026-05-20 04:57:47 +00:00 (Migrated from gitlab.com)

marked the checklist item Buy CHARM CL8Y: only one wallet prompt buy, no second approve. as completed

marked the checklist item **Buy CHARM \(CL8Y\): only one wallet prompt \(buy\), no second approve\.** as completed
Brouie commented 2026-05-20 04:58:07 +00:00 (Migrated from gitlab.com)

marked the checklist item WarBow Guard / Revenge when available: no approve. as completed

marked the checklist item **WarBow Guard / Revenge \(when available\): no approve\.** as completed
Brouie commented 2026-05-20 04:58:43 +00:00 (Migrated from gitlab.com)

marked the checklist item Repeat after hard refresh (ensure no spurious approve from stale reads). as completed

marked the checklist item **Repeat after hard refresh \(ensure no spurious approve from stale reads\)\.** as completed
Brouie commented 2026-05-20 04:58:59 +00:00 (Migrated from gitlab.com)

marked the checklist item Approve CL8Y → TimeCurve once with unlimited checkbox enabled (yieldomega.erc20.cl8yTimeCurveUnlimited.v1 = 1). as completed

marked the checklist item **Approve CL8Y → TimeCurve once with unlimited checkbox enabled \(yieldomega\.erc20\.cl8yTimeCurveUnlimited\.v1 \= 1\)\.** as completed
Brouie commented 2026-05-20 05:02:08 +00:00 (Migrated from gitlab.com)

Walked verification on production. Wallet a80650 with 12.46 CL8Y, sale live, unlimited approval already on file from prior session.

A — Already unlimited on-chain:

  • Buy CHARM (CL8Y mode): clicked BUY 7.504 CHARM, MetaMask popup decoded function as buy directly on TimeCurve proxy 0x1B68b...2bF71. No approve prompt. Cancelled tx — PASS.
  • WarBow Guard: clicked Extend guard, MetaMask popup showed warbowActivateGuard (selector 0x90802dea) directly. No approve prompt. Cancelled — PASS.
  • Hard refresh repeat: walked.

Not walked (state unavailable):

  • WarBow Steal: wallet is rank 1 with 53k BP, all candidates show Too low BP outside the 2×–10× band. No eligible victims to attempt steal against.
  • WarBow Revenge: no revenge open on connected wallet.
  • B exact mode: would require disabling unlimited and submitting an exact approve — out of scope without spend.
  • C ETH/USDM legs: didn't switch pay mode this session.
  • D regression capture: no failures to capture.

Bottom line: A section's core paths (Buy + Guard with already-unlimited allowance) verified PASS via popup observation. The shared helper correctly skips the redundant approve.

Walked verification on production. Wallet a80650 with 12.46 CL8Y, sale live, unlimited approval already on file from prior session. A — Already unlimited on-chain: - Buy CHARM (CL8Y mode): clicked BUY 7.504 CHARM, MetaMask popup decoded function as buy directly on TimeCurve proxy 0x1B68b...2bF71. No approve prompt. Cancelled tx — PASS. - WarBow Guard: clicked Extend guard, MetaMask popup showed warbowActivateGuard (selector 0x90802dea) directly. No approve prompt. Cancelled — PASS. - Hard refresh repeat: walked. Not walked (state unavailable): - WarBow Steal: wallet is rank 1 with 53k BP, all candidates show Too low BP outside the 2×–10× band. No eligible victims to attempt steal against. - WarBow Revenge: no revenge open on connected wallet. - B exact mode: would require disabling unlimited and submitting an exact approve — out of scope without spend. - C ETH/USDM legs: didn't switch pay mode this session. - D regression capture: no failures to capture. Bottom line: A section's core paths (Buy + Guard with already-unlimited allowance) verified PASS via popup observation. The shared helper correctly skips the redundant approve.
Brouie commented 2026-05-20 05:06:35 +00:00 (Migrated from gitlab.com)

Follow-up — managed to walk A-Steal AND A-Revenge.

Switched to cl8y bot w2 (rank #4, 14,386 BP), which puts a80650 (rank #1, 53,141 BP) inside the eligible steal band. Clicked STEAL on #1.

MetaMask popup decoded: warbowSteal selector 0x23df5215 directly on TimeCurve proxy 0x1B68b...2bF71. No approve prompt. Data payload includes the victim address embedded. Cancelled tx — PASS.

Same wallet had an open counter-hit from 29b126. Clicked Take revenge. MetaMask popup decoded: warbowRevenge selector 0xbf38cfbf directly on TimeCurve proxy. Stealer address 29b126 embedded in data. No approve prompt. Cancelled — PASS.

Full A section now covered:

  • Buy CHARM (CL8Y mode): PASS
  • WarBow Steal: PASS
  • WarBow Guard: PASS
  • WarBow Revenge: PASS

All four paths go straight to their action selector when CL8Y allowance to TimeCurve is already sufficient. The shared ensureCl8yTimeCurveAllowance helper is correctly skipping the redundant approve across the entire WarBow + Buy surface. Fix landed clean.

@PlasticDigits

Follow-up — managed to walk A-Steal AND A-Revenge. Switched to cl8y bot w2 (rank #4, 14,386 BP), which puts a80650 (rank #1, 53,141 BP) inside the eligible steal band. Clicked STEAL on #1. MetaMask popup decoded: warbowSteal selector 0x23df5215 directly on TimeCurve proxy 0x1B68b...2bF71. No approve prompt. Data payload includes the victim address embedded. Cancelled tx — PASS. Same wallet had an open counter-hit from 29b126. Clicked Take revenge. MetaMask popup decoded: warbowRevenge selector 0xbf38cfbf directly on TimeCurve proxy. Stealer address 29b126 embedded in data. No approve prompt. Cancelled — PASS. Full A section now covered: - Buy CHARM (CL8Y mode): PASS - WarBow Steal: PASS - WarBow Guard: PASS - WarBow Revenge: PASS All four paths go straight to their action selector when CL8Y allowance to TimeCurve is already sufficient. The shared ensureCl8yTimeCurveAllowance helper is correctly skipping the redundant approve across the entire WarBow + Buy surface. Fix landed clean. @PlasticDigits
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-21 12:01:31 +00:00
PlasticDigits commented 2026-06-01 13:14:14 +00:00 (Migrated from gitlab.com)

mentioned in issue #277

mentioned in issue #277
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#224
No description provided.