diff --git a/DEVELOPMENT_GUIDE.md b/DEVELOPMENT_GUIDE.md index 48616829d2..94a01dc1d5 100644 --- a/DEVELOPMENT_GUIDE.md +++ b/DEVELOPMENT_GUIDE.md @@ -94,27 +94,7 @@ import { isAddress, isAddressEqual, zeroAddress, type Address } from 'viem' enforce(isAddress(data.rewardTokenId)).isTruthy() ``` -## 6. BigDecimal - -A custom `BigDecimal` implementation is used for precise numerical operations: - -- Use `BigDecimal` for all financial calculations to avoid floating-point errors -- Implement utility functions that work with `BigDecimal` for common operations - -## 7. Custom Hooks - -Several custom hooks are used throughout the project: - -- Create hooks for reusable logic (e.g., `useChainId`, `useCurve`) -- Implement hooks that combine multiple queries for complex data fetching scenarios - -Example: - -```typescript -const { data: curve } = useCurve() -``` - -## 8. TypeScript +## 6. TypeScript The project heavily uses TypeScript: diff --git a/apps/main/src/dao/store/createAppSlice.ts b/apps/main/src/dao/store/createAppSlice.ts index 536c13c8cb..f97e7898c2 100644 --- a/apps/main/src/dao/store/createAppSlice.ts +++ b/apps/main/src/dao/store/createAppSlice.ts @@ -41,7 +41,6 @@ const createAppSlice = (set: SetState, get: GetState): AppSlice => const isNetworkSwitched = prevApi?.chainId != api.chainId log('Hydrating DAO', api?.chainId, { - wallet: wallet?.chainId ?? '', isNetworkSwitched, }) diff --git a/apps/main/src/dex/store/createGlobalSlice.ts b/apps/main/src/dex/store/createGlobalSlice.ts index 39732e51da..39b049df78 100644 --- a/apps/main/src/dex/store/createGlobalSlice.ts +++ b/apps/main/src/dex/store/createGlobalSlice.ts @@ -62,7 +62,7 @@ const createGlobalSlice = (set: SetState, get: GetState): GlobalSl }), ) }, - hydrate: async (curveApi, prevCurveApi, wallet) => { + hydrate: async (curveApi, prevCurveApi) => { if (!curveApi) return const state = get() @@ -70,7 +70,6 @@ const createGlobalSlice = (set: SetState, get: GetState): GlobalSl const isUserSwitched = prevCurveApi?.signerAddress !== curveApi.signerAddress const { chainId } = curveApi log('Hydrating DEX', curveApi?.chainId, { - wallet: wallet?.chainId ?? '', isNetworkSwitched, isUserSwitched, hasRPC: !curveApi.isNoRPC, diff --git a/apps/main/src/lend/store/createAppSlice.ts b/apps/main/src/lend/store/createAppSlice.ts index f07d6e42b4..aa5998fcb3 100644 --- a/apps/main/src/lend/store/createAppSlice.ts +++ b/apps/main/src/lend/store/createAppSlice.ts @@ -21,7 +21,7 @@ export interface AppSlice { } const createAppSlice = (set: SetState, get: GetState): AppSlice => ({ - hydrate: async (api, prevApi, wallet) => { + hydrate: async (api, prevApi) => { if (!api) return const isNetworkSwitched = !!prevApi?.chainId && prevApi.chainId !== api.chainId @@ -29,7 +29,6 @@ const createAppSlice = (set: SetState, get: GetState): AppSlice => const state = get() log('Hydrating Lend', api.chainId, { - wallet: wallet?.chainId ?? '', chainId: [prevApi?.chainId, api.chainId], signerAddress: [prevApi?.signerAddress, api.signerAddress], }) diff --git a/apps/main/src/loan/store/createAppSlice.ts b/apps/main/src/loan/store/createAppSlice.ts index 2f60a87250..51f847b3fe 100644 --- a/apps/main/src/loan/store/createAppSlice.ts +++ b/apps/main/src/loan/store/createAppSlice.ts @@ -41,7 +41,7 @@ const createAppSlice = (set: SetState, get: GetState): AppSlice => ) }, - hydrate: async (curveApi, prevCurveApi, wallet) => { + hydrate: async (curveApi, prevCurveApi) => { if (!curveApi) return const { loans, collaterals } = get() @@ -49,7 +49,6 @@ const createAppSlice = (set: SetState, get: GetState): AppSlice => const isNetworkSwitched = !!prevCurveApi?.chainId && prevCurveApi.chainId !== curveApi.chainId const isUserSwitched = !!prevCurveApi?.signerAddress && prevCurveApi.signerAddress !== curveApi.signerAddress log('Hydrate crvUSD', curveApi?.chainId, { - wallet: wallet?.chainId ?? '', isNetworkSwitched, isUserSwitched, }) diff --git a/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionContext.tsx b/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionContext.tsx index d6ddea4161..b01595ec32 100644 --- a/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionContext.tsx +++ b/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionContext.tsx @@ -59,11 +59,10 @@ export function useWagmiWallet() { client?.transport.request && { provider: { request: client.transport.request }, account: { address }, // the ensName is set later when detected - chainId: client.chain.id, } hackSignerInCypress(wallet) return { wallet, provider: wallet ? new BrowserProvider(wallet.provider) : null } - }, [address, client?.chain.id, client?.transport.request]) ?? null), + }, [address, client?.transport.request]) ?? null), } } diff --git a/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionProvider.tsx b/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionProvider.tsx index d58096ee1b..4327d70dd5 100644 --- a/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionProvider.tsx +++ b/packages/curve-ui-kit/src/features/connect-wallet/lib/ConnectionProvider.tsx @@ -1,5 +1,5 @@ import { type ReactNode, useEffect, useState } from 'react' -import { useSwitchChain } from 'wagmi' +import { useChainId, useSwitchChain } from 'wagmi' import type { NetworkDef } from '@ui/utils' import { ConnectionContext, useWagmiWallet } from '@ui-kit/features/connect-wallet/lib/ConnectionContext' import { @@ -38,6 +38,7 @@ export const ConnectionProvider = ({ children: ReactNode }) => { const [connectState, setConnectState] = useState(LOADING) + const walletChainId = useChainId() const { switchChainAsync } = useSwitchChain() const { wallet, provider, isReconnecting } = useWagmiWallet() const isFocused = useIsDocumentFocused() @@ -49,12 +50,12 @@ export const ConnectionProvider = ({ * This is separate from the rest of initApp to avoid unnecessary reinitialization, as isFocused can change frequently. */ async function updateWalletChain() { - const chainId = Number(network.chainId) as AppChainId - if (wallet && wallet?.chainId !== chainId) { + const networkChainId = Number(network.chainId) as AppChainId + if (networkChainId !== walletChainId) { setConnectState(LOADING) - if (isFocused && !(await switchChainAsync({ chainId: chainId as WagmiChainId }))) { + if (isFocused && !(await switchChainAsync({ chainId: networkChainId as WagmiChainId }))) { setConnectState(FAILURE) - onChainUnavailable([chainId, wallet?.chainId as AppChainId]) + onChainUnavailable([networkChainId, walletChainId as AppChainId]) } return // hook is called again after since it depends on walletChainId } @@ -63,7 +64,7 @@ export const ConnectionProvider = ({ console.error('Error updating wallet chain', e) setConnectState(FAILURE) }) - }, [isFocused, network.chainId, onChainUnavailable, switchChainAsync, wallet]) + }, [isFocused, walletChainId, network.chainId, onChainUnavailable, switchChainAsync, wallet]) useEffect(() => { if (isReconnecting) return // wait for wagmi to auto-reconnect @@ -84,14 +85,14 @@ export const ConnectionProvider = ({ * Initialize the app by connecting to the wallet and setting up the library. */ const initLib = async () => { - const chainId = Number(network.chainId) as AppChainId + const networkChainId = Number(network.chainId) as AppChainId try { - if (wallet && wallet?.chainId !== chainId) { + if (walletChainId !== networkChainId) { return // wait for the wallet to be connected to the right chain } const prevLib = globalLibs.get(libKey) - if (isWalletMatching(wallet, prevLib, chainId)) { + if (isWalletMatching(wallet, prevLib, networkChainId)) { return await hydrateApp(prevLib) // already connected to the right chain and wallet, no need to reinitialize } @@ -99,7 +100,7 @@ export const ConnectionProvider = ({ setConnectState(LOADING) console.info( `Initializing ${libKey} for ${network.name} (${network.chainId})`, - wallet ? `Wallet ${wallet?.account?.address} with chain ${wallet?.chainId}` : 'without wallet', + wallet ? `Wallet ${wallet?.account?.address} with chain ${walletChainId}` : 'without wallet', prevLib ? `Old library had ${prevLib.signerAddress ? `signer ${prevLib.signerAddress}` : 'no signer'} with chain ${prevLib.chainId}` : `First initialization`, @@ -117,7 +118,7 @@ export const ConnectionProvider = ({ } void initLib() return () => abort.abort() - }, [app, hydrate, isReconnecting, libKey, network, wallet]) + }, [app, hydrate, isReconnecting, libKey, network, wallet, walletChainId]) // the following statements are skipping the render cycle, only update the libs when connectState changes too! const curveApi = globalLibs.getMatching('curveApi', wallet, network?.chainId) diff --git a/packages/curve-ui-kit/src/features/connect-wallet/lib/types.ts b/packages/curve-ui-kit/src/features/connect-wallet/lib/types.ts index 9cbd9ca520..8ab39ba802 100644 --- a/packages/curve-ui-kit/src/features/connect-wallet/lib/types.ts +++ b/packages/curve-ui-kit/src/features/connect-wallet/lib/types.ts @@ -6,10 +6,9 @@ import { type default as llamaApi } from '@curvefi/llamalend-api' import type { IChainId as LlamaChainId, INetworkName as LlamaNetworkId } from '@curvefi/llamalend-api/lib/interfaces' import { AppName } from '@ui-kit/shared/routes' -export type Wallet = { +export type Wallet = { readonly provider?: Eip1193Provider readonly account: { address: Address; ensName?: string } - readonly chainId: TChainId } export enum ConnectState { diff --git a/packages/curve-ui-kit/src/lib/validation/validation.d.ts b/packages/curve-ui-kit/src/lib/validation/validation.d.ts deleted file mode 100644 index b4176fcc18..0000000000 --- a/packages/curve-ui-kit/src/lib/validation/validation.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// declare global { -// namespace n4s { -// interface EnforceCustomMatchers { -// isAddress(value: string): R -// isBigDecimal(value: string): R -// isNotZeroAddress(value: string): R -// isPositiveNumber(value: number): R -// isValidChainId(value: number): R -// } -// } -// } - -// export {}