Skip to content

Commit

Permalink
feat(ECO-2876): Add arena candlesticks to SDK (#640)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt <[email protected]>
  • Loading branch information
CRBl69 and xbtmatt committed Mar 5, 2025
1 parent 0f02017 commit 7f30668
Show file tree
Hide file tree
Showing 18 changed files with 830 additions and 110 deletions.
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:4.0.2'
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:4.0.2'
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
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 @@ -22,11 +22,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 { deserializeToHexString, 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 @@ -148,6 +152,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 @@ -163,6 +168,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 @@ -175,6 +181,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 @@ -189,6 +196,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 @@ -222,6 +230,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 @@ -238,10 +247,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 @@ -481,6 +506,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 @@ -660,6 +686,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 @@ -864,6 +895,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 @@ -922,6 +957,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 @@ -952,6 +988,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

0 comments on commit 7f30668

Please sign in to comment.