Skip to content

Commit d5943af

Browse files
committed
Merge branch 'main' into chore/dep-cleanup
2 parents fc7797a + c6356d6 commit d5943af

106 files changed

Lines changed: 4446 additions & 969 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ TENDERLY_ACCOUNT=
44
TENDERLY_PROJECT=
55
NEXT_PUBLIC_ENV=prod
66
NEXT_PUBLIC_ENABLE_GOVERNANCE=true
7+
NEXT_PUBLIC_USE_GOVERNANCE_CACHE=true
8+
NEXT_PUBLIC_GOVERNANCE_CACHE_URL=https://governance-cache-api.aave.com/graphql
79
NEXT_PUBLIC_ENABLE_STAKING=true
810
NEXT_PUBLIC_API_BASEURL=https://aave-api-v2.aave.com
911
NEXT_PUBLIC_TRANSAK_APP_URL=https://global.transak.com
@@ -45,3 +47,6 @@ FAMILY_API_KEY=
4547
FAMILY_API_URL=
4648
COINGECKO_API_KEY=
4749
PLAIN_API_KEY=
50+
COMPLIANCE_API_URL=
51+
COMPLIANCE_SECRET=
52+
SENTRY_AUTH_TOKEN=

package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "3.0.1",
44
"private": true,
55
"license": "BSD-3-Clause",
6+
"resolutions": {
7+
"h3": "^1.15.5"
8+
},
69
"scripts": {
710
"dev": "next dev",
811
"dev:special": "NODE_OPTIONS='--inspect --max_old_space_size=8000' next dev",
@@ -28,15 +31,15 @@
2831
"test:headless": "export DOTENV_CONFIG_PATH='../../../.env.local' && cypress run --config-file './cypress/configs/local/full.config.ts'"
2932
},
3033
"dependencies": {
31-
"@aave/contract-helpers": "1.37.0",
34+
"@aave/contract-helpers": "1.37.1",
3235
"@aave/graphql": "^0.11.0",
33-
"@aave/math-utils": "1.37.0",
36+
"@aave/math-utils": "1.37.1",
3437
"@aave/react": "^0.8.2",
3538
"@amplitude/analytics-browser": "^2.13.0",
36-
"@bgd-labs/aave-address-book": "^4.38.2",
37-
"@cowprotocol/cow-sdk": "7.2.4",
38-
"@cowprotocol/sdk-ethers-v5-adapter": "0.3.0",
39-
"@cowprotocol/sdk-flash-loans": "1.6.0",
39+
"@bgd-labs/aave-address-book": "^4.44.6",
40+
"@cowprotocol/cow-sdk": "7.3.4",
41+
"@cowprotocol/sdk-ethers-v5-adapter": "0.3.5",
42+
"@cowprotocol/sdk-flash-loans": "1.7.4",
4043
"@emotion/cache": "11.10.3",
4144
"@emotion/react": "11.10.4",
4245
"@emotion/server": "latest",
@@ -89,7 +92,7 @@
8992
"remark-gfm": "^3.0.1",
9093
"sonner": "^2.0.3",
9194
"tiny-invariant": "^1.3.1",
92-
"viem": "^2.37.6",
95+
"viem": "^2.45.1",
9396
"wagmi": "^2.15.2",
9497
"zustand": "^5.0.2"
9598
},

pages/_app.page.tsx

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { TransactionEventHandler } from 'src/components/TransactionEventHandler'
1818
import { GasStationProvider } from 'src/components/transactions/GasStation/GasStationProvider';
1919
import { CowOrderToast } from 'src/components/transactions/Swap/modals/result/CowOrderToast';
2020
import { AppDataProvider } from 'src/hooks/app-data-provider/useAppDataProvider';
21+
import { ComplianceProvider } from 'src/hooks/compliance/compliance';
2122
import { ModalContextProvider } from 'src/hooks/useModal';
2223
import { SwapOrdersTrackingProvider } from 'src/hooks/useSwapOrdersTracking';
2324
import { Web3ContextProvider } from 'src/libs/web3-data-provider/Web3Provider';
@@ -160,38 +161,40 @@ export default function MyApp(props: MyAppProps) {
160161
>
161162
<Web3ContextProvider>
162163
<AppGlobalStyles>
163-
<AddressBlocked>
164-
<SwapOrdersTrackingProvider>
165-
<ModalContextProvider>
166-
<SharedDependenciesProvider>
167-
<AppDataProvider>
168-
<GasStationProvider>
169-
{getLayout(<Component {...pageProps} />)}
170-
<SupplyModal />
171-
<WithdrawModal />
172-
<BorrowModal />
173-
<RepayModal />
174-
<CollateralChangeModal />
175-
<ClaimRewardsModal />
176-
<EmodeModal />
177-
<FaucetModal />
178-
<TransactionEventHandler />
179-
<StakingMigrateModal />
180-
<BridgeModal />
181-
<ReadOnlyModal />
164+
<ComplianceProvider>
165+
<AddressBlocked>
166+
<SwapOrdersTrackingProvider>
167+
<ModalContextProvider>
168+
<SharedDependenciesProvider>
169+
<AppDataProvider>
170+
<GasStationProvider>
171+
{getLayout(<Component {...pageProps} />)}
172+
<SupplyModal />
173+
<WithdrawModal />
174+
<BorrowModal />
175+
<RepayModal />
176+
<CollateralChangeModal />
177+
<ClaimRewardsModal />
178+
<EmodeModal />
179+
<FaucetModal />
180+
<TransactionEventHandler />
181+
<StakingMigrateModal />
182+
<BridgeModal />
183+
<ReadOnlyModal />
182184

183-
{/* Swap Modals */}
184-
<SwapModal />
185-
<CollateralSwapModal />
186-
<DebtSwapModal />
187-
<CancelCowOrderModal />
188-
<CowOrderToast />
189-
</GasStationProvider>
190-
</AppDataProvider>
191-
</SharedDependenciesProvider>
192-
</ModalContextProvider>
193-
</SwapOrdersTrackingProvider>
194-
</AddressBlocked>
185+
{/* Swap Modals */}
186+
<SwapModal />
187+
<CollateralSwapModal />
188+
<DebtSwapModal />
189+
<CancelCowOrderModal />
190+
<CowOrderToast />
191+
</GasStationProvider>
192+
</AppDataProvider>
193+
</SharedDependenciesProvider>
194+
</ModalContextProvider>
195+
</SwapOrdersTrackingProvider>
196+
</AddressBlocked>
197+
</ComplianceProvider>
195198
</AppGlobalStyles>
196199
</Web3ContextProvider>
197200
</ConnectKitProvider>

pages/api/preflight-compliance.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import type { NextApiRequest, NextApiResponse } from 'next';
2+
import { isAddress } from 'viem';
3+
4+
const COMPLIANCE_API_URL = process.env.COMPLIANCE_API_URL;
5+
const COMPLIANCE_SECRET = process.env.COMPLIANCE_SECRET;
6+
7+
type ComplianceApiResponse = {
8+
result: boolean;
9+
lastChecked: string;
10+
nextCheck: string;
11+
};
12+
13+
type PreflightResponse = {
14+
result: boolean;
15+
nextCheck: string;
16+
};
17+
18+
type ErrorResponse = {
19+
error: string;
20+
};
21+
22+
export default async function handler(
23+
req: NextApiRequest,
24+
res: NextApiResponse<PreflightResponse | ErrorResponse>
25+
) {
26+
if (req.method !== 'GET') {
27+
return res.status(405).json({ error: 'Method not allowed' });
28+
}
29+
30+
const { address } = req.query;
31+
32+
if (!address || typeof address !== 'string') {
33+
return res.status(400).json({ error: 'Address is required' });
34+
}
35+
36+
// Validate address format to prevent SSRF attacks
37+
// const ethereumAddressRegex = /^0x[a-fA-F0-9]{40}$/;
38+
if (!isAddress(address)) {
39+
return res.status(400).json({ error: 'Invalid address format' });
40+
}
41+
42+
if (!COMPLIANCE_API_URL || !COMPLIANCE_SECRET) {
43+
console.error('Compliance API not configured');
44+
// Fail open in development if not configured
45+
if (process.env.NODE_ENV === 'development') {
46+
return res.status(200).json({
47+
result: true,
48+
nextCheck: new Date(Date.now() + 2 * 60 * 60 * 1000).toISOString(),
49+
});
50+
}
51+
return res.status(500).json({ error: 'Service unavailable' });
52+
}
53+
54+
try {
55+
// use ?overrideResultStatus=false | true if you want to override the result
56+
57+
const response = await fetch(`${COMPLIANCE_API_URL}/check/${encodeURIComponent(address)}`, {
58+
method: 'GET',
59+
headers: {
60+
'x-compliance-secret': COMPLIANCE_SECRET,
61+
},
62+
});
63+
64+
if (!response.ok) {
65+
if (response.status === 401) {
66+
console.error('Compliance API: Invalid secret');
67+
return res.status(500).json({ error: 'Service configuration error' });
68+
}
69+
if (response.status === 400) {
70+
return res.status(400).json({ error: 'Invalid address format' });
71+
}
72+
return res.status(500).json({ error: 'Compliance check failed' });
73+
}
74+
75+
const data: ComplianceApiResponse = await response.json();
76+
77+
return res.status(200).json({
78+
result: data.result,
79+
nextCheck: data.nextCheck,
80+
});
81+
} catch (error) {
82+
console.error('Compliance API error:', error);
83+
return res.status(500).json({ error: 'Service unavailable' });
84+
}
85+
}

pages/api/rpc-proxy.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ChainId } from '@aave/contract-helpers';
22
import { NextApiRequest, NextApiResponse } from 'next';
3+
import { mantle, megaeth } from 'viem/chains';
34

45
// Documentation: ./server-side-rpc-proxy.md
56
const NETWORK_CONFIG: Record<number, { network: string; apiKey: string }> = {
@@ -27,6 +28,8 @@ const NETWORK_CONFIG: Record<number, { network: string; apiKey: string }> = {
2728
[ChainId.soneium]: { network: 'soneium-mainnet', apiKey: process.env.SONEIUM_RPC_API_KEY || '' },
2829
[ChainId.ink]: { network: 'ink-mainnet', apiKey: process.env.INK_RPC_API_KEY || '' },
2930
[ChainId.plasma]: { network: 'plasma-mainnet', apiKey: process.env.PLASMA_RPC_API_KEY || '' },
31+
[megaeth.id]: { network: 'megaeth-mainnet', apiKey: process.env.MEGAETH_RPC_API_KEY || '' },
32+
[mantle.id]: { network: 'mantle-mainnet', apiKey: process.env.MANTLE_RPC_API_KEY || '' },
3033

3134
// Testnets
3235
[ChainId.sepolia]: { network: 'eth-sepolia', apiKey: process.env.MAINNET_RPC_API_KEY || '' },

pages/api/sgho-apy.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
3030
endDate,
3131
});
3232

33-
res.status(200).json(result);
33+
return res.status(200).json(result);
3434
} catch (error) {
3535
console.error('API route error:', error);
3636

@@ -45,9 +45,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
4545
error: 'Failed to fetch data from external service',
4646
});
4747
}
48-
}
4948

50-
res.status(500).json({
51-
error: 'Internal server error',
52-
});
49+
return res.status(500).json({
50+
error: 'Internal server error',
51+
});
52+
}
5353
}

pages/api/support-create-ticket.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
5858
}
5959

6060
try {
61-
const { email, text, walletAddress } = req.body;
61+
const { email, text, walletAddress, country } = req.body;
62+
63+
const sanitizedCountry = typeof country === 'string' ? country.trim() : '';
6264

6365
if (!email || !text) {
6466
return res.status(400).json({ message: 'Email and text are required.' });
@@ -71,6 +73,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
7173
if (!text?.trim()) {
7274
return res.status(400).json({ error: 'Missing inquiry' });
7375
}
76+
7477
let sanitizedWalletAddress: string | undefined = undefined;
7578
if (walletAddress && typeof walletAddress === 'string') {
7679
const candidate = walletAddress.trim();
@@ -172,6 +175,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
172175
type: 'STRING',
173176
stringValue: sanitizedWalletAddress ?? '',
174177
},
178+
{
179+
key: 'webform_country',
180+
type: 'STRING',
181+
stringValue: sanitizedCountry,
182+
},
175183
],
176184
},
177185
};

0 commit comments

Comments
 (0)