Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
114328f
refactor: sdk integrated in market page
AGMASO Sep 26, 2025
940cdf4
chore: clean code
AGMASO Sep 26, 2025
fcb1a39
fix: simplified icon fetch logic & clean code
AGMASO Sep 29, 2025
92eeffd
fix: build error
AGMASO Sep 29, 2025
a80c04b
fix: build error
AGMASO Sep 29, 2025
4a5e1fe
fix: build error
AGMASO Sep 29, 2025
eff6ed6
chore: clean code
AGMASO Sep 30, 2025
8653eb9
chore: clean code
AGMASO Sep 30, 2025
75769d3
refactor: integrate sdk into reserve-overview. missing few flags from…
AGMASO Oct 3, 2025
be28f80
fix: show disabled only for > 0 amounts
AGMASO Oct 3, 2025
c4d503f
Merge branch 'refactor/sdk-in-markets' into refactor/reserve-overview…
AGMASO Oct 3, 2025
9f5d624
fix: solved issue on tokenIcons in reserve-overview page
AGMASO Oct 6, 2025
47ec420
fix: clean code
AGMASO Oct 6, 2025
18dadae
fix: clean code
AGMASO Oct 6, 2025
27eb9b8
fix: clean code
AGMASO Oct 6, 2025
8f7da60
chore: clean code
AGMASO Oct 7, 2025
2e502e9
feat: added interest Rate Strategy Address to link, after updated sdk
AGMASO Oct 8, 2025
d3d3e45
fix: use typescript guards
AGMASO Oct 10, 2025
3610842
fix: simplified code
AGMASO Oct 10, 2025
4e83b97
refactor: move incentives calculation to parent component
AGMASO Oct 10, 2025
de6b877
chore: clean code
AGMASO Oct 13, 2025
cdc1ae9
Merge branch 'refactor/sdk-in-markets' into refactor/reserve-overview…
AGMASO Oct 13, 2025
98b4714
refactor: wip supply assets list finished with sdk
AGMASO Oct 14, 2025
9292a2f
refactor: wip supplies positions listo, aun pequenos fallos
AGMASO Oct 15, 2025
9d13c1b
refactor: wip your borrows terminado perfecto
AGMASO Oct 16, 2025
59326b7
refactor: only dashboard top panel left
AGMASO Oct 17, 2025
abff5a8
refactor: only dashboard top panel left
AGMASO Oct 17, 2025
94b2eb9
refactor: refactored dashboard with sdk
AGMASO Oct 20, 2025
f8fa340
feat: added Pts-ethena tokens to mapping
AGMASO Oct 21, 2025
5b6f0ee
chore: trigger rebuild
AGMASO Oct 21, 2025
7b35f28
Merge remote-tracking branch 'origin/refactor/sdk-in-markets' into re…
AGMASO Oct 21, 2025
3a9fc62
chore: clean code
AGMASO Oct 21, 2025
d8b34d3
chore: clean code
AGMASO Oct 21, 2025
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: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
},
"dependencies": {
"@aave/contract-helpers": "1.36.1",
"@aave/graphql": "^0.7.0",
"@aave/math-utils": "1.36.1",
"@aave/react": "0.6.1",
"@aave/react": "^0.7.0",
"@amplitude/analytics-browser": "^2.13.0",
"@bgd-labs/aave-address-book": "^4.31.0",
"@bgd-labs/aave-address-book": "^4.34.1",
"@cowprotocol/app-data": "^3.1.0",
"@cowprotocol/cow-sdk": "6.0.0-RC.47",
"@emotion/cache": "11.10.3",
Expand Down
28 changes: 19 additions & 9 deletions pages/reserve-overview.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import StyledToggleButton from 'src/components/StyledToggleButton';
import StyledToggleButtonGroup from 'src/components/StyledToggleButtonGroup';
import {
ComputedReserveData,
ReserveWithId,
useAppDataContext,
} from 'src/hooks/app-data-provider/useAppDataProvider';
import { AssetCapsProvider } from 'src/hooks/useAssetCaps';
import { AssetCapsProviderSDK } from 'src/hooks/useAssetCapsSDK';
import { MainLayout } from 'src/layouts/MainLayout';
import { ReserveActions } from 'src/modules/reserve-overview/ReserveActions';
import { ReserveConfigurationWrapper } from 'src/modules/reserve-overview/ReserveConfigurationWrapper';
Expand Down Expand Up @@ -44,23 +46,28 @@ const UnStakeModal = dynamic(() =>

export default function ReserveOverview() {
const router = useRouter();
const { reserves } = useAppDataContext();
const { supplyReserves, reserves } = useAppDataContext();
const underlyingAsset = router.query.underlyingAsset as string;

const [mode, setMode] = useState<'overview' | 'actions' | ''>('overview');
const trackEvent = useRootStore((store) => store.trackEvent);

const reserve = reserves.find(
(reserve) => reserve.underlyingAsset === underlyingAsset
) as ComputedReserveData;
//With SDK
const reserve = supplyReserves.find((reserve) => {
return reserve.underlyingToken.address.toLowerCase() === underlyingAsset?.toLowerCase();
}) as ReserveWithId;

//With Reserves
const reserveLegacy = reserves.find((reserve) => {
return reserve.underlyingAsset.toLowerCase() === underlyingAsset?.toLowerCase();
}) as ComputedReserveData;
const [pageEventCalled, setPageEventCalled] = useState(false);

useEffect(() => {
if (!pageEventCalled && reserve && reserve.iconSymbol && underlyingAsset) {
if (!pageEventCalled && reserve && reserve.underlyingToken.symbol && underlyingAsset) {
trackEvent('Page Viewed', {
'Page Name': 'Reserve Overview',
Reserve: reserve.iconSymbol,
Reserve: reserve.underlyingToken.symbol,
Asset: underlyingAsset,
});
setPageEventCalled(true);
Expand All @@ -70,7 +77,7 @@ export default function ReserveOverview() {
const isOverview = mode === 'overview';

return (
<AssetCapsProvider asset={reserve}>
<AssetCapsProviderSDK asset={reserve}>
<ReserveTopDetailsWrapper underlyingAsset={underlyingAsset} />

<ContentContainer>
Expand Down Expand Up @@ -120,11 +127,14 @@ export default function ReserveOverview() {
width: { xs: '100%', lg: '416px' },
}}
>
<ReserveActions reserve={reserve} />
{/* Wrapped in AssetCapsProvider to provide the data using legacy method to avoid braking actions */}
<AssetCapsProvider asset={reserveLegacy}>
<ReserveActions reserve={reserveLegacy} />
</AssetCapsProvider>
</Box>
</Box>
</ContentContainer>
</AssetCapsProvider>
</AssetCapsProviderSDK>
);
}

Expand Down
55 changes: 55 additions & 0 deletions src/components/incentives/incentives.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { AaveBorrowIncentive, AaveSupplyIncentive, ReserveIncentive } from '@aave/graphql';
import type { ReserveIncentiveResponse } from '@aave/math-utils/dist/esm/formatters/incentive/calculate-reserve-incentives';

//Typescript GUARDS
const isAaveSupplyIncentive = (incentive: ReserveIncentive): incentive is AaveSupplyIncentive => {
return incentive.__typename === 'AaveSupplyIncentive';
};

const isAaveBorrowIncentive = (incentive: ReserveIncentive): incentive is AaveBorrowIncentive => {
return incentive.__typename === 'AaveBorrowIncentive';
};

export const isAaveProtocolIncentive = (incentive: ReserveIncentive): boolean => {
return isAaveSupplyIncentive(incentive) || isAaveBorrowIncentive(incentive);
};

export const getIncentiveAPR = (incentive: ReserveIncentive): string => {
// For AaveSupplyIncentive
if (isAaveSupplyIncentive(incentive) && incentive.extraSupplyApr?.value) {
return incentive.extraSupplyApr.value.toString();
}

// For AaveBorrowIncentive
if (isAaveBorrowIncentive(incentive) && incentive.borrowAprDiscount?.value) {
return incentive.borrowAprDiscount.value.toString();
}

// Fallback for previous structure)
if ('incentiveAPR' in incentive) {
return String(incentive.incentiveAPR);
}

return '0';
};

// Mapping sdk structure to legacy structure used in incentives card logic
export const mapAaveProtocolIncentives = (
incentives: ReserveIncentive[] | undefined,
direction: 'supply' | 'borrow'
): ReserveIncentiveResponse[] => {
if (!incentives || incentives.length === 0) {
return [];
}

const typedIncentives =
direction === 'supply'
? incentives.filter(isAaveSupplyIncentive)
: incentives.filter(isAaveBorrowIncentive);

return typedIncentives.map((incentive) => ({
incentiveAPR: getIncentiveAPR(incentive),
rewardTokenAddress: incentive.rewardTokenAddress,
rewardTokenSymbol: incentive.rewardTokenSymbol,
}));
};
9 changes: 6 additions & 3 deletions src/components/lists/ListMobileItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Divider, Skeleton, Typography } from '@mui/material';
import { ReactNode } from 'react';
import { IsolatedEnabledBadge } from 'src/components/isolationMode/IsolatedBadge';
import { useAssetCaps } from 'src/hooks/useAssetCaps';
import { useAssetCapsSDK } from 'src/hooks/useAssetCapsSDK';
import { CustomMarket } from 'src/ui-config/marketsConfig';

import { Link, ROUTES } from '../primitives/Link';
Expand All @@ -20,6 +20,7 @@ interface ListMobileItemProps {
showBorrowCapTooltips?: boolean;
showDebtCeilingTooltips?: boolean;
isIsolated: boolean;
onIconError?: () => void;
}

export const ListMobileItem = ({
Expand All @@ -35,8 +36,9 @@ export const ListMobileItem = ({
showBorrowCapTooltips = false,
showDebtCeilingTooltips = false,
isIsolated,
onIconError,
}: ListMobileItemProps) => {
const { supplyCap, borrowCap, debtCeiling } = useAssetCaps();
const { supplyCap, borrowCap, debtCeiling } = useAssetCapsSDK();
return (
<Box>
<Divider />
Expand All @@ -59,7 +61,7 @@ export const ListMobileItem = ({
href={ROUTES.reserveOverview(underlyingAsset, currentMarket)}
sx={{ display: 'inline-flex', alignItems: 'center' }}
>
<TokenIcon symbol={iconSymbol} sx={{ fontSize: '40px' }} />
<TokenIcon symbol={iconSymbol} sx={{ fontSize: '40px' }} onError={onIconError} />
<Box sx={{ ml: 2 }}>
<Typography variant="h4">{name}</Typography>
<Box display="flex" alignItems="center">
Expand All @@ -73,6 +75,7 @@ export const ListMobileItem = ({
)}
</Box>
</Box>

{showSupplyCapTooltips && supplyCap.displayMaxedTooltip({ supplyCap })}
{showBorrowCapTooltips && borrowCap.displayMaxedTooltip({ borrowCap })}
{showDebtCeilingTooltips && debtCeiling.displayMaxedTooltip({ debtCeiling })}
Expand Down
93 changes: 91 additions & 2 deletions src/hooks/app-data-provider/useAppDataProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import type {
EmodeMarketCategory,
Market,
MarketUserReserveBorrowPosition,
MarketUserReserveSupplyPosition,
MarketUserState,
PercentValue,
Reserve,
TokenAmount,
} from '@aave/graphql';
import { UserReserveData } from '@aave/math-utils';
import { client } from 'pages/_app.page';
import React, { PropsWithChildren, useContext } from 'react';
import { EmodeCategory } from 'src/helpers/types';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
Expand All @@ -16,6 +27,9 @@ import {
import { usePoolReservesHumanized } from '../pool/usePoolReserves';
import { useUserPoolReservesHumanized } from '../pool/useUserPoolReserves';
import { FormattedUserReserves } from '../pool/useUserSummaryAndIncentives';
import { useMarketsData } from './useMarketsData';
import { useUserBorrows } from './useUserBorrows';
import { useUserSupplies } from './useUserSupplies';

/**
* removes the marketPrefix from a symbol
Expand All @@ -40,9 +54,28 @@ export type ComputedUserReserveData = FormattedUserReserves;
* @deprecated Use ExtendedFormattedUser type from useExtendedUserSummaryAndIncentives hook
*/
export type ExtendedFormattedUser = _ExtendedFormattedUser;

export type ReserveWithId = Reserve & {
id: string;
supplyAPY?: number;
borrowAPY?: number;
underlyingBalance?: string;
usageAsCollateralEnabledOnUser?: boolean;
isCollateralPosition?: boolean;
apyPosition?: PercentValue;
balancePosition?: TokenAmount;
};
export interface AppDataContextType {
loading: boolean;
/** SDK market snapshot */
market?: Market;
totalBorrows?: number;
supplyReserves: ReserveWithId[];
borrowReserves: ReserveWithId[];
eModeCategories: EmodeMarketCategory[];
userState?: MarketUserState;
userSupplies?: MarketUserReserveSupplyPosition[];
userBorrows?: MarketUserReserveBorrowPosition[];
/** Legacy fields (deprecated) kept temporarily for incremental migration */
reserves: ComputedReserveData[];
eModes: Record<number, EmodeCategory>;
user?: ExtendedFormattedUser;
Expand All @@ -62,6 +95,46 @@ export const AppDataProvider: React.FC<PropsWithChildren> = ({ children }) => {

const currentMarketData = useRootStore((state) => state.currentMarketData);

const { data, isPending } = useMarketsData({
client,
marketData: currentMarketData,
account: currentAccount,
});

const { data: userSuppliesData, isPending: userSuppliesLoading } = useUserSupplies({
client,
marketData: currentMarketData,
account: currentAccount,
});

const { data: userBorrowsData, isPending: userBorrowsLoading } = useUserBorrows({
client,
marketData: currentMarketData,
account: currentAccount,
});

const marketAddress = currentMarketData.addresses.LENDING_POOL.toLowerCase();

const sdkMarket = data?.find((item) => item.address.toLowerCase() === marketAddress);

const totalBorrows = sdkMarket?.borrowReserves.reduce((acc, reserve) => {
const value = reserve.borrowInfo?.total?.usd ?? 0;
return acc + Number(value);
}, 0);

const supplyReserves = (sdkMarket?.supplyReserves ?? []).map((reserve) => ({
...reserve,
id: `${sdkMarket?.address}-${reserve.underlyingToken.address}`,
}));

const borrowReserves = (sdkMarket?.borrowReserves ?? []).map((reserve) => ({
...reserve,
id: `${sdkMarket?.address}-${reserve.underlyingToken.address}`,
}));

const eModeCategories = sdkMarket?.eModeCategories ?? [];
const marketUserState = sdkMarket?.userState ?? undefined;

const { data: reservesData, isPending: reservesDataLoading } =
usePoolReservesHumanized(currentMarketData);
const { data: formattedPoolReserves, isPending: formattedPoolReservesLoading } =
Expand All @@ -81,10 +154,26 @@ export const AppDataProvider: React.FC<PropsWithChildren> = ({ children }) => {
const isReservesLoading = reservesDataLoading || formattedPoolReservesLoading;
const isUserDataLoading = userReservesDataLoading || userSummaryLoading;

const loading =
isPending ||
userSuppliesLoading ||
userBorrowsLoading ||
isReservesLoading ||
(!!currentAccount && isUserDataLoading);

return (
<AppDataContext.Provider
value={{
loading: isReservesLoading || (!!currentAccount && isUserDataLoading),
loading,
market: sdkMarket,
totalBorrows,
supplyReserves,
borrowReserves,
eModeCategories,
userState: marketUserState,
userSupplies: userSuppliesData,
userBorrows: userBorrowsData,
// Legacy fields (to be removed once consumers migrate)
reserves: formattedPoolReserves || [],
eModes,
user: userSummary,
Expand Down
38 changes: 38 additions & 0 deletions src/hooks/app-data-provider/useMarketsData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AaveClient, chainId, evmAddress, OrderDirection } from '@aave/client';
import { markets } from '@aave/client/actions';
import { useQuery } from '@tanstack/react-query';
import { MarketDataType } from 'src/ui-config/marketsConfig';
import { queryKeysFactory } from 'src/ui-config/queries';

type UseMarketsDataParams = {
client: AaveClient;
marketData: MarketDataType;
account?: string | null;
};

export const useMarketsData = ({ client, marketData, account }: UseMarketsDataParams) => {
const userAddress = account ? evmAddress(account) : undefined;
const marketKey = [
...queryKeysFactory.market(marketData),
...queryKeysFactory.user(userAddress ?? 'anonymous'),
];

return useQuery({
queryKey: marketKey,
enabled: !!client,
queryFn: async () => {
const response = await markets(client, {
chainIds: [chainId(marketData.chainId)],
user: userAddress,
suppliesOrderBy: { tokenName: OrderDirection.Asc },
borrowsOrderBy: { tokenName: OrderDirection.Asc },
});

if (response.isErr()) {
throw response.error;
}

return response.value;
},
});
};
39 changes: 39 additions & 0 deletions src/hooks/app-data-provider/useUserBorrows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { AaveClient, chainId, evmAddress, OrderDirection } from '@aave/client';
import { userBorrows } from '@aave/client/actions';
import { useQuery } from '@tanstack/react-query';
import { MarketDataType } from 'src/ui-config/marketsConfig';
import { queryKeysFactory } from 'src/ui-config/queries';

type UseUserBorrowsDataParams = {
client: AaveClient;
marketData: MarketDataType;
account?: string | null;
};

export const useUserBorrows = ({ client, marketData, account }: UseUserBorrowsDataParams) => {
const userAddress = account ? evmAddress(account) : undefined;

return useQuery({
queryKey: [
...queryKeysFactory.market(marketData),
...queryKeysFactory.user(userAddress ?? 'anonymous'),
'userBorrows',
],
enabled: !!client && !!userAddress,
queryFn: async () => {
const response = await userBorrows(client, {
markets: [
{
chainId: chainId(marketData.chainId),
address: evmAddress(marketData.addresses.LENDING_POOL),
},
],
user: userAddress!,
orderBy: { debt: OrderDirection.Asc },
});

if (response.isErr()) throw response.error;
return response.value;
},
});
};
Loading