feat(uploads): live progress for external-signer flow + wagmi fixes - #66
Merged
Merged
Conversation
5 tasks
…external-signer Builds on top of #65 (direct-path progress wiring) to also drive a live progress bar through the WalletConnect / external-signer flow, plus a small grab-bag of fixes that surfaced during end-to-end Sepolia testing. The three external-signer Tauri commands now spawn the same forwarder PR #65 introduced and pass it into ant-core's new `_with_progress` upstream methods: start_upload → file_prepare_upload_with_progress confirm_upload → finalize_upload_with_progress confirm_upload_merkle → finalize_upload_merkle_with_progress ant-core dep is pinned to the upstream PR's branch (`feat/external-signer-progress-events`) until that lands and a tag ships. Swap the dep back to a tagged `ant-core-vX.Y.Z` once #68 is merged + tagged. External-signer's transfer_id is the opaque `quote-...` string returned by `start_upload`, not the row id. The progress listener gains a `_transferIdToRowId` map, populated as soon as `getUploadQuote` knows the id (BEFORE invoking start_upload, so quote-phase events route from the very first event). The wallet/download paths still use `String(id)` and fall through to the numeric parse — both flows share one listener. - `showsProgressBar` widened to render during `quoting` / `paying` too, not just `uploading`. The bar otherwise vanished during the wallet popup and the bulk of the work on the external-signer path. - `stageDetail()` switched to per-stage percent ("Storing · 67%") instead of fractions ("Storing · 6/9"). Bar = global progress, label = local. - `StatusBadge` gets `max-w-xs truncate` + a `title` tooltip so long failure messages don't blow the table width. - **V2-236** chain auto-switch — `ensureActiveChain()` calls `switchChain` before `writeContract` so the wallet is always on the target chain. Without it, a wallet on Arbitrum One signing for an Arbitrum Sepolia tx blew up with a chain-mismatch error and no clear recovery in the UI. - **V2-231** EIP-1559 fee invariant — override BOTH `maxFeePerGas` and `maxPriorityFeePerGas` explicitly (1 gwei / 0.1 gwei). viem's partial auto-estimation produced an invalid pair on Arbitrum's tiny base fees, surfacing as either a base-fee race or a "User rejected" wrapper around the underlying invariant violation. Three sites (payForQuotes, payForMerkleTree, approve in ensureAllowance). End-to-end on a Sepolia-EVM devnet (`start-devnet-sepolia` from ant-client + MetaMask Mobile via WalletConnect, funded Sepolia wallet): - 9-chunk file, full external-signer flow: quote → MM popup → store - Bar climbs 0→50% during quoting (per-chunk ChunkQuoted), pauses at 50% during the MM popup, climbs 50→100% during storage. - Tx hash confirmed on chain, `External-signer upload finalized` logged - 21/21 vitest pass, cargo check clean against the branch ant-core dep Path-dep to upstream branch will fail any CI that pulls a registry-only ant-core. Hold until #68 lands, then bump the dep to the new tag and unmark draft. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…umn layout Layout changes (pages/files.vue): - Status column moved one to the left in both upload and download tables. - File name cell becomes the wider one: filename on top, progress bar below (only when active). Bar gets a min-w-[8rem] so flex-1 segments don't collapse to invisible widths in narrow rows. - Status cell stacks the badge on top with the stage detail line below it, so badge + sub-text track together visually. Progress bar (components/ProgressLine.vue + new BarSegment.vue + PayDot.vue): - Upload bar is now segmented [quote] · [pay-dot] · [store], conveying the three-phase shape of the external-signer flow at a glance. Wallet-flow and downloads use the same component but the dot stays solid (wallet) or the bar collapses to a single fill (download). - Bar fill is now stage-driven, not status-driven. Wallet-flow JS pre-flips status='uploading' before any quoting starts; the old logic took that literally and rendered the left segment full + dot solid before any work was done. New logic prefers the live `stage` from ant-core's events and uses status only as a "we're past quoting" fallback (paying / complete). - PayDot's empty state uses bg-autonomi-surface (same as the bar tracks) instead of a transparent bordered ring, for tighter visual cohesion. Status label (pages/files.vue + components/StatusBadge.vue): - statusLabel() now consults `stage` when the outer status disagrees with the inner phase. Wallet-flow uploads under stage='quoting' now show "Quoting" instead of "Uploading"; downloads under stage='resolving' show "Resolving datamap" instead of "Downloading". Badge + sub-text stay in sync. - StatusBadge: non-error labels render at natural width with whitespace-nowrap (no truncate, no max-w), so the column auto-sizes tight to its widest live label. Error labels keep `max-w-xs truncate` so a viem stacktrace can't blow the column out. - New badge entries for "Encrypting…" and "Resolving datamap". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…reloads Previously the runtime FileEntry tracked gas_cost (rendered as a small "+ X gas" line under cost in the table) but the persisted UploadHistoryEntry shape didn't carry it. On app reload / Files-page refresh, every completed upload reloaded with cost intact but gas_cost dropped — the second line silently vanished. Adds optional gas_cost?: string | null on both the TS UploadHistoryEntry and the Rust struct (with #[serde(default)] for backwards compat with existing history files). loadHistory() and persistHistory() round-trip the field. Legacy entries written before this change remain valid and just render without the gas line, same as before. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…istory V2-233: each settled (failed / complete / downloaded) row now reveals a hover affordance on the right — `✕` for remove. Wires to the existing `removeEntry()` store action. V2-234: failed upload rows also show a `↻ Retry` button. Reuses `entry.path` so the user doesn't re-pick the file from disk; the new `retryUpload()` store action clears stale per-attempt fields (error, progress, stage*, address, datamap, costs, gas), flips status to `queued_for_upload`, and lets the page scheduler re-run `startRealUpload` (fresh quote + fresh wagmi sign). V2-232: bulk "Clear history" moves out of the Files page header and into Settings as a confirmation-gated action. The per-row × covers the common case of trimming one entry; bulk wipe is one click further away to prevent accidental loss. The new Settings card shows the count of settled entries that would be removed and is disabled when there's nothing to clear. Companion rename surfaced earlier in the session: external-signer's `paying` status now renders as "Awaiting approval" instead of "Paying" — more accurate while wagmi is awaiting the wallet signature, and unambiguous since the wallet flow never enters this state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nic-dorman
force-pushed
the
feat/external-signer-progress-events-gui
branch
from
April 30, 2026 09:39
4ae63ee to
8ed72c2
Compare
Nic-dorman
marked this pull request as ready for review
April 30, 2026 09:41
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
upload-progressTauri-event pipeline feat(uploads/downloads): live progress bar driven by ant-core events #65 introduced for the wallet-flow + downloads.start_upload/confirm_upload/confirm_upload_merkleall spawnspawn_upload_progress_forwarderand pass it into ant-core's_with_progressmethods (now inant-core-v0.2.2).quote-...transfer ids by introducing a_transferIdToRowIdmap in the files store, populated beforestart_uploadis invoked so quote-phase events route from the very first event.showsProgressBarwidening, per-stage percent in label, status badge truncation).What changed
Rust (
src-tauri/src/autonomi_ops.rs)All three spawn
spawn_upload_progress_forwarder(app, upload_id)(already on main from #65) so events route via the same Tauriupload-progresschannel.Frontend
stores/files.ts—_transferIdToRowId: Record<string, number>populated bygetUploadQuote(path, transferRowId?)beforeinvoke('start_upload'). Listener falls back toNumber(transfer_id)so the wallet/download paths (which stringify the row id) keep working unchanged.pages/files.vue—showsProgressBar()now returns true forquoting/payingtoo.stageDetail()returns a per-stage percent ("Storing · 67%") instead of a fraction.components/StatusBadge.vue—max-w-xs truncate+titleso long error messages don't widen the table.utils/payment.ts
ensureActiveChain(wagmiConfig)callsswitchChainbefore eachwriteContractif the wallet's currentchainIddoesn't matchgetActiveChainId(). This is the same chain-mismatch issue reported against the 0.6.7 release ("current chain id 1 does not match target chain id 42161 - Arbitrum One") — surfaces whenever MetaMask is sitting on a different chain than the manifest expects.writeContractsites now pass bothmaxFeePerGas: 1_000_000_000nandmaxPriorityFeePerGas: 100_000_000n. An earlier fix that set only the priority fee tripped EIP-1559'smaxFee >= maxPriorityinvariant on Arbitrum's tiny base fees and surfaced as a generic "User rejected the request" wrapper.Test plan
cargo check --all-targetsclean againstant-core-v0.2.2(just-merged via chore(deps): bump ant-core 0.2.0 -> 0.2.2 #67)cargo clippy --all-targets -- -D warningscleancargo fmt --checkclean