agentic-team-templates 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +280 -0
  2. package/bin/cli.js +5 -0
  3. package/package.json +47 -0
  4. package/src/index.js +521 -0
  5. package/templates/_shared/code-quality.md +162 -0
  6. package/templates/_shared/communication.md +114 -0
  7. package/templates/_shared/core-principles.md +62 -0
  8. package/templates/_shared/git-workflow.md +165 -0
  9. package/templates/_shared/security-fundamentals.md +173 -0
  10. package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
  11. package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
  12. package/templates/blockchain/.cursorrules/overview.md +130 -0
  13. package/templates/blockchain/.cursorrules/security.md +318 -0
  14. package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
  15. package/templates/blockchain/.cursorrules/testing.md +415 -0
  16. package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
  17. package/templates/blockchain/CLAUDE.md +389 -0
  18. package/templates/cli-tools/.cursorrules/architecture.md +412 -0
  19. package/templates/cli-tools/.cursorrules/arguments.md +406 -0
  20. package/templates/cli-tools/.cursorrules/distribution.md +546 -0
  21. package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
  22. package/templates/cli-tools/.cursorrules/overview.md +136 -0
  23. package/templates/cli-tools/.cursorrules/testing.md +537 -0
  24. package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
  25. package/templates/cli-tools/CLAUDE.md +356 -0
  26. package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
  27. package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
  28. package/templates/data-engineering/.cursorrules/overview.md +85 -0
  29. package/templates/data-engineering/.cursorrules/performance.md +339 -0
  30. package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
  31. package/templates/data-engineering/.cursorrules/security.md +460 -0
  32. package/templates/data-engineering/.cursorrules/testing.md +452 -0
  33. package/templates/data-engineering/CLAUDE.md +974 -0
  34. package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
  35. package/templates/devops-sre/.cursorrules/change-management.md +584 -0
  36. package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
  37. package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
  38. package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
  39. package/templates/devops-sre/.cursorrules/observability.md +714 -0
  40. package/templates/devops-sre/.cursorrules/overview.md +230 -0
  41. package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
  42. package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
  43. package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
  44. package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
  45. package/templates/devops-sre/CLAUDE.md +1007 -0
  46. package/templates/documentation/.cursorrules/adr.md +277 -0
  47. package/templates/documentation/.cursorrules/api-documentation.md +411 -0
  48. package/templates/documentation/.cursorrules/code-comments.md +253 -0
  49. package/templates/documentation/.cursorrules/maintenance.md +260 -0
  50. package/templates/documentation/.cursorrules/overview.md +82 -0
  51. package/templates/documentation/.cursorrules/readme-standards.md +306 -0
  52. package/templates/documentation/CLAUDE.md +120 -0
  53. package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
  54. package/templates/fullstack/.cursorrules/architecture.md +298 -0
  55. package/templates/fullstack/.cursorrules/overview.md +109 -0
  56. package/templates/fullstack/.cursorrules/shared-types.md +348 -0
  57. package/templates/fullstack/.cursorrules/testing.md +386 -0
  58. package/templates/fullstack/CLAUDE.md +349 -0
  59. package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
  60. package/templates/ml-ai/.cursorrules/deployment.md +601 -0
  61. package/templates/ml-ai/.cursorrules/model-development.md +538 -0
  62. package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
  63. package/templates/ml-ai/.cursorrules/overview.md +131 -0
  64. package/templates/ml-ai/.cursorrules/security.md +637 -0
  65. package/templates/ml-ai/.cursorrules/testing.md +678 -0
  66. package/templates/ml-ai/CLAUDE.md +1136 -0
  67. package/templates/mobile/.cursorrules/navigation.md +246 -0
  68. package/templates/mobile/.cursorrules/offline-first.md +302 -0
  69. package/templates/mobile/.cursorrules/overview.md +71 -0
  70. package/templates/mobile/.cursorrules/performance.md +345 -0
  71. package/templates/mobile/.cursorrules/testing.md +339 -0
  72. package/templates/mobile/CLAUDE.md +233 -0
  73. package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
  74. package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
  75. package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
  76. package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
  77. package/templates/platform-engineering/.cursorrules/observability.md +747 -0
  78. package/templates/platform-engineering/.cursorrules/overview.md +215 -0
  79. package/templates/platform-engineering/.cursorrules/security.md +855 -0
  80. package/templates/platform-engineering/.cursorrules/testing.md +878 -0
  81. package/templates/platform-engineering/CLAUDE.md +850 -0
  82. package/templates/utility-agent/.cursorrules/action-control.md +284 -0
  83. package/templates/utility-agent/.cursorrules/context-management.md +186 -0
  84. package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
  85. package/templates/utility-agent/.cursorrules/overview.md +78 -0
  86. package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
  87. package/templates/utility-agent/CLAUDE.md +513 -0
  88. package/templates/web-backend/.cursorrules/api-design.md +255 -0
  89. package/templates/web-backend/.cursorrules/authentication.md +309 -0
  90. package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
  91. package/templates/web-backend/.cursorrules/error-handling.md +366 -0
  92. package/templates/web-backend/.cursorrules/overview.md +69 -0
  93. package/templates/web-backend/.cursorrules/security.md +358 -0
  94. package/templates/web-backend/.cursorrules/testing.md +395 -0
  95. package/templates/web-backend/CLAUDE.md +366 -0
  96. package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
  97. package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
  98. package/templates/web-frontend/.cursorrules/overview.md +72 -0
  99. package/templates/web-frontend/.cursorrules/performance.md +325 -0
  100. package/templates/web-frontend/.cursorrules/state-management.md +227 -0
  101. package/templates/web-frontend/.cursorrules/styling.md +271 -0
  102. package/templates/web-frontend/.cursorrules/testing.md +311 -0
  103. package/templates/web-frontend/CLAUDE.md +399 -0
@@ -0,0 +1,538 @@
1
+ # Web3 Frontend Integration
2
+
3
+ Patterns for building secure, user-friendly Web3 frontends using modern tooling.
4
+
5
+ ## Technology Stack
6
+
7
+ ### Recommended Stack (2025)
8
+
9
+ | Layer | Technology | Purpose |
10
+ |-------|------------|---------|
11
+ | Ethereum Interface | Viem | Low-level, type-safe RPC client |
12
+ | React Hooks | Wagmi | React hooks for wallet/chain interaction |
13
+ | Wallet Connection | ConnectKit/RainbowKit | Pre-built wallet UIs |
14
+ | State Management | React Query (via Wagmi) | Caching and synchronization |
15
+ | Type Generation | wagmi cli | Generate types from ABIs |
16
+
17
+ ### Project Setup
18
+
19
+ ```bash
20
+ npm install wagmi viem @tanstack/react-query
21
+ npm install connectkit # or rainbowkit
22
+ ```
23
+
24
+ ## Configuration
25
+
26
+ ### Wagmi Config
27
+
28
+ ```typescript
29
+ // lib/wagmi.ts
30
+ import { createConfig, http } from 'wagmi';
31
+ import { mainnet, sepolia, arbitrum } from 'wagmi/chains';
32
+ import { coinbaseWallet, injected, walletConnect } from 'wagmi/connectors';
33
+
34
+ export const config = createConfig({
35
+ chains: [mainnet, arbitrum, sepolia],
36
+ connectors: [
37
+ injected(),
38
+ coinbaseWallet({ appName: 'My App' }),
39
+ walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID! }),
40
+ ],
41
+ transports: {
42
+ [mainnet.id]: http(process.env.NEXT_PUBLIC_MAINNET_RPC),
43
+ [arbitrum.id]: http(process.env.NEXT_PUBLIC_ARBITRUM_RPC),
44
+ [sepolia.id]: http(process.env.NEXT_PUBLIC_SEPOLIA_RPC),
45
+ },
46
+ });
47
+ ```
48
+
49
+ ### Provider Setup
50
+
51
+ ```typescript
52
+ // app/providers.tsx
53
+ 'use client';
54
+
55
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
56
+ import { WagmiProvider } from 'wagmi';
57
+ import { ConnectKitProvider } from 'connectkit';
58
+ import { config } from '@/lib/wagmi';
59
+
60
+ const queryClient = new QueryClient();
61
+
62
+ export function Providers({ children }: { children: React.ReactNode }) {
63
+ return (
64
+ <WagmiProvider config={config}>
65
+ <QueryClientProvider client={queryClient}>
66
+ <ConnectKitProvider>
67
+ {children}
68
+ </ConnectKitProvider>
69
+ </QueryClientProvider>
70
+ </WagmiProvider>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ## Wallet Connection
76
+
77
+ ### Basic Connection
78
+
79
+ ```typescript
80
+ // components/ConnectButton.tsx
81
+ import { useAccount, useConnect, useDisconnect } from 'wagmi';
82
+
83
+ export function ConnectButton() {
84
+ const { address, isConnected } = useAccount();
85
+ const { connect, connectors, isPending } = useConnect();
86
+ const { disconnect } = useDisconnect();
87
+
88
+ if (isConnected) {
89
+ return (
90
+ <div>
91
+ <span>{address?.slice(0, 6)}...{address?.slice(-4)}</span>
92
+ <button onClick={() => disconnect()}>Disconnect</button>
93
+ </div>
94
+ );
95
+ }
96
+
97
+ return (
98
+ <div>
99
+ {connectors.map((connector) => (
100
+ <button
101
+ key={connector.id}
102
+ onClick={() => connect({ connector })}
103
+ disabled={isPending}
104
+ >
105
+ {connector.name}
106
+ </button>
107
+ ))}
108
+ </div>
109
+ );
110
+ }
111
+ ```
112
+
113
+ ### Using ConnectKit (Recommended)
114
+
115
+ ```typescript
116
+ import { ConnectKitButton } from 'connectkit';
117
+
118
+ export function Header() {
119
+ return (
120
+ <header>
121
+ <ConnectKitButton />
122
+ </header>
123
+ );
124
+ }
125
+ ```
126
+
127
+ ## Contract Interactions
128
+
129
+ ### Type-Safe Contract Hooks
130
+
131
+ ```typescript
132
+ // hooks/useVault.ts
133
+ import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
134
+ import { parseEther, formatEther } from 'viem';
135
+ import { vaultAbi } from '@/contracts/abi';
136
+
137
+ const VAULT_ADDRESS = '0x...' as const;
138
+
139
+ export function useVaultBalance(address: `0x${string}` | undefined) {
140
+ return useReadContract({
141
+ address: VAULT_ADDRESS,
142
+ abi: vaultAbi,
143
+ functionName: 'balanceOf',
144
+ args: address ? [address] : undefined,
145
+ query: {
146
+ enabled: !!address,
147
+ },
148
+ });
149
+ }
150
+
151
+ export function useVaultDeposit() {
152
+ const { data: hash, writeContract, isPending, error } = useWriteContract();
153
+
154
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
155
+ hash,
156
+ });
157
+
158
+ const deposit = async (amount: string) => {
159
+ writeContract({
160
+ address: VAULT_ADDRESS,
161
+ abi: vaultAbi,
162
+ functionName: 'deposit',
163
+ args: [parseEther(amount)],
164
+ });
165
+ };
166
+
167
+ return {
168
+ deposit,
169
+ hash,
170
+ isPending,
171
+ isConfirming,
172
+ isSuccess,
173
+ error,
174
+ };
175
+ }
176
+ ```
177
+
178
+ ### Using the Hook
179
+
180
+ ```typescript
181
+ // components/DepositForm.tsx
182
+ import { useState } from 'react';
183
+ import { useAccount } from 'wagmi';
184
+ import { useVaultDeposit, useVaultBalance } from '@/hooks/useVault';
185
+
186
+ export function DepositForm() {
187
+ const [amount, setAmount] = useState('');
188
+ const { address } = useAccount();
189
+ const { data: balance } = useVaultBalance(address);
190
+ const { deposit, isPending, isConfirming, isSuccess, error } = useVaultDeposit();
191
+
192
+ const handleSubmit = (e: React.FormEvent) => {
193
+ e.preventDefault();
194
+ deposit(amount);
195
+ };
196
+
197
+ return (
198
+ <form onSubmit={handleSubmit}>
199
+ <input
200
+ type="text"
201
+ value={amount}
202
+ onChange={(e) => setAmount(e.target.value)}
203
+ placeholder="Amount in ETH"
204
+ disabled={isPending || isConfirming}
205
+ />
206
+
207
+ <button type="submit" disabled={isPending || isConfirming}>
208
+ {isPending ? 'Confirm in wallet...' : isConfirming ? 'Confirming...' : 'Deposit'}
209
+ </button>
210
+
211
+ {isSuccess && <p>Deposit successful!</p>}
212
+ {error && <p>Error: {error.message}</p>}
213
+ </form>
214
+ );
215
+ }
216
+ ```
217
+
218
+ ## Transaction Handling
219
+
220
+ ### Transaction States
221
+
222
+ ```typescript
223
+ type TransactionState =
224
+ | 'idle' // No transaction
225
+ | 'pending' // Waiting for wallet signature
226
+ | 'submitted' // Signed, waiting for confirmation
227
+ | 'confirming' // In mempool, waiting for block
228
+ | 'confirmed' // Included in block
229
+ | 'failed'; // Reverted or rejected
230
+
231
+ // Visual feedback for each state
232
+ const transactionMessages: Record<TransactionState, string> = {
233
+ idle: '',
234
+ pending: 'Please confirm in your wallet...',
235
+ submitted: 'Transaction submitted, waiting for confirmation...',
236
+ confirming: 'Transaction is being confirmed...',
237
+ confirmed: 'Transaction confirmed!',
238
+ failed: 'Transaction failed',
239
+ };
240
+ ```
241
+
242
+ ### Transaction Tracking Component
243
+
244
+ ```typescript
245
+ // components/TransactionStatus.tsx
246
+ import { useWaitForTransactionReceipt } from 'wagmi';
247
+
248
+ interface TransactionStatusProps {
249
+ hash: `0x${string}` | undefined;
250
+ onSuccess?: () => void;
251
+ }
252
+
253
+ export function TransactionStatus({ hash, onSuccess }: TransactionStatusProps) {
254
+ const { isLoading, isSuccess, isError, error } = useWaitForTransactionReceipt({
255
+ hash,
256
+ onSuccess,
257
+ });
258
+
259
+ if (!hash) return null;
260
+
261
+ return (
262
+ <div className="transaction-status">
263
+ {isLoading && (
264
+ <div className="flex items-center gap-2">
265
+ <Spinner />
266
+ <span>Confirming transaction...</span>
267
+ <a href={`https://etherscan.io/tx/${hash}`} target="_blank">
268
+ View on Etherscan
269
+ </a>
270
+ </div>
271
+ )}
272
+
273
+ {isSuccess && (
274
+ <div className="text-green-600">
275
+ Transaction confirmed!
276
+ </div>
277
+ )}
278
+
279
+ {isError && (
280
+ <div className="text-red-600">
281
+ Transaction failed: {error?.message}
282
+ </div>
283
+ )}
284
+ </div>
285
+ );
286
+ }
287
+ ```
288
+
289
+ ## Error Handling
290
+
291
+ ### Contract Error Parsing
292
+
293
+ ```typescript
294
+ // utils/errors.ts
295
+ import { BaseError, ContractFunctionRevertedError } from 'viem';
296
+
297
+ export function parseContractError(error: unknown): string {
298
+ if (error instanceof BaseError) {
299
+ // Check for contract revert
300
+ const revertError = error.walk(
301
+ (err) => err instanceof ContractFunctionRevertedError
302
+ );
303
+
304
+ if (revertError instanceof ContractFunctionRevertedError) {
305
+ const errorName = revertError.data?.errorName ?? 'Unknown error';
306
+
307
+ // Map custom errors to user-friendly messages
308
+ const errorMessages: Record<string, string> = {
309
+ InsufficientBalance: 'You don\'t have enough balance',
310
+ Unauthorized: 'You\'re not authorized to perform this action',
311
+ SlippageExceeded: 'Price moved too much, try again',
312
+ Expired: 'Transaction expired, please try again',
313
+ };
314
+
315
+ return errorMessages[errorName] ?? errorName;
316
+ }
317
+
318
+ // Check for user rejection
319
+ if (error.message.includes('User rejected')) {
320
+ return 'Transaction cancelled';
321
+ }
322
+ }
323
+
324
+ return 'An unexpected error occurred';
325
+ }
326
+ ```
327
+
328
+ ### Error Boundary
329
+
330
+ ```typescript
331
+ // components/Web3ErrorBoundary.tsx
332
+ import { Component, ReactNode } from 'react';
333
+
334
+ interface Props {
335
+ children: ReactNode;
336
+ fallback?: ReactNode;
337
+ }
338
+
339
+ interface State {
340
+ hasError: boolean;
341
+ error?: Error;
342
+ }
343
+
344
+ export class Web3ErrorBoundary extends Component<Props, State> {
345
+ state: State = { hasError: false };
346
+
347
+ static getDerivedStateFromError(error: Error): State {
348
+ return { hasError: true, error };
349
+ }
350
+
351
+ render() {
352
+ if (this.state.hasError) {
353
+ return this.props.fallback ?? (
354
+ <div className="error-container">
355
+ <h2>Something went wrong</h2>
356
+ <p>{this.state.error?.message}</p>
357
+ <button onClick={() => this.setState({ hasError: false })}>
358
+ Try again
359
+ </button>
360
+ </div>
361
+ );
362
+ }
363
+
364
+ return this.props.children;
365
+ }
366
+ }
367
+ ```
368
+
369
+ ## Network Handling
370
+
371
+ ### Chain Switching
372
+
373
+ ```typescript
374
+ import { useSwitchChain, useChainId } from 'wagmi';
375
+ import { mainnet, arbitrum } from 'wagmi/chains';
376
+
377
+ export function NetworkSwitcher() {
378
+ const chainId = useChainId();
379
+ const { switchChain, isPending } = useSwitchChain();
380
+
381
+ const supportedChains = [mainnet, arbitrum];
382
+
383
+ return (
384
+ <select
385
+ value={chainId}
386
+ onChange={(e) => switchChain({ chainId: Number(e.target.value) })}
387
+ disabled={isPending}
388
+ >
389
+ {supportedChains.map((chain) => (
390
+ <option key={chain.id} value={chain.id}>
391
+ {chain.name}
392
+ </option>
393
+ ))}
394
+ </select>
395
+ );
396
+ }
397
+ ```
398
+
399
+ ### Wrong Network Warning
400
+
401
+ ```typescript
402
+ import { useChainId, useAccount } from 'wagmi';
403
+
404
+ const SUPPORTED_CHAIN_IDS = [1, 42161]; // Mainnet, Arbitrum
405
+
406
+ export function NetworkGuard({ children }: { children: React.ReactNode }) {
407
+ const chainId = useChainId();
408
+ const { isConnected } = useAccount();
409
+
410
+ if (isConnected && !SUPPORTED_CHAIN_IDS.includes(chainId)) {
411
+ return (
412
+ <div className="warning">
413
+ <p>Please switch to a supported network</p>
414
+ <NetworkSwitcher />
415
+ </div>
416
+ );
417
+ }
418
+
419
+ return <>{children}</>;
420
+ }
421
+ ```
422
+
423
+ ## Security Best Practices
424
+
425
+ ### 1. Validate Before Signing
426
+
427
+ ```typescript
428
+ // Always show transaction details before signing
429
+ function ConfirmTransaction({
430
+ action,
431
+ amount,
432
+ recipient,
433
+ onConfirm,
434
+ }: ConfirmTransactionProps) {
435
+ return (
436
+ <div className="confirmation-modal">
437
+ <h3>Confirm Transaction</h3>
438
+ <dl>
439
+ <dt>Action</dt>
440
+ <dd>{action}</dd>
441
+ <dt>Amount</dt>
442
+ <dd>{amount} ETH</dd>
443
+ <dt>Recipient</dt>
444
+ <dd>{recipient}</dd>
445
+ </dl>
446
+ <button onClick={onConfirm}>Confirm</button>
447
+ <button onClick={onCancel}>Cancel</button>
448
+ </div>
449
+ );
450
+ }
451
+ ```
452
+
453
+ ### 2. Simulate Before Sending
454
+
455
+ ```typescript
456
+ import { useSimulateContract } from 'wagmi';
457
+
458
+ function useDepositWithSimulation(amount: bigint) {
459
+ // Simulate first
460
+ const { data: simulation, error: simulationError } = useSimulateContract({
461
+ address: VAULT_ADDRESS,
462
+ abi: vaultAbi,
463
+ functionName: 'deposit',
464
+ args: [amount],
465
+ });
466
+
467
+ const { writeContract } = useWriteContract();
468
+
469
+ const deposit = () => {
470
+ if (simulationError) {
471
+ throw new Error(`Transaction would fail: ${simulationError.message}`);
472
+ }
473
+ writeContract(simulation!.request);
474
+ };
475
+
476
+ return { deposit, simulationError };
477
+ }
478
+ ```
479
+
480
+ ### 3. Never Trust URL Parameters for Addresses
481
+
482
+ ```typescript
483
+ // Bad: Using address from URL
484
+ const address = searchParams.get('recipient');
485
+ writeContract({ args: [address] }); // Phishing risk!
486
+
487
+ // Good: Always use known addresses or user confirmation
488
+ const KNOWN_CONTRACTS = {
489
+ vault: '0x...',
490
+ staking: '0x...',
491
+ };
492
+
493
+ // Or require explicit user confirmation
494
+ const [confirmed, setConfirmed] = useState(false);
495
+ ```
496
+
497
+ ### 4. Rate Limit Sensitive Operations
498
+
499
+ ```typescript
500
+ import { useCallback, useRef } from 'react';
501
+
502
+ function useRateLimitedAction(cooldownMs: number = 5000) {
503
+ const lastAction = useRef<number>(0);
504
+
505
+ const canExecute = useCallback(() => {
506
+ const now = Date.now();
507
+ if (now - lastAction.current < cooldownMs) {
508
+ return false;
509
+ }
510
+ lastAction.current = now;
511
+ return true;
512
+ }, [cooldownMs]);
513
+
514
+ return canExecute;
515
+ }
516
+ ```
517
+
518
+ ## Performance Tips
519
+
520
+ 1. **Use query keys properly** - Wagmi handles caching, don't duplicate
521
+ 2. **Batch reads** - Use `useReadContracts` for multiple reads
522
+ 3. **Avoid unnecessary re-renders** - Memoize callbacks and values
523
+ 4. **Lazy load Web3** - Don't block initial page load
524
+
525
+ ```typescript
526
+ // Batch multiple contract reads
527
+ import { useReadContracts } from 'wagmi';
528
+
529
+ function useVaultStats() {
530
+ return useReadContracts({
531
+ contracts: [
532
+ { address: VAULT, abi, functionName: 'totalAssets' },
533
+ { address: VAULT, abi, functionName: 'totalSupply' },
534
+ { address: VAULT, abi, functionName: 'asset' },
535
+ ],
536
+ });
537
+ }
538
+ ```