Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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,
),
Comment thread
creed-victor marked this conversation as resolved.
},
},
};
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(',', '.');
Comment thread
creed-victor marked this conversation as resolved.
Outdated
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