From 32f0edf09d3a107265fd9b8a2f0319cf72c41440 Mon Sep 17 00:00:00 2001 From: sainathr19 Date: Wed, 19 Aug 2026 14:47:27 +0530 Subject: [PATCH] feat: wire create/claim/cancel buttons to the real pool flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "act on this plan" buttons only ever called the devnet demo writer; pool mode just showed a static "not wired yet" message. Wires them to strk20.js's real create/claim/cancel via the Wallet API route from #20. - strk20.js: createPlan/claim/cancel now resolve in_token/out_token internally (one cached view call per contract address) instead of requiring the caller to already know them — matches devnet-writer.js's existing viewCall convention, and lets App.jsx's demo and pool code paths share the same params shape. - App.jsx: buttons are gated on demoMode OR an actually-detected, STRK20-capable wallet (detectPrivacyCapable from #20's wallet-account-v6.js) rather than just "not demo mode" — so the button's enabled state matches what a click would actually do, never promises something that immediately fails. Verified: vite build succeeds, ui test suite still 4/4 (unaffected — touches strk20.js/App.jsx, not iceberg.js). Not verified: an actual live Ready wallet clicking these buttons end to end — still no such environment available here. This is the last piece before the required mainnet transactions can happen through the real UI; needs a human test before relying on it for those. --- ui/src/App.jsx | 67 ++++++++++++++++++++++++++++++++++++------------ ui/src/strk20.js | 28 +++++++++++++++++--- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/ui/src/App.jsx b/ui/src/App.jsx index 7563e1c..5741284 100644 --- a/ui/src/App.jsx +++ b/ui/src/App.jsx @@ -2,6 +2,8 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react" import "./App.css"; import { cancelDemo, claimDemo, createPlanDemo, isDevnetRpc } from "./devnet-writer.js"; import { fetchBatches, fetchPlan, fetchStatus, makeProvider, planCommitment } from "./iceberg.js"; +import { cancel as poolCancel, claim as poolClaim, createPlan as poolCreatePlan } from "./strk20.js"; +import { detectPrivacyCapable } from "./wallet-account-v6.js"; const stored = (key, fallback) => localStorage.getItem(key) ?? fallback; @@ -120,6 +122,30 @@ export default function App() { const [actionResult, setActionResult] = useState(""); const demoMode = isDevnetRpc(rpcUrl); + // Pool mode's write buttons are gated on an actually-connected, STRK20-capable + // wallet rather than just "not demo mode" — same check strk20.js itself makes + // before submitting, so the button state never promises something a click + // would immediately fail on. + const [walletCapable, setWalletCapable] = useState(false); + useEffect(() => { + if (demoMode) { + setWalletCapable(false); + return; + } + let cancelled = false; + detectPrivacyCapable(provider) + .then((capable) => { + if (!cancelled) setWalletCapable(capable); + }) + .catch(() => { + if (!cancelled) setWalletCapable(false); + }); + return () => { + cancelled = true; + }; + }, [provider, demoMode]); + const canAct = demoMode || walletCapable; + const runAction = async (label, action) => { setBusy(true); setActionResult(`${label}…`); @@ -134,21 +160,28 @@ export default function App() { } }; - const onCreate = () => - runAction("create", () => - createPlanDemo({ - rpcUrl, - icebergAddress: address, - chunkAmount: - BigInt(Math.round(Number(chunkInput) * 100)) * 10n ** (BigInt(inDecimals) - 2n), - numChunks: Number(chunksInput), - secret, - }), + const onCreate = () => { + const chunkAmount = + BigInt(Math.round(Number(chunkInput) * 100)) * 10n ** (BigInt(inDecimals) - 2n); + const numChunks = Number(chunksInput); + return runAction("create", () => + demoMode + ? createPlanDemo({ rpcUrl, icebergAddress: address, chunkAmount, numChunks, secret }) + : poolCreatePlan(provider, { icebergAddress: address, chunkAmount, numChunks, secret }), ); + }; const onClaim = () => - runAction("claim", () => claimDemo({ rpcUrl, icebergAddress: address, secret })); + runAction("claim", () => + demoMode + ? claimDemo({ rpcUrl, icebergAddress: address, secret }) + : poolClaim(provider, { icebergAddress: address, secret }), + ); const onCancel = () => - runAction("cancel", () => cancelDemo({ rpcUrl, icebergAddress: address, secret })); + runAction("cancel", () => + demoMode + ? cancelDemo({ rpcUrl, icebergAddress: address, secret }) + : poolCancel(provider, { icebergAddress: address, secret }), + ); const executedChunks = useCallback( (currentPlan) => { @@ -630,7 +663,7 @@ export default function App() {