Frontend: wire TimeCurveBuyRouter single-tx ETH/USDM buy (buyViaKumbaya) #66

Closed
opened 2026-04-26 07:51:34 +00:00 by PlasticDigits · 11 comments
PlasticDigits commented 2026-04-26 07:51:34 +00:00 (Migrated from gitlab.com)

Context

Onchain companion TimeCurveBuyRouter + TimeCurve.buyFor shipped in issue #65 / TimeCurveBuyRouter.sol. The sale still settles in CL8Y through buyFor; the UI today uses separate Kumbaya exactOutput + TimeCurve.buy in useTimeCurveSaleSession / TimeCurveSimplePage.

Goal

Offer an optional single-signature path when VITE_* (or runtime config) exposes a deployed TimeCurveBuyRouter and timeCurveBuyRouter is set on TimeCurve:

  • ETH and USDM (stable) pay modes: build the same packed path as today (buildV3PathExactOutput / routingForPayAsset), derive swapDeadline and amountInMaximum (quoter + existing slippage helpers, e.g. swapMaxInputFromQuoted), call buyViaKumbaya with PAY_ETH / PAY_STABLE.
  • Fail closed if router address is missing or chain unsupported — align with kumbaya.md and issue #56 quote/CTA loading behavior.
  • Keep CL8Y direct buy unchanged.

Acceptance criteria

  • Env + kumbayaRoutes (or small helper) resolve TimeCurveBuyRouter address when present; no silent fallback.
  • Simple (and Arena if applicable) buy flow can submit one tx for ETH/USDM when router is configured.
  • Quote refresh / disabled CTA behavior preserved for multi-asset pay modes.
  • E2E or integration note in docs/testing/e2e-anvil.md if Anvil stack deploys the router (see DeployKumbayaAnvilFixtures).

References

  • contracts/src/TimeCurveBuyRouter.sol
  • docs/integrations/kumbaya.md (single-tx section)
  • frontend/src/pages/timecurve/useTimeCurveSaleSession.ts, frontend/src/lib/kumbayaRoutes.ts
## Context Onchain companion `TimeCurveBuyRouter` + `TimeCurve.buyFor` shipped in [issue #65](https://gitlab.com/PlasticDigits/yieldomega/-/issues/65) / `TimeCurveBuyRouter.sol`. The sale still settles in CL8Y through `buyFor`; the UI today uses separate Kumbaya `exactOutput` + `TimeCurve.buy` in `useTimeCurveSaleSession` / `TimeCurveSimplePage`. ## Goal Offer an optional **single-signature** path when `VITE_*` (or runtime config) exposes a deployed `TimeCurveBuyRouter` and `timeCurveBuyRouter` is set on TimeCurve: - **ETH** and **USDM** (stable) pay modes: build the same packed path as today (`buildV3PathExactOutput` / `routingForPayAsset`), derive `swapDeadline` and `amountInMaximum` (quoter + existing slippage helpers, e.g. `swapMaxInputFromQuoted`), call `buyViaKumbaya` with `PAY_ETH` / `PAY_STABLE`. - **Fail closed** if router address is missing or chain unsupported — align with [kumbaya.md](docs/integrations/kumbaya.md) and [issue #56](https://gitlab.com/PlasticDigits/yieldomega/-/issues/56) quote/CTA loading behavior. - Keep **CL8Y** direct `buy` unchanged. ## Acceptance criteria - [ ] Env + `kumbayaRoutes` (or small helper) resolve **TimeCurveBuyRouter** address when present; no silent fallback. - [ ] Simple (and Arena if applicable) buy flow can submit **one tx** for ETH/USDM when router is configured. - [ ] Quote refresh / disabled CTA behavior preserved for multi-asset pay modes. - [ ] E2E or integration note in `docs/testing/e2e-anvil.md` if Anvil stack deploys the router (see `DeployKumbayaAnvilFixtures`). ## References - `contracts/src/TimeCurveBuyRouter.sol` - `docs/integrations/kumbaya.md` (single-tx section) - `frontend/src/pages/timecurve/useTimeCurveSaleSession.ts`, `frontend/src/lib/kumbayaRoutes.ts`
PlasticDigits commented 2026-04-26 07:51:46 +00:00 (Migrated from gitlab.com)

Companion: indexer work for buyFor + ETH/USDM enrichment — https://gitlab.com/PlasticDigits/yieldomega/-/issues/67

Companion: indexer work for `buyFor` + ETH/USDM enrichment — https://gitlab.com/PlasticDigits/yieldomega/-/issues/67
PlasticDigits commented 2026-04-26 07:51:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #67

mentioned in issue #67
PlasticDigits commented 2026-04-26 08:17:01 +00:00 (Migrated from gitlab.com)

mentioned in commit 2a89c4941e

mentioned in commit 2a89c4941eda9f7f5c589e2d8786d0005bbbd050
PlasticDigits commented 2026-04-26 10:26:54 +00:00 (Migrated from gitlab.com)

mentioned in commit 46c4523f97

mentioned in commit 46c4523f9751886c0fce19c7dbff764e095bdea5
PlasticDigits commented 2026-04-26 10:26:54 +00:00 (Migrated from gitlab.com)

mentioned in commit aba4a6d6a1

mentioned in commit aba4a6d6a15c89a1a030afb7112db1097d425633
PlasticDigits commented 2026-04-26 10:27:18 +00:00 (Migrated from gitlab.com)

@brouie — #66 fix merged to main (commit aba4a6d on the merge; branch fix/issue-66-buy-via-kumbaya worktree removed after push).

What changed

  • Single-tx Kumbaya path when TimeCurve.timeCurveBuyRouter() != 0 for ETH and USDM pay modes: quote → slippage → USDM.approve to router as needed → TimeCurveBuyRouter.buyViaKumbaya with the same plantWarBowFlag / pay-kind wiring as the rest of the app (see frontend/src/lib/timeCurveKumbayaSingleTx.ts, kumbayaRoutes.ts resolveTimeCurveBuyRouterForKumbayaSingleTx).
  • Fail closed: optional VITE_KUMBAYA_TIMECURVE_BUY_ROUTER must match the onchain router when set; mismatch or unsupported chain → no silent fallback to two-step.
  • CL8Y direct TimeCurve.buy path unchanged.
  • Docs / invariants: docs/integrations/kumbaya.md, docs/testing/invariants-and-business-logic.md (#66 + cross-refs to #56/#63/#67), docs/testing/e2e-anvil.md, skills/README.md, .cursor/skills/yieldomega-guardrails/SKILL.md.
  • Anvil: scripts/lib/anvil_deploy_dev.sh surfaces KUMBAYA_BUY_ROUTER; scripts/e2e-anvil.sh exports VITE_KUMBAYA_TIMECURVE_BUY_ROUTER when non-empty.
  • Tests: frontend npm test includes kumbayaRoutes.test.ts cases for the resolver.

Verification checklist (please spot-check in your env)

  • On a chain where timeCurveBuyRouter is zero: ETH/USDM Kumbaya still use the two-step flow; no regression to CL8Y buy.
  • When router is set onchain: ETH and USDM purchases complete in one user signature (approve + buy when USDM needs allowance), and WarBow plant toggle matches buy / buyFor behavior.
  • Set VITE_KUMBAYA_TIMECURVE_BUY_ROUTER to a wrong address: UI does not use single-tx (clear fail-closed behavior, no wrong-router swap).
  • Quote/CTA: while a Kumbaya quote is refreshing, primary CTA stays consistent with [issue #56] expectations (no SFX/UX regressions on hot refetch).
  • Optional: run bash scripts/e2e-anvil.sh with a deploy that prints KUMBAYA_BUY_ROUTER and confirm the app picks up the env mirror.

Leaving the issue open for your sign-off. Thanks!

@brouie — **#66 fix merged to `main`** (commit `aba4a6d` on the merge; branch `fix/issue-66-buy-via-kumbaya` worktree removed after push). **What changed** - **Single-tx Kumbaya path** when `TimeCurve.timeCurveBuyRouter() != 0` for **ETH** and **USDM** pay modes: quote → slippage → `USDM.approve` to router as needed → `TimeCurveBuyRouter.buyViaKumbaya` with the same `plantWarBowFlag` / pay-kind wiring as the rest of the app (see `frontend/src/lib/timeCurveKumbayaSingleTx.ts`, `kumbayaRoutes.ts` `resolveTimeCurveBuyRouterForKumbayaSingleTx`). - **Fail closed:** optional `VITE_KUMBAYA_TIMECURVE_BUY_ROUTER` must **match** the onchain router when set; mismatch or unsupported chain → no silent fallback to two-step. - **CL8Y** direct `TimeCurve.buy` path unchanged. - **Docs / invariants:** `docs/integrations/kumbaya.md`, `docs/testing/invariants-and-business-logic.md` (#66 + cross-refs to #56/#63/#67), `docs/testing/e2e-anvil.md`, `skills/README.md`, `.cursor/skills/yieldomega-guardrails/SKILL.md`. - **Anvil:** `scripts/lib/anvil_deploy_dev.sh` surfaces `KUMBAYA_BUY_ROUTER`; `scripts/e2e-anvil.sh` exports `VITE_KUMBAYA_TIMECURVE_BUY_ROUTER` when non-empty. - **Tests:** `frontend` `npm test` includes `kumbayaRoutes.test.ts` cases for the resolver. **Verification checklist** (please spot-check in your env) - [ ] On a chain where `timeCurveBuyRouter` is **zero**: ETH/USDM Kumbaya still use the **two-step** flow; no regression to CL8Y `buy`. - [ ] When router is **set** onchain: ETH and USDM purchases complete in **one** user signature (approve + buy when USDM needs allowance), and WarBow **plant** toggle matches `buy` / `buyFor` behavior. - [ ] Set `VITE_KUMBAYA_TIMECURVE_BUY_ROUTER` to a **wrong** address: UI **does not** use single-tx (clear fail-closed behavior, no wrong-router swap). - [ ] **Quote/CTA:** while a Kumbaya quote is refreshing, primary CTA stays consistent with [issue #56] expectations (no SFX/UX regressions on hot refetch). - [ ] Optional: run `bash scripts/e2e-anvil.sh` with a deploy that prints `KUMBAYA_BUY_ROUTER` and confirm the app picks up the env mirror. Leaving the issue **open** for your sign-off. Thanks!
Brouie commented 2026-04-27 02:46:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #72

mentioned in issue #72
Brouie commented 2026-04-27 04:01:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #74

mentioned in issue #74
Brouie commented 2026-04-27 04:02:14 +00:00 (Migrated from gitlab.com)

@PlasticDigits source-level verification of aba4a6d.

Source review

Resolver (frontend/src/lib/kumbayaRoutes.ts):

  • L234 resolveTimeCurveBuyRouterForKumbayaSingleTx with explicit 4-branch fail-closed semantics
  • L237 onchain zero + env unset -> { kind: 'none' }
  • L239-247 onchain zero + env set -> { kind: 'mismatch', message } (env-without-onchain case)
  • L249-254 onchain set + env mismatch -> { kind: 'mismatch', message } (case-insensitive comparison)
  • L255 onchain set + env unset OR env match -> { kind: 'ok', router }

Submit path (frontend/src/pages/timecurve/useTimeCurveSaleSession.ts):

  • L855-858 resolver called with onchain + import.meta.env
  • L859-862 mismatch -> setBuyError(message) + return (no tx) — AC3 fail closed
  • L863-878 ok + (payWith === 'eth' || 'usdm') -> submitKumbayaSingleTxBuy with plantWarBowFlag + codeHash threaded through
  • Fall-through (kind === 'none' OR payWith === 'cl8y') -> existing two-step / CL8Y direct buy unchanged — AC1 regression-free

Display path:

  • L462 resolver also called for derived display state
  • L475 singleTxBuyRouterRes.kind === 'mismatch' feeds session error/CTA disable

Helper (frontend/src/lib/timeCurveKumbayaSingleTx.ts):

  • New 113-line module
  • L48 timeCurveBuyRouter param threaded
  • L62-71 destructured + cast to 0x address
  • L105 timeCurveBuyRouterAbi imported from lib/abis
  • erc20Abi for the USDM allowance approve before buyViaKumbaya call

Tests

cd frontend && npx vitest run src/lib/kumbayaRoutes.test.ts:

  • 18/18 passing
  • Resolver-specific suite at L148 has 5 cases covering all 4 logic branches:
    • L150 onchain zero + env unset -> none
    • L155 onchain undefined + env unset -> none
    • L160 onchain zero + env set -> mismatch
    • L167 onchain set + env unset -> ok
    • L172 onchain set + env mismatch -> mismatch (case-insensitive)

Anvil / e2e env mirror

scripts/lib/anvil_deploy_dev.sh:

  • L13 doc on KUMBAYA_BUY_ROUTER
  • L59 extract from forge log via _yieldomega_extract_k 'TimeCurveBuyRouter (single-tx'
  • L66 print line in stack output

scripts/e2e-anvil.sh:

  • L53-54 conditional export VITE_KUMBAYA_TIMECURVE_BUY_ROUTER only when KUMBAYA_BUY_ROUTER non-empty (no silent fallback)

Docs

References to issue #66 / buyViaKumbaya in:

  • docs/integrations/kumbaya.md
  • docs/testing/invariants-and-business-logic.md
  • docs/testing/e2e-anvil.md

Browser-side verification deferred

Filed #74 to track the live walkthrough items: ETH single-signature buy, USDM single-signature with approve+buy, WarBow plant flag-through, quote-refresh CTA preservation per #56, fail-closed visual confirmation on mismatched env, two-step fallback when onchain zero.

Closing #66 at the source / unit-test / env-mirror level. Live walkthrough proceeds via #74 in a future frontend session.

@PlasticDigits source-level verification of aba4a6d. ## Source review Resolver (frontend/src/lib/kumbayaRoutes.ts): - L234 resolveTimeCurveBuyRouterForKumbayaSingleTx with explicit 4-branch fail-closed semantics - L237 onchain zero + env unset -> { kind: 'none' } - L239-247 onchain zero + env set -> { kind: 'mismatch', message } (env-without-onchain case) - L249-254 onchain set + env mismatch -> { kind: 'mismatch', message } (case-insensitive comparison) - L255 onchain set + env unset OR env match -> { kind: 'ok', router } Submit path (frontend/src/pages/timecurve/useTimeCurveSaleSession.ts): - L855-858 resolver called with onchain + import.meta.env - L859-862 mismatch -> setBuyError(message) + return (no tx) — AC3 fail closed - L863-878 ok + (payWith === 'eth' || 'usdm') -> submitKumbayaSingleTxBuy with plantWarBowFlag + codeHash threaded through - Fall-through (kind === 'none' OR payWith === 'cl8y') -> existing two-step / CL8Y direct buy unchanged — AC1 regression-free Display path: - L462 resolver also called for derived display state - L475 singleTxBuyRouterRes.kind === 'mismatch' feeds session error/CTA disable Helper (frontend/src/lib/timeCurveKumbayaSingleTx.ts): - New 113-line module - L48 timeCurveBuyRouter param threaded - L62-71 destructured + cast to 0x address - L105 timeCurveBuyRouterAbi imported from lib/abis - erc20Abi for the USDM allowance approve before buyViaKumbaya call ## Tests cd frontend && npx vitest run src/lib/kumbayaRoutes.test.ts: - 18/18 passing - Resolver-specific suite at L148 has 5 cases covering all 4 logic branches: - L150 onchain zero + env unset -> none - L155 onchain undefined + env unset -> none - L160 onchain zero + env set -> mismatch - L167 onchain set + env unset -> ok - L172 onchain set + env mismatch -> mismatch (case-insensitive) ## Anvil / e2e env mirror scripts/lib/anvil_deploy_dev.sh: - L13 doc on KUMBAYA_BUY_ROUTER - L59 extract from forge log via _yieldomega_extract_k 'TimeCurveBuyRouter (single-tx' - L66 print line in stack output scripts/e2e-anvil.sh: - L53-54 conditional export VITE_KUMBAYA_TIMECURVE_BUY_ROUTER only when KUMBAYA_BUY_ROUTER non-empty (no silent fallback) ## Docs References to issue #66 / buyViaKumbaya in: - docs/integrations/kumbaya.md - docs/testing/invariants-and-business-logic.md - docs/testing/e2e-anvil.md ## Browser-side verification deferred Filed #74 to track the live walkthrough items: ETH single-signature buy, USDM single-signature with approve+buy, WarBow plant flag-through, quote-refresh CTA preservation per #56, fail-closed visual confirmation on mismatched env, two-step fallback when onchain zero. Closing #66 at the source / unit-test / env-mirror level. Live walkthrough proceeds via #74 in a future frontend session.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-27 04:02:15 +00:00
PlasticDigits commented 2026-04-27 07:24:01 +00:00 (Migrated from gitlab.com)

mentioned in issue #83

mentioned in issue #83
PlasticDigits commented 2026-05-04 04:17:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #118

mentioned in issue #118
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#66
No description provided.