npx agentspec-cli install d38fc7c9-de10-49e9-9699-823c444513c3 --file-type cursor-rules→ .cursor/rules/
---
description:
globs:
alwaysApply: false
---
MDC
# :jigsaw: Reown AppKit: Overview
**Reown AppKit** is a free, open-source toolkit to integrate wallet connections and Web3 features in any app. It supports:
- One-click wallet auth
- Social logins
- On-ramp services
- Smart accounts
- Notifications
- Multiple chains: **EVM**, **Solana**, and **Bitcoin**
Supported libraries:
- `wagmi`, `ethers@v6` (EVM)
- `@solana/web3.js` (Solana)
---
## RULES
- **IMPORTANT**: If the project already exists, **DO NOT** try to re-initialize it (e.g., using `create-next-app`). Verify the existing project structure first.
- Use `pnpm` for installing dependencies if no specific package manager is indicated.
- Ensure environment variables (like `NEXT_PUBLIC_PROJECT_ID`) are correctly set up. You might need to create `.env.local` manually due to security restrictions.
- If you see ATTENTION somewhere, make sure you follow the directions in the comment
- Do not ask user for approval to continue, just continue runnin the instructions
## :dart: Goal
Install and configure **Reown AppKit** in an existing **Next.js** app using **Wagmi** and **Ethereum**.
---
## :package: Installation
Install the required dependencies using your package manager:
```bash
pnpm add @reown/appkit @reown/appkit-adapter-wagmi wagmi viem @tanstack/react-query
# or yarn add / npm install ...
```
---
## :deciduous_tree: Environment Setup
1. Create a `.env.local` file in your project root (if it doesn't exist).
2. Add your WalletConnect Cloud Project ID:
```.env.local
NEXT_PUBLIC_PROJECT_ID="YOUR_PROJECT_ID"
```
You can add this to the .env.local now
---
## :gear: Wagmi Adapter Setup
> Create a file `config/index.tsx` (e.g., outside your `app` or `src/app` directory).
```ts
// config/index.tsx
import { cookieStorage, createStorage } from 'wagmi' // Use 'wagmi' directly (Wagmi v2+)
import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { mainnet, arbitrum } from '@reown/appkit/networks'
import type { Chain } from 'viem' // Import Chain type for explicit typing
// Read Project ID from environment variables
export const projectId = process.env.NEXT_PUBLIC_PROJECT_ID
// Ensure Project ID is defined at build time
if (!projectId) {
throw new Error('NEXT_PUBLIC_PROJECT_ID is not defined. Please set it in .env.local')
}
// Define supported networks, explicitly typed as a non-empty array of Chains
export const networks: [Chain, ...Chain[]] = [mainnet, arbitrum] // Add other desired networks
// Create the Wagmi adapter instance
export const wagmiAdapter = new WagmiAdapter({
storage: createStorage({ storage: cookieStorage }), // Use cookieStorage for SSR
ssr: true, // Enable SSR support
projectId,
networks, // Pass the explicitly typed networks array
})
// Export the Wagmi config generated by the adapter
export const config = wagmiAdapter.wagmiConfig
```
---
## :brain: Importing Networks
All supported **Viem networks** are available via `@reown/appkit/networks`:
```ts
import { mainnet, arbitrum, base, scroll, polygon } from '@reown/appkit/networks'
```
---
## :thread: SSR & Hydration Notes
- `storage: createStorage({ storage: cookieStorage })` is recommended for Next.js SSR to handle hydration correctly.
- `ssr: true` further aids SSR compatibility.
---
## :bricks: App Context Setup
> Create `context/index.tsx` (must be a Client Component).
```tsx
// context/index.tsx
'use client'
import React, { ReactNode } from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider, cookieToInitialState, type Config } from 'wagmi'
import { createAppKit } from '@reown/appkit/react'
// Import config, networks, projectId, and wagmiAdapter from your config file
import { config, networks, projectId, wagmiAdapter } from '@/config'
// Import the default network separately if needed
import { mainnet } from '@reown/appkit/networks'
const queryClient = new QueryClient()
const metadata = {
name: 'Your App Name',
description: 'Your App Description',
url: typeof window !== 'undefined' ? window.location.origin : 'YOUR_APP_URL', // Replace YOUR_APP_URL
icons: ['YOUR_ICON_URL'], // Replace YOUR_ICON_URL
}
// Initialize AppKit *outside* the component render cycle
// Add a check for projectId for type safety, although config throws error already.
if (!projectId) {
console.error("AppKit Initialization Error: Project ID is missing.");
// Optionally throw an error or render fallback UI
} else {
createAppKit({
adapters: [wagmiAdapter],
// Use non-null assertion `!` as projectId is checked runtime, needed for TypeScript
projectId: projectId!,
// Pass networks directly (type is now correctly inferred from config)
networks: networks,
defaultNetwork: mainnet, // Or your preferred default
metadata,
features: { analytics: true }, // Optional features
})
}
export default function ContextProvider({
children,
cookies,
}: {
children: ReactNode
cookies: string | null // Cookies from server for hydration
}) {
// Calculate initial state for Wagmi SSR hydration
const initialState = cookieToInitialState(config as Config, cookies)
return (
// Cast config as Config for WagmiProvider
<WagmiProvider config={config as Config} initialState={initialState}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</WagmiProvider>
)
}
```
---
## :jigsaw: App Layout Setup
> Modify your root layout file (`app/layout.tsx` or `src/app/layout.tsx`) to use `ContextProvider`.
> **Note:** Verify the exact path to your layout file.
```tsx
// app/layout.tsx or src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google' // Or your preferred font
import './globals.css'
import { headers } from 'next/headers' // Import headers function
import ContextProvider from '@/context' // Adjust import path if needed
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Your App Title',
description: 'Your App Description',
}
// ATTENTION!!! RootLayout must be an async function to use headers()
export default async function RootLayout({ children }: { children: React.ReactNode }) {
// Retrieve cookies from request headers on the server
const headersObj = await headers() // IMPORTANT: await the headers() call
const cookies = headersObj.get('cookie')
return (
<html lang="en">
<body className={inter.className}>
{/* Wrap children with ContextProvider, passing cookies */}
<ContextProvider cookies={cookies}>{children}</ContextProvider>
</body>
</html>
)
}
```
---
## :radio_button: Trigger the AppKit Modal
Use the `<appkit-button>` web component in any client or server component to trigger the wallet modal:
```tsx
// Example usage in app/page.tsx or any component
export default function ConnectPage() {
return (
<div>
<h1>Connect Your Wallet</h1>
<appkit-button />
</div>
)
}
```
No need to import—it's a global web component registered by `createAppKit`.
**Note for TypeScript users:**
To prevent type errors when using `<appkit-button>`, add the following declaration to a `.d.ts` file (e.g., `global.d.ts`) in your project root or `src` directory:
```ts
// global.d.ts
import 'react';
declare global {
namespace JSX {
interface IntrinsicElements {
/**
* The AppKit button web component. Registered globally by AppKit.
*/
'appkit-button': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
}
}
}
// Ensures file is treated as a module
export {};
```
---
## :test_tube: Reading from Smart Contracts (Example)
```ts
// Example component (ensure it's a Client Component: 'use client')
'use client'
import { useReadContract } from 'wagmi'
// import { USDTAbi } from '../abi/USDTAbi' // Replace with your ABI import
// const USDTAddress = '0x...' // Replace with your contract address
function ReadContractExample() {
// const { data, error, isLoading } = useReadContract({
// abi: USDTAbi,
// address: USDTAddress,
// functionName: 'totalSupply',
// })
// if (isLoading) return <div>Loading...</div>
// if (error) return <div>Error reading contract: {error.message}</div>
// return <div>Total Supply: {data?.toString()}</div>
return <div>Contract Reading Example (Code commented out)</div>
}
export default ReadContractExample;
```
---
## :bulb: Additional Rules & Reminders
1. **Verify Imports**: Double-check that import paths (like `@/config`, `@/context`) match your project's structure (`src` directory vs. root `app`/`pages`).
2. **Type Safety**: Use explicit types where needed (like for `networks`) to prevent TypeScript errors.
3. **Async/Await**: Remember to use `await` when calling async functions like `headers()`.
4. **Client Components**: Components using hooks (`useReadContract`, `useState`, etc.) or AppKit initialization (`createAppKit`) often need the `'use client'` directive at the top.wdk
Tether Wallet Development Kit (WDK) for building non-custodial multi-chain wallets. Use when working with @tetherto/wdk-core, wallet modules (wdk-wallet-btc, wdk-wallet-evm, wdk-wallet-evm-erc-4337, wdk-wallet-solana, wdk-wallet-spark, wdk-wallet-ton, wdk-wallet-tron, ton-gasless, tron-gasfree), and protocol modules including swap (wdk-protocol-swap-velora-evm), bridge (wdk-protocol-bridge-usdt0-evm), and lending (wdk-protocol-lending-aave-evm). Covers wallet creation, transactions, token transfers, DEX swa
by AgentHub Crawler
Windsurf Rules for Portfolione Project
This project aims to develop a modern, responsive portfolio management application built on Next.js 14, leveraging the App Router, TypeScript, and shadcn/ui components. The core functionality revolves around enabling users to view and rebalance their cryptocurrency portfolios. Initially, the application will focus on **single-chain operations on Base**, utilizing 1inch Fusion Swap for efficient token exchanges. A key architectural principle is the design of highly composable and modular swap fun
by AgentHub Crawler
Project Instructions
Sign in to leave a comment.
This is a reusable **Next.js App Router starter**. It ships architecture, conventions, and one example per layer as a foundation for new projects.
by AgentHub Crawler