Add cursor and privy provider
This commit is contained in:
82
.cursor/rules/backend.mdc
Normal file
82
.cursor/rules/backend.mdc
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
description: Guideline for .NET C# backend
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# .NET Development Rules for Quantitative Finance
|
||||||
|
|
||||||
|
You are a senior .NET backend developer and experimental quant with deep expertise in financial mathematics, algorithmic trading, and market indicators.
|
||||||
|
|
||||||
|
## Quantitative Finance Core Principles
|
||||||
|
- Prioritize numerical precision (use `decimal` for monetary calculations)
|
||||||
|
- Implement proven financial mathematics (e.g., Black-Scholes, Monte Carlo methods)
|
||||||
|
- Optimize time-series processing for tick data/OHLCV series
|
||||||
|
- Validate models with historical backtesting frameworks
|
||||||
|
- Maintain audit trails for financial calculations
|
||||||
|
|
||||||
|
## Code Style and Structure
|
||||||
|
- Write concise, idiomatic C# code with accurate examples.
|
||||||
|
- Follow .NET and ASP.NET Core conventions and best practices.
|
||||||
|
- Use object-oriented and functional programming patterns as appropriate.
|
||||||
|
- Prefer LINQ and lambda expressions for collection operations.
|
||||||
|
- Use descriptive variable and method names (e.g., 'IsUserSignedIn', 'CalculateTotal').
|
||||||
|
- Structure files according to .NET conventions (Controllers, Models, Services, etc.).
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
- Use PascalCase for class names, method names, and public members.
|
||||||
|
- Use camelCase for local variables and private fields.
|
||||||
|
- Use UPPERCASE for constants.
|
||||||
|
- Prefix interface names with "I" (e.g., 'IUserService').
|
||||||
|
|
||||||
|
## C# and .NET Usage
|
||||||
|
- Use C# 10+ features when appropriate (e.g., record types, pattern matching, null-coalescing assignment).
|
||||||
|
- Leverage built-in ASP.NET Core features and middleware.
|
||||||
|
- Use Entity Framework Core effectively for database operations.
|
||||||
|
|
||||||
|
## Syntax and Formatting
|
||||||
|
- Follow the C# Coding Conventions (https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions)
|
||||||
|
- Use C#'s expressive syntax (e.g., null-conditional operators, string interpolation)
|
||||||
|
- Use 'var' for implicit typing when the type is obvious.
|
||||||
|
|
||||||
|
## Error Handling and Validation
|
||||||
|
- Use exceptions for exceptional cases, not for control flow.
|
||||||
|
- Implement proper error logging using built-in .NET logging or a third-party logger.
|
||||||
|
- Use Data Annotations or Fluent Validation for model validation.
|
||||||
|
- Implement global exception handling middleware.
|
||||||
|
- Return appropriate HTTP status codes and consistent error responses.
|
||||||
|
|
||||||
|
## API Design
|
||||||
|
- Follow RESTful API design principles.
|
||||||
|
- Use attribute routing in controllers.
|
||||||
|
- Implement versioning for your API.
|
||||||
|
- Use action filters for cross-cutting concerns.
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
- Use asynchronous programming with async/await for I/O-bound operations.
|
||||||
|
- Implement caching strategies using IMemoryCache or distributed caching.
|
||||||
|
- Use efficient LINQ queries and avoid N+1 query problems.
|
||||||
|
- Implement pagination for large data sets.
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
- Use Dependency Injection for loose coupling and testability.
|
||||||
|
- Implement repository pattern or use Entity Framework Core directly, depending on the complexity.
|
||||||
|
- Use AutoMapper for object-to-object mapping if needed.
|
||||||
|
- Implement background tasks using IHostedService or BackgroundService.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
- Write unit tests using xUnit, NUnit, or MSTest.
|
||||||
|
- Use Moq or NSubstitute for mocking dependencies.
|
||||||
|
- Implement integration tests for API endpoints.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
- Use Authentication and Authorization middleware.
|
||||||
|
- Implement JWT authentication for stateless API authentication.
|
||||||
|
- Use HTTPS and enforce SSL.
|
||||||
|
- Implement proper CORS policies.
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
- Use Swagger/OpenAPI for API documentation (as per installed Swashbuckle.AspNetCore package).
|
||||||
|
- Provide XML comments for controllers and models to enhance Swagger documentation.
|
||||||
|
|
||||||
|
Follow the official Microsoft documentation and ASP.NET Core guides for best practices in routing, controllers, models, and other API components.
|
||||||
72
.cursor/rules/frontend.mdc
Normal file
72
.cursor/rules/frontend.mdc
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
description: Guideline for React Vite app frontend
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
|
||||||
|
You are an expert in Solidity, TypeScript, Node.js, Next.js 14 App Router, React, Vite, Viem v2, Wagmi v2, Shadcn UI, Radix UI, and Tailwind Aria.
|
||||||
|
|
||||||
|
Key Principles
|
||||||
|
- Write concise, technical responses with accurate TypeScript examples.
|
||||||
|
- Use functional, declarative programming. Avoid classes.
|
||||||
|
- Prefer iteration and modularization over duplication.
|
||||||
|
- Use descriptive variable names with auxiliary verbs (e.g., isLoading).
|
||||||
|
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
|
||||||
|
- Favor named exports for components.
|
||||||
|
- Use the Receive an Object, Return an Object (RORO) pattern.
|
||||||
|
|
||||||
|
JavaScript/TypeScript
|
||||||
|
- Use "function" keyword for pure functions. Omit semicolons.
|
||||||
|
- Use TypeScript for all code. Prefer interfaces over types. Avoid enums, use maps.
|
||||||
|
- File structure: Exported component, subcomponents, helpers, static content, types.
|
||||||
|
- Avoid unnecessary curly braces in conditional statements.
|
||||||
|
- For single-line statements in conditionals, omit curly braces.
|
||||||
|
- Use concise, one-line syntax for simple conditional statements (e.g., if (condition) doSomething()).
|
||||||
|
|
||||||
|
Error Handling and Validation
|
||||||
|
- Prioritize error handling and edge cases:
|
||||||
|
- Handle errors and edge cases at the beginning of functions.
|
||||||
|
- Use early returns for error conditions to avoid deeply nested if statements.
|
||||||
|
- Place the happy path last in the function for improved readability.
|
||||||
|
- Avoid unnecessary else statements; use if-return pattern instead.
|
||||||
|
- Use guard clauses to handle preconditions and invalid states early.
|
||||||
|
- Implement proper error logging and user-friendly error messages.
|
||||||
|
- Consider using custom error types or error factories for consistent error handling.
|
||||||
|
|
||||||
|
React/Next.js
|
||||||
|
- Use functional components and TypeScript interfaces.
|
||||||
|
- Use declarative JSX.
|
||||||
|
- Use function, not const, for components.
|
||||||
|
- Use Shadcn UI, Radix, and Tailwind Aria for components and styling.
|
||||||
|
- Implement responsive design with Tailwind CSS.
|
||||||
|
- Use mobile-first approach for responsive design.
|
||||||
|
- Place static content and interfaces at file end.
|
||||||
|
- Use content variables for static content outside render functions.
|
||||||
|
- Minimize 'use client', 'useEffect', and 'setState'. Favor RSC.
|
||||||
|
- Use Zod for form validation.
|
||||||
|
- Wrap client components in Suspense with fallback.
|
||||||
|
- Use dynamic loading for non-critical components.
|
||||||
|
- Optimize images: WebP format, size data, lazy loading.
|
||||||
|
- Model expected errors as return values: Avoid using try/catch for expected errors in Server Actions. Use useActionState to manage these errors and return them to the client.
|
||||||
|
- Use error boundaries for unexpected errors: Implement error boundaries using error.tsx and global-error.tsx files to handle unexpected errors and provide a fallback UI.
|
||||||
|
- Use useActionState with react-hook-form for form validation.
|
||||||
|
- Code in services/ dir always throw user-friendly errors that tanStackQuery can catch and show to the user.
|
||||||
|
- Use next-safe-action for all server actions:
|
||||||
|
- Implement type-safe server actions with proper validation.
|
||||||
|
- Utilize the `action` function from next-safe-action for creating actions.
|
||||||
|
- Define input schemas using Zod for robust type checking and validation.
|
||||||
|
- Handle errors gracefully and return appropriate responses.
|
||||||
|
- Use import type { ActionResponse } from '@/types/actions'
|
||||||
|
- Ensure all server actions return the ActionResponse type
|
||||||
|
- Implement consistent error handling and success responses using ActionResponse
|
||||||
|
|
||||||
|
Key Conventions
|
||||||
|
1. Rely on Next.js App Router for state changes.
|
||||||
|
2. Prioritize Web Vitals (LCP, CLS, FID).
|
||||||
|
3. Minimize 'use client' usage:
|
||||||
|
- Prefer server components and Next.js SSR features.
|
||||||
|
- Use 'use client' only for Web API access in small components.
|
||||||
|
- Avoid using 'use client' for data fetching or state management.
|
||||||
|
|
||||||
|
Refer to Next.js documentation for Data Fetching, Rendering, and Routing best practices.
|
||||||
|
|
||||||
141
.cursorban
Normal file
141
.cursorban
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# Prevent sending sensitive configuration files to AI services
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# GENERAL RULES
|
||||||
|
#######################
|
||||||
|
|
||||||
|
# App settings files
|
||||||
|
**/appsettings*.json
|
||||||
|
**/appSettings*.json
|
||||||
|
**/app.settings*.json
|
||||||
|
**/app.config
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
**/.env*
|
||||||
|
**/*.env
|
||||||
|
|
||||||
|
# Key files and certificates
|
||||||
|
**/*.pfx
|
||||||
|
**/*.key
|
||||||
|
**/*.pem
|
||||||
|
**/*.p12
|
||||||
|
**/*.cer
|
||||||
|
**/*.crt
|
||||||
|
|
||||||
|
# Credentials and tokens
|
||||||
|
**/credentials.json
|
||||||
|
**/token.json
|
||||||
|
**/secrets.json
|
||||||
|
**/auth.json
|
||||||
|
|
||||||
|
# Config files that might contain secrets
|
||||||
|
**/connection.json
|
||||||
|
**/database.json
|
||||||
|
**/firebase.json
|
||||||
|
**/aws.json
|
||||||
|
**/azure.json
|
||||||
|
**/google-services.json
|
||||||
|
**/googleservices.json
|
||||||
|
|
||||||
|
# Local development overrides
|
||||||
|
**/local.settings.json
|
||||||
|
**/launchSettings.json
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
**/*.user
|
||||||
|
**/*.pubxml
|
||||||
|
|
||||||
|
# Other potentially sensitive files
|
||||||
|
**/privatekey.json
|
||||||
|
**/private_key.json
|
||||||
|
**/service-account.json
|
||||||
|
**/firebaserc
|
||||||
|
**/firebase-adminsdk.json
|
||||||
|
**/firebase-service-account.json
|
||||||
|
|
||||||
|
# Log files (may contain sensitive info)
|
||||||
|
**/logs/
|
||||||
|
**/*.log
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# BACKEND RULES (.NET)
|
||||||
|
#######################
|
||||||
|
|
||||||
|
# Database migrations and sensitive data models
|
||||||
|
**/Migrations/
|
||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
|
||||||
|
# .NET specific configuration
|
||||||
|
**/Properties/PublishProfiles/
|
||||||
|
**/Properties/ServiceDependencies/
|
||||||
|
**/*.Development.json
|
||||||
|
**/*.Production.json
|
||||||
|
**/*.Staging.json
|
||||||
|
|
||||||
|
# Sensitive backend services
|
||||||
|
**/Services/Auth/
|
||||||
|
**/Services/Payment/
|
||||||
|
**/Infrastructure/Security/
|
||||||
|
**/Infrastructure/Database/Configurations/
|
||||||
|
|
||||||
|
# API keys and connection strings
|
||||||
|
**/Managing.Infrastructure.Database/MongoDb/Configurations/
|
||||||
|
**/Managing.Infrastructure.Messengers/Discord/
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# FRONTEND RULES
|
||||||
|
#######################
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
**/node_modules/
|
||||||
|
**/dist/
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Frontend configuration with sensitive data
|
||||||
|
**/src/config/api.ts
|
||||||
|
**/src/config/auth.ts
|
||||||
|
**/src/config/keys.ts
|
||||||
|
**/src/config/endpoints.ts
|
||||||
|
|
||||||
|
# Authentication related components
|
||||||
|
**/src/services/auth/
|
||||||
|
**/src/hooks/useAuth.ts
|
||||||
|
**/src/stores/authStore.ts
|
||||||
|
|
||||||
|
# Web3 wallet configurations
|
||||||
|
**/src/config/wallet.ts
|
||||||
|
**/src/config/web3.ts
|
||||||
|
**/src/config/chains.ts
|
||||||
|
|
||||||
|
# Large generated files
|
||||||
|
**/src/generated/
|
||||||
|
**/*.generated.ts
|
||||||
|
**/*.graphql.ts
|
||||||
|
|
||||||
|
# Test data with potentially sensitive information
|
||||||
|
**/src/mocks/
|
||||||
|
**/src/__tests__/fixtures/
|
||||||
|
**/cypress/fixtures/
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# PROJECT SPECIFIC
|
||||||
|
#######################
|
||||||
|
|
||||||
|
# Discord bot configuration
|
||||||
|
**/Managing.Infrastructure.Messengers/Discord/DiscordBotConfig.cs
|
||||||
|
|
||||||
|
# Web3 wallet integration
|
||||||
|
**/Managing.Infrastructure.Web3/Wallets/
|
||||||
|
|
||||||
|
# Trading strategies with proprietary algorithms
|
||||||
|
**/Managing.Application/Trading/Strategies/
|
||||||
|
|
||||||
|
# User data and analytics
|
||||||
|
**/Managing.Application/Users/
|
||||||
|
**/Managing.Application/Analytics/
|
||||||
|
|
||||||
|
# Database schemas with sensitive fields
|
||||||
|
**/Managing.Domain/Entities/User.cs
|
||||||
|
**/Managing.Domain/Entities/Wallet.cs
|
||||||
|
**/Managing.Domain/Entities/ApiKey.cs
|
||||||
53
README.md
53
README.md
@@ -148,3 +148,56 @@ Bot types availables :
|
|||||||
| ScalpingBot | This bot will open position and wait before opening a new one |
|
| ScalpingBot | This bot will open position and wait before opening a new one |
|
||||||
| FlippingBot | The flipping bot flipping the position only when a strategy trigger an opposite signal |
|
| FlippingBot | The flipping bot flipping the position only when a strategy trigger an opposite signal |
|
||||||
|
|
||||||
|
## Privy Integration
|
||||||
|
|
||||||
|
This project uses [Privy](https://privy.io/) for wallet authentication and management. Privy provides a seamless authentication experience with support for both embedded wallets and external wallet connections.
|
||||||
|
|
||||||
|
### Supported Networks
|
||||||
|
|
||||||
|
- Ethereum Mainnet
|
||||||
|
- Arbitrum One
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
To use Privy in this project, you need to:
|
||||||
|
|
||||||
|
1. Create a Privy account at [https://console.privy.io/](https://console.privy.io/)
|
||||||
|
2. Create a new app in the Privy dashboard
|
||||||
|
3. Copy your Privy App ID to the `.env` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
VITE_PRIVY_APP_ID=your-privy-app-id
|
||||||
|
```
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **Multi-chain support**: Connect to Ethereum and Arbitrum networks
|
||||||
|
- **Embedded wallets**: Create and manage wallets directly in the browser
|
||||||
|
- **Social login**: Authenticate with email, Google, and other providers
|
||||||
|
- **Seamless integration**: Works with wagmi for blockchain interactions
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
The Privy provider is configured in `src/main.tsx` and can be used throughout the application with the `usePrivy` hook:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { usePrivy } from '@privy-io/react-auth';
|
||||||
|
|
||||||
|
function MyComponent() {
|
||||||
|
const { user, login, logout, authenticated } = usePrivy();
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
return <button onClick={login}>Login</button>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Welcome, {user.email}</p>
|
||||||
|
<button onClick={logout}>Logout</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information, see the [Privy documentation](https://docs.privy.io/).
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Managing.Application.Users;
|
namespace Managing.Application.Users;
|
||||||
|
|
||||||
@@ -10,24 +11,28 @@ public class UserService : IUserService
|
|||||||
private readonly IEvmManager _evmManager;
|
private readonly IEvmManager _evmManager;
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
|
private readonly ILogger<UserService> _logger;
|
||||||
|
|
||||||
private string[] authorizedAddresses = [
|
private string[] authorizedAddresses =
|
||||||
|
[
|
||||||
"0x6781920674dA695aa5120d95D80c4B1788046806", // Macbook
|
"0x6781920674dA695aa5120d95D80c4B1788046806", // Macbook
|
||||||
"0xA2B43AFF0992a47838DF2e6099A8439981f0B717", // Phone
|
"0xA2B43AFF0992a47838DF2e6099A8439981f0B717", // Phone
|
||||||
"0xAD4bcf258852e9d47E580798d312E1a52D59E721", // Razil
|
"0xAD4bcf258852e9d47E580798d312E1a52D59E721", // Razil
|
||||||
"0xAd6D6c80910096b40e45690506a9f1052e072dCB", // Teru
|
"0xAd6D6c80910096b40e45690506a9f1052e072dCB", // Teru
|
||||||
"0x309b9235edbe1C6f840816771c6C21aDa6c275EE", // Cowchain
|
"0x309b9235edbe1C6f840816771c6C21aDa6c275EE", // Cowchain
|
||||||
"0x23AA99254cfaA2c374bE2bA5B55C68018cCdFCb3" // Local optiflex
|
"0x23AA99254cfaA2c374bE2bA5B55C68018cCdFCb3", // Local optiflex
|
||||||
|
"0x932167388dD9aad41149b3cA23eBD489E2E2DD78" // Embedded wallet
|
||||||
];
|
];
|
||||||
|
|
||||||
public UserService(
|
public UserService(
|
||||||
IEvmManager evmManager,
|
IEvmManager evmManager,
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
IAccountService accountService)
|
IAccountService accountService, ILogger<UserService> logger)
|
||||||
{
|
{
|
||||||
_evmManager = evmManager;
|
_evmManager = evmManager;
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> Authenticate(string name, string address, string message, string signature)
|
public async Task<User> Authenticate(string name, string address, string message, string signature)
|
||||||
@@ -35,10 +40,16 @@ public class UserService : IUserService
|
|||||||
var recoveredAddress = _evmManager.VerifySignature(signature, message);
|
var recoveredAddress = _evmManager.VerifySignature(signature, message);
|
||||||
|
|
||||||
if (!authorizedAddresses.Contains(recoveredAddress))
|
if (!authorizedAddresses.Contains(recoveredAddress))
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Address {recoveredAddress} not authorized");
|
||||||
throw new Exception("Address not authorized");
|
throw new Exception("Address not authorized");
|
||||||
|
}
|
||||||
|
|
||||||
if (recoveredAddress == null || !recoveredAddress.Equals(address))
|
if (recoveredAddress == null || !recoveredAddress.Equals(address))
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Address {recoveredAddress} not corresponding");
|
||||||
throw new Exception("Address not corresponding");
|
throw new Exception("Address not corresponding");
|
||||||
|
}
|
||||||
|
|
||||||
// Check if account exist
|
// Check if account exist
|
||||||
var account = await _accountService.GetAccountByKey(recoveredAddress, true, false);
|
var account = await _accountService.GetAccountByKey(recoveredAddress, true, false);
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ VITE_WORKER_URL_LOCAL=https://localhost:5002
|
|||||||
VITE_WORKER_URL_SERVER=https://dev-managing-worker.apps.managing.live
|
VITE_WORKER_URL_SERVER=https://dev-managing-worker.apps.managing.live
|
||||||
ALCHEMY_ID=Bao7OirVe4bmYiDbPh0l8cs5gYb5D4_9
|
ALCHEMY_ID=Bao7OirVe4bmYiDbPh0l8cs5gYb5D4_9
|
||||||
WALLET_CONNECT_PROJECT_ID=363bf09c10fec2293b21ee199b2ce8d5
|
WALLET_CONNECT_PROJECT_ID=363bf09c10fec2293b21ee199b2ce8d5
|
||||||
|
VITE_PRIVY_APP_ID=cm7u09v0u002zrkuf2yjjr58p
|
||||||
|
|||||||
@@ -18,11 +18,15 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@microsoft/signalr": "^6.0.5",
|
"@microsoft/signalr": "^6.0.5",
|
||||||
"@tanstack/react-query": "^5.36.1",
|
"@privy-io/react-auth": "^2.6.1",
|
||||||
|
"@privy-io/wagmi": "^1.0.3",
|
||||||
|
"@tailwindcss/typography": "^0.5.0",
|
||||||
|
"@tanstack/react-query": "^5.67.1",
|
||||||
"@wagmi/chains": "^0.2.9",
|
"@wagmi/chains": "^0.2.9",
|
||||||
"@wagmi/connectors": "^5.7.3",
|
"@wagmi/connectors": "^5.7.3",
|
||||||
"@wagmi/core": "^2.16.3",
|
"@wagmi/core": "^2.16.3",
|
||||||
"@walletconnect/universal-provider": "^2.8.6",
|
"@walletconnect/universal-provider": "^2.8.6",
|
||||||
|
"autoprefixer": "^10.4.7",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"connectkit": "^1.8.2",
|
"connectkit": "^1.8.2",
|
||||||
@@ -32,6 +36,7 @@
|
|||||||
"lightweight-charts": "git+https://github.com/ntf/lightweight-charts.git",
|
"lightweight-charts": "git+https://github.com/ntf/lightweight-charts.git",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.3",
|
||||||
"plotly.js": "^2.18.1",
|
"plotly.js": "^2.18.1",
|
||||||
|
"postcss": "^8.4.13",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-cookie": "^4.1.1",
|
"react-cookie": "^4.1.1",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
@@ -46,14 +51,11 @@
|
|||||||
"react-table": "^7.8.0",
|
"react-table": "^7.8.0",
|
||||||
"react-toastify": "^9.0.1",
|
"react-toastify": "^9.0.1",
|
||||||
"reactflow": "^11.8.3",
|
"reactflow": "^11.8.3",
|
||||||
|
"tailwindcss": "^3.0.23",
|
||||||
"viem": "2.x",
|
"viem": "2.x",
|
||||||
"wagmi": "^2.14.9",
|
"wagmi": "^2.14.12",
|
||||||
"web3": "^4.16.0",
|
"web3": "^4.16.0",
|
||||||
"zustand": "^4.4.1",
|
"zustand": "^4.4.1"
|
||||||
"postcss": "^8.4.13",
|
|
||||||
"autoprefixer": "^10.4.7",
|
|
||||||
"@tailwindcss/typography": "^0.5.0",
|
|
||||||
"tailwindcss": "^3.0.23"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.9",
|
"@types/react": "^18.0.9",
|
||||||
|
|||||||
95
src/Managing.WebApp/src/components/WalletInfo.tsx
Normal file
95
src/Managing.WebApp/src/components/WalletInfo.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import { usePrivy } from '@privy-io/react-auth'
|
||||||
|
import { useAccount, useBalance, useChainId, useSwitchChain } from 'wagmi'
|
||||||
|
import { arbitrum, mainnet } from 'viem/chains'
|
||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to display wallet information and test the Privy integration
|
||||||
|
*/
|
||||||
|
export const WalletInfo = () => {
|
||||||
|
const { user, ready, authenticated, login, logout } = usePrivy()
|
||||||
|
const { address, isConnected } = useAccount()
|
||||||
|
const chainId = useChainId()
|
||||||
|
const { data: balance } = useBalance({
|
||||||
|
address,
|
||||||
|
})
|
||||||
|
const { switchChainAsync } = useSwitchChain()
|
||||||
|
|
||||||
|
const switchToEthereum = useCallback(async () => {
|
||||||
|
if (chainId !== mainnet.id) {
|
||||||
|
try {
|
||||||
|
await switchChainAsync({ chainId: mainnet.id })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to switch to Ethereum:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [chainId, switchChainAsync])
|
||||||
|
|
||||||
|
const switchToArbitrum = useCallback(async () => {
|
||||||
|
if (chainId !== arbitrum.id) {
|
||||||
|
try {
|
||||||
|
await switchChainAsync({ chainId: arbitrum.id })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to switch to Arbitrum:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [chainId, switchChainAsync])
|
||||||
|
|
||||||
|
if (!ready) {
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
return (
|
||||||
|
<div className="p-4 border rounded-lg shadow-sm">
|
||||||
|
<h2 className="text-xl font-bold mb-4">Wallet Connection</h2>
|
||||||
|
<p className="mb-4">Please connect your wallet to continue.</p>
|
||||||
|
<button
|
||||||
|
onClick={login}
|
||||||
|
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||||
|
>
|
||||||
|
Connect Wallet
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4 border rounded-lg shadow-sm">
|
||||||
|
<h2 className="text-xl font-bold mb-4">Wallet Information</h2>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<p><strong>Connected:</strong> {isConnected ? 'Yes' : 'No'}</p>
|
||||||
|
<p><strong>Address:</strong> {address ? address : 'Not connected'}</p>
|
||||||
|
<p><strong>Chain:</strong> {chainId === mainnet.id ? 'Ethereum' : chainId === arbitrum.id ? 'Arbitrum' : chainId}</p>
|
||||||
|
<p><strong>Balance:</strong> {balance ? `${balance.formatted} ${balance.symbol}` : 'Unknown'}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex space-x-2 mb-4">
|
||||||
|
<button
|
||||||
|
onClick={switchToEthereum}
|
||||||
|
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||||
|
disabled={chainId === mainnet.id}
|
||||||
|
>
|
||||||
|
Switch to Ethereum
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={switchToArbitrum}
|
||||||
|
className="px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600"
|
||||||
|
disabled={chainId === arbitrum.id}
|
||||||
|
>
|
||||||
|
Switch to Arbitrum
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={logout}
|
||||||
|
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
|
||||||
|
>
|
||||||
|
Disconnect
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WalletInfo
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { StatusOfflineIcon } from '@heroicons/react/solid'
|
import { StatusOfflineIcon } from '@heroicons/react/solid'
|
||||||
import type { SubmitHandler } from 'react-hook-form'
|
import type { SubmitHandler } from 'react-hook-form'
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { useAccount, useDisconnect, useSignMessage } from 'wagmi'
|
import { usePrivy, useSignMessage } from '@privy-io/react-auth'
|
||||||
|
|
||||||
import useApiUrlStore from '../../../app/store/apiStore'
|
import useApiUrlStore from '../../../app/store/apiStore'
|
||||||
import { UserClient } from '../../../generated/ManagingApi'
|
import { UserClient } from '../../../generated/ManagingApi'
|
||||||
@@ -13,38 +13,66 @@ import Toast from '../Toast/Toast'
|
|||||||
const LogIn = () => {
|
const LogIn = () => {
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
const { register, handleSubmit } = useForm<ILoginFormInput>()
|
const { register, handleSubmit } = useForm<ILoginFormInput>()
|
||||||
const { disconnect } = useDisconnect()
|
const { user, logout, ready, authenticated } = usePrivy()
|
||||||
const { address } = useAccount()
|
const { signMessage } = useSignMessage()
|
||||||
const { signMessageAsync } = useSignMessage({})
|
|
||||||
const { setCookie } = useCookie()
|
const { setCookie } = useCookie()
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<ILoginFormInput> = async (form) => {
|
const onSubmit: SubmitHandler<ILoginFormInput> = async (form) => {
|
||||||
const message = 'wagmi'
|
if (!authenticated || !user || !user.wallet?.address) {
|
||||||
const signature = await signMessageAsync({ message })
|
const t = new Toast('Error: Not authenticated')
|
||||||
const t = new Toast('Creating token')
|
t.update('error', 'Please connect your wallet first')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (signature && address) {
|
try {
|
||||||
|
const message = 'wagmi'
|
||||||
|
const t = new Toast('Signing message...')
|
||||||
|
|
||||||
|
// Use Privy's signMessage function - returns { signature: string }
|
||||||
|
const { signature } = await signMessage({ message })
|
||||||
|
|
||||||
|
t.update('info', 'Creating token...')
|
||||||
|
|
||||||
|
// Use the Privy embedded wallet address
|
||||||
|
const walletAddress = user.linkedAccounts[1]?.address
|
||||||
|
|
||||||
|
if (signature && walletAddress) {
|
||||||
const userClient = new UserClient({}, apiUrl)
|
const userClient = new UserClient({}, apiUrl)
|
||||||
|
|
||||||
await userClient
|
await userClient
|
||||||
.user_CreateToken({
|
.user_CreateToken({
|
||||||
address: address.toString(),
|
address: walletAddress,
|
||||||
message: message,
|
message: message,
|
||||||
name: form.name,
|
name: form.name,
|
||||||
signature: signature,
|
signature: signature,
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setCookie('token', data, 1)
|
setCookie('token', data, 1)
|
||||||
|
t.update('success', 'Login successful!')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
location.assign("/");
|
location.assign("/");
|
||||||
}, 1000);
|
}, 1000);
|
||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
t.update('error', 'Error : Some thing bad happen')
|
console.error('Login error:', err)
|
||||||
|
t.update('error', 'Error: Something went wrong')
|
||||||
})
|
})
|
||||||
}else{
|
} else {
|
||||||
t.update('error', 'Error : No signature')
|
t.update('error', 'Error: No signature or address')
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Signing error:', error)
|
||||||
|
const t = new Toast('Error')
|
||||||
|
t.update('error', `Error signing message: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ready) {
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
return <div>Please connect your wallet first</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -87,7 +115,8 @@ const LogIn = () => {
|
|||||||
Sign and login
|
Sign and login
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => disconnect}
|
onClick={() => logout()}
|
||||||
|
type="button"
|
||||||
className="btn bg-primary w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
|
className="btn bg-primary w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
|
||||||
>
|
>
|
||||||
Disconnect wallet{' '}
|
Disconnect wallet{' '}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useIsFetching } from '@tanstack/react-query'
|
import { useIsFetching } from '@tanstack/react-query'
|
||||||
import { ConnectKitButton } from 'connectkit'
|
import { usePrivy } from '@privy-io/react-auth'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
@@ -44,6 +44,38 @@ const GlobalLoader = () => {
|
|||||||
return isFetching ? <Loader size="xs"></Loader> : null
|
return isFetching ? <Loader size="xs"></Loader> : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom Privy wallet button component
|
||||||
|
const PrivyWalletButton = () => {
|
||||||
|
const { login, logout, authenticated, user } = usePrivy()
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={login}
|
||||||
|
className="btn btn-primary btn-sm"
|
||||||
|
>
|
||||||
|
Connect Wallet
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display wallet address or user info if authenticated
|
||||||
|
const displayAddress = user?.wallet?.address
|
||||||
|
? `${user.wallet.address.slice(0, 6)}...${user.wallet.address.slice(-4)}`
|
||||||
|
: 'Connected'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dropdown dropdown-end">
|
||||||
|
<label tabIndex={0} className="btn btn-primary btn-sm">
|
||||||
|
{displayAddress}
|
||||||
|
</label>
|
||||||
|
<ul tabIndex={0} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52">
|
||||||
|
<li><a onClick={logout}>Disconnect</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function SecondaryNavbar() {
|
export function SecondaryNavbar() {
|
||||||
const { toggleApiUrl, isProd } = useApiUrlStore()
|
const { toggleApiUrl, isProd } = useApiUrlStore()
|
||||||
|
|
||||||
@@ -61,7 +93,7 @@ export function SecondaryNavbar() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<ConnectKitButton />
|
<PrivyWalletButton />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/Managing.WebApp/src/config/privy.ts
Normal file
19
src/Managing.WebApp/src/config/privy.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { arbitrum, mainnet } from 'viem/chains'
|
||||||
|
import { createConfig } from '@privy-io/wagmi'
|
||||||
|
import { http } from 'wagmi'
|
||||||
|
|
||||||
|
// Define the Privy App ID - this should be added to your .env file
|
||||||
|
const PRIVY_APP_ID = import.meta.env.VITE_PRIVY_APP_ID || 'your-privy-app-id'
|
||||||
|
|
||||||
|
// Create the Privy Wagmi config with Ethereum and Arbitrum chains
|
||||||
|
export const privyWagmiConfig = createConfig({
|
||||||
|
chains: [mainnet, arbitrum],
|
||||||
|
transports: {
|
||||||
|
// You can customize RPC providers here if needed
|
||||||
|
[mainnet.id]: http(`https://ethereum.publicnode.com`),
|
||||||
|
[arbitrum.id]: http(`https://arbitrum-one.publicnode.com`),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Export the supported chains for use elsewhere in the app
|
||||||
|
export const supportedChains = [mainnet, arbitrum]
|
||||||
65
src/Managing.WebApp/src/hooks/usePrivyWallet.ts
Normal file
65
src/Managing.WebApp/src/hooks/usePrivyWallet.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { usePrivy } from '@privy-io/react-auth'
|
||||||
|
import { useAccount, useConnect, useDisconnect } from 'wagmi'
|
||||||
|
import { useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook to integrate Privy wallet with wagmi
|
||||||
|
* This hook handles connecting and disconnecting the Privy wallet
|
||||||
|
* and provides a simplified interface for wallet interactions
|
||||||
|
*/
|
||||||
|
export const usePrivyWallet = () => {
|
||||||
|
const { user, ready, authenticated, login, logout } = usePrivy()
|
||||||
|
const { isConnected } = useAccount()
|
||||||
|
const { connectAsync, connectors } = useConnect()
|
||||||
|
const { disconnectAsync } = useDisconnect()
|
||||||
|
|
||||||
|
// Connect the wallet when the user is authenticated
|
||||||
|
useEffect(() => {
|
||||||
|
const connectWallet = async () => {
|
||||||
|
if (ready && authenticated && user && !isConnected) {
|
||||||
|
try {
|
||||||
|
// Get the embedded wallet if available
|
||||||
|
const embeddedWallet = user.wallet?.address ? user.wallet : null
|
||||||
|
|
||||||
|
if (embeddedWallet && connectors.length > 0) {
|
||||||
|
// Connect using the Privy connector
|
||||||
|
// The Privy connector is automatically added by the Privy WagmiProvider
|
||||||
|
const privyConnector = connectors.find(c => c.name === 'Privy') || connectors[0]
|
||||||
|
|
||||||
|
await connectAsync({
|
||||||
|
connector: privyConnector,
|
||||||
|
chainId: 1 // Default to Ethereum mainnet
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to connect wallet:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectWallet()
|
||||||
|
}, [ready, authenticated, user, isConnected, connectAsync, connectors])
|
||||||
|
|
||||||
|
// Disconnect the wallet when the user logs out
|
||||||
|
const handleLogout = useCallback(async () => {
|
||||||
|
if (isConnected) {
|
||||||
|
try {
|
||||||
|
await disconnectAsync()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to disconnect wallet:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logout()
|
||||||
|
}, [isConnected, disconnectAsync, logout])
|
||||||
|
|
||||||
|
return {
|
||||||
|
isAuthenticated: authenticated,
|
||||||
|
isConnected,
|
||||||
|
isReady: ready,
|
||||||
|
user,
|
||||||
|
login,
|
||||||
|
logout: handleLogout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default usePrivyWallet
|
||||||
@@ -1,35 +1,47 @@
|
|||||||
import './styles/globals.css'
|
import './styles/globals.css'
|
||||||
|
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { ConnectKitProvider, getDefaultConfig } from 'connectkit'
|
import { PrivyProvider } from '@privy-io/react-auth'
|
||||||
|
import { WagmiProvider } from '@privy-io/wagmi'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { WagmiConfig, createConfig } from 'wagmi'
|
|
||||||
|
|
||||||
import App from './app'
|
import App from './app'
|
||||||
|
import { privyWagmiConfig, supportedChains } from './config/privy'
|
||||||
|
|
||||||
import 'react-grid-layout/css/styles.css'
|
import 'react-grid-layout/css/styles.css'
|
||||||
import 'react-resizable/css/styles.css'
|
import 'react-resizable/css/styles.css'
|
||||||
import 'react-toastify/dist/ReactToastify.css'
|
import 'react-toastify/dist/ReactToastify.css'
|
||||||
import { ToastContainer } from 'react-toastify'
|
import { ToastContainer } from 'react-toastify'
|
||||||
|
|
||||||
const config = createConfig(
|
|
||||||
getDefaultConfig({
|
|
||||||
alchemyId: import.meta.env.VITE_ALCHEMY_ID,
|
|
||||||
appName: 'Managing App',
|
|
||||||
walletConnectProjectId: import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const element = document.getElementById('root') as HTMLElement
|
const element = document.getElementById('root') as HTMLElement
|
||||||
|
|
||||||
const root = createRoot(element)
|
const root = createRoot(element)
|
||||||
const queryClient = new QueryClient()
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
|
// Configure Privy login methods and appearance
|
||||||
|
const privyConfig = {
|
||||||
|
appearance: {
|
||||||
|
theme: 'light' as const,
|
||||||
|
accentColor: '#3B82F6' as `#${string}`, // Customize this to match your app's theme
|
||||||
|
logo: <img src="/src/assets/logo.svg" alt="logo" />,
|
||||||
|
},
|
||||||
|
loginMethods: ['wallet', 'email', 'google'] as Array<'wallet' | 'email' | 'google'>,
|
||||||
|
embeddedWallets: {
|
||||||
|
ethereum: {
|
||||||
|
createOnLogin: 'all-users' as const
|
||||||
|
},
|
||||||
|
noPromptOnSignature: false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<WagmiConfig config={config}>
|
<PrivyProvider
|
||||||
<ConnectKitProvider theme="auto">
|
appId={import.meta.env.VITE_PRIVY_APP_ID}
|
||||||
|
config={privyConfig}
|
||||||
|
>
|
||||||
|
<WagmiProvider config={privyWagmiConfig}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<App />
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
@@ -44,7 +56,7 @@ root.render(
|
|||||||
pauseOnHover
|
pauseOnHover
|
||||||
/>
|
/>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</ConnectKitProvider>
|
</WagmiProvider>
|
||||||
</WagmiConfig>
|
</PrivyProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,37 +1,50 @@
|
|||||||
import { ConnectKitButton } from 'connectkit'
|
import { usePrivy } from '@privy-io/react-auth'
|
||||||
import { useAccount } from 'wagmi'
|
import { useAccount } from 'wagmi'
|
||||||
|
|
||||||
import LogIn from '../../components/mollecules/LogIn/LogIn'
|
import LogIn from '../../components/mollecules/LogIn/LogIn'
|
||||||
import useCookie from '../../hooks/useCookie'
|
import useCookie from '../../hooks/useCookie'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
|
||||||
export const Auth = ({ children }: any) => {
|
export const Auth = ({ children }: any) => {
|
||||||
const { getCookie, deleteCookie } = useCookie()
|
const { getCookie, deleteCookie } = useCookie()
|
||||||
const { isConnected } = useAccount()
|
const { isConnected } = useAccount()
|
||||||
|
const { login, ready, authenticated, user } = usePrivy()
|
||||||
const token = getCookie('token')
|
const token = getCookie('token')
|
||||||
console.log('token', token)
|
|
||||||
console.log('isConnected', isConnected)
|
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (ready) {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, 2000); // Adjust the timeout duration as needed
|
}, 1000);
|
||||||
|
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}, []);
|
}
|
||||||
|
}, [ready]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (!ready || isLoading) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!authenticated) {
|
||||||
deleteCookie('token')
|
deleteCookie('token')
|
||||||
return (
|
return (
|
||||||
<div style={{ ...styles }}>
|
<div style={{ ...styles }}>
|
||||||
<ConnectKitButton />
|
<button
|
||||||
|
onClick={login}
|
||||||
|
style={{
|
||||||
|
padding: '10px 20px',
|
||||||
|
backgroundColor: '#3B82F6',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login with Privy
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
} else if (!token) {
|
} else if (!token) {
|
||||||
@@ -41,7 +54,6 @@ export const Auth = ({ children }: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|||||||
Reference in New Issue
Block a user