diff --git a/react/react-siwx-wagmi/.env.test b/react/react-siwx-wagmi/.env.test new file mode 100644 index 0000000..545af0c --- /dev/null +++ b/react/react-siwx-wagmi/.env.test @@ -0,0 +1 @@ +VITE_PROJECT_ID= \ No newline at end of file diff --git a/react/react-siwx-wagmi/.gitignore b/react/react-siwx-wagmi/.gitignore new file mode 100644 index 0000000..0eed27d --- /dev/null +++ b/react/react-siwx-wagmi/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.vercel + +.env \ No newline at end of file diff --git a/react/react-siwx-wagmi/README.md b/react/react-siwx-wagmi/README.md new file mode 100644 index 0000000..3132e21 --- /dev/null +++ b/react/react-siwx-wagmi/README.md @@ -0,0 +1,17 @@ +# Reown AppKit Example using wagmi (Vite + React) + +This is a [Vite](https://vitejs.dev) project together with React. + +## Usage + +1. Go to [Reown Cloud](https://cloud.reown.com) and create a new project. +2. Copy your `Project ID` +3. Rename `.env.example` to `.env` and paste your `Project ID` as the value for `VITE_PROJECT_ID` +4. Run `pnpm install` to install dependencies +5. Run `pnpm run dev` to start the development server + +## Resources + +- [Reown — Docs](https://docs.reown.com) +- [Vite — GitHub](https://github.com/vitejs/vite) +- [Vite — Docs](https://vitejs.dev/guide/) diff --git a/react/react-siwx-wagmi/eslint.config.js b/react/react-siwx-wagmi/eslint.config.js new file mode 100644 index 0000000..092408a --- /dev/null +++ b/react/react-siwx-wagmi/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/react/react-siwx-wagmi/index.html b/react/react-siwx-wagmi/index.html new file mode 100644 index 0000000..c4c4f5f --- /dev/null +++ b/react/react-siwx-wagmi/index.html @@ -0,0 +1,13 @@ + + + + + + + Reown Appkit Example + + +
+ + + diff --git a/react/react-siwx-wagmi/package.json b/react/react-siwx-wagmi/package.json new file mode 100644 index 0000000..4824324 --- /dev/null +++ b/react/react-siwx-wagmi/package.json @@ -0,0 +1,35 @@ +{ + "name": "react-wagmi-appkit", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@reown/appkit": "1.6.4", + "@reown/appkit-adapter-wagmi": "1.6.4", + "@reown/appkit-siwx": "1.6.4", + "@tanstack/react-query": "^5.56.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "viem": "^2.21.53", + "wagmi": "^2.13.3" + }, + "devDependencies": { + "@eslint/js": "^9.9.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^9.9.0", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.9", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "typescript-eslint": "^8.0.1", + "vite": "^5.4.1" + } +} diff --git a/react/react-siwx-wagmi/public/favicon.ico b/react/react-siwx-wagmi/public/favicon.ico new file mode 100644 index 0000000..db58b9a Binary files /dev/null and b/react/react-siwx-wagmi/public/favicon.ico differ diff --git a/react/react-siwx-wagmi/public/reown.svg b/react/react-siwx-wagmi/public/reown.svg new file mode 100644 index 0000000..99353d6 --- /dev/null +++ b/react/react-siwx-wagmi/public/reown.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/react/react-siwx-wagmi/src/App.css b/react/react-siwx-wagmi/src/App.css new file mode 100644 index 0000000..2f2a8d1 --- /dev/null +++ b/react/react-siwx-wagmi/src/App.css @@ -0,0 +1,113 @@ +:root { + --background: #ffffff; + --foreground: #171717; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + color: var(--foreground); + background: var(--background); + font-family: Arial, Helvetica, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +a { + color: inherit; + text-decoration: none; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } +} + +section { + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 16px; + background-color: #f9f9f9; + padding: 13px; + margin: 10px; + width: 90%; + text-align: left; +} + +.pages { + align-items: center; + justify-items: center; + text-align: center; +} + +button { + padding: 10px 15px; + background-color: white; + color: black; + border: 2px solid black; + border-radius: 6px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + margin: 15px; /* Space between buttons */ +} + +button:hover { + background-color: black; + color: white; +} + +button:active { + background-color: #333; /* Dark gray on click */ + color: white; +} + +h1 { + margin: 20px; +} + +h2 { + padding-bottom: 6px; +} + +pre { + white-space: pre-wrap; /* Wrap text */ + word-wrap: break-word; /* Break long words */ + word-break: break-all; +} + + +.link-button { + background-color: black; + color: white; + padding: 5px 10px; + text-decoration: none; + border-radius: 5px; +} + +.link-button:hover { + background-color: #333; /* Darken the background on hover */ +} + +.link-button:hover { + background-color: white; /* Change background to white on hover */ + color: black; /* Change text color to black on hover */ +} + +.advice { + text-align: 'center'; + margin-bottom: 10px; + line-height: 25px; +} \ No newline at end of file diff --git a/react/react-siwx-wagmi/src/App.tsx b/react/react-siwx-wagmi/src/App.tsx new file mode 100644 index 0000000..3efe1cc --- /dev/null +++ b/react/react-siwx-wagmi/src/App.tsx @@ -0,0 +1,89 @@ +import { createAppKit } from '@reown/appkit/react' +import { + DefaultSIWX, + InformalMessenger, + EIP155Verifier, + SolanaVerifier, + LocalStorage +} from '@reown/appkit-siwx' + +import { WagmiProvider } from 'wagmi' +import { useState } from 'react' + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { ActionButtonList } from './components/ActionButtonList' +import { InfoList } from './components/InfoList' +import { projectId, metadata, networks, wagmiAdapter } from './config' + +import "./App.css" + +const queryClient = new QueryClient() + +const generalConfig = { + projectId, + networks, + metadata, + themeMode: 'light' as const, + themeVariables: { + '--w3m-accent': '#000000', + } +} + +// Create modal +createAppKit({ + adapters: [wagmiAdapter], + ...generalConfig, + siwx: new DefaultSIWX({ + messenger: new InformalMessenger({ + domain: 'reown.com', + uri: 'https://reown.com', + getNonce: async () => Math.round(Math.random() * 10000).toString() + }), + verifiers: [new EIP155Verifier(), new SolanaVerifier()], + storage: new LocalStorage({ key: '@appkit/siwx' }) + }), + features: { + analytics: true // Optional - defaults to your Cloud configuration + } +}) + +export function App() { + const [transactionHash, setTransactionHash] = useState<`0x${string}` | undefined>(undefined); + const [signedMsg, setSignedMsg] = useState(''); + const [balance, setBalance] = useState(''); + + const receiveHash = (hash: `0x${string}`) => { + setTransactionHash(hash); // Update the state with the transaction hash + }; + + const receiveSignedMsg = (signedMsg: string) => { + setSignedMsg(signedMsg); // Update the state with the transaction hash + }; + + const receivebalance = (balance: string) => { + setBalance(balance) + } + + + return ( +
+ Reown +

AppKit Wagmi React dApp Example

+ + + + +
+

+ This projectId only works on localhost.
+ Go to Reown Cloud to get your own. +

+
+ +
+
+
+ ) +} + +export default App diff --git a/react/react-siwx-wagmi/src/assets/react.svg b/react/react-siwx-wagmi/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/react/react-siwx-wagmi/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/react-siwx-wagmi/src/components/ActionButtonList.tsx b/react/react-siwx-wagmi/src/components/ActionButtonList.tsx new file mode 100644 index 0000000..b4a5b00 --- /dev/null +++ b/react/react-siwx-wagmi/src/components/ActionButtonList.tsx @@ -0,0 +1,85 @@ +import { useEffect } from 'react'; +import { useDisconnect, useAppKit, useAppKitNetwork, useAppKitAccount } from '@reown/appkit/react' +import { parseGwei, type Address } from 'viem' +import { useEstimateGas, useSendTransaction, useSignMessage, useBalance } from 'wagmi' +import { networks } from '../config' + +// test transaction +const TEST_TX = { + to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" as Address, // vitalik address + value: parseGwei('0.0001') +} + +interface ActionButtonListProps { + sendHash: (hash: `0x${string}` ) => void; + sendSignMsg: (hash: string) => void; + sendBalance: (balance: string) => void; +} + +export const ActionButtonList = ({ sendHash, sendSignMsg, sendBalance }: ActionButtonListProps) => { + const { disconnect } = useDisconnect(); // AppKit hook to disconnect + const { open } = useAppKit(); // AppKit hook to open the modal + const { switchNetwork } = useAppKitNetwork(); // AppKithook to switch network + const { address, isConnected } = useAppKitAccount() // AppKit hook to get the address and check if the user is connected + + const { data: gas } = useEstimateGas({...TEST_TX}); // Wagmi hook to estimate gas + const { data: hash, sendTransaction, } = useSendTransaction(); // Wagmi hook to send a transaction + const { signMessageAsync } = useSignMessage() // Wagmi hook to sign a message + const { refetch } = useBalance({ + address: address as Address + }); // Wagmi hook to get the balance + + + useEffect(() => { + if (hash) { + sendHash(hash); + } + }, [hash]); + + // function to send a tx + const handleSendTx = () => { + try { + sendTransaction({ + ...TEST_TX, + gas // Add the gas to the transaction + }); + } catch (err) { + console.log('Error sending transaction:', err); + } + } + + // function to sing a msg + const handleSignMsg = async () => { + const msg = "Hello Reown AppKit!" // message to sign + const sig = await signMessageAsync({ message: msg, account: address as Address }); + sendSignMsg(sig); + } + + // function to get the balance + const handleGetBalance = async () => { + const balance = await refetch() + sendBalance(balance?.data?.value.toString() + " " + balance?.data?.symbol.toString()) + } + + const handleDisconnect = async () => { + try { + await disconnect(); + } catch (error) { + console.error("Failed to disconnect:", error); + } + }; + + + return ( + isConnected && ( +
+ + + + + + +
+ ) + ) +} diff --git a/react/react-siwx-wagmi/src/components/InfoList.tsx b/react/react-siwx-wagmi/src/components/InfoList.tsx new file mode 100644 index 0000000..f7ed450 --- /dev/null +++ b/react/react-siwx-wagmi/src/components/InfoList.tsx @@ -0,0 +1,98 @@ +import { useEffect } from 'react' +import { + useAppKitState, + useAppKitTheme, + useAppKitEvents, + useAppKitAccount, + useWalletInfo + } from '@reown/appkit/react' +import { useWaitForTransactionReceipt } from 'wagmi' + +interface InfoListProps { + hash: `0x${string}` | undefined; + signedMsg: string; + balance: string; +} + +export const InfoList = ({ hash, signedMsg, balance }: InfoListProps) => { + const kitTheme = useAppKitTheme(); // AppKit hook to get the theme information and theme actions + const state = useAppKitState(); // AppKit hook to get the state + const {address, caipAddress, isConnected, status, embeddedWalletInfo } = useAppKitAccount(); // AppKit hook to get the account information + const events = useAppKitEvents() // AppKit hook to get the events + const { walletInfo } = useWalletInfo() // AppKit hook to get the wallet info + + const { data: receipt } = useWaitForTransactionReceipt({ hash, confirmations: 2, // Wait for at least 2 confirmation + timeout: 300000, // Timeout in milliseconds (5 minutes) + pollingInterval: 1000, }) + + useEffect(() => { + console.log("Events: ", events); + }, [events]); + + useEffect(() => { + console.log("Embedded Wallet Info: ", embeddedWalletInfo); + }, [embeddedWalletInfo]); + + return ( + <> + {balance && ( +
+

Balance: {balance}

+
+ )} + {hash && ( +
+

Sign Tx

+
+                Hash: {hash}
+ Status: {receipt?.status.toString()}
+
+
+ )} + {signedMsg && ( +
+

Sign msg

+
+                signedMsg: {signedMsg}
+
+
+ )} +
+

useAppKit

+
+                Address: {address}
+ caip Address: {caipAddress}
+ Connected: {isConnected.toString()}
+ Status: {status}
+ Account Type: {embeddedWalletInfo?.accountType}
+ {embeddedWalletInfo?.user?.email && (`Email: ${embeddedWalletInfo?.user?.email}\n`)} + {embeddedWalletInfo?.user?.username && (`Username: ${embeddedWalletInfo?.user?.username}\n`)} +
+
+ +
+

Theme

+
+                Theme: {kitTheme.themeMode}
+
+
+ +
+

State

+
+                activeChain: {state.activeChain}
+ loading: {state.loading.toString()}
+ open: {state.open.toString()}
+ selectedNetworkId: {state.selectedNetworkId?.toString()}
+
+
+ +
+

WalletInfo

+
+                Name: {JSON.stringify(walletInfo)}
+
+
+ + ) +} diff --git a/react/react-siwx-wagmi/src/config/index.tsx b/react/react-siwx-wagmi/src/config/index.tsx new file mode 100644 index 0000000..ade3306 --- /dev/null +++ b/react/react-siwx-wagmi/src/config/index.tsx @@ -0,0 +1,31 @@ +import { WagmiAdapter } from '@reown/appkit-adapter-wagmi' +import { mainnet, arbitrum, sepolia } from '@reown/appkit/networks' +import type { AppKitNetwork } from '@reown/appkit/networks' +import { createStorage } from 'wagmi' + +// Get projectId from https://cloud.reown.com +export const projectId = import.meta.env.VITE_PROJECT_ID || "b56e18d47c72ab683b10814fe9495694" // this is a public projectId only to use on localhost + +if (!projectId) { + throw new Error('Project ID is not defined') +} + +export const metadata = { + name: 'AppKit', + description: 'AppKit Example', + url: 'https://reown.com', // origin must match your domain & subdomain + icons: ['https://avatars.githubusercontent.com/u/179229932'] + } + +// for custom networks visit -> https://docs.reown.com/appkit/react/core/custom-networks +export const networks = [mainnet, arbitrum, sepolia] as [AppKitNetwork, ...AppKitNetwork[]] + +//Set up the Wagmi Adapter (Config) +export const wagmiAdapter = new WagmiAdapter({ + projectId, + networks, + ssr: true, + storage: createStorage({ storage: localStorage }) +}) + +export const config = wagmiAdapter.wagmiConfig \ No newline at end of file diff --git a/react/react-siwx-wagmi/src/main.tsx b/react/react-siwx-wagmi/src/main.tsx new file mode 100644 index 0000000..feac8ee --- /dev/null +++ b/react/react-siwx-wagmi/src/main.tsx @@ -0,0 +1,9 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react/react-siwx-wagmi/src/vite-env.d.ts b/react/react-siwx-wagmi/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/react/react-siwx-wagmi/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/react/react-siwx-wagmi/tsconfig.app.json b/react/react-siwx-wagmi/tsconfig.app.json new file mode 100644 index 0000000..f0a2350 --- /dev/null +++ b/react/react-siwx-wagmi/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/react/react-siwx-wagmi/tsconfig.app.tsbuildinfo b/react/react-siwx-wagmi/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000..a9957b8 --- /dev/null +++ b/react/react-siwx-wagmi/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/actionbuttonlist.tsx","./src/components/infolist.tsx","./src/config/index.tsx"],"version":"5.6.2"} \ No newline at end of file diff --git a/react/react-siwx-wagmi/tsconfig.json b/react/react-siwx-wagmi/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/react/react-siwx-wagmi/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react/react-siwx-wagmi/tsconfig.node.json b/react/react-siwx-wagmi/tsconfig.node.json new file mode 100644 index 0000000..0d3d714 --- /dev/null +++ b/react/react-siwx-wagmi/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/react/react-siwx-wagmi/tsconfig.node.tsbuildinfo b/react/react-siwx-wagmi/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000..98ef2f9 --- /dev/null +++ b/react/react-siwx-wagmi/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.2"} \ No newline at end of file diff --git a/react/react-siwx-wagmi/vite.config.ts b/react/react-siwx-wagmi/vite.config.ts new file mode 100644 index 0000000..5a33944 --- /dev/null +++ b/react/react-siwx-wagmi/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +})