Conversation
…d wallet integration - Introduced Dockerfile for Playwright to set up the testing environment. - Created docker-compose configuration for orchestrating services including PostgreSQL and the application. - Added detailed instructions for running Playwright tests locally in RUNNING_LOCALLY.md. - Implemented authentication fixtures to handle wallet session management during tests. - Developed wallet fixture for CIP-0030 wallet injection and interaction with the application. - Added global setup for environment variable validation and context loading. - Implemented helper functions for signing transactions and fetching UTxOs from Blockfrost. - Created a comprehensive ring transfer test suite to validate multi-signature transactions. - Added configuration for Playwright tests including output directories and reporting.
fix: instantiate provider lazily in resolveAdaHandle to prevent crashes in preprod environments feat: persist hasCheckedSession in sessionStorage to avoid redundant session checks and modal displays refactor: make NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET optional for better environment handling fix: ensure BlockfrostProvider is instantiated only with a valid API key
- Updated walletFixture to improve error handling and state management during wallet interactions. - Modified meshSign to correctly handle transaction signing with CIP-30 compliance. - Enhanced ring-transfer tests to include better diagnostics and ensure spendable UTxOs are available before transactions. - Improved new transaction page to handle insufficient funds gracefully. - Updated UTxO selector to reset state on fetch failure. - Added early return in sendDiscordMessage for empty recipient lists. - Configured default network setting in Zustand store based on environment variable. - Introduced stored payment script wallet handling in wallet building logic. - Excluded additional directories from TypeScript compilation.
- Added build arguments for Blockfrost API keys in docker-compose files to ensure consistent client bundle paths. - Updated Dockerfile to handle Blockfrost API keys as environment variables for production builds. - Modified CI workflow to allow insecure cookies for wallet sessions during testing. - Refactored wallet handling in various components to use the new useMeshWallet hook, ensuring compatibility with the latest wallet API. - Enhanced error handling in wallet session management to prevent issues with unconnected wallets.
…and added parallel playwright workers
- Add notification center for handling signature required notifications. - Create email channel for sending notifications via Resend. - Define types for email messages and send results. - Implement event types and notification statuses for email notifications. - Create outbox for managing notification deliveries. - Resolve signature recipients based on notification settings. - Develop email templates for signature required and email verification notifications. - Implement worker to drain notification outbox and send emails. - Create API endpoints for draining notifications and verifying email addresses. - Add TRPC router for managing wallet signer notification settings and sending reminders.
…cess - Update wallet notification settings to utilize connected wallet address for managing notifications. - Improve email verification flow with enhanced error handling and user feedback. - Introduce new utility functions for address normalization and authorization checks. - Refactor notification API to support signer address in queries and mutations. - Update environment configuration for notification link base URL.
…ent generation step
Feature/email notification center
- Updated @playwright/test from ^1.50.0 to 1.60.0 in package.json and package-lock.json. - Removed unnecessary comments and improved code readability in resolve-adahandle.tsx. - Simplified session checking logic in layout.tsx by removing sessionStorage handling. - Cleaned up data-testid attributes in RecipientRow.tsx and index.tsx. - Removed redundant state management in UTxOSelector.tsx. - Removed unused broadcastDone state in transaction-card.tsx. - Enforced required Blockfrost API key in env.js. - Refactored wallet session cookie handling in walletSession.ts. - Removed unused function buildStoredPaymentScriptWallet in common.ts. - Simplified getProvider function to directly return BlockfrostProvider instance.
…and address encoding
… lookupMultisigWallet API
…al/non-critical step failures
…in governance routes
Add Playwright end-to-end testing setup with email notifications
…t summaries and truncation
…uthorize" createUser is a protectedProcedure (it needs a wallet session), but the onboarding effects call it on *connect* — seconds before the user approves the signing prompt. That first attempt always runs unauthenticated and is rejected UNAUTHORIZED, and it never retries once the session cookie is set. The result: useUser() stays null and the connect button is permanently stuck on "Authorize" even though signing succeeded. Returning users with a live 7-day session cookie were unaffected, which is why it slipped through the Mesh 2.0 / preprod merge. Re-run createUser in handleAuthModalAuthorized — after the wallet-session cookie exists — for both regular browser wallets (stake/DRep from the 1.9 IWallet) and the UTXOS smart wallet (stake/DRep from its CIP-30 interface). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(auth): create User after authorization so login isn't stuck on "Authorize"
- Moved metadata fetching and normalization logic to a dedicated module. - Introduced `fetchProposalMetadataWithFallback` to streamline metadata retrieval with fallback options. - Simplified proposal metadata normalization and fallback creation. - Added tests for proposal metadata helpers to ensure functionality and reliability. - Removed redundant code and improved overall code organization for better maintainability.
Feature/email notification center
Landing: new "Connect your AI agent" section at the top of the homepage with the downloadable skill, an animated typing prompt, and copy that makes clear the agent reads/drafts but never signs — keys and signatures stay with the co-signers. Blog: markdown-based SEO blog at /blog with two starter posts (AI-agent skill, Cardano multisig basics). Per-post <head> is server-rendered (title, canonical, og:type=article, Article JSON-LD) by returning a resolved seo via pageProps, which _app renders outside the ssr:false boundary; posts are listed in the sitemap with lastmod. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat: AI-agent landing section + SEO blog
Three governance tools, answering the three questions a treasury actually
asks:
governance_list_ballots the team's internal decision log — how the
signers decided on each proposal, with any
drafted rationale
governance_vote_history what the wallet's DRep actually put on-chain,
newest first, with proposal titles
governance_open_proposals active proposals this wallet has NOT voted on
— the outstanding decisions. Cross-references
live proposals against on-chain vote history;
includeVoted returns the whole active set
annotated with how we voted.
open_proposals degrades rather than fails: if the DRep is unset or Koios is
unreachable it still returns the active set and flags
voteHistoryUnavailable, so a model can say "I could not check" instead of
implying nothing has been voted on.
Two handler changes to support them, both mirroring the pattern already
used for botBallotsUpsert:
- botBallots gains a human branch. It was bot-only and required
ballot:write even to GET; a wallet signer can already read these ballots
through the tRPC router, so the bot gate now sits behind isBotJwt and
humans are authorized by the same signer-or-owner predicate.
- drepInfo gains a wallet-access check. It previously looked up ANY
walletId for ANY authenticated caller, letting anyone map a wallet id to
its DRep credential. Now goes through authorizeProxyReadForV1, the
canonical dual-identity read check. This is a pre-existing hole, fixed
here because this change exposes the endpoint through MCP.
Landing page: the hero now leads with MCP rather than one vendor. It shows
the endpoint and a plain `mcpServers` JSON block that works in any client,
with a per-vendor CLI mentioned only as an aside. Prompts in the demo were
rewritten to match tools we actually expose, including the governance
ones. The setup card is vendor-neutral for the same reason and gained an
anchor the hero links to.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(mcp): governance tools, and a vendor-neutral setup guide
MCP governance tools + vendor-neutral setup guide
The top hero had no MCP entry point at all — connecting an agent was only reachable by scrolling to the developer section. It now sits alongside Connect Wallet and Explore features, in both the signed-in and signed-out states, and it is the one thing a visitor can set up before owning a wallet. Also renames the card's primary button from "Setup guide" to "MCP setup guide", so the label says what it links to. The page scrolls inside `main` rather than the window, so the fragment link was worth checking rather than assuming: clicking it moves 5,100px and lands #connect-mcp at the top of the viewport. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add a "Connect via MCP" button to the hero
…endpoint Agents can now draft a rationale and publish it; submitting the vote and signing remain with the wallet's signers. **Security fix.** POST /api/pinata-storage/put had no authentication at all — anyone on the internet could pin arbitrary content to the project's Pinata account, burn its quota, and leave no record of who did it. It now requires the app's wallet session or a v1 bearer token. Both existing callers (registerDrep, updateDrep) are same-origin in-app fetches that already send the session cookie, so they are unaffected. **New endpoint.** POST /api/v1/ballotRationaleAnchor turns the text already stored in a ballot's rationaleComments into a CIP-100/136 JSON-LD document, pins it, and writes the anchor URL and hash back at the same proposal index. Anchors were previously only settable by hand — pasted in, or round-tripped through the ballot CSV. Authorization matches botBallotsUpsert: bots need ballot:write plus wallet access, humans are gated on the shared signer-or-owner check. **The hashing is the subtle part.** hashDrepAnchor is not a JSON-LD canonicalisation — it is blake2b-256 over JSON.stringify(doc, null, 2). Verified empirically: reordering keys changes the digest, and the digest matches the two-space pretty form, not the minified one. So the bytes pinned must be exactly that form or a verifier fetching the URL and re-hashing gets a different answer than the chain records. serializeRationale is the single place that decides those bytes, and both the pin and the hash read from it. Checked end to end against the real hashDrepAnchor: hash === blake2b256(pinned bytes). Empty optional fields are omitted rather than emitted as empty strings, since every key changes the hash. Extracts the Pinata call into src/lib/server/pinataUpload.ts so the new endpoint pins directly instead of looping back through an HTTP route. The MCP tool `ballot_publish_rationale` (scope ballots:write) is the second and last write tool. mcpTools.test.ts now asserts exactly two writable tools, both non-destructive — widening that list stays a deliberate act. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Publish ballot rationales to IPFS (and close the open pin endpoint)
…ed tool list Three connected changes: users can now see what the tools are, control what each client may do, and audit what it actually did. **Permissions are now enforceable, not just displayed.** The MCP endpoint previously trusted the access token's `scope` claim. Those tokens are self-contained and live an hour, so removing a permission — or revoking a connection outright — did nothing until the token happened to expire, which makes a permissions UI a lie. `resolveMcpCaller` now reads the stored OAuthGrant on every request: a missing grant is a 401, and the token's scopes are *intersected* with the grant's, so a change applies on the very next call and a token can never gain reach it was not issued with. Costs one indexed lookup, on the same path that already does one for bots. The profile card gains per-scope checkboxes and a save action. `updateConnectionScopes` moves the grant and its live refresh tokens in one transaction, so a refresh cannot re-widen what was just narrowed. Emptying a grant is refused: a connection that authenticates but can do nothing reads as broken, and revoking is the honest action. **Tool calls are now recorded.** Every invocation writes an AuditLog row from the single wrapper in `createMcpServer` — tool, client, scope, status, duration — keyed to the wallet it touched, so the per-wallet view is an indexed lookup rather than a scan. Only the walletId is read from the arguments: tool inputs carry user-authored prose (rationales, descriptions) that has no place in an audit row. Writes are fire-and-forget; an audit miss must never break a tool call. **Wallet overview gains an AI client activity card**, listing the clients that used *this* wallet with call counts and failures, expandable to the individual calls. The profile answers "what have I connected"; this answers "what has touched this wallet", which is the question a co-signer asks. **The landing page lists the tools**, grouped by the permission each needs. The list lives in `src/data/mcp-tools.ts` rather than importing the registry, which would drag the API handlers and Mesh WASM into the client bundle; a test asserts the two match name-for-name and scope-for-scope. A second test pins the audit action string the tRPC router hard-codes for the same reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(mcp): permissions management, per-wallet activity, and a published tool list
…iners Three separate overflows on the landing page, all invisible in the built output because an ancestor clipped them instead of scrolling. The MCP card was the worst: a grid item defaults to min-width:auto, so the column refused to shrink below the min-content width of the JSON config block (482px). On a 375px phone that forced the single column to 395px inside a 261px card, and the wrapper's overflow-hidden clipped the heading and body copy clean off — no scrollbar, just missing text. min-w-0 down the chain lets the <pre>, which already had overflow-x-auto, scroll on its own. The two button rows overflowed sideways because a third CTA was added to a nowrap row. The hero's three buttons need 747px in a 673px container below ~780px; the MCP row turns horizontal at sm but its grid column halves at md, so between those breakpoints its buttons ran into the panel alongside. Wrapping self-corrects at every width. The hero also aligns to the top now: its first CTA carries a subtitle, so centring floated the other two. Verified by measuring container spill at 375 / 640 / 768 / 900 / 1024 / 1280: previously 118px (MCP) and 74px (hero), now zero at every width, with both rows still on a single line at desktop. A sweep of the fully mounted page confirms no other element loses content to a clipping ancestor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fix(homepage): stop the CTA rows and MCP card overflowing their containers
…grant The two ballot tools could not be granted by anyone. Clients request exactly the `scope` from the 401 challenge rather than the scopes_supported catalogue, and the challenge named only the two read scopes — so no grant ever covered ballots:write, however the user connected. The comment above CHALLENGE_SCOPES described this failure mode precisely and then omitted the scope anyway, reasoning it should stay "opt-in for a client that asks for it explicitly". No client asks; they follow the challenge. Withholding a scope was never the server's call. The challenge now advertises all three and the consent screen decides, one checkbox per scope, pre-ticked with what the client asked for. /api/oauth/decision intersects the posted selection with the signed request handle, so the body can only narrow the grant, never widen it past what /authorize already validated. An approval that grants nothing is refused rather than recorded: a zero-scope token authenticates and exposes no tools, which reads to a client as a broken server rather than a refusal. A client that sends no scope at all still defaults to wallets:read only. Two scope descriptions were understating themselves, which matters more now they are what the user reads at the moment of deciding: governance:read also exposes the team's internal ballots and DRep vote history, and ballots:write publishes rationale documents publicly and near-permanently to IPFS. Adds oauthDecision.test.ts — the endpoint had no tests, and it is the point where consent becomes a durable grant. Mutation-checked: reverting the narrowing logic fails 4 of the 8. Consent screen verified rendering against a production build: three checkboxes, correct copy, toggle working, and the empty-selection guard confirmed live independently of the session gate.
fix(mcp): make every scope reachable, and let the user pick which to grant
…rnance activity - Added new API endpoint `/api/governance/txGovernance` to fetch governance activities (votes and DRep certificates) per transaction using Koios `tx_info`. - Introduced helper functions in `koios.ts` for making GET and POST requests to Koios API. - Implemented logic to filter and normalize governance certificates and votes. - Joined proposal titles to votes for better context in the response. - Added rate limiting and input validation for the new endpoint. - Created a new hook `useTxGovernanceBadges` to fetch governance badges based on transaction hashes. - Added tests for the new API endpoint to ensure correct behavior and error handling. - Updated existing types and utility functions to support the new governance features.
…dresses into lane cards
Feat/sign off tx visualization
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…nhance SSRF defenses in tests
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.
No description provided.