diff --git a/packages/marginfi-v2-ui-state/src/lib/mrgnlend.ts b/packages/marginfi-v2-ui-state/src/lib/mrgnlend.ts index 83cd083f75..7a62d79d6b 100644 --- a/packages/marginfi-v2-ui-state/src/lib/mrgnlend.ts +++ b/packages/marginfi-v2-ui-state/src/lib/mrgnlend.ts @@ -158,15 +158,14 @@ export async function fetchBirdeyePrices(mints: PublicKey[], apiKey?: string): P throw new Error("Failed to fetch price"); } -export async function fetchEmissionsPriceMap( - banks: Bank[], - connection: Connection, +export async function makeExtendedBankEmission( + banks: ExtendedBankInfo[], + extendedBankMetadatas: ExtendedBankMetadata[], + tokenMap: TokenPriceMap, apiKey?: string -): Promise { - const banksWithEmissions = banks.filter((bank) => !bank.emissionsMint.equals(PublicKey.default)); - const emissionsMints = banksWithEmissions.map((bank) => bank.emissionsMint); - - let birdeyePrices = emissionsMints.map((m) => new BigNumber(0)); +): Promise<[ExtendedBankInfo[], ExtendedBankMetadata[]]> { + const emissionsMints = Object.keys(tokenMap).map((key) => new PublicKey(key)); + let birdeyePrices = emissionsMints.map(() => new BigNumber(0)); try { birdeyePrices = await fetchBirdeyePrices(emissionsMints, apiKey); @@ -174,12 +173,60 @@ export async function fetchEmissionsPriceMap( console.log("Failed to fetch emissions prices from Birdeye", err); } + emissionsMints.map((mint, idx) => { + tokenMap[mint.toBase58()] = { ...tokenMap[mint.toBase58()], price: birdeyePrices[idx] }; + }); + + const updatedBanks = banks.map((bank) => { + const rawBank = bank.info.rawBank; + const emissionTokenData = tokenMap[rawBank.emissionsMint.toBase58()]; + let emissionsRate: number = 0; + let emissions = Emissions.Inactive; + if ((rawBank.emissionsActiveLending || rawBank.emissionsActiveBorrowing) && emissionTokenData) { + const emissionsRateAmount = new BigNumber(nativeToUi(rawBank.emissionsRate, emissionTokenData.decimals)); + const emissionsRateValue = emissionsRateAmount.times(emissionTokenData.price); + const emissionsRateAdditionalyApy = emissionsRateValue.div(bank.info.oraclePrice.price); + + emissionsRate = emissionsRateAdditionalyApy.toNumber(); + + if (rawBank.emissionsActiveBorrowing) { + emissions = Emissions.Borrowing; + } else if (rawBank.emissionsActiveLending) { + emissions = Emissions.Lending; + } + + bank.info.state = { + ...bank.info.state, + emissionsRate, + emissions, + }; + } + return bank; + }); + + const sortedExtendedBankInfos = updatedBanks.sort( + (a, b) => b.info.state.totalDeposits * b.info.state.price - a.info.state.totalDeposits * a.info.state.price + ); + + const sortedExtendedBankMetadatas = extendedBankMetadatas.sort((am, bm) => { + const a = sortedExtendedBankInfos.find((a) => a.address.equals(am.address))!; + const b = sortedExtendedBankInfos.find((b) => b.address.equals(bm.address))!; + return b.info.state.totalDeposits * b.info.state.price - a.info.state.totalDeposits * a.info.state.price; + }); + + return [sortedExtendedBankInfos, sortedExtendedBankMetadatas]; +} + +export async function makeEmissionsPriceMap(banks: Bank[], connection: Connection): Promise { + const banksWithEmissions = banks.filter((bank) => !bank.emissionsMint.equals(PublicKey.default)); + const emissionsMints = banksWithEmissions.map((bank) => bank.emissionsMint); + const mintAis = await connection.getMultipleAccountsInfo(emissionsMints); const mint = mintAis.map((ai) => MintLayout.decode(ai!.data)); const emissionsPrices = banksWithEmissions.map((bank, i) => ({ mint: bank.emissionsMint, - price: birdeyePrices[i], + price: new BigNumber(0), decimals: mint[0].decimals, })); diff --git a/packages/marginfi-v2-ui-state/src/store/mrgnlendStore.ts b/packages/marginfi-v2-ui-state/src/store/mrgnlendStore.ts index 3ee7b7cf0a..1c3649cfe4 100644 --- a/packages/marginfi-v2-ui-state/src/store/mrgnlendStore.ts +++ b/packages/marginfi-v2-ui-state/src/store/mrgnlendStore.ts @@ -12,7 +12,7 @@ import { Bank, OraclePrice } from "@mrgnlabs/marginfi-client-v2"; import { Connection, PublicKey } from "@solana/web3.js"; import { DEFAULT_ACCOUNT_SUMMARY, - fetchEmissionsPriceMap, + makeEmissionsPriceMap, computeAccountSummary, fetchTokenAccounts, makeExtendedBankInfo, @@ -21,6 +21,7 @@ import { TokenAccountMap, ExtendedBankMetadata, makeExtendedBankMetadata, + makeExtendedBankEmission, } from "../lib"; import { getPointsSummary } from "../lib/points"; import { create, StateCreator } from "zustand"; @@ -131,7 +132,7 @@ const stateCreator: StateCreator = (set, get) => ({ const banks = [...marginfiClient.banks.values()]; const birdEyeApiKey = args?.birdEyeApiKey ?? get().birdEyeApiKey; - const priceMap = await fetchEmissionsPriceMap(banks, connection, birdEyeApiKey); + const priceMap = await makeEmissionsPriceMap(banks, connection); let nativeSolBalance: number = 0; let tokenAccountMap: TokenAccountMap; @@ -252,7 +253,7 @@ const stateCreator: StateCreator = (set, get) => ({ accountSummary = computeAccountSummary(selectedAccount, extendedBankInfos); } - const pointSummary = await getPointsSummary(); + const pointsTotal = get().protocolStats.pointsTotal; set({ initialized: true, @@ -268,13 +269,31 @@ const stateCreator: StateCreator = (set, get) => ({ deposits, borrows, tvl: deposits - borrows, - pointsTotal: pointSummary.points_total, + pointsTotal: pointsTotal, }, selectedAccount, nativeSolBalance, accountSummary, birdEyeApiKey, }); + + const pointSummary = await getPointsSummary(); + + set({ + protocolStats: { deposits, borrows, tvl: deposits - borrows, pointsTotal: pointSummary.points_total }, + }); + + const [sortedExtendedBankEmission, sortedExtendedBankMetadatasEmission] = await makeExtendedBankEmission( + sortedExtendedBankInfos, + sortedExtendedBankMetadatas, + priceMap, + birdEyeApiKey + ); + + set({ + extendedBankInfos: sortedExtendedBankEmission, + extendedBankMetadatas: sortedExtendedBankMetadatasEmission, + }); } catch (err) { console.error("error refreshing state: ", err); set({ isRefreshingStore: false });