diff --git a/src/typescript/frontend/src/app/home/HomePage.tsx b/src/typescript/frontend/src/app/home/HomePage.tsx index 870c3b6f0..40593916d 100644 --- a/src/typescript/frontend/src/app/home/HomePage.tsx +++ b/src/typescript/frontend/src/app/home/HomePage.tsx @@ -1,11 +1,16 @@ import { ARENA_MODULE_ADDRESS } from "@sdk/const"; -import type { ArenaInfoModel, MarketStateModel, DatabaseModels } from "@sdk/indexer-v2/types"; +import { + type ArenaInfoModel, + type MarketStateModel, + type DatabaseModels, +} from "@sdk/indexer-v2/types"; import { ArenaCard } from "components/pages/home/components/arena-card"; import EmojiTable from "components/pages/home/components/emoji-table"; import MainCard from "components/pages/home/components/main-card/MainCard"; import { PriceFeed } from "components/price-feed"; import TextCarousel from "components/text-carousel/TextCarousel"; import { type MarketDataSortByHomePage } from "lib/queries/sorting/types"; +import { toAptLockedFromProps } from "./utils"; export interface HomePageProps { markets: Array; @@ -43,7 +48,7 @@ export default async function HomePageComponent({ market1Symbol={meleeData.market1.market.symbolEmojis.join("")} rewardsRemaining={meleeData.melee.rewardsRemaining} meleeVolume={meleeData.melee.volume} - aptLocked={meleeData.melee.aptLocked} + aptLocked={toAptLockedFromProps(meleeData)} startTime={meleeData.melee.startTime} duration={meleeData.melee.duration / 1000n / 1000n} /> diff --git a/src/typescript/frontend/src/app/home/utils.ts b/src/typescript/frontend/src/app/home/utils.ts new file mode 100644 index 000000000..bc38863c7 --- /dev/null +++ b/src/typescript/frontend/src/app/home/utils.ts @@ -0,0 +1,14 @@ +import { toTotalAptLocked } from "@sdk/indexer-v2/types"; +import { type HomePageProps } from "./HomePage"; + +export const toAptLockedFromProps = (meleeData: Exclude) => + toTotalAptLocked({ + market0: { + state: meleeData.market0.state, + locked: meleeData.melee.emojicoin0Locked, + }, + market1: { + state: meleeData.market1.state, + locked: meleeData.melee.emojicoin1Locked, + }, + }); diff --git a/src/typescript/sdk/src/indexer-v2/types/index.ts b/src/typescript/sdk/src/indexer-v2/types/index.ts index 32157f160..6272438e9 100644 --- a/src/typescript/sdk/src/indexer-v2/types/index.ts +++ b/src/typescript/sdk/src/indexer-v2/types/index.ts @@ -30,6 +30,7 @@ import { toAccountAddressString } from "../../utils"; import Big from "big.js"; import { q64ToBig } from "../../utils/nominal-price"; import { type AnyArenaEvent } from "../../types/arena-types"; +import { calculateCurvePrice, type ReservesAndBondingCurveState } from "../../markets"; export type TransactionMetadata = { version: bigint; @@ -152,6 +153,7 @@ const toArenaExitFromDatabase = ( tapOutFee: BigInt(data.tap_out_fee), emojicoin0Proceeds: BigInt(data.emojicoin_0_proceeds), emojicoin1Proceeds: BigInt(data.emojicoin_1_proceeds), + aptProceeds: BigInt(data.apt_proceeds), emojicoin0ExchangeRateBase: BigInt(data.emojicoin_0_exchange_rate_base), emojicoin0ExchangeRateQuote: BigInt(data.emojicoin_0_exchange_rate_quote), emojicoin1ExchangeRateBase: BigInt(data.emojicoin_1_exchange_rate_base), @@ -207,11 +209,33 @@ const toArenaLeaderboardFromDatabase = ( withdrawals: BigInt(data.withdrawals), }); +const toAptLocked = (reserves: ReservesAndBondingCurveState, locked: bigint) => { + const curvePrice = calculateCurvePrice(reserves); + const bigLocked = Big(locked.toString()); + const roundedResult = curvePrice.mul(bigLocked).round(0, Big.roundHalfEven); + return BigInt(roundedResult.toString()); +}; + +export const toTotalAptLocked = (args: { + market0: { + state: MarketStateModel["state"]; + locked: ArenaInfoModel["emojicoin0Locked"]; + }; + market1: { + state: MarketStateModel["state"]; + locked: ArenaInfoModel["emojicoin1Locked"]; + }; +}): bigint => { + const { market0, market1 } = args; + return toAptLocked(market0.state, market0.locked) + toAptLocked(market1.state, market1.locked); +}; + const toArenaInfoFromDatabase = (data: DatabaseStructType["ArenaInfo"]): Types["ArenaInfo"] => ({ meleeID: BigInt(data.melee_id), volume: BigInt(data.volume), rewardsRemaining: BigInt(data.rewards_remaining), - aptLocked: BigInt(data.apt_locked), + emojicoin0Locked: BigInt(data.emojicoin_0_locked), + emojicoin1Locked: BigInt(data.emojicoin_1_locked), emojicoin0MarketAddress: toAccountAddressString(data.emojicoin_0_market_address), emojicoin0Symbols: data.emojicoin_0_symbols, emojicoin0MarketID: BigInt(data.emojicoin_0_market_id), diff --git a/src/typescript/sdk/src/indexer-v2/types/json-types.ts b/src/typescript/sdk/src/indexer-v2/types/json-types.ts index 963cf72f1..9b89b87e3 100644 --- a/src/typescript/sdk/src/indexer-v2/types/json-types.ts +++ b/src/typescript/sdk/src/indexer-v2/types/json-types.ts @@ -269,7 +269,9 @@ type ArenaMeleeEventData = Flatten< >; type ArenaEnterEventData = FlattenedExchangeRateWithEventIndex<"ArenaEnterEvent">; -type ArenaExitEventData = FlattenedExchangeRateWithEventIndex<"ArenaExitEvent">; +type ArenaExitEventData = FlattenedExchangeRateWithEventIndex<"ArenaExitEvent"> & { + apt_proceeds: Uint64String; +}; type ArenaSwapEventData = FlattenedExchangeRateWithEventIndex<"ArenaSwapEvent">; type ArenaVaultBalanceUpdateEventData = { @@ -293,7 +295,8 @@ type ArenaInfoData = { melee_id: Uint64String; volume: Uint64String; rewards_remaining: Uint64String; - apt_locked: Uint64String; + emojicoin_0_locked: Uint64String; + emojicoin_1_locked: Uint64String; emojicoin_0_market_address: AccountAddressString; emojicoin_0_symbols: SymbolEmoji[]; emojicoin_0_market_id: Uint64String; diff --git a/src/typescript/sdk/src/indexer-v2/types/postgres-numeric-types.ts b/src/typescript/sdk/src/indexer-v2/types/postgres-numeric-types.ts index 1197551b1..db30d0da2 100644 --- a/src/typescript/sdk/src/indexer-v2/types/postgres-numeric-types.ts +++ b/src/typescript/sdk/src/indexer-v2/types/postgres-numeric-types.ts @@ -119,7 +119,9 @@ export const floatColumns: Set = new Set([ "losses", "volume", "rewards_remaining", - "apt_locked", + "emojicoin_0_locked", + "emojicoin_1_locked", + "apt_proceeds", ]); /** diff --git a/src/typescript/sdk/src/markets/utils.ts b/src/typescript/sdk/src/markets/utils.ts index 12d642b07..48e2debec 100644 --- a/src/typescript/sdk/src/markets/utils.ts +++ b/src/typescript/sdk/src/markets/utils.ts @@ -348,7 +348,7 @@ export function calculateTvlGrowth(periodicStateTracker1D: Types["PeriodicStateT return b.mul(c).div(a.mul(d)).toString(); } -type ReservesAndBondingCurveState = Flatten< +export type ReservesAndBondingCurveState = Flatten< AtLeastOne<{ inBondingCurve: boolean; lpCoinSupply: bigint; diff --git a/src/typescript/sdk/src/types/arena-types.ts b/src/typescript/sdk/src/types/arena-types.ts index 92a16c8f5..59f432335 100644 --- a/src/typescript/sdk/src/types/arena-types.ts +++ b/src/typescript/sdk/src/types/arena-types.ts @@ -53,6 +53,7 @@ export type ArenaTypes = { tapOutFee: bigint; emojicoin0Proceeds: bigint; emojicoin1Proceeds: bigint; + aptProceeds: bigint; emojicoin0ExchangeRateBase: bigint; emojicoin0ExchangeRateQuote: bigint; emojicoin1ExchangeRateBase: bigint; @@ -140,7 +141,8 @@ export type ArenaTypes = { meleeID: bigint; volume: bigint; rewardsRemaining: bigint; - aptLocked: bigint; + emojicoin0Locked: bigint; + emojicoin1Locked: bigint; emojicoin0MarketAddress: AccountAddressString; emojicoin0Symbols: SymbolEmoji[]; emojicoin0MarketID: bigint; @@ -245,6 +247,11 @@ export const toArenaExitEvent = ( tapOutFee: BigInt(data.tap_out_fee), emojicoin0Proceeds: BigInt(data.emojicoin_0_proceeds), emojicoin1Proceeds: BigInt(data.emojicoin_1_proceeds), + aptProceeds: + (BigInt(data.emojicoin_0_proceeds) * BigInt(data.emojicoin_0_exchange_rate.quote)) / + BigInt(data.emojicoin_0_exchange_rate.base) + + (BigInt(data.emojicoin_1_proceeds) * BigInt(data.emojicoin_1_exchange_rate.quote)) / + BigInt(data.emojicoin_1_exchange_rate.base), ...toExchangeRate(data), eventName: "ArenaExit" as const, ...withVersionAndEventIndex({ version, eventIndex }), diff --git a/src/typescript/sdk/tests/e2e/arena/general/arena.test.ts b/src/typescript/sdk/tests/e2e/arena/general/arena.test.ts index aec1d64e5..2bf0dc769 100644 --- a/src/typescript/sdk/tests/e2e/arena/general/arena.test.ts +++ b/src/typescript/sdk/tests/e2e/arena/general/arena.test.ts @@ -139,7 +139,8 @@ describe("ensures an arena correctly unfolds and the processor data is accurate" expect(arenaInfo?.duration).toEqual(melee.view.duration); expect(arenaInfo?.startTime).toEqual(melee.view.startTime); expect(arenaInfo?.volume).toEqual(0n); - expect(arenaInfo?.aptLocked).toEqual(0n); + expect(arenaInfo?.emojicoin0Locked).toEqual(0n); + expect(arenaInfo?.emojicoin1Locked).toEqual(0n); expect(arenaInfo?.maxMatchAmount).toEqual(melee.view.maxMatchAmount); expect(arenaInfo?.maxMatchPercentage).toEqual(melee.view.maxMatchPercentage); expect(arenaInfo?.rewardsRemaining).toEqual(melee.view.availableRewards); @@ -204,7 +205,8 @@ describe("ensures an arena correctly unfolds and the processor data is accurate" expect(position.emojicoin1Balance).toEqual(viewEnterEvent.emojicoin1Proceeds); expect(arenaInfo?.volume).toEqual(viewEnterEvent.quoteVolume); - expect(arenaInfo?.aptLocked).toEqual(viewEnterEvent.quoteVolume); + expect(arenaInfo?.emojicoin0Locked).toEqual(viewEnterEvent.emojicoin0Proceeds); + expect(arenaInfo?.emojicoin1Locked).toEqual(viewEnterEvent.emojicoin1Proceeds); const swapResponse = await emojicoin.arena.swap( account,