From cab2b949f6e173da373f1f9ed92afe31ff4a1f90 Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:47:08 -0800 Subject: [PATCH] remove resources from 4361 --- README.md | 4 +- frontend/src/App.tsx | 13 +++- frontend/src/components/SessionManager.tsx | 78 ++++++++++++++-------- frontend/vite.config.ts | 23 ++++++- package.json | 1 + src/crypto.ts | 3 - src/session.ts | 26 +------- 7 files changed, 87 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 19663a8..f963c2b 100644 --- a/README.md +++ b/README.md @@ -263,8 +263,8 @@ git clone git@github.com:Uniswap/smallocator.git && cd smallocator # 2. Copy example environment file (modify as needed) cp .env.example .env -# 3. Install dependencies -pnpm install +# 3. Install frontend and backend dependencies +pnpm install:all # 4. Run tests pnpm test diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cd8e088..a6c1257 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,7 +4,7 @@ import { WagmiProvider } from 'wagmi'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { http } from 'wagmi'; import '@rainbow-me/rainbowkit/styles.css'; -import { useState } from 'react'; +import { useState, useMemo } from 'react'; import { WalletConnect } from './components/WalletConnect'; import { SessionManager } from './components/SessionManager'; @@ -19,10 +19,17 @@ const config = getDefaultConfig({ }, }); -const queryClient = new QueryClient(); - function App() { const [hasSession, setHasSession] = useState(false); + + const queryClient = useMemo(() => new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + refetchOnWindowFocus: false, + }, + }, + }), []); return ( diff --git a/frontend/src/components/SessionManager.tsx b/frontend/src/components/SessionManager.tsx index 4e147c7..4699b58 100644 --- a/frontend/src/components/SessionManager.tsx +++ b/frontend/src/components/SessionManager.tsx @@ -1,5 +1,5 @@ import { useAccount, useSignMessage, useChainId } from 'wagmi'; -import { useState, useEffect } from 'react'; +import { useState, useCallback } from 'react'; interface SessionManagerProps { onSessionCreated: () => void; @@ -10,32 +10,36 @@ export function SessionManager({ onSessionCreated }: SessionManagerProps) { const { signMessageAsync } = useSignMessage(); const chainId = useChainId(); const [sessionToken, setSessionToken] = useState(null); + const [isLoading, setIsLoading] = useState(false); - const createSession = async () => { - if (!address || !chainId) return; + const createSession = useCallback(async () => { + if (!address || !chainId || isLoading) { + return; + } + setIsLoading(true); try { // First, get the payload from server - const payloadResponse = await fetch(`/session/${address}`); + const payloadResponse = await fetch(`/session/${chainId}/${address}`); if (!payloadResponse.ok) { throw new Error('Failed to get session payload'); } - const { payload } = await payloadResponse.json(); + const { session } = await payloadResponse.json(); // Format the message according to EIP-4361 const message = [ - `${payload.domain} wants you to sign in with your Ethereum account:`, - payload.address, + `${session.domain} wants you to sign in with your Ethereum account:`, + session.address, '', - payload.statement, + session.statement, '', - `URI: ${payload.uri}`, - `Version: ${payload.version}`, - `Chain ID: ${payload.chainId}`, - `Nonce: ${payload.nonce}`, - `Issued At: ${payload.issuedAt}`, - `Expiration Time: ${payload.expirationTime}`, + `URI: ${session.uri}`, + `Version: ${session.version}`, + `Chain ID: ${session.chainId}`, + `Nonce: ${session.nonce}`, + `Issued At: ${session.issuedAt}`, + `Expiration Time: ${session.expirationTime}`, ].join('\n'); // Get signature from wallet @@ -51,35 +55,55 @@ export function SessionManager({ onSessionCreated }: SessionManagerProps) { }, body: JSON.stringify({ signature, - payload, + payload: { + ...session, + chainId: parseInt(session.chainId.toString(), 10), // Ensure chainId is a number + }, }), }); if (response.ok) { const data = await response.json(); - setSessionToken(data.token); + setSessionToken(data.session.id); onSessionCreated(); } else { - console.error('Failed to create session:', await response.text()); + const errorText = await response.text(); + console.error('Failed to create session:', errorText); } } catch (error) { console.error('Failed to create session:', error); + } finally { + setIsLoading(false); } - }; - - useEffect(() => { - if (isConnected && address && !sessionToken && chainId) { - createSession(); - } - }, [isConnected, address, sessionToken, chainId]); + }, [address, chainId, signMessageAsync, onSessionCreated]); if (!isConnected) { return ( -
-

Please connect your wallet to continue.

+
+

Please connect your wallet to continue.

); } - return null; + if (sessionToken) { + return null; + } + + const canLogin = isConnected && address && chainId && !isLoading; + + return ( +
+ +
+ ); } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 7a23832..25bafe9 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -12,10 +12,29 @@ export default defineConfig(({ mode }) => { plugins: [react()], server: { proxy: { - '/api': { + '/session': { + target: baseUrl, + changeOrigin: true, + }, + '/health': { + target: baseUrl, + changeOrigin: true, + }, + '/compact': { + target: baseUrl, + changeOrigin: true, + }, + '/compacts': { + target: baseUrl, + changeOrigin: true, + }, + '/balance': { + target: baseUrl, + changeOrigin: true, + }, + '/balances': { target: baseUrl, changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ''), }, }, }, diff --git a/package.json b/package.json index 5b25d8c..0af3e6c 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "start": "node dist/index.js", "dev": "tsx watch src/index.ts", "dev:all": "concurrently \"pnpm dev\" \"cd frontend && pnpm dev\"", + "install:all": "pnpm install && cd frontend && pnpm install && cd -", "prebuild": "rm -rf dist && cd frontend && pnpm build", "build": "esbuild src/index.ts --bundle --platform=node --outdir=dist --format=esm --sourcemap --packages=external && cp .env dist/ 2>/dev/null || true && cp -r frontend/dist dist/frontend", "build:all": "pnpm build", diff --git a/src/crypto.ts b/src/crypto.ts index d5652a6..8869d6d 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -187,9 +187,6 @@ export async function generateSignature( `Nonce: ${payload.nonce}`, `Issued At: ${payload.issuedAt}`, `Expiration Time: ${payload.expirationTime}`, - payload.resources - ? `Resources:\n${payload.resources.join('\n')}` - : '', ].join('\n'); // Sign the message using the private key directly diff --git a/src/session.ts b/src/session.ts index 10a6f4f..9fb31b1 100644 --- a/src/session.ts +++ b/src/session.ts @@ -15,7 +15,6 @@ export interface SessionPayload { nonce: string; issuedAt: string; expirationTime: string; - resources?: string[]; } export interface Session { @@ -262,20 +261,6 @@ function isValidPayload(payload: SessionPayload): boolean { throw new Error('Invalid chain ID'); } - // Validate resources URIs if present - if (payload.resources) { - for (const resource of payload.resources) { - if (typeof resource !== 'string') { - throw new Error('Invalid resource type'); - } - try { - new URL(resource); - } catch { - throw new Error('Invalid resource URI'); - } - } - } - return true; } catch (error) { console.error('Payload validation failed:', { @@ -287,7 +272,7 @@ function isValidPayload(payload: SessionPayload): boolean { } function formatMessage(payload: SessionPayload): string { - const lines = [ + return [ `${payload.domain} wants you to sign in with your Ethereum account:`, payload.address, '', @@ -299,12 +284,5 @@ function formatMessage(payload: SessionPayload): string { `Nonce: ${payload.nonce}`, `Issued At: ${payload.issuedAt}`, `Expiration Time: ${payload.expirationTime}`, - ]; - - if (payload.resources?.length) { - lines.push('Resources:'); - lines.push(...payload.resources.map((r) => `- ${r}`)); - } - - return lines.join('\n'); + ].join('\n'); }