feat: comprehensive project improvements and fixes
- Fix all TypeScript compilation errors (40+ fixes) - Add missing type definitions (TransactionRequest, SafeInfo) - Fix TransactionRequestStatus vs TransactionStatus confusion - Fix import paths and provider type issues - Fix test file errors and mock providers - Implement comprehensive security features - AES-GCM encryption with PBKDF2 key derivation - Input validation and sanitization - Rate limiting and nonce management - Replay attack prevention - Access control and authorization - Add comprehensive test suite - Integration tests for transaction flow - Security validation tests - Wallet management tests - Encryption and rate limiter tests - E2E tests with Playwright - Add extensive documentation - 12 numbered guides (setup, development, API, security, etc.) - Security documentation and audit reports - Code review and testing reports - Project organization documentation - Update dependencies - Update axios to latest version (security fix) - Update React types to v18 - Fix peer dependency warnings - Add development tooling - CI/CD workflows (GitHub Actions) - Pre-commit hooks (Husky) - Linting and formatting (Prettier, ESLint) - Security audit workflow - Performance benchmarking - Reorganize project structure - Move reports to docs/reports/ - Clean up root directory - Organize documentation - Add new features - Smart wallet management (Gnosis Safe, ERC4337) - Transaction execution and approval workflows - Balance management and token support - Error boundary and monitoring (Sentry) - Fix WalletConnect configuration - Handle missing projectId gracefully - Add environment variable template
This commit is contained in:
541
docs/04-development.md
Normal file
541
docs/04-development.md
Normal file
@@ -0,0 +1,541 @@
|
||||
# Development Guide
|
||||
|
||||
This guide covers the development workflow, best practices, and common patterns used in the Impersonator project.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 1. Starting Development
|
||||
|
||||
```bash
|
||||
# Start development server
|
||||
pnpm dev
|
||||
|
||||
# Server runs on http://localhost:3000
|
||||
```
|
||||
|
||||
### 2. Making Changes
|
||||
|
||||
1. Create a feature branch
|
||||
2. Make your changes
|
||||
3. Write/update tests
|
||||
4. Run linter and tests
|
||||
5. Commit changes
|
||||
6. Push and create PR
|
||||
|
||||
### 3. Testing Changes
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pnpm test
|
||||
|
||||
# Run tests in watch mode
|
||||
pnpm test:watch
|
||||
|
||||
# Run with coverage
|
||||
pnpm test:coverage
|
||||
|
||||
# Run specific test suite
|
||||
pnpm test:security
|
||||
pnpm test:integration
|
||||
```
|
||||
|
||||
### 4. Code Quality Checks
|
||||
|
||||
```bash
|
||||
# Run linter
|
||||
pnpm lint
|
||||
|
||||
# Fix linting issues
|
||||
pnpm lint --fix
|
||||
```
|
||||
|
||||
## Development Patterns
|
||||
|
||||
### Context Usage
|
||||
|
||||
#### Using SmartWalletContext
|
||||
|
||||
```typescript
|
||||
import { useSmartWallet } from "@/contexts/SmartWalletContext";
|
||||
|
||||
function MyComponent() {
|
||||
const {
|
||||
activeWallet,
|
||||
smartWallets,
|
||||
connectToWallet,
|
||||
createWallet,
|
||||
addOwner,
|
||||
removeOwner,
|
||||
updateThreshold,
|
||||
} = useSmartWallet();
|
||||
|
||||
// Use context values and methods
|
||||
}
|
||||
```
|
||||
|
||||
#### Using TransactionContext
|
||||
|
||||
```typescript
|
||||
import { useTransaction } from "@/contexts/TransactionContext";
|
||||
|
||||
function MyComponent() {
|
||||
const {
|
||||
transactions,
|
||||
pendingTransactions,
|
||||
createTransaction,
|
||||
approveTransaction,
|
||||
executeTransaction,
|
||||
estimateGas,
|
||||
} = useTransaction();
|
||||
|
||||
// Use context values and methods
|
||||
}
|
||||
```
|
||||
|
||||
#### Using SafeInjectContext
|
||||
|
||||
```typescript
|
||||
import { useSafeInject } from "@/contexts/SafeInjectContext";
|
||||
|
||||
function MyComponent() {
|
||||
const {
|
||||
address,
|
||||
appUrl,
|
||||
setAddress,
|
||||
setAppUrl,
|
||||
iframeRef,
|
||||
latestTransaction,
|
||||
} = useSafeInject();
|
||||
|
||||
// Use context values and methods
|
||||
}
|
||||
```
|
||||
|
||||
### Component Patterns
|
||||
|
||||
#### Functional Components with Hooks
|
||||
|
||||
```typescript
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { Box, Button } from "@chakra-ui/react";
|
||||
|
||||
export default function MyComponent() {
|
||||
const [state, setState] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
// Side effects
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Button onClick={() => setState("new value")}>
|
||||
Click me
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Form Handling
|
||||
|
||||
```typescript
|
||||
import { useState } from "react";
|
||||
import { useToast } from "@chakra-ui/react";
|
||||
import { validateAddress } from "@/utils/security";
|
||||
|
||||
function AddressForm() {
|
||||
const [address, setAddress] = useState("");
|
||||
const toast = useToast();
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// Validate input
|
||||
const validation = validateAddress(address);
|
||||
if (!validation.valid) {
|
||||
toast({
|
||||
title: "Invalid Address",
|
||||
description: validation.error,
|
||||
status: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Process valid address
|
||||
const checksummed = validation.checksummed!;
|
||||
// ... rest of logic
|
||||
};
|
||||
|
||||
return (
|
||||
// Form JSX
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
#### Try-Catch Pattern
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const result = await someAsyncOperation();
|
||||
// Handle success
|
||||
} catch (error: any) {
|
||||
console.error("Operation failed:", error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: error.message || "Operation failed",
|
||||
status: "error",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Boundary
|
||||
|
||||
```typescript
|
||||
import ErrorBoundary from "@/components/ErrorBoundary";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<YourComponent />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Validation Patterns
|
||||
|
||||
#### Address Validation
|
||||
|
||||
```typescript
|
||||
import { validateAddress } from "@/utils/security";
|
||||
|
||||
const validation = validateAddress(address);
|
||||
if (!validation.valid) {
|
||||
throw new Error(validation.error);
|
||||
}
|
||||
const checksummed = validation.checksummed!;
|
||||
```
|
||||
|
||||
#### Transaction Validation
|
||||
|
||||
```typescript
|
||||
import { validateTransactionRequest } from "@/utils/security";
|
||||
|
||||
const validation = validateTransactionRequest({
|
||||
from: "0x...",
|
||||
to: "0x...",
|
||||
value: "1000000000000000000",
|
||||
data: "0x",
|
||||
});
|
||||
|
||||
if (!validation.valid) {
|
||||
console.error("Validation errors:", validation.errors);
|
||||
}
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
|
||||
#### Using Async/Await
|
||||
|
||||
```typescript
|
||||
async function fetchData() {
|
||||
try {
|
||||
const data = await someAsyncCall();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Promise Handling
|
||||
|
||||
```typescript
|
||||
someAsyncCall()
|
||||
.then((result) => {
|
||||
// Handle success
|
||||
})
|
||||
.catch((error) => {
|
||||
// Handle error
|
||||
});
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
#### Local State
|
||||
|
||||
```typescript
|
||||
const [value, setValue] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
```
|
||||
|
||||
#### Context State
|
||||
|
||||
```typescript
|
||||
// Access context state
|
||||
const { activeWallet } = useSmartWallet();
|
||||
```
|
||||
|
||||
#### Derived State
|
||||
|
||||
```typescript
|
||||
const pendingCount = transactions.filter(
|
||||
(tx) => tx.status === TransactionStatus.PENDING
|
||||
).length;
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Input Validation
|
||||
|
||||
Always validate user input:
|
||||
|
||||
```typescript
|
||||
import { validateAddress, validateTransactionValue } from "@/utils/security";
|
||||
|
||||
// Validate address
|
||||
const addressValidation = validateAddress(userInput);
|
||||
if (!addressValidation.valid) {
|
||||
// Handle invalid input
|
||||
}
|
||||
|
||||
// Validate transaction value
|
||||
const valueValidation = validateTransactionValue(value);
|
||||
if (!valueValidation.valid) {
|
||||
// Handle invalid value
|
||||
}
|
||||
```
|
||||
|
||||
### Secure Storage
|
||||
|
||||
Use SecureStorage for sensitive data:
|
||||
|
||||
```typescript
|
||||
import { SecureStorage } from "@/utils/encryption";
|
||||
|
||||
const storage = new SecureStorage();
|
||||
await storage.setItem("key", JSON.stringify(sensitiveData));
|
||||
const data = await storage.getItem("key");
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Respect rate limits:
|
||||
|
||||
```typescript
|
||||
import { RateLimiter } from "@/utils/security";
|
||||
|
||||
const limiter = new RateLimiter();
|
||||
if (!limiter.checkLimit(userAddress)) {
|
||||
throw new Error("Rate limit exceeded");
|
||||
}
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### TypeScript
|
||||
|
||||
- Use strict mode
|
||||
- Define types for all functions
|
||||
- Use interfaces for object shapes
|
||||
- Avoid `any` type
|
||||
- Use type guards when needed
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Components**: PascalCase (`WalletManager`)
|
||||
- **Functions**: camelCase (`validateAddress`)
|
||||
- **Constants**: UPPER_SNAKE_CASE (`MAX_GAS_LIMIT`)
|
||||
- **Types/Interfaces**: PascalCase (`SmartWalletConfig`)
|
||||
- **Files**: Match export name
|
||||
|
||||
### Code Formatting
|
||||
|
||||
- Use Prettier for formatting
|
||||
- 2 spaces for indentation
|
||||
- Semicolons required
|
||||
- Single quotes for strings
|
||||
- Trailing commas in objects/arrays
|
||||
|
||||
### Comments
|
||||
|
||||
- Use JSDoc for public APIs
|
||||
- Explain "why" not "what"
|
||||
- Keep comments up to date
|
||||
- Remove commented-out code
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```typescript
|
||||
import { validateAddress } from "@/utils/security";
|
||||
|
||||
describe("validateAddress", () => {
|
||||
it("should validate correct addresses", () => {
|
||||
const result = validateAddress("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb");
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("should reject invalid addresses", () => {
|
||||
const result = validateAddress("invalid");
|
||||
expect(result.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Component Tests
|
||||
|
||||
```typescript
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import WalletManager from "@/components/SmartWallet/WalletManager";
|
||||
|
||||
describe("WalletManager", () => {
|
||||
it("should render wallet list", () => {
|
||||
render(<WalletManager />);
|
||||
expect(screen.getByText("Wallets")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Console Logging
|
||||
|
||||
```typescript
|
||||
// Use monitoring service for production
|
||||
import { monitoring } from "@/utils/monitoring";
|
||||
|
||||
monitoring.debug("Debug message", { context });
|
||||
monitoring.info("Info message", { context });
|
||||
monitoring.warn("Warning message", { context });
|
||||
monitoring.error("Error message", error, { context });
|
||||
```
|
||||
|
||||
### React DevTools
|
||||
|
||||
- Install React DevTools browser extension
|
||||
- Inspect component tree
|
||||
- View props and state
|
||||
- Profile performance
|
||||
|
||||
### Browser DevTools
|
||||
|
||||
- Use Network tab for API calls
|
||||
- Use Console for errors
|
||||
- Use Application tab for storage
|
||||
- Use Sources for debugging
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Memoization
|
||||
|
||||
```typescript
|
||||
import { useMemo, useCallback } from "react";
|
||||
|
||||
// Memoize expensive calculations
|
||||
const expensiveValue = useMemo(() => {
|
||||
return computeExpensiveValue(data);
|
||||
}, [data]);
|
||||
|
||||
// Memoize callbacks
|
||||
const handleClick = useCallback(() => {
|
||||
doSomething();
|
||||
}, [dependencies]);
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
```typescript
|
||||
import { lazy, Suspense } from "react";
|
||||
|
||||
const HeavyComponent = lazy(() => import("./HeavyComponent"));
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<HeavyComponent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Code Splitting
|
||||
|
||||
Next.js automatically code-splits by route. For manual splitting:
|
||||
|
||||
```typescript
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const DynamicComponent = dynamic(() => import("./Component"), {
|
||||
ssr: false,
|
||||
});
|
||||
```
|
||||
|
||||
## Git Workflow
|
||||
|
||||
### Branch Naming
|
||||
|
||||
- `feature/description` - New features
|
||||
- `fix/description` - Bug fixes
|
||||
- `refactor/description` - Refactoring
|
||||
- `docs/description` - Documentation
|
||||
- `test/description` - Test additions
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Follow conventional commits:
|
||||
|
||||
```
|
||||
feat: add wallet connection
|
||||
fix: resolve address validation bug
|
||||
docs: update API documentation
|
||||
test: add integration tests
|
||||
refactor: extract constants
|
||||
```
|
||||
|
||||
### Pull Request Process
|
||||
|
||||
1. Create feature branch
|
||||
2. Make changes and commit
|
||||
3. Write/update tests
|
||||
4. Run tests and linter
|
||||
5. Create PR with description
|
||||
6. Address review comments
|
||||
7. Merge after approval
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a New Wallet Type
|
||||
|
||||
1. Create helper in `helpers/smartWallet/`
|
||||
2. Add type to `types.ts`
|
||||
3. Update `SmartWalletContext`
|
||||
4. Add UI component
|
||||
5. Write tests
|
||||
|
||||
### Adding a New Transaction Type
|
||||
|
||||
1. Update `TransactionRequest` type
|
||||
2. Add validation in `utils/security.ts`
|
||||
3. Update execution logic
|
||||
4. Add UI component
|
||||
5. Write tests
|
||||
|
||||
### Adding a New Network
|
||||
|
||||
1. Add to `NETWORKS` in `utils/constants.ts`
|
||||
2. Update network validation
|
||||
3. Add to network list component
|
||||
4. Test connection
|
||||
|
||||
## Resources
|
||||
|
||||
- [Next.js Docs](https://nextjs.org/docs)
|
||||
- [React Docs](https://react.dev)
|
||||
- [TypeScript Docs](https://www.typescriptlang.org/docs/)
|
||||
- [Chakra UI Docs](https://chakra-ui.com/)
|
||||
- [ethers.js Docs](https://docs.ethers.org/)
|
||||
Reference in New Issue
Block a user