feat: Safe admin integration + V2 audit follow-ups#8
Merged
Conversation
Two small UX wins around the Safe story: Deploy form (packages/webapp/src/pages/Deploy.tsx): - "+ Add my wallet" button (when connected) — appends the EOA to the admins textarea - "+ Add Safe address" toggle — opens an inline input with an Add button that validates checksummed-address before appending - appendAdmin helper handles dedup so the same address can't land twice - Existing "Heads up" hint now links to /docs/safe-admin Removes friction for the recommended pattern (EOA + Safe co-admins from genesis) — users no longer have to copy-paste two addresses. ProxyAdminSafeBanner (packages/webapp/src/components/): - Both EOA banners (mainnet rose + dev amber) now link to /docs/safe-admin via react-router Link - "Safe admin guide" call-to-action is the actionable next step for someone who lands on the warning Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Foundation for routing webapp admin actions through a Safe multisig
when one is whitelisted, instead of forcing users to a CLI.
src/hooks/useSafePropose.ts:
- Builds an AdminOp into a SafeTx via packages/safe-tx (buildSafeTx)
- Signs EIP-712 via wagmi.signTypedData (no private key on the
webapp side — uses the connected wallet's signing UI)
- Posts to Den's STS via api-kit (POST .../multisig-transactions/)
- Returns { propose, isProposing, proposed, error, denUrl, reset }
- Caller passes the target Safe address (typically derived from the
proxy's admins list)
src/hooks/useSafeAdmin.ts:
- Convenience: scans a proxy's admins via useAdmins + useSafeStatuses,
returns the first detected Safe address (or undefined)
- Multi-Safe edge case: takes the first match, picker can come later
src/components/SetFeesPanel.tsx (PoC integration):
- Keeps the existing direct-write buttons for direct EOA admins
- When useSafeAdmin finds a Safe in the admins list, surfaces a second
"Propose via Safe" button per fee field (fixed + percentage)
- Click -> uses ops.v2Admin.setDepositFixedFee / setDepositPercentageFee
to build the AdminOp, then useSafePropose handles the Safe path
- Success state shows the safeTxHash + a link to Den UI for co-signing
Confirm + execute remain in Den UI (per discussion: don't rebuild what
Den does well — Discord/Telegram bots, Tenderly simulations, owner
notifications). The webapp's role is to be the entry point for admin
intents.
Other 5+ admin panels (Withdraw, Admins, UpgradeAuthority, Versions,
ClaimLimits, FundPool, Reclaim) follow the same pattern — refactor
landing in a follow-up commit once this PoC is validated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaces the Safe transaction queue from Den's STS directly inside
the proxy detail page, so an owner doesn't have to context-switch to
discover what's awaiting their signature.
src/hooks/usePendingSafeTxs.ts:
- usePendingSafeTxs(safe): polls Den STS via apiKit.getPendingTxs
- Returns { txs, isLoading, error, refetch }
- Refresh on demand (button) — no aggressive polling, owners typically
refresh after coming back from Den UI
src/components/PendingSafeTxsPanel.tsx:
- Lists each pending tx: nonce + target + confirmations count
- Per-row "Sign in Den" deep link (transactions/tx?safe=int:...&id=
multisig_<safe>_<safeTxHash>) — opens directly the right Safe
detail page in Den
- Top "Open in Den" link to the queue overview
- Empty state and error state both handled cleanly
- Read-only by design — co-sign / execute happen in Den (per the
delegation strategy decided earlier, we don't rebuild Safe's
signing UX)
src/components/AdminsTab.tsx:
- Renders PendingSafeTxsPanel when useSafeAdmin detects a Safe in
the fee admins list — otherwise the panel doesn't appear (no Safe,
no queue to display)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
useSafePropose / usePendingSafeTxs / SetFeesPanel import from @intuition-fee-proxy/safe-tx but the webapp's package.json didn't declare it. Vite couldn't resolve the import at dev start, blocking the page with a 500. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Admins section used <Field> which renders a <label>. Putting <button>s inside a <label> leads to ambiguous interactive behavior on hover/focus — the browser routes interaction events between label children in ways that depend on the form control they're associated with. Replaces <Field> with an equivalent <div>-based block keeping the exact visual layout (label-style heading, hint, action buttons, Safe input row, textarea, callout). No <label>, no propagation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an "intuitionFork" hardhat network entry pointing at http://127.0.0.1:8545 with chainId 1155 — matches what Anvil exposes when forking Intuition mainnet, so contracts deployed through hardhat land on the fork (which inherits all mainnet state, including the Safe at 0xf10D...). Wires: - packages/contracts/hardhat.config.ts: new network entry, uses the well-known LOCAL_DEV_KEY (no PRIVATE_KEY required) - packages/contracts/package.json: deploy:fork script alias - package.json (root): contracts:deploy:fork workspace alias Use case: developer wants to test the Safe-aware webapp paths (propose via Safe, PendingSafeTxsPanel) end-to-end. Workflow: anvil --fork-url https://rpc.intuition.systems --chain-id 1155 bun contracts:deploy:fork # take the printed Factory address, set VITE_FACTORY_ADDRESS in # packages/webapp/.env.local, restart bun webapp:dev # then deploy a proxy from the webapp with the Safe as admin Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous gate restricted the dev override to testnet. With Anvil fork now used to test Safe-aware webapp flows on chainId 1155 (the fork has the real Safe state), the developer needs to point the webapp at a freshly-deployed local Factory on what wagmi resolves as "mainnet". The override only applies when the env var is explicitly set in packages/webapp/.env.local, which is gitignored and absent in the prod build — production behavior is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Side effects of declaring @intuition-fee-proxy/safe-tx as a webapp workspace dep (commit fa80074) and as a bin in safe-tx/package.json (commit 2a1d483). Bun installs the workspace symlink and chmods the bin file to 0755 — committing the artifacts so the working tree is clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The textarea + dual-button pattern made deletion clumsy (find the right line, select, delete). Replaces with a chip-list UX: - Each added admin renders as a rounded pill with truncated address + a × button that removes it - Single input below: paste/type an address, press Enter or click Add - Inline validation: invalid format -> "Invalid address.", duplicate -> "Already added." - "+ my wallet" quick-action only shown when the connected EOA isn't already in the list (auto-hides after first add) Internal state changes from `adminsRaw: string` to `admins: Address[]` — `deploy()` already received an Address[], no shape change at the call site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Bundle of work tracks landed on this branch — see commits + .claude/SAFE_INTEGRATION_PLAN.md for context.