Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="GET_ID_FROM_WALLET_CONNET" # See https://cloud.walletconnect.com
ENVIRONMENT=localhost

NEXT_PUBLIC_ALCHEMY_API_KEY=
NEXT_PUBLIC_ALCHEMY_API_KEY=

# used for querying block with given timestamp
ETHERSCAN_API_KEY=
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ module.exports = {
// APIs
'@typescript-eslint/prefer-includes': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
'@typescript-eslint/prefer-optional-chain': 'warn',

// Hard to migrate
// Errors for all try/catch blocks and any types from third-parties
Expand Down
42 changes: 39 additions & 3 deletions app/api/block/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ import { SmartBlockFinder } from '@/utils/blockFinder';
import { SupportedNetworks } from '@/utils/networks';
import { mainnetClient, baseClient } from '@/utils/rpc';

const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;

async function getBlockFromEtherscan(timestamp: number, chainId: number): Promise<number | null> {
try {
const response = await fetch(
`https://api.etherscan.io/v2/api?chainid=${chainId}&module=block&action=getblocknobytime&timestamp=${timestamp}&closest=before&apikey=${ETHERSCAN_API_KEY}`,
);

const data = (await response.json()) as { status: string; message: string; result: string };

if (data.status === '1' && data.message === 'OK') {
return parseInt(data.result);
}

return null;
} catch (error) {
console.error('Etherscan API error:', error);
return null;
}
}

export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
Expand All @@ -18,16 +39,31 @@ export async function GET(request: NextRequest) {
}

const numericChainId = parseInt(chainId);
const numericTimestamp = parseInt(timestamp);

// Fallback to SmartBlockFinder
const client = numericChainId === SupportedNetworks.Mainnet ? mainnetClient : baseClient;

// Try Etherscan API first
const etherscanBlock = await getBlockFromEtherscan(numericTimestamp, numericChainId);
if (etherscanBlock !== null) {
// For Etherscan results, we need to fetch the block to get its timestamp
const block = await client.getBlock({ blockNumber: BigInt(etherscanBlock) });

return NextResponse.json({
blockNumber: Number(block.number),
timestamp: Number(block.timestamp),
});
} else {
console.log('etherscanBlock is null', timestamp, chainId);
}

if (!client) {
return NextResponse.json({ error: 'Unsupported chain ID' }, { status: 400 });
}

const finder = new SmartBlockFinder(client as any as PublicClient, numericChainId);

console.log('GET functino trying to find nearest block', timestamp);
const block = await finder.findNearestBlock(parseInt(timestamp));
const block = await finder.findNearestBlock(numericTimestamp);

return NextResponse.json({
blockNumber: Number(block.number),
Expand Down
15 changes: 0 additions & 15 deletions app/api/positions/historical/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,6 @@ export async function GET(request: NextRequest) {
const userAddress = searchParams.get('userAddress');
const chainId = parseInt(searchParams.get('chainId') ?? '1');

// console.log(`Historical position request:`, {
// blockNumber,
// marketId,
// userAddress,
// chainId,
// });

if (!marketId || !userAddress || (!blockNumber && blockNumber !== 0)) {
console.error('Missing required parameters:', {
blockNumber: !!blockNumber,
Expand All @@ -162,14 +155,6 @@ export async function GET(request: NextRequest) {
// Get position data at the specified blockNumber
const position = await getPositionAtBlock(marketId, userAddress, blockNumber, chainId);

// console.log(`Successfully retrieved historical position data:`, {
// blockNumber,
// marketId,
// userAddress,
// chainId,
// position,
// });

return NextResponse.json({
position,
});
Expand Down
6 changes: 3 additions & 3 deletions app/positions/components/PositionsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Positions() {
});

const handleRefetch = () => {
refetch(() => toast.info('Data refreshed', { icon: <span>🚀</span> }));
void refetch(() => toast.info('Data refreshed', { icon: <span>🚀</span> }));
};

return (
Expand Down Expand Up @@ -112,7 +112,7 @@ export default function Positions() {
setShowWithdrawModal(false);
setSelectedPosition(null);
}}
refetch={refetch}
refetch={() => void refetch()}
/>
)}

Expand Down Expand Up @@ -171,7 +171,7 @@ export default function Positions() {
setShowWithdrawModal={setShowWithdrawModal}
setShowSupplyModal={setShowSupplyModal}
setSelectedPosition={setSelectedPosition}
refetch={refetch}
refetch={() => void refetch()}
isRefetching={isRefetching}
isLoadingEarnings={isEarningsLoading}
rebalancerInfo={rebalancerInfo}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"@radix-ui/react-navigation-menu": "^1.1.4",
"@rainbow-me/rainbowkit": "2",
"@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^5.20.1",
"@tanstack/react-query": "^5.69.0",
"@tanstack/react-query-devtools": "^5.69.0",
"@types/react-table": "^7.7.20",
"@uniswap/permit2-sdk": "^1.2.1",
"abitype": "^0.10.3",
Expand Down
34 changes: 25 additions & 9 deletions src/components/providers/ClientProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
'use client';

import { ReactNode } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { MarketsProvider } from '@/contexts/MarketsContext';
import { OnboardingProvider } from 'app/positions/components/onboarding/OnboardingContext';
import { ConnectRedirectProvider } from './ConnectRedirectProvider';
import { ThemeProviders } from './ThemeProvider';
import { TokenProvider } from './TokenProvider';

// Create a client with default configuration
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30000, // Default stale time of 30 seconds
retry: 2,
refetchOnWindowFocus: false,
},
},
});

type ClientProvidersProps = {
children: ReactNode;
};

export function ClientProviders({ children }: ClientProvidersProps) {
return (
<ThemeProviders>
<TokenProvider>
<ConnectRedirectProvider>
<MarketsProvider>
<OnboardingProvider>{children}</OnboardingProvider>
</MarketsProvider>
</ConnectRedirectProvider>
</TokenProvider>
</ThemeProviders>
<QueryClientProvider client={queryClient}>
<ThemeProviders>
<TokenProvider>
<ConnectRedirectProvider>
<MarketsProvider>
<OnboardingProvider>{children}</OnboardingProvider>
</MarketsProvider>
</ConnectRedirectProvider>
</TokenProvider>
</ThemeProviders>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
Loading