Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ECO-2876): Add arena candlesticks to SDK #640

Merged
merged 15 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from 12 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
4 changes: 2 additions & 2 deletions src/docker/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
PROCESSOR_WS_URL: 'ws://processor:${PROCESSOR_WS_PORT}/ws'
PORT: '${BROKER_PORT}'
RUST_LOG: 'info,broker=trace'
image: 'econialabs/emojicoin-dot-fun-indexer-broker'
image: 'econialabs/emojicoin-dot-fun-indexer-broker:6.0.0'
container_name: 'broker'
healthcheck:
test: 'curl -f http://localhost:${BROKER_PORT}/live || exit 1'
Expand Down Expand Up @@ -83,7 +83,7 @@ services:
depends_on:
postgres:
condition: 'service_healthy'
image: 'econialabs/emojicoin-dot-fun-indexer-processor'
image: 'econialabs/emojicoin-dot-fun-indexer-processor:6.0.0'
container_name: 'processor'
healthcheck:
test: 'curl -sf http://localhost:${PROCESSOR_WS_PORT} || exit 1'
Expand Down
2 changes: 1 addition & 1 deletion src/rust/processor
Submodule processor updated 27 files
+132 −0 .github/workflows/check-n-lines-changed.yaml
+34 −0 .github/workflows/conventional-commits.yaml
+2 −0 rust/processor/src/db/common/models/emojicoin_models/constants.rs
+34 −1 rust/processor/src/db/common/models/emojicoin_models/enums.rs
+27 −3 rust/processor/src/db/common/models/emojicoin_models/json_types.rs
+152 −0 rust/processor/src/db/common/models/emojicoin_models/models/arena_candlesticks.rs
+9 −1 rust/processor/src/db/common/models/emojicoin_models/models/arena_exit_event.rs
+26 −5 rust/processor/src/db/common/models/emojicoin_models/models/arena_info.rs
+26 −0 rust/processor/src/db/common/models/emojicoin_models/models/arena_leaderboard_history.rs
+44 −30 rust/processor/src/db/common/models/emojicoin_models/models/arena_position.rs
+9 −1 rust/processor/src/db/common/models/emojicoin_models/models/arena_swap_event.rs
+3 −0 rust/processor/src/db/common/models/emojicoin_models/models/chat_event.rs
+8 −16 rust/processor/src/db/common/models/emojicoin_models/models/market_1m_periods_in_last_day.rs
+23 −1 rust/processor/src/db/common/models/emojicoin_models/models/market_latest_state_event.rs
+3 −0 rust/processor/src/db/common/models/emojicoin_models/models/market_registration_event.rs
+8 −5 rust/processor/src/db/common/models/emojicoin_models/models/mod.rs
+88 −56 rust/processor/src/db/common/models/emojicoin_models/queries/insertion_queries.rs
+37 −43 rust/processor/src/db/common/models/emojicoin_models/queries/leaderboard.sql
+3 −0 rust/processor/src/db/postgres/migrations/2025-01-08-171729_emojicoin_arena/down.sql
+31 −0 rust/processor/src/db/postgres/migrations/2025-01-08-171729_emojicoin_arena/up.sql
+0 −2 rust/processor/src/db/postgres/migrations/2025-02-16-140146_leaderboard_helpers/down.sql
+0 −44 rust/processor/src/db/postgres/migrations/2025-02-16-140146_leaderboard_helpers/up.sql
+15 −0 rust/processor/src/db/postgres/migrations/2025-02-26-040113_add_user_history_indexes/down.sql
+142 −0 rust/processor/src/db/postgres/migrations/2025-02-26-040113_add_user_history_indexes/up.sql
+34 −0 rust/processor/src/db/postgres/schema.rs
+867 −592 rust/processor/src/processors/emojicoin_dot_fun/processor.rs
+102 −0 rust/processor/src/utils/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { FormattedNumber } from "components/FormattedNumber";
import { useAptos } from "context/wallet-context/AptosContextProvider";
import ButtonWithConnectWalletFallback from "components/header/wallet-button/ConnectWalletButton";
import { CloseIcon } from "components/svg";
import type { UserTransactionResponse } from "@aptos-labs/ts-sdk";
import { isUserTransactionResponse, type UserTransactionResponse } from "@aptos-labs/ts-sdk";
import { ARENA_MODULE_ADDRESS } from "@sdk/const";
import { emoji } from "utils";
import { q64ToBig } from "@sdk/utils";
Expand Down Expand Up @@ -220,23 +220,27 @@ const EnterTabLockPhase: React.FC<{
scale="lg"
onClick={() => {
if (!account) return;
submit(transactionBuilder).then((r) => {
if (!r || r?.error) {
submit(transactionBuilder).then((res) => {
if (!res || res?.error) {
errorOut();
} else if (
(r.response as UserTransactionResponse).events.find(
(res.response as UserTransactionResponse).events.find(
(e) => e.type === `${ARENA_MODULE_ADDRESS}::emojicoin_arena::Melee`
)
) {
setCranked();
} else {
const enterEvent = (r.response as UserTransactionResponse).events.find(
const { response } = res;
if (!response || !isUserTransactionResponse(response)) return;
const version = BigInt(response.version);
const enterEvent = response.events.find(
(e) => e.type === `${ARENA_MODULE_ADDRESS}::emojicoin_arena::Enter`
)!;

if (!enterEvent) return;
if (position && position.open) {
setPosition({
...position,
version,
deposits: position.deposits + BigInt(enterEvent.data.input_amount),
matchAmount: position.matchAmount + BigInt(enterEvent.data.match_amount),
emojicoin0Balance:
Expand All @@ -247,6 +251,7 @@ const EnterTabLockPhase: React.FC<{
} else {
setPosition({
open: true,
version,
user: account.address as `0x${string}`,
meleeID: BigInt(enterEvent.data.melee_id),
deposits: BigInt(enterEvent.data.input_amount),
Expand Down
1 change: 1 addition & 0 deletions src/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"test:frontend:e2e": "pnpm run load-env:test -- turbo run test:e2e --filter @econia-labs/emojicoin-frontend --log-prefix none",
"test:sdk": "pnpm run load-env:test -- turbo run test --filter @econia-labs/emojicoin-sdk --log-prefix none",
"test:sdk:arena": "pnpm run load-env:test -- turbo run test:sdk:arena --filter @econia-labs/emojicoin-sdk --log-prefix none",
"test:sdk:arena-candlesticks": "pnpm run load-env:test -- turbo run test:sdk:arena-candlesticks --filter @econia-labs/emojicoin-sdk --log-prefix none",
"test:sdk:e2e": "pnpm run load-env:test -- turbo run test:sdk:e2e --filter @econia-labs/emojicoin-sdk --force --log-prefix none",
"test:sdk:parallel": "pnpm run load-env:test -- turbo run test:sdk:parallel --filter @econia-labs/emojicoin-sdk --force --log-prefix none",
"test:sdk:sequential": "pnpm run load-env:test -- turbo run test:sdk:sequential --filter @econia-labs/emojicoin-sdk --force --log-prefix none",
Expand Down
6 changes: 4 additions & 2 deletions src/typescript/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@
"prepublishOnly": "pnpm clean && pnpm i && pnpm check && pnpm build:publish",
"test": "pnpm run test:sdk:arena && pnpm run test:sdk:arena-ws && pnpm run test:sdk:parallel && pnpm run test:sdk:sequential && pnpm run test:unit",
"test:e2e": "pnpm run test:sdk:parallel && pnpm run test:sdk:sequential",
"test:sdk:arena": "pnpm jest tests/e2e/arena/general --runInBand",
"test:sdk:arena-ws": "pnpm jest tests/e2e/arena/ws --runInBand",
"test:sdk:arena": "pnpm run test:sdk:arena-candlesticks && pnpm run test:sdk:arena-general && pnpm run test:sdk:arena-ws",
"test:sdk:arena-general": "pnpm jest tests/e2e/arena/general.test.ts --runInBand",
"test:sdk:arena-candlesticks": "pnpm jest tests/e2e/arena/candlesticks.test.ts --runInBand",
"test:sdk:arena-ws": "pnpm jest tests/e2e/arena/websockets.test.ts --runInBand",
"test:sdk:parallel": "pnpm jest tests/e2e --testPathIgnorePatterns=\"(arena/|broker/)\"",
"test:sdk:sequential": "pnpm jest tests/e2e/broker --runInBand",
"test:unit": "pnpm jest tests/unit",
Expand Down
37 changes: 36 additions & 1 deletion src/typescript/sdk/src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ export const INITIAL_REAL_RESERVES: Types["Reserves"] = {
quote: 0n,
};

/// As defined in the database, aka the enum string.
export enum Period {
Period1M = "period_1m",
Period5M = "period_5m",
Expand All @@ -165,6 +164,17 @@ export enum Period {
Period1D = "period_1d",
}

export enum ArenaPeriod {
Period15S = "period_15s",
Period1M = "period_1m",
Period5M = "period_5m",
Period15M = "period_15m",
Period30M = "period_30m",
Period1H = "period_1h",
Period4H = "period_4h",
Period1D = "period_1d",
}

/// As defined in the database, aka the enum string.
export enum Trigger {
PackagePublication = "package_publication",
Expand Down Expand Up @@ -199,6 +209,31 @@ export const toPeriod = (s: DatabaseStructType["PeriodicStateMetadata"]["period"
throw new Error(`Unknown period: ${s}`);
})();

export const toArenaPeriod = (s: DatabaseStructType["ArenaCandlestick"]["period"]) =>
({
// From the database.
period_15s: ArenaPeriod.Period15S,
period_1m: ArenaPeriod.Period1M,
period_5m: ArenaPeriod.Period5M,
period_15m: ArenaPeriod.Period15M,
period_30m: ArenaPeriod.Period30M,
period_1h: ArenaPeriod.Period1H,
period_4h: ArenaPeriod.Period4H,
period_1d: ArenaPeriod.Period1D,
// From the broker.
FifteenSeconds: ArenaPeriod.Period15S,
OneMinute: ArenaPeriod.Period1M,
FiveMinutes: ArenaPeriod.Period5M,
FifteenMinutes: ArenaPeriod.Period15M,
ThirtyMinutes: ArenaPeriod.Period30M,
OneHour: ArenaPeriod.Period1H,
FourHours: ArenaPeriod.Period4H,
OneDay: ArenaPeriod.Period1D,
})[s as ValueOf<typeof Period>] ??
(() => {
throw new Error(`Unknown period: ${s}`);
})();

export const toTrigger = (s: DatabaseStructType["GlobalStateEventData"]["trigger"]) =>
({
// From the database.
Expand Down
2 changes: 1 addition & 1 deletion src/typescript/sdk/src/indexer-v2/json-bigint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const tryWithFallbackParse = (parser: (v: any) => any) => (v: any) => {
return v;
}
};
const parseFloat = (v: any) => Big(v).toString();
const parseFloat = (v: any) => (v === null ? null : Big(v).toString());
const parseBigInt = (v: any) => BigInt(v);
const parseInteger = (v: any) => Number(v);
const parseDefault = (v: any) => v;
Expand Down
13 changes: 7 additions & 6 deletions src/typescript/sdk/src/indexer-v2/queries/app/arena.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from "../../types";
import { ORDER_BY } from "../../const";
import { toAccountAddressString } from "../../../utils/account-address";
import { type AccountAddressInput } from "@aptos-labs/ts-sdk";

const selectMelee = () =>
postgrest
Expand All @@ -31,19 +32,19 @@ const selectArenaInfo = () =>
.limit(1)
.single();

const selectPosition = ({ user, meleeID }: { user: string; meleeID: bigint }) =>
const selectPosition = ({ user, meleeID }: { user: AccountAddressInput; meleeID: bigint }) =>
postgrest
.from(TableName.ArenaPosition)
.select("*")
.eq("user", user)
.eq("user", toAccountAddressString(user))
.eq("melee_id", meleeID)
.maybeSingle();

const selectLatestPosition = ({ user }: { user: string }) =>
const selectLatestPosition = ({ user }: { user: AccountAddressInput }) =>
postgrest
.from(TableName.ArenaPosition)
.select("*")
.eq("user", user)
.eq("user", toAccountAddressString(user))
.order("melee_id", ORDER_BY.DESC)
.limit(1)
.maybeSingle();
Expand All @@ -53,7 +54,7 @@ const selectArenaLeaderboardHistoryWithInfo = ({
page = 1,
pageSize,
}: {
user: string;
user: AccountAddressInput;
page: number;
pageSize: number;
}) =>
Expand All @@ -69,7 +70,7 @@ const selectMarketStateByAddress = ({ address }: { address: string }) =>
postgrest
.from(TableName.MarketState)
.select("*")
.eq("market_address", address)
.eq("market_address", toAccountAddressString(address))
.limit(1)
.maybeSingle();

Expand Down
41 changes: 39 additions & 2 deletions src/typescript/sdk/src/indexer-v2/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ import {
type BlockAndEventIndexMetadata,
} from "./json-types";
import { type MarketEmojiData, type SymbolEmoji, toMarketEmojiData } from "../../emoji_data";
import { toPeriod, toTrigger, type Period, type Trigger } from "../../const";
import { toArenaPeriod, toPeriod, toTrigger, type Period, type Trigger } from "../../const";
import { toAccountAddressString } from "../../utils";
import Big from "big.js";
import { q64ToBig } from "../../utils/nominal-price";
import { type AnyArenaEvent } from "../../types/arena-types";
import {
ARENA_CANDLESTICK_NAME,
safeParseBigIntOrPostgresTimestamp,
type AnyArenaEvent,
} from "../../types/arena-types";
import { calculateCurvePrice, type ReservesAndBondingCurveState } from "../../markets";

export type TransactionMetadata = {
Expand Down Expand Up @@ -158,6 +162,7 @@ const toArenaExitFromDatabase = (
emojicoin0ExchangeRateQuote: BigInt(data.emojicoin_0_exchange_rate_quote),
emojicoin1ExchangeRateBase: BigInt(data.emojicoin_1_exchange_rate_base),
emojicoin1ExchangeRateQuote: BigInt(data.emojicoin_1_exchange_rate_quote),
duringMelee: data.during_melee,
});

const toArenaSwapFromDatabase = (
Expand All @@ -173,6 +178,7 @@ const toArenaSwapFromDatabase = (
emojicoin0ExchangeRateQuote: BigInt(data.emojicoin_0_exchange_rate_quote),
emojicoin1ExchangeRateBase: BigInt(data.emojicoin_1_exchange_rate_base),
emojicoin1ExchangeRateQuote: BigInt(data.emojicoin_1_exchange_rate_quote),
duringMelee: data.during_melee,
});

const toArenaVaultBalanceUpdateFromDatabase = (
Expand All @@ -185,6 +191,7 @@ const toArenaPositionFromDatabase = (
data: DatabaseStructType["ArenaPosition"]
): Types["ArenaPosition"] => ({
meleeID: BigInt(data.melee_id),
version: BigInt(data.last_transaction_version),
user: toAccountAddressString(data.user),
open: data.open,
emojicoin0Balance: BigInt(data.emojicoin_0_balance),
Expand All @@ -199,6 +206,7 @@ const toArenaLeaderboardFromDatabase = (
data: DatabaseStructType["ArenaLeaderboard"]
): Types["ArenaLeaderboard"] => ({
user: toAccountAddressString(data.user),
version: BigInt(data.last_transaction_version),
open: data.open,
emojicoin0Balance: BigInt(data.emojicoin_0_balance),
emojicoin1Balance: BigInt(data.emojicoin_1_balance),
Expand Down Expand Up @@ -232,6 +240,7 @@ export const toTotalAptLocked = (args: {

const toArenaInfoFromDatabase = (data: DatabaseStructType["ArenaInfo"]): Types["ArenaInfo"] => ({
meleeID: BigInt(data.melee_id),
version: BigInt(data.last_transaction_version),
volume: BigInt(data.volume),
rewardsRemaining: BigInt(data.rewards_remaining),
emojicoin0Locked: BigInt(data.emojicoin_0_locked),
Expand All @@ -248,10 +257,26 @@ const toArenaInfoFromDatabase = (data: DatabaseStructType["ArenaInfo"]): Types["
maxMatchAmount: BigInt(data.max_match_amount),
});

const toArenaCandlestickFromDatabase = (
data: DatabaseStructType["ArenaCandlestick"]
): Types["ArenaCandlestick"] => ({
meleeID: BigInt(data.melee_id),
version: BigInt(data.last_transaction_version),
volume: BigInt(data.volume),
period: toArenaPeriod(data.period),
startTime: safeParseBigIntOrPostgresTimestamp(data.start_time),
openPrice: Number(data.open_price),
closePrice: Number(data.close_price),
highPrice: Number(data.high_price),
lowPrice: Number(data.low_price),
nSwaps: BigInt(data.n_swaps),
});

const toArenaLeaderboardHistoryFromDatabase = (
data: DatabaseStructType["ArenaLeaderboardHistory"]
): Types["ArenaLeaderboardHistory"] => ({
user: toAccountAddressString(data.user),
version: BigInt(data.last_transaction_version),
meleeID: BigInt(data.melee_id),
profits: BigInt(data.profits),
losses: BigInt(data.losses),
Expand Down Expand Up @@ -491,6 +516,7 @@ export type ArenaPositionModel = ReturnType<typeof toArenaPositionModel>;
export type ArenaLeaderboardModel = ReturnType<typeof toArenaLeaderboardModel>;
export type ArenaLeaderboardHistoryModel = ReturnType<typeof toArenaLeaderboardHistoryModel>;
export type ArenaInfoModel = ReturnType<typeof toArenaInfoModel>;
export type ArenaCandlestickModel = ReturnType<typeof toArenaCandlestickModel>;
export type UserPoolsRPCModel = ReturnType<typeof toUserPoolsRPCResponse>;
export type AggregateMarketStateModel = ReturnType<typeof toAggregateMarketState>;
export type ArenaLeaderboardHistoryWithArenaInfoModel = ReturnType<
Expand Down Expand Up @@ -687,6 +713,11 @@ export const GuidGetters = {
eventName: EVENT_NAMES.ArenaVaultBalanceUpdate,
guid: `${EVENT_NAMES.ArenaVaultBalanceUpdate}::${sender}::${version}::${event_index}`,
}),
arenaCandlestick: ({ melee_id, start_time, period }: DatabaseJsonType["arena_candlesticks"]) => ({
// Not a real contract event, but used to classify the type of data.
eventName: ARENA_CANDLESTICK_NAME,
guid: `${ARENA_CANDLESTICK_NAME}::${melee_id}::${period}::${start_time}`,
}),
};

export const toGlobalStateEventModel = (data: DatabaseJsonType["global_state_events"]) => ({
Expand Down Expand Up @@ -897,6 +928,10 @@ export const toArenaPositionModel = toArenaPositionFromDatabase;
export const toArenaLeaderboardModel = toArenaLeaderboardFromDatabase;
export const toArenaLeaderboardHistoryModel = toArenaLeaderboardHistoryFromDatabase;
export const toArenaInfoModel = toArenaInfoFromDatabase;
export const toArenaCandlestickModel = (data: DatabaseJsonType["arena_candlesticks"]) => ({
...toArenaCandlestickFromDatabase(data),
...GuidGetters.arenaCandlestick(data),
});

export const calculateDeltaPercentageForQ64s = (open: AnyNumberString, close: AnyNumberString) =>
q64ToBig(close.toString()).div(q64ToBig(open.toString())).mul(100).sub(100).toNumber();
Expand Down Expand Up @@ -951,6 +986,7 @@ export const DatabaseTypeConverter = {
[TableName.ArenaExitEvents]: toArenaExitModel,
[TableName.ArenaSwapEvents]: toArenaSwapModel,
[TableName.ArenaInfo]: toArenaInfoModel,
[TableName.ArenaCandlesticks]: toArenaCandlestickModel,
[TableName.ArenaPosition]: toArenaPositionModel,
[TableName.ArenaVaultBalanceUpdateEvents]: toArenaVaultBalanceUpdateModel,
[TableName.ArenaLeaderboard]: toArenaLeaderboardModel,
Expand Down Expand Up @@ -981,6 +1017,7 @@ export type DatabaseModels = {
[TableName.ArenaVaultBalanceUpdateEvents]: ArenaVaultBalanceUpdateModel;
[TableName.ArenaPosition]: ArenaPositionModel;
[TableName.ArenaInfo]: ArenaInfoModel;
[TableName.ArenaCandlesticks]: ArenaCandlestickModel;
[TableName.ArenaLeaderboard]: ArenaLeaderboardModel;
[TableName.ArenaLeaderboardHistory]: ArenaLeaderboardHistoryModel;
[TableName.ArenaLeaderboardHistoryWithArenaInfo]: ArenaLeaderboardHistoryWithArenaInfoModel;
Expand Down
Loading
Loading