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
6 changes: 3 additions & 3 deletions apps/indexer/src/app/plugins/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ const redisCachePlugin: FastifyPluginAsync<RedisCachePluginOptions> = async (
) => {
const redis = opts.redisClient ?? cacheRedisConnection;

const defaultTtl = opts.defaultTtlSeconds ?? 60;
const defaultStaleTtl = opts.defaultStaleTtlSeconds ?? 600; // 10 minutes
const defaultTtl = opts.defaultTtlSeconds ?? 10; // 10 seconds
const defaultStaleTtl = opts.defaultStaleTtlSeconds ?? 60; // 1 minute
const keyPrefix = opts.keyPrefix ?? 'route-cache';

// @ts-expect-error declare decorator
Expand Down Expand Up @@ -305,7 +305,7 @@ export const maybeCache = async <T = unknown>(

const redis = cacheRedisConnection;

const ttl = opts.ttlSeconds ?? 30; // 30 seconds
const ttl = opts.ttlSeconds ?? 10; // 10 seconds

const cacheKey = 'maybe-cache:fn:' + encode.sha256(key);

Expand Down
67 changes: 62 additions & 5 deletions apps/indexer/src/app/routes/_chain/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { client } from '../../../database/client';
import { tTokens } from '../../../database/schema';
import { tTokensSelectors } from '../../../database/selectors';
import {
fetchEmodeCategoryData,
fetchPoolList,
fetchPoolReserves,
fetchUserReserves,
Expand Down Expand Up @@ -112,6 +113,12 @@ export default async function (fastify: ZodFastifyInstance) {
pool,
);

const categories = await fetchEmodeCategoryData(
req.chain.chainId,
pool,
reservesData,
);

const tokens = await client.query.tTokens.findMany({
columns: tTokensSelectors.columns,
where: and(
Expand Down Expand Up @@ -157,13 +164,29 @@ export default async function (fastify: ZodFastifyInstance) {
.mul(100)
.toFixed(USD_DECIMALS),
canBeCollateral: item.usageAsCollateralEnabled,
stableBorrowRateEnabled: item.stableBorrowRateEnabled,
isActive: item.isActive,
isFroze: item.isFrozen,
// eModes: item.eModes,

eModeCategoryId: item.eModeCategoryId,
borrowCap: item.borrowCap.toString(),
supplyCap: item.supplyCap.toString(),
eModeLtv: item.eModeLtv,
eModeLiquidationThreshold: item.eModeLiquidationThreshold,
eModeLiquidationBonus: item.eModeLiquidationBonus,
eModePriceSource: item.eModePriceSource.toString(),
eModeLabel: item.eModeLabel.toString(),
};
});

return { data: { reservesData: items, baseCurrencyData } };
const eModes = categories.map((category) => ({
...category,
assets: category.assets.map((asset) => {
return tokens.find((t) => areAddressesEqual(t.address, asset));
}),
}));

return { data: { reservesData: items, baseCurrencyData, eModes } };
},
);

Expand Down Expand Up @@ -376,18 +399,48 @@ export default async function (fastify: ZodFastifyInstance) {
.mul(100)
.toFixed(USD_DECIMALS),
canBeCollateral: item.reserve.usageAsCollateralEnabled,
stableBorrowRateEnabled: item.reserve.stableBorrowRateEnabled,
isActive: item.reserve.isActive,
isFroze: item.reserve.isFrozen,
// eModes: item.reserve.eModes,

eModeCategoryId: item.reserve.eModeCategoryId,
borrowCap: item.reserve.borrowCap.toString(),
supplyCap: item.reserve.supplyCap.toString(),
eModeLtv: item.reserve.eModeLtv,
eModeLiquidationThreshold: item.reserve.eModeLiquidationThreshold,
eModeLiquidationBonus: item.reserve.eModeLiquidationBonus,
eModePriceSource: item.reserve.eModePriceSource.toString(),
eModeLabel: item.reserve.eModeLabel.toString(),
},
supplied: item.underlyingBalance,
suppliedUsd: item.underlyingBalanceUSD,
suppliedBalanceMarketReferenceCurrency: Decimal.from(
item.underlyingBalanceMarketReferenceCurrency,
baseCurrencyData.marketReferenceCurrencyDecimals,
).toFixed(USD_DECIMALS),

supplyApy: Decimal.from(item.reserve.supplyAPY).mul(100).toString(),
canToggleCollateral,

borrowed: item.variableBorrows,
borrowedUsd: item.variableBorrowsUSD,
borrowed: Decimal.from(item.totalBorrows).toString(),
borrowedUsd: Decimal.from(item.totalBorrowsUSD).toString(),
borrowedBalanceMarketReferenceCurrency: Decimal.from(
item.totalBorrowsMarketReferenceCurrency,
baseCurrencyData.marketReferenceCurrencyDecimals,
).toFixed(USD_DECIMALS),

borrowedStable: Decimal.from(item.stableBorrows).toString(),
borrowedStableUsd: Decimal.from(item.stableBorrowsUSD).toString(),
borrowedBalanceStableMarketReferenceCurrency: Decimal.from(
item.stableBorrowsMarketReferenceCurrency,
baseCurrencyData.marketReferenceCurrencyDecimals,
).toFixed(USD_DECIMALS),
borrowedVariable: Decimal.from(item.variableBorrows).toString(),
borrowedVariableUsd: Decimal.from(item.variableBorrowsUSD).toString(),
borrowedBalanceVariableMarketReferenceCurrency: Decimal.from(
item.variableBorrowsMarketReferenceCurrency,
baseCurrencyData.marketReferenceCurrencyDecimals,
).toFixed(USD_DECIMALS),

collateral: item.usageAsCollateralEnabledOnUser,

Expand Down Expand Up @@ -441,6 +494,10 @@ export default async function (fastify: ZodFastifyInstance) {
netWorthUsd: summary.netWorthUSD,
userEmodeCategoryId: summary.userEmodeCategoryId,
isInIsolationMode: summary.isInIsolationMode,

underlyingBalanceMarketReferenceCurrency: Decimal.from(
summary.totalBorrowsUSD,
),
},
},
};
Expand Down
98 changes: 98 additions & 0 deletions apps/indexer/src/libs/loaders/money-market.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Decimal } from '@sovryn/slayer-shared';
import { Address } from 'viem';
import { maybeCache } from '../../app/plugins/cache';
import { ChainId, chains, ChainSelector } from '../../configs/chains';
Expand Down Expand Up @@ -411,6 +412,55 @@ const uiPoolDataProviderAbi = [
},
] as const;

const poolAbi = [
{
inputs: [
{
internalType: 'uint8',
name: 'id',
type: 'uint8',
},
],
name: 'getEModeCategoryData',
outputs: [
{
components: [
{
internalType: 'uint16',
name: 'ltv',
type: 'uint16',
},
{
internalType: 'uint16',
name: 'liquidationThreshold',
type: 'uint16',
},
{
internalType: 'uint16',
name: 'liquidationBonus',
type: 'uint16',
},
{
internalType: 'address',
name: 'priceSource',
type: 'address',
},
{
internalType: 'string',
name: 'label',
type: 'string',
},
],
internalType: 'struct DataTypes.EModeCategory',
name: '',
type: 'tuple',
},
],
stateMutability: 'view',
type: 'function',
},
] as const;

export type PoolDefinition = {
id: string | 'default';
name: string;
Expand Down Expand Up @@ -700,3 +750,51 @@ export async function fetchUserReserves(
userEmodeCategoryId,
};
}

export async function fetchEmodeCategoryData(
chainId: ChainSelector,
pool: PoolDefinition,
reserves: Awaited<ReturnType<typeof fetchPoolReserves>>['reservesData'],
) {
const chain = chains.get(chainId);
if (!chain) {
throw new Error(`Unsupported chain: ${chainId}`);
}

const categoryIds = Array.from(
new Set(reserves.map((reserve) => reserve.eModeCategoryId)),
).filter((id) => id !== 0);

const results = await chain.rpc.multicall({
contracts: categoryIds.map((id) => ({
address: pool.address,
abi: poolAbi,
functionName: 'getEModeCategoryData',
args: [id],
})),
});

return results
.map(({ result }, index) => {
if (!result) {
return null;
}

const { ltv, liquidationThreshold, liquidationBonus, label } = result;
const categoryId = categoryIds[index];

return {
id: categoryId,
ltv: Decimal.from(ltv).div(100).toString(),
liquidationThreshold: Decimal.from(liquidationThreshold)
.div(100)
.toString(),
liquidationBonus: Decimal.from(liquidationBonus).div(100).toString(),
label,
assets: reserves
.filter((reserve) => reserve.eModeCategoryId === categoryId)
.map((reserve) => reserve.underlyingAsset.toLowerCase()),
};
})
.filter((item) => item != null);
}
12 changes: 11 additions & 1 deletion apps/web-app/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,15 @@
"confirm": "Confirm",
"continue": "Continue",
"abort": "Abort",
"loading": "Loading..."
"loading": "Loading...",
"tx": {
"title": "Transaction Confirmation",
"description": "Please review and confirm transactions in your wallet",
"preparing": "Preparing transaction...",
"connectWallet": "Connect your wallet to proceed.",
"switchNetwork": "Switch to {{name}} network",
"signMessage": "Sign Message",
"signTypedData": "Sign Typed Data",
"sendTransaction": "Send Transaction"
}
}
10 changes: 0 additions & 10 deletions apps/web-app/public/locales/en/tx.json

This file was deleted.

2 changes: 0 additions & 2 deletions apps/web-app/src/@types/i18next.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { resources as common } from 'public/locales/en/common';
import type { resources as glossary } from 'public/locales/en/glossary';
import type { resources as tx } from 'public/locales/en/tx';
import type { resources as validation } from 'public/locales/en/validation';
import { defaultNS } from '../i18n';

Expand All @@ -12,7 +11,6 @@ declare module 'i18next' {
common: typeof common;
glossary: typeof glossary;
validation: typeof validation;
tx: typeof tx;
};
}
}
16 changes: 16 additions & 0 deletions apps/web-app/src/@types/react-query.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import '@tanstack/react-query';

interface GlobalQueryMeta extends Record<string, unknown> {
revalidateCache?: boolean;
}

interface GlobalMutationMeta extends Record<string, unknown> {
invalidates?: Array<QueryKey>;
}

declare module '@tanstack/react-query' {
interface Register {
queryMeta: GlobalQueryMeta;
mutationMeta: GlobalMutationMeta;
}
}
15 changes: 10 additions & 5 deletions apps/web-app/src/components/FormComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ import { Checkbox } from './ui/checkbox';
import { Field, FieldDescription, FieldError, FieldLabel } from './ui/field';
import { InputGroup, InputGroupAddon, InputGroupInput } from './ui/input-group';

export function SubscribeButton({ label }: { label: string }) {
export function SubscribeButton({
label,
disabled,
}: {
label: string;
disabled?: boolean;
}) {
const form = useFormContext();
return (
<form.Subscribe
Expand All @@ -27,7 +33,7 @@ export function SubscribeButton({ label }: { label: string }) {
{([isSubmitting, isFormValid]) => (
<Button
type="submit"
disabled={isSubmitting || !isFormValid}
disabled={isSubmitting || !isFormValid || disabled}
form={form.formId}
>
<Loader2Icon
Expand Down Expand Up @@ -272,8 +278,9 @@ export function AmountField({
);

const handleChange = (input: string) => {
const value = input.replace(/,/g, '.');
setRenderedValue(input);
field.setValue(tryDecimalValue(input) as never, {
field.setValue(tryDecimalValue(value) as never, {
dontRunListeners: true,
});
};
Expand Down Expand Up @@ -331,8 +338,6 @@ export function AmountField({
placeholder={placeholder}
onBlur={field.handleBlur}
onChange={(e) => handleChange(e.target.value)}
type="number"
step="0.00001"
/>
{addonRight && (
<InputGroupAddon align="inline-end">{addonRight}</InputGroupAddon>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { Accordion } from '@/components/ui/accordion';
import { Alert, AlertDescription } from '@/components/ui/alert';
import type { MoneyMarketPoolReserve } from '@sovryn/slayer-sdk';
import { CircleAlert } from 'lucide-react';
import { useState, type FC } from 'react';
import { AssetsTable } from './components/AssetsTable/AssetsTable';

type BorrowAssetsListProps = {
borrowAssets: MoneyMarketPoolReserve[];
eModesCategoryId?: number;
loading?: boolean;
};

export const BorrowAssetsList: FC<BorrowAssetsListProps> = ({
borrowAssets,
eModesCategoryId,
}) => {
const [open, setOpen] = useState(true);

return (
<Accordion
label={<span className="text-[1rem] font-medium">Assets to borrow</span>}
Expand All @@ -21,6 +24,16 @@ export const BorrowAssetsList: FC<BorrowAssetsListProps> = ({
open={open}
onClick={setOpen}
>
{!!eModesCategoryId && (
<Alert>
<CircleAlert />
<AlertDescription>
In E-Mode some assets are not borrowable. Exit E-Mode to get access
to all assets.
</AlertDescription>
</Alert>
)}

<AssetsTable assets={borrowAssets} />
</Accordion>
);
Expand Down
Loading
Loading