From 45317be921f4261d22e67be32ae1c961d3beb339 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 30 Oct 2024 09:42:01 -0400 Subject: [PATCH 01/29] wip --- packages/database/lib/schema.ts | 100 ++-- packages/new_indexer/Dockerfile | 23 + packages/new_indexer/package.json | 47 ++ packages/new_indexer/readme.md | 30 ++ .../new_indexer/src/adapters/telegram-bot.ts | 88 +++ packages/new_indexer/src/connection.ts | 19 + packages/new_indexer/src/index.ts | 60 +++ packages/new_indexer/src/indexEvents.ts | 505 ++++++++++++++++++ packages/new_indexer/src/logger.ts | 83 +++ .../new_indexer/src/populateSignatures.ts | 154 ++++++ packages/new_indexer/tsconfig.json | 9 + packages/v4_indexer/Dockerfile | 23 + packages/v4_indexer/package.json | 47 ++ .../v4_indexer/src/adapters/telegram-bot.ts | 88 +++ packages/v4_indexer/src/connection.ts | 19 + packages/v4_indexer/src/index.ts | 60 +++ packages/v4_indexer/src/indexEvents.ts | 505 ++++++++++++++++++ packages/v4_indexer/src/logger.ts | 83 +++ packages/v4_indexer/src/populateSignatures.ts | 155 ++++++ packages/v4_indexer/tsconfig.json | 9 + 20 files changed, 2063 insertions(+), 44 deletions(-) create mode 100644 packages/new_indexer/Dockerfile create mode 100644 packages/new_indexer/package.json create mode 100644 packages/new_indexer/readme.md create mode 100644 packages/new_indexer/src/adapters/telegram-bot.ts create mode 100644 packages/new_indexer/src/connection.ts create mode 100644 packages/new_indexer/src/index.ts create mode 100644 packages/new_indexer/src/indexEvents.ts create mode 100644 packages/new_indexer/src/logger.ts create mode 100644 packages/new_indexer/src/populateSignatures.ts create mode 100644 packages/new_indexer/tsconfig.json create mode 100644 packages/v4_indexer/Dockerfile create mode 100644 packages/v4_indexer/package.json create mode 100644 packages/v4_indexer/src/adapters/telegram-bot.ts create mode 100644 packages/v4_indexer/src/connection.ts create mode 100644 packages/v4_indexer/src/index.ts create mode 100644 packages/v4_indexer/src/indexEvents.ts create mode 100644 packages/v4_indexer/src/logger.ts create mode 100644 packages/v4_indexer/src/populateSignatures.ts create mode 100644 packages/v4_indexer/tsconfig.json diff --git a/packages/database/lib/schema.ts b/packages/database/lib/schema.ts index c05b7999..0604ac97 100644 --- a/packages/database/lib/schema.ts +++ b/packages/database/lib/schema.ts @@ -295,22 +295,6 @@ export enum InstructionType { VaultRedeemConditionalTokensForUnderlyingTokens = "vault_redeem_conditional_tokens_for_underlying_tokens", } -export const transactions = pgTable( - "transactions", - { - txSig: transaction("tx_sig").primaryKey(), - slot: biggerSlot("slot").notNull(), - blockTime: timestamp("block_time", { withTimezone: true }).notNull(), - failed: boolean("failed").notNull(), - payload: text("payload").notNull(), - serializerLogicVersion: smallint("serializer_logic_version").notNull(), - mainIxType: pgEnum("main_ix_type", InstructionType), - }, - (table) => ({ - slotIdx: index("txn_slot_index").on(table.slot), - }) -); - // These are responsible for getting all signatures involving an account // historically and real time, and writing them to the transactions table for processing. // Each proposal / spot market / autocrat version upgrade will result in another entry. @@ -324,13 +308,13 @@ export enum TransactionWatchStatus { export const transactionWatchers = pgTable("transaction_watchers", { acct: pubkey("acct").primaryKey(), latestTxSig: transaction("latest_tx_sig").references( - () => transactions.txSig + () => transactions.signature ), /** * We can use this to monitor if the transaction history is being cleared by the rpc. * Ideally this should not change once set. */ - firstTxSig: transaction("first_tx_sig").references(() => transactions.txSig), + firstTxSig: transaction("first_tx_sig").references(() => transactions.signature), /** * This may be significantly higher than the slot of the latest signature. The invariant here * is that no new transaction observed by the watcher may be less than or equal to the checkedUpToSlot @@ -352,7 +336,7 @@ export const transactionWatcherTransactions = pgTable( .references(() => transactionWatchers.acct) .notNull(), txSig: transaction("tx_sig") - .references(() => transactions.txSig) + .references(() => transactions.signature) .notNull(), slot: biggerSlot("slot").notNull(), }, @@ -374,6 +358,7 @@ export enum IndexerImplementation { AutocratDaoIndexer = "AutocratDaoIndexer", AutocratProposalIndexer = "AutocratProposalIndexer", TokenMintIndexer = "TokenMintIndexer", + } export enum IndexerType { TXHistory = "TXHistory", @@ -403,7 +388,7 @@ export const indexerAccountDependencies = pgTable( .notNull(), acct: pubkey("acct").notNull(), latestTxSigProcessed: transaction("latest_tx_sig_processed").references( - () => transactions.txSig + () => transactions.signature ), status: pgEnum("status", IndexerAccountDependencyStatus).default( IndexerAccountDependencyStatus.Active @@ -456,7 +441,7 @@ export const tokenAcctBalances = pgTable( .notNull() .default(sql`0`), slot: biggerSlot("slot"), - txSig: transaction("tx_sig").references(() => transactions.txSig), + txSig: transaction("tx_sig").references(() => transactions.signature), }, (table) => ({ pk: primaryKey( @@ -494,7 +479,7 @@ export const orders = pgTable( { orderTxSig: transaction("order_tx_sig") .primaryKey() - .references(() => transactions.txSig), + .references(() => transactions.signature), marketAcct: pubkey("market_acct") .references(() => markets.marketAcct) .notNull(), @@ -872,36 +857,63 @@ export const userPerformance = pgTable( } ); -export const signature_accounts = pgTable("signature_accounts", { - signature: transaction("signature").notNull(), - account: pubkey("account").notNull(), - insertedAt: timestamp("inserted_at", { withTimezone: true }) - .notNull() - .defaultNow(), -}, (table) => ({ - pk: primaryKey({ columns: [table.signature, table.account] }), - accountIdx: index("account_index").on(table.account), -})); - -export const signatures = pgTable( - "signatures", +export const transactions = pgTable( + "transactions", { signature: transaction("signature").primaryKey(), slot: biggerSlot("slot").notNull(), - didErr: boolean("did_err").notNull(), - err: text("err"), - blockTime: timestamp("block_time", { withTimezone: true }), + blockTime: timestamp("block_time", { withTimezone: true }).notNull(), + failed: boolean("failed").notNull(), insertedAt: timestamp("inserted_at", { withTimezone: true }) .notNull() .defaultNow(), - seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), }, (table) => ({ - slotIdx: index("slot_index").on(table.slot), - sequenceNumIdx: index("sequence_num_index").on(table.seqNum), + slotIdx: index("txn_slot_index").on(table.slot), }) ); +export const transaction_accounts = pgTable("transaction_accounts", { + signature: transaction("signature").notNull(), + account: pubkey("account").notNull(), + insertedAt: timestamp("inserted_at", { withTimezone: true }) + .notNull() + .defaultNow(), +}, (table) => ({ + pk: primaryKey({ columns: [table.signature, table.account] }), + accountIdx: index("account_index").on(table.account), +})); + +// export const transactionSequenceNumbers = pgTable( +// "transactions_seqnums", +// { +// signature: transaction("signature").notNull().references(() => transactions.signature), +// seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), +// }, +// (table) => ({ +// pk: primaryKey({ columns: [table.signature, table.seqNum] }), +// sequenceNumIdx: index("sequence_num_index").on(table.seqNum), +// }) +// ) +// export const signatures = pgTable( +// "signatures", +// { +// signature: transaction("signature").primaryKey(), +// slot: biggerSlot("slot").notNull(), +// didErr: boolean("did_err").notNull(), +// err: text("err"), +// blockTime: timestamp("block_time", { withTimezone: true }), +// insertedAt: timestamp("inserted_at", { withTimezone: true }) +// .notNull() +// .defaultNow(), +// seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), +// }, +// (table) => ({ +// slotIdx: index("slot_index").on(table.slot), +// sequenceNumIdx: index("sequence_num_index").on(table.seqNum), +// }) +// ); + export const v0_4_amms = pgTable("v0_4_amms", { ammAddr: pubkey("amm_addr").primaryKey(), createdAtSlot: biggerSlot("created_at_slot").notNull(), @@ -1003,7 +1015,7 @@ export const v0_4_splits = pgTable( id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), - signature: transaction("signature").notNull().references(() => signatures.signature), + signature: transaction("signature").notNull().references(() => transactions.signature), slot: biggerSlot("slot").notNull(), amount: bigint("amount", { mode: "bigint" }).notNull(), createdAt: timestamp("created_at", { withTimezone: true }) @@ -1021,7 +1033,7 @@ export const v0_4_merges = pgTable("v0_4_merges", { id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), - signature: transaction("signature").notNull().references(() => signatures.signature), + signature: transaction("signature").notNull().references(() => transactions.signature), slot: biggerSlot("slot").notNull(), amount: bigint("amount", { mode: "bigint" }).notNull(), createdAt: timestamp("created_at", { withTimezone: true }) @@ -1166,7 +1178,7 @@ export const proposalTotalTradeVolume = pgView("proposal_total_trade_volume", { export const userDeposits = pgTable("user_deposits", { txSig: transaction("tx_sig") - .references(() => transactions.txSig) + .references(() => transactions.signature) .notNull(), userAcct: pubkey("user_acct") diff --git a/packages/new_indexer/Dockerfile b/packages/new_indexer/Dockerfile new file mode 100644 index 00000000..29b666ef --- /dev/null +++ b/packages/new_indexer/Dockerfile @@ -0,0 +1,23 @@ +FROM node:alpine3.18 + +# Some of the dependencies require node-gyp +RUN apk add --no-cache python3 make g++ +RUN if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi + +# Bun requires glibc https://github.com/oven-sh/bun/issues/5545#issuecomment-1722306576 +RUN apk --no-cache add ca-certificates wget +RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub +RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk +RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk + +RUN apk add --no-cache git + +EXPOSE 8080 +RUN corepack prepare pnpm@9.11.0 --activate +RUN corepack enable +ENV REPO_DIR /home/indexer/futarchy-indexer +RUN mkdir -p $REPO_DIR +WORKDIR $REPO_DIR +COPY . . +RUN pnpm install +CMD ["pnpm", "start-service"] diff --git a/packages/new_indexer/package.json b/packages/new_indexer/package.json new file mode 100644 index 00000000..c111aea3 --- /dev/null +++ b/packages/new_indexer/package.json @@ -0,0 +1,47 @@ +{ + "name": "@metadaoproject/indexer-service", + "description": "indexer microservice", + "private": "true", + "scripts": { + "cli": "bun src/cli/index.ts", + "start": "bun src/index.ts", + "test": "bun test" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.29.0", + "@debridge-finance/solana-transaction-parser": "^2.0.1", + "@lukasdeco/prom-client": "^15.1.4", + "@metadaoproject/futarchy": "^0.4.0-alpha.18", + "@metadaoproject/futarchy-sdk": "4.0.0-alpha.31", + "@metadaoproject/indexer-db": "workspace:*", + "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", + "@metaplex-foundation/umi-uploader-bundlr": "^0.9.1", + "@openbook-dex/openbook-v2": "^0.1.9", + "@orca-so/whirlpools-sdk": "^0.12.5", + "@solana/spl-token": "^0.3.8", + "@solana/web3.js": "^1.90.0", + "@types/cors": "^2.8.17", + "ansicolor": "^2.0.1", + "axios": "^1.7.2", + "bs58": "^4.0.1", + "commander": "^12.0.0", + "cors": "^2.8.5", + "croner": "^8.0.2", + "drizzle-orm": "^0.30.6", + "express": "^4.19.2", + "fastq": "^1.17.1", + "inquirer": "^9.2.14", + "jsonwebtoken": "^9.0.2", + "match-discriminated-union": "^1.0.0", + "tweetnacl": "^1.0.3", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/bs58": "^4.0.1", + "@types/express": "^4.17.21", + "@types/inquirer": "^9.0.7", + "@types/jsonwebtoken": "^9.0.6", + "@types/node": "^20.10.6", + "bun-types": "^1.0.30" + } +} diff --git a/packages/new_indexer/readme.md b/packages/new_indexer/readme.md new file mode 100644 index 00000000..4ed7b1fc --- /dev/null +++ b/packages/new_indexer/readme.md @@ -0,0 +1,30 @@ +New Indexer Architecture + + +Transaction Indexer + +Indexes all transactions across all programs v3 and v4. Populates transactions table where the signature is the pk and transaction_accounts, +which links each signature to an account_id (program) + +Split into 2 parts - frontfiller and backfiller + +Frontfiller - checks for new transactions every second, and when a new txn is detected, first inserts into transactions table, +then asynchronously triggers processTransaction() if there is no conflict in the insert (which implies the txn has already been processed) to +process the transaction and populate other tables as necessary. This way, we process transactions as soon as they are detected, minimizing latency +as compared to having seperate workers that track the transactions table and process transactions (such as fetchEligibleSignatures in v4 indexer). + +Backfiller - the purpose of this is a failsafe in case a transaction fails to be picked up by the RPC or indexer. +Runs every 15 mins and fetches all signatures within the last 15 mins and adds to transactions table. +If the txn doesn't already exist in the transaction table, we process the transaction as it hasn't been indexed. + +On startup, the transaction indexer fetches all historical txns from the creation of the programs + + + +processTransaction(txn, version) + +if version is v4, we check the events emitted in the transaction and call handleAmmEvent() and/or handleVaultEvent() accordingly to populate the +appropriate tables + +if version is v3, we take the transaction response and call indexTransactin() in instruction-dispatch.ts to index the txn and populate the +appropriate tables diff --git a/packages/new_indexer/src/adapters/telegram-bot.ts b/packages/new_indexer/src/adapters/telegram-bot.ts new file mode 100644 index 00000000..07a4ea08 --- /dev/null +++ b/packages/new_indexer/src/adapters/telegram-bot.ts @@ -0,0 +1,88 @@ +import axios, { AxiosInstance, AxiosResponse } from "axios"; + +type TelegramBotConfig = { + token: string; +}; + +export class TelegramBotAPI implements AlertChatBotInterface { + private readonly apiUrl: string; + private readonly httpClient: AxiosInstance; + + constructor(config: TelegramBotConfig) { + this.apiUrl = `https://api.telegram.org/bot${config.token}/`; + this.httpClient = axios.create({ + baseURL: this.apiUrl, + headers: { + "Content-Type": "application/json", + }, + }); + } + + private async request( + method: "GET" | "POST", + endpoint: string, + params?: object + ): Promise> { + let response: AxiosResponse>; + try { + if (method === "GET") { + response = await this.httpClient.get(endpoint, { params }); + } else { + response = await this.httpClient.post(endpoint, params); + } + return response.data; + } catch (error) { + throw new Error(`Failed to make request: ${error}`); + } + } + + public async getMe(): Promise> { + return this.request("GET", "getMe"); + } + + public async sendMessage( + chatId: number | string, + text: string + ): Promise | null> { + const params = { chat_id: chatId, text }; + try { + return this.request("POST", "sendMessage", params); + } catch (e) { + console.error(e); + return null; + } + } + + public async getUpdates( + offset?: number, + limit?: number, + timeout?: number, + allowed_updates?: string[] + ): Promise> { + const params = { offset, limit, timeout, allowed_updates }; + return this.request("GET", "getUpdates", params); + } + + // Add more methods as needed for other API endpoints +} + +type ChatbotApiResponse = { + ok: boolean; + result?: T; + description?: string; + error_code?: number; +}; + +export interface AlertChatBotInterface { + getMe(): Promise>; + sendMessage( + chatId: number | string, + text: string + ): Promise | null>; + getUpdates( + offset?: number, + limit?: number, + timeout?: number, + allowed_updates?: string[] + ): Promise>; +} diff --git a/packages/new_indexer/src/connection.ts b/packages/new_indexer/src/connection.ts new file mode 100644 index 00000000..eafd196f --- /dev/null +++ b/packages/new_indexer/src/connection.ts @@ -0,0 +1,19 @@ +import { Connection } from "@solana/web3.js"; +import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { ConditionalVaultClient, AmmClient } from "@metadaoproject/futarchy/v0.4"; + +export const RPC_ENDPOINT = process.env.RPC_ENDPOINT ?? ""; + +if (!RPC_ENDPOINT) { + throw new Error("RPC_ENDPOINT is not set"); +} + +export const connection: Connection = new Connection(RPC_ENDPOINT, "confirmed"); +// the indexer will only be reading, not writing +export const readonlyWallet: Wallet = undefined as unknown as Wallet; +export const provider = new AnchorProvider(connection, readonlyWallet, { + commitment: "confirmed", +}); + +export const ammClient = AmmClient.createClient({ provider }); +export const conditionalVaultClient = ConditionalVaultClient.createClient({ provider }); diff --git a/packages/new_indexer/src/index.ts b/packages/new_indexer/src/index.ts new file mode 100644 index 00000000..a3413acd --- /dev/null +++ b/packages/new_indexer/src/index.ts @@ -0,0 +1,60 @@ +import { indexAmmEvents, indexVaultEvents } from "./indexEvents.js"; +import { backfill, frontfill } from "./populateSignatures.js"; + +// NEW FUTARCHY INDEXER + +// To minimize complexity, the indexer is split into two parts: +// 1. signature ingestion +// 2. signature processing + +// SIGNATURE INGESTION +// Signature ingestion is responsible for fetching new signatures +// from the network and storing them in the `signatures` table. +// Today, this is done by the `populateSignatures` function. Under +// the hood, it uses the `getSignaturesForAddress` RPC endpoint. +// This is nice because it means that the indexer can fetch +// historical data. However, it is higher latency than subscribing +// to transactions via a websocket, like the below: +// https://docs.helius.dev/webhooks-and-websockets/enhanced-websockets +// We could use this to get real-time transaction data in the future. + +// SIGNATURE PROCESSING +// Signature processing is responsible for fetching the transactions +// corresponding to the signatures and parsing them to extract event data. +// This is done by the `indexAmmEvents` and `indexVaultEvents` functions. +// Today, insertion of new accounts (questions, conditional vaults, AMMs) +// works. However, updating them (when, for example, a swap happens) doesn't. + +// For it to work, we need to do the following: +// 1) Add `slot_last_applied` and `signature_last_applied` columns to the +// `amm` and `conditional_vault` tables. +// 2) When processing a signature, fetch the account from the DB and check +// if the signature's slot is greater than the account's `slot_last_applied`. +// If it isn't, skip it. If it's greater, apply it. If it's equal, we need +// to run a `getBlock` RPC call and check which transaction is latest. + + +async function main() { + // await populateSignatures(); + // await indexAmms(); + // console.log("indexAmmEvents"); + // await indexVaultEvents(); + // await indexAmmEvents(); + + await backfill(); + await Promise.all([ + frontfill(), + setInterval(async () => { + await Promise.all([ + indexAmmEvents(), + indexVaultEvents(), + ]) + }, 1000), + ]); + // await Promise.all([ + // populateSignatures(), + // indexAmmEvents(), + // ]) +} + +main(); \ No newline at end of file diff --git a/packages/new_indexer/src/indexEvents.ts b/packages/new_indexer/src/indexEvents.ts new file mode 100644 index 00000000..0b576ed8 --- /dev/null +++ b/packages/new_indexer/src/indexEvents.ts @@ -0,0 +1,505 @@ +import { AddLiquidityEvent, AMM_PROGRAM_ID, AmmEvent, CONDITIONAL_VAULT_PROGRAM_ID, ConditionalVaultEvent, CreateAmmEvent, getVaultAddr, InitializeConditionalVaultEvent, InitializeQuestionEvent, SwapEvent, PriceMath, SplitTokensEvent, MergeTokensEvent, RemoveLiquidityEvent } from "@metadaoproject/futarchy/v0.4"; +import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; +import * as anchor from "@coral-xyz/anchor"; +import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; +import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; +import * as token from "@solana/spl-token"; + +import { connection, ammClient, conditionalVaultClient } from "./connection"; +import { Program } from "@coral-xyz/anchor"; + +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + +type Market = { + marketAcct: string; + baseMint: string; + quoteMint: string; +} + +type DBConnection = any; // TODO: Fix typing.. + +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +const parseEvents = (program: Program, transactionResponse: VersionedTransactionResponse | TransactionResponse): { name: string; data: any }[] => { + const events: { name: string; data: any }[] = []; + try { + const inner: CompiledInnerInstruction[] = + transactionResponse?.meta?.innerInstructions ?? []; + const idlProgramId = program.programId; + for (let i = 0; i < inner.length; i++) { + for (let j = 0; j < inner[i].instructions.length; j++) { + const ix = inner[i].instructions[j]; + const programPubkey = + transactionResponse?.transaction.message.staticAccountKeys[ + ix.programIdIndex + ]; + if ( + programPubkey === undefined || + !programPubkey.equals(idlProgramId) + ) { + // we are at instructions that does not match the linked program + continue; + } + + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + events.push(event); + } + } + } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error parsing events: ${error.message}` + : "Unknown error parsing events" + ]); + } + + return events; +} + +async function fetchEligibleSignatures(programId: string, limit: number) { + try { + return await usingDb(async (db) => { + let lastSlotIndexerQuery = await db.select() + .from(schema.indexers) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")); + const indexerResult = await lastSlotIndexerQuery; + if (indexerResult.length === 0) throw Error("Indexer not found in indexers table"); + const lastSlotProcessed = indexerResult[0].latestSlotProcessed; + + return db.select({signature: schema.signatures.signature, slot: schema.signatures.slot}) + .from(schema.signatures) + .innerJoin(schema.signature_accounts, eq(schema.signatures.signature, schema.signature_accounts.signature)) + .where( + and( + eq(schema.signature_accounts.account, programId), + gt(schema.signatures.slot, lastSlotProcessed) + ) + ) + .orderBy(desc(schema.signatures.slot)) + .limit(limit); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error fetching eligible signatures: ${error.message}` + : "Unknown error fetching eligible signatures" + ]); + return []; + } +} + +async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { + try { + return await connection.getTransactions( + eligibleSignatures.map(s => s.signature), + { commitment: "confirmed", maxSupportedTransactionVersion: 1 } + ); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error fetching transaction responses: ${error.message}` + : "Unknown error fetching transaction responses" + ]); + return []; + } +} + +//set latestProcessedSlot in db +async function setLatestProcessedSlot(slot: number) { + try { + await usingDb(async (db) => { + await db.update(schema.indexers) + .set({ latestSlotProcessed: BigInt(slot) }) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .execute(); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error setting latest processed slot: ${error.message}` + : "Unknown error setting latest processed slot" + ]); + } +} + +export async function indexAmmEvents() { + try { + const eligibleSignatures = await fetchEligibleSignatures(AMM_PROGRAM_ID.toString(), 100); + if (eligibleSignatures.length === 0) { + console.log("No signatures for AMM events"); + return; + } + + const transactionResponses = await fetchTransactionResponses(eligibleSignatures); + + for (const [index, transactionResponse] of transactionResponses.entries()) { + if (!transactionResponse) { + console.log("No transaction response"); + continue; + } + + const signature = eligibleSignatures[index].signature; + const events = parseEvents(ammClient.program, transactionResponse as VersionedTransactionResponse); + + for (const event of events) { + await processAmmEvent(event, signature, transactionResponse); + } + } + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in indexAmmEvents: ${error.message}` + : "Unknown error in indexAmmEvents" + ]); + } +} + +async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "CreateAmmEvent": + await handleCreateAmmEvent(event.data as CreateAmmEvent); + break; + case "AddLiquidityEvent": + await handleAddLiquidityEvent(event.data as AddLiquidityEvent); + break; + case "RemoveLiquidityEvent": + await handleRemoveLiquidityEvent(event.data as RemoveLiquidityEvent); + break; + case "SwapEvent": + await handleSwapEvent(event.data as SwapEvent, signature, transactionResponse); + break; + default: + console.log("Unknown event", event); + } +} +async function handleCreateAmmEvent(event: CreateAmmEvent) { + await usingDb(async (db: DBConnection) => { + await insertTokenIfNotExists(db, event.lpMint); + await insertTokenIfNotExists(db, event.baseMint); + await insertTokenIfNotExists(db, event.quoteMint); + await insertMarketIfNotExists(db, { + marketAcct: event.common.amm.toBase58(), + baseMint: event.baseMint.toString(), + quoteMint: event.quoteMint.toString(), + }); + + await db.insert(schema.v0_4_amms).values({ + ammAddr: event.common.amm.toString(), + lpMintAddr: event.lpMint.toString(), + createdAtSlot: BigInt(event.common.slot.toString()), + baseMintAddr: event.baseMint.toString(), + quoteMintAddr: event.quoteMint.toString(), + latestAmmSeqNumApplied: 0n, + baseReserves: 0n, + quoteReserves: 0n, + }).onConflictDoNothing(); + }); +} + +async function handleAddLiquidityEvent(event: AddLiquidityEvent) { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); +} + +async function handleRemoveLiquidityEvent(event: RemoveLiquidityEvent) { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); +} + +async function handleSwapEvent(event: SwapEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + if (transactionResponse.blockTime === null || transactionResponse.blockTime === undefined) { + return; + }; + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_swaps).values({ + signature: signature, + slot: BigInt(transactionResponse.slot), + // @ts-ignore - fixed above in the if statement + blockTime: new Date(transactionResponse.blockTime * 1000), + swapType: event.swapType.buy ? V04SwapType.Buy : V04SwapType.Sell, + ammAddr: event.common.amm.toString(), + userAddr: event.common.user.toString(), + inputAmount: event.inputAmount.toString(), + outputAmount: event.outputAmount.toString(), + ammSeqNum: BigInt(event.common.seqNum.toString()) + }).onConflictDoNothing(); + + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + }); +} + +async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_splits).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); +} + +async function handleMergeEvent(event: MergeTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_merges).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); +} + +async function insertTokenIfNotExists(db: DBConnection, mintAcct: PublicKey) { + const existingToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, mintAcct.toString())).limit(1); + if (existingToken.length === 0) { + console.log("Inserting token", mintAcct.toString()); + const mint: token.Mint = await token.getMint(connection, mintAcct); + await db.insert(schema.tokens).values({ + mintAcct: mintAcct.toString(), + symbol: mintAcct.toString().slice(0, 3), + name: mintAcct.toString().slice(0, 3), + decimals: mint.decimals, + supply: mint.supply, + updatedAt: new Date(), + }).onConflictDoNothing(); + } +} + +export async function indexVaultEvents() { + try { + const eligibleSignatures = await fetchEligibleSignatures(CONDITIONAL_VAULT_PROGRAM_ID.toString(), 1000); + + if (eligibleSignatures.length === 0) { + console.log("No signatures for Vault events"); + return; + } + + const transactionResponses = await fetchTransactionResponses(eligibleSignatures); + + for (const [index, transactionResponse] of transactionResponses.entries()) { + if (!transactionResponse) { + console.log("No transaction response"); + continue; + } + + const signature = eligibleSignatures[index].signature; + const events = parseEvents(conditionalVaultClient.vaultProgram, transactionResponse as VersionedTransactionResponse); + + for (const event of events) { + await processVaultEvent(event, signature, transactionResponse); + } + } + + //set last process slot + await setLatestProcessedSlot(Number(eligibleSignatures[0].slot)); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in indexVaultEvents: ${error.message}` + : "Unknown error in indexVaultEvents" + ]); + } +} + +async function processVaultEvent(event: { name: string; data: ConditionalVaultEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "InitializeQuestionEvent": + await handleInitializeQuestionEvent(event.data as InitializeQuestionEvent); + break; + case "InitializeConditionalVaultEvent": + await handleInitializeConditionalVaultEvent(event.data as InitializeConditionalVaultEvent); + break; + case "SplitTokensEvent": + await handleSplitEvent(event.data as SplitTokensEvent, signature, transactionResponse); + break; + case "MergeTokensEvent": + await handleMergeEvent(event.data as MergeTokensEvent, signature, transactionResponse); + break; + default: + console.log("Unknown Vault event", event.name); + } +} + +async function handleInitializeQuestionEvent(event: InitializeQuestionEvent) { + await usingDb(async (db) => { + await db.insert(schema.v0_4_questions).values({ + questionAddr: event.question.toString(), + isResolved: false, + oracleAddr: event.oracle.toString(), + numOutcomes: event.numOutcomes, + payoutNumerators: Array(event.numOutcomes).fill(0), + payoutDenominator: 0n, + questionId: event.questionId, + }).onConflictDoNothing(); + }); +} + +async function handleInitializeConditionalVaultEvent(event: InitializeConditionalVaultEvent) { + const vaultAddr = getVaultAddr(conditionalVaultClient.vaultProgram.programId, event.question, event.underlyingTokenMint)[0]; + await usingDb(async (db) => { + await db.transaction(async (trx) => { + if (!await doesQuestionExist(trx, event)) { + return; + } + await insertTokenIfNotExists(trx, event.underlyingTokenMint); + await insertTokenAccountIfNotExists(trx, event); + await insertConditionalVault(trx, event, vaultAddr); + }); + }); +} + +async function doesQuestionExist(db: DBConnection, event: InitializeConditionalVaultEvent): Promise { + const existingQuestion = await db.select().from(schema.v0_4_questions).where(eq(schema.v0_4_questions.questionAddr, event.question.toString())).limit(1); + return existingQuestion.length > 0; + // if (existingQuestion.length === 0) { + // await trx.insert(schema.v0_4_questions).values({ + // questionAddr: event.question.toString(), + // isResolved: false, + // oracleAddr: event.oracle.toString(), + // numOutcomes: event.numOutcomes, + // payoutNumerators: Array(event.numOutcomes).fill(0), + // payoutDenominator: 0n, + // questionId: event.questionId, + // }); + // } +} + +async function insertTokenAccountIfNotExists(db: DBConnection, event: InitializeConditionalVaultEvent) { + const existingTokenAcct = await db.select().from(schema.tokenAccts).where(eq(schema.tokenAccts.tokenAcct, event.vaultUnderlyingTokenAccount.toString())).limit(1); + if (existingTokenAcct.length === 0) { + await db.insert(schema.tokenAccts).values({ + tokenAcct: event.vaultUnderlyingTokenAccount.toString(), + mintAcct: event.underlyingTokenMint.toString(), + ownerAcct: event.vaultUnderlyingTokenAccount.toString(), + amount: 0n, + // Add other required fields for token_accts table + }); + } +} + +async function insertMarketIfNotExists(db: DBConnection, market: Market) { + const existingMarket = await db.select().from(schema.markets).where(eq(schema.markets.marketAcct, market.marketAcct)).limit(1); + if (existingMarket.length === 0) { + await db.insert(schema.markets).values({ + marketAcct: market.marketAcct, + baseMintAcct: market.baseMint, + quoteMintAcct: market.quoteMint, + marketType: 'amm', + createTxSig: '', + baseLotSize: 0n, + quoteLotSize: 0n, + quoteTickSize: 0n, + baseMakerFee: 0, + quoteMakerFee: 0, + baseTakerFee: 0, + quoteTakerFee: 0 + }).onConflictDoNothing(); + // TODO: I don't like this on Conflict.... + } +} + +async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { + const existingPrice = await db.select().from(schema.prices).where(and(eq(schema.prices.marketAcct, event.common.amm.toBase58()), eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())))).limit(1); + if (existingPrice.length > 0) { + console.log("Price already exists", event.common.amm.toBase58(), BigInt(event.common.slot.toString())); + return; + } + // Get's the AMM details for the current price from liquidity event or swap event + const ammPrice = PriceMath.getAmmPriceFromReserves(event.common.postBaseReserves, event.common.postQuoteReserves); + const baseToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].baseMintAddr)).limit(1); + const quoteToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].quoteMintAddr)).limit(1); + const humanPrice = PriceMath.getHumanPrice(ammPrice, baseToken[0].decimals, quoteToken[0].decimals); + + // Inserts the price into the prices table + await db.insert(schema.prices).values({ + marketAcct: event.common.amm.toBase58(), + baseAmount: BigInt(event.common.postBaseReserves.toString()), + quoteAmount: BigInt(event.common.postQuoteReserves.toString()), + price: humanPrice.toString(), + updatedSlot: BigInt(event.common.slot.toString()), + createdBy: 'amm-market-indexer', + pricesType: PricesType.Conditional, + }).onConflictDoNothing(); +} + +async function insertConditionalVault(db: DBConnection, event: InitializeConditionalVaultEvent, vaultAddr: PublicKey) { + await db.insert(schema.v0_4_conditional_vaults).values({ + conditionalVaultAddr: vaultAddr.toString(), + questionAddr: event.question.toString(), + underlyingMintAcct: event.underlyingTokenMint.toString(), + underlyingTokenAcct: event.vaultUnderlyingTokenAccount.toString(), + pdaBump: event.pdaBump, + latestVaultSeqNumApplied: 0n, + }).onConflictDoNothing(); +} \ No newline at end of file diff --git a/packages/new_indexer/src/logger.ts b/packages/new_indexer/src/logger.ts new file mode 100644 index 00000000..f9315a0b --- /dev/null +++ b/packages/new_indexer/src/logger.ts @@ -0,0 +1,83 @@ +import { Counter } from "@lukasdeco/prom-client"; +import { AlertChatBotInterface, TelegramBotAPI } from "./adapters/telegram-bot"; + +const TELEGRAM_ALERT_CHAT_ID = process.env.TELEGRAM_ALERT_CHAT_ID ?? ""; + +export class Logger { + // private errorCounter; + // private warnCounter; + private chatBotApi: AlertChatBotInterface; + + constructor(chatBotApi: AlertChatBotInterface) { + // this.errorCounter = new Counter({ + // name: "errors", + // help: "number of errors", + // }); + + // this.warnCounter = new Counter({ + // name: "warnings", + // help: "number of warnings", + // }); + this.chatBotApi = chatBotApi; + } + + private formatData(data: any[]): string { + return data + .map((item) => { + if (typeof item === "object") { + try { + const jsonItem = JSON.stringify(item); + if (item.message && !jsonItem.includes(item.message)) { + return jsonItem + " " + item.message; + } + return jsonItem; + } catch (error) { + return "[Circular]"; + } + } + if (typeof item === "undefined") { + return "undefined"; + } + try { + return item.toString(); + } catch (e) { + return ""; + } + }) + .join(" "); + } + + log(...data: any[]): void { + console.log(this.formatData(data)); + } + + info(...data: any[]): void { + console.info(this.formatData(data)); + } + + error(...data: any[]): void { + console.error(this.formatData(data)); + // this.errorCounter.inc(); + } + + errorWithChatBotAlert(...data: any[]): void { + const formattedData = this.formatData(data); + console.error(formattedData); + // this.errorCounter.inc(); + if (TELEGRAM_ALERT_CHAT_ID) { + this.chatBotApi.sendMessage(TELEGRAM_ALERT_CHAT_ID, formattedData); + } + } + + warn(message: string): void { + console.warn(message); + // this.warnCounter.inc(); + } +} + +// TODO: add lint rule preventing default exports (default exports are antithetical to IDE auto refactors) +const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; +const telegramBotAPI = new TelegramBotAPI({ + token: TELEGRAM_BOT_TOKEN ?? "", +}); +export const logger = new Logger(telegramBotAPI); diff --git a/packages/new_indexer/src/populateSignatures.ts b/packages/new_indexer/src/populateSignatures.ts new file mode 100644 index 00000000..0890b9df --- /dev/null +++ b/packages/new_indexer/src/populateSignatures.ts @@ -0,0 +1,154 @@ +import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; +import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + + +const RPC_ENDPOINT = process.env.RPC_ENDPOINT; + +if (!RPC_ENDPOINT) { + throw new Error("RPC_ENDPOINT is not set"); +} +const connection = new Connection(RPC_ENDPOINT); +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +// it's possible that there are signatures BEFORE the oldest signature +// because the indexer may not have been running when those signatures were created + +// it's also possible that there are signatures AFTER the newest signature + +// we assume that there aren't signatures between the oldest and newest signatures + +// we split these into two functions: +// - backfillHistoricalSignatures +// - insertNewSignatures + +const backfillHistoricalSignatures = async ( + programId: PublicKey, +) => { + let backfilledSignatures: ConfirmedSignatureInfo[] = []; + let oldestSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature }) + .from(schema.signatures) + .orderBy(asc(schema.signatures.slot)) + .limit(1) + .then(signatures => signatures[0] ? signatures[0].signature : undefined); + }); + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { before: oldestSignature, limit: 1000 }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + backfilledSignatures = backfilledSignatures.concat(signatures); + oldestSignature = signatures[signatures.length - 1].signature; + + console.log(`backfilled ${backfilledSignatures.length} historical signatures so far...`); + } + + console.log(`now done backfilling. backfilled ${backfilledSignatures.length} historical signatures`); + return backfilledSignatures; +}; + +const insertNewSignatures = async (programId: PublicKey) => { + let allSignatures: ConfirmedSignatureInfo[] = []; + let latestRecordedSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) + .from(schema.signatures) + .orderBy(desc(schema.signatures.slot)) + .limit(100) + .then(signatures => { + if (signatures.length === 0) return undefined; + + const latestSlot = signatures[0].slot; + for (let i = 1; i < signatures.length; i++) { + if (signatures[i].slot < latestSlot) { + return signatures[i].signature; + } + } + return signatures[signatures.length - 1].signature; + }); + }); + + let oldestSignatureInserted: string | undefined; + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { limit: 1000, until: latestRecordedSignature, before: oldestSignatureInserted }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + allSignatures = allSignatures.concat(signatures); + oldestSignatureInserted = signatures[signatures.length - 1].signature; + } + + return allSignatures; +} + +const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAddr: PublicKey) => { + await usingDb(async (db) => { + await db.insert(schema.transactions).values(signatures.map(tx => ({ + signature: tx.signature, + slot: BigInt(tx.slot), + failed: tx.err !== null, + blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, + }))).onConflictDoNothing().execute(); + await db.insert(schema.signature_accounts).values(signatures.map(tx => ({ + signature: tx.signature, + account: queriedAddr.toString() + }))).onConflictDoNothing().execute(); + }); +} + +const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; + +export const backfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + const backfilledSignatures = await backfillHistoricalSignatures(programId); + console.log(`backfilled ${backfilledSignatures.length} signatures for ${programId.toString()}`); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} + +export const frontfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + setInterval(async () => { + const newSignatures = await insertNewSignatures(programId); + console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); + }, 1000); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} + +// export const populateSignatures = async () => { + +// // use promise.all so they all run concurrently +// await Promise.all(programIds.map(programId => backfillAndSubscribe(programId))); +// }; \ No newline at end of file diff --git a/packages/new_indexer/tsconfig.json b/packages/new_indexer/tsconfig.json new file mode 100644 index 00000000..c69e542e --- /dev/null +++ b/packages/new_indexer/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "bundler", + "types": ["node", "bun-types", "inquirer"] + } +} diff --git a/packages/v4_indexer/Dockerfile b/packages/v4_indexer/Dockerfile new file mode 100644 index 00000000..29b666ef --- /dev/null +++ b/packages/v4_indexer/Dockerfile @@ -0,0 +1,23 @@ +FROM node:alpine3.18 + +# Some of the dependencies require node-gyp +RUN apk add --no-cache python3 make g++ +RUN if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi + +# Bun requires glibc https://github.com/oven-sh/bun/issues/5545#issuecomment-1722306576 +RUN apk --no-cache add ca-certificates wget +RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub +RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk +RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk + +RUN apk add --no-cache git + +EXPOSE 8080 +RUN corepack prepare pnpm@9.11.0 --activate +RUN corepack enable +ENV REPO_DIR /home/indexer/futarchy-indexer +RUN mkdir -p $REPO_DIR +WORKDIR $REPO_DIR +COPY . . +RUN pnpm install +CMD ["pnpm", "start-service"] diff --git a/packages/v4_indexer/package.json b/packages/v4_indexer/package.json new file mode 100644 index 00000000..c111aea3 --- /dev/null +++ b/packages/v4_indexer/package.json @@ -0,0 +1,47 @@ +{ + "name": "@metadaoproject/indexer-service", + "description": "indexer microservice", + "private": "true", + "scripts": { + "cli": "bun src/cli/index.ts", + "start": "bun src/index.ts", + "test": "bun test" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.29.0", + "@debridge-finance/solana-transaction-parser": "^2.0.1", + "@lukasdeco/prom-client": "^15.1.4", + "@metadaoproject/futarchy": "^0.4.0-alpha.18", + "@metadaoproject/futarchy-sdk": "4.0.0-alpha.31", + "@metadaoproject/indexer-db": "workspace:*", + "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", + "@metaplex-foundation/umi-uploader-bundlr": "^0.9.1", + "@openbook-dex/openbook-v2": "^0.1.9", + "@orca-so/whirlpools-sdk": "^0.12.5", + "@solana/spl-token": "^0.3.8", + "@solana/web3.js": "^1.90.0", + "@types/cors": "^2.8.17", + "ansicolor": "^2.0.1", + "axios": "^1.7.2", + "bs58": "^4.0.1", + "commander": "^12.0.0", + "cors": "^2.8.5", + "croner": "^8.0.2", + "drizzle-orm": "^0.30.6", + "express": "^4.19.2", + "fastq": "^1.17.1", + "inquirer": "^9.2.14", + "jsonwebtoken": "^9.0.2", + "match-discriminated-union": "^1.0.0", + "tweetnacl": "^1.0.3", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/bs58": "^4.0.1", + "@types/express": "^4.17.21", + "@types/inquirer": "^9.0.7", + "@types/jsonwebtoken": "^9.0.6", + "@types/node": "^20.10.6", + "bun-types": "^1.0.30" + } +} diff --git a/packages/v4_indexer/src/adapters/telegram-bot.ts b/packages/v4_indexer/src/adapters/telegram-bot.ts new file mode 100644 index 00000000..07a4ea08 --- /dev/null +++ b/packages/v4_indexer/src/adapters/telegram-bot.ts @@ -0,0 +1,88 @@ +import axios, { AxiosInstance, AxiosResponse } from "axios"; + +type TelegramBotConfig = { + token: string; +}; + +export class TelegramBotAPI implements AlertChatBotInterface { + private readonly apiUrl: string; + private readonly httpClient: AxiosInstance; + + constructor(config: TelegramBotConfig) { + this.apiUrl = `https://api.telegram.org/bot${config.token}/`; + this.httpClient = axios.create({ + baseURL: this.apiUrl, + headers: { + "Content-Type": "application/json", + }, + }); + } + + private async request( + method: "GET" | "POST", + endpoint: string, + params?: object + ): Promise> { + let response: AxiosResponse>; + try { + if (method === "GET") { + response = await this.httpClient.get(endpoint, { params }); + } else { + response = await this.httpClient.post(endpoint, params); + } + return response.data; + } catch (error) { + throw new Error(`Failed to make request: ${error}`); + } + } + + public async getMe(): Promise> { + return this.request("GET", "getMe"); + } + + public async sendMessage( + chatId: number | string, + text: string + ): Promise | null> { + const params = { chat_id: chatId, text }; + try { + return this.request("POST", "sendMessage", params); + } catch (e) { + console.error(e); + return null; + } + } + + public async getUpdates( + offset?: number, + limit?: number, + timeout?: number, + allowed_updates?: string[] + ): Promise> { + const params = { offset, limit, timeout, allowed_updates }; + return this.request("GET", "getUpdates", params); + } + + // Add more methods as needed for other API endpoints +} + +type ChatbotApiResponse = { + ok: boolean; + result?: T; + description?: string; + error_code?: number; +}; + +export interface AlertChatBotInterface { + getMe(): Promise>; + sendMessage( + chatId: number | string, + text: string + ): Promise | null>; + getUpdates( + offset?: number, + limit?: number, + timeout?: number, + allowed_updates?: string[] + ): Promise>; +} diff --git a/packages/v4_indexer/src/connection.ts b/packages/v4_indexer/src/connection.ts new file mode 100644 index 00000000..eafd196f --- /dev/null +++ b/packages/v4_indexer/src/connection.ts @@ -0,0 +1,19 @@ +import { Connection } from "@solana/web3.js"; +import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { ConditionalVaultClient, AmmClient } from "@metadaoproject/futarchy/v0.4"; + +export const RPC_ENDPOINT = process.env.RPC_ENDPOINT ?? ""; + +if (!RPC_ENDPOINT) { + throw new Error("RPC_ENDPOINT is not set"); +} + +export const connection: Connection = new Connection(RPC_ENDPOINT, "confirmed"); +// the indexer will only be reading, not writing +export const readonlyWallet: Wallet = undefined as unknown as Wallet; +export const provider = new AnchorProvider(connection, readonlyWallet, { + commitment: "confirmed", +}); + +export const ammClient = AmmClient.createClient({ provider }); +export const conditionalVaultClient = ConditionalVaultClient.createClient({ provider }); diff --git a/packages/v4_indexer/src/index.ts b/packages/v4_indexer/src/index.ts new file mode 100644 index 00000000..a3413acd --- /dev/null +++ b/packages/v4_indexer/src/index.ts @@ -0,0 +1,60 @@ +import { indexAmmEvents, indexVaultEvents } from "./indexEvents.js"; +import { backfill, frontfill } from "./populateSignatures.js"; + +// NEW FUTARCHY INDEXER + +// To minimize complexity, the indexer is split into two parts: +// 1. signature ingestion +// 2. signature processing + +// SIGNATURE INGESTION +// Signature ingestion is responsible for fetching new signatures +// from the network and storing them in the `signatures` table. +// Today, this is done by the `populateSignatures` function. Under +// the hood, it uses the `getSignaturesForAddress` RPC endpoint. +// This is nice because it means that the indexer can fetch +// historical data. However, it is higher latency than subscribing +// to transactions via a websocket, like the below: +// https://docs.helius.dev/webhooks-and-websockets/enhanced-websockets +// We could use this to get real-time transaction data in the future. + +// SIGNATURE PROCESSING +// Signature processing is responsible for fetching the transactions +// corresponding to the signatures and parsing them to extract event data. +// This is done by the `indexAmmEvents` and `indexVaultEvents` functions. +// Today, insertion of new accounts (questions, conditional vaults, AMMs) +// works. However, updating them (when, for example, a swap happens) doesn't. + +// For it to work, we need to do the following: +// 1) Add `slot_last_applied` and `signature_last_applied` columns to the +// `amm` and `conditional_vault` tables. +// 2) When processing a signature, fetch the account from the DB and check +// if the signature's slot is greater than the account's `slot_last_applied`. +// If it isn't, skip it. If it's greater, apply it. If it's equal, we need +// to run a `getBlock` RPC call and check which transaction is latest. + + +async function main() { + // await populateSignatures(); + // await indexAmms(); + // console.log("indexAmmEvents"); + // await indexVaultEvents(); + // await indexAmmEvents(); + + await backfill(); + await Promise.all([ + frontfill(), + setInterval(async () => { + await Promise.all([ + indexAmmEvents(), + indexVaultEvents(), + ]) + }, 1000), + ]); + // await Promise.all([ + // populateSignatures(), + // indexAmmEvents(), + // ]) +} + +main(); \ No newline at end of file diff --git a/packages/v4_indexer/src/indexEvents.ts b/packages/v4_indexer/src/indexEvents.ts new file mode 100644 index 00000000..0b576ed8 --- /dev/null +++ b/packages/v4_indexer/src/indexEvents.ts @@ -0,0 +1,505 @@ +import { AddLiquidityEvent, AMM_PROGRAM_ID, AmmEvent, CONDITIONAL_VAULT_PROGRAM_ID, ConditionalVaultEvent, CreateAmmEvent, getVaultAddr, InitializeConditionalVaultEvent, InitializeQuestionEvent, SwapEvent, PriceMath, SplitTokensEvent, MergeTokensEvent, RemoveLiquidityEvent } from "@metadaoproject/futarchy/v0.4"; +import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; +import * as anchor from "@coral-xyz/anchor"; +import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; +import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; +import * as token from "@solana/spl-token"; + +import { connection, ammClient, conditionalVaultClient } from "./connection"; +import { Program } from "@coral-xyz/anchor"; + +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + +type Market = { + marketAcct: string; + baseMint: string; + quoteMint: string; +} + +type DBConnection = any; // TODO: Fix typing.. + +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +const parseEvents = (program: Program, transactionResponse: VersionedTransactionResponse | TransactionResponse): { name: string; data: any }[] => { + const events: { name: string; data: any }[] = []; + try { + const inner: CompiledInnerInstruction[] = + transactionResponse?.meta?.innerInstructions ?? []; + const idlProgramId = program.programId; + for (let i = 0; i < inner.length; i++) { + for (let j = 0; j < inner[i].instructions.length; j++) { + const ix = inner[i].instructions[j]; + const programPubkey = + transactionResponse?.transaction.message.staticAccountKeys[ + ix.programIdIndex + ]; + if ( + programPubkey === undefined || + !programPubkey.equals(idlProgramId) + ) { + // we are at instructions that does not match the linked program + continue; + } + + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + events.push(event); + } + } + } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error parsing events: ${error.message}` + : "Unknown error parsing events" + ]); + } + + return events; +} + +async function fetchEligibleSignatures(programId: string, limit: number) { + try { + return await usingDb(async (db) => { + let lastSlotIndexerQuery = await db.select() + .from(schema.indexers) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")); + const indexerResult = await lastSlotIndexerQuery; + if (indexerResult.length === 0) throw Error("Indexer not found in indexers table"); + const lastSlotProcessed = indexerResult[0].latestSlotProcessed; + + return db.select({signature: schema.signatures.signature, slot: schema.signatures.slot}) + .from(schema.signatures) + .innerJoin(schema.signature_accounts, eq(schema.signatures.signature, schema.signature_accounts.signature)) + .where( + and( + eq(schema.signature_accounts.account, programId), + gt(schema.signatures.slot, lastSlotProcessed) + ) + ) + .orderBy(desc(schema.signatures.slot)) + .limit(limit); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error fetching eligible signatures: ${error.message}` + : "Unknown error fetching eligible signatures" + ]); + return []; + } +} + +async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { + try { + return await connection.getTransactions( + eligibleSignatures.map(s => s.signature), + { commitment: "confirmed", maxSupportedTransactionVersion: 1 } + ); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error fetching transaction responses: ${error.message}` + : "Unknown error fetching transaction responses" + ]); + return []; + } +} + +//set latestProcessedSlot in db +async function setLatestProcessedSlot(slot: number) { + try { + await usingDb(async (db) => { + await db.update(schema.indexers) + .set({ latestSlotProcessed: BigInt(slot) }) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .execute(); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error setting latest processed slot: ${error.message}` + : "Unknown error setting latest processed slot" + ]); + } +} + +export async function indexAmmEvents() { + try { + const eligibleSignatures = await fetchEligibleSignatures(AMM_PROGRAM_ID.toString(), 100); + if (eligibleSignatures.length === 0) { + console.log("No signatures for AMM events"); + return; + } + + const transactionResponses = await fetchTransactionResponses(eligibleSignatures); + + for (const [index, transactionResponse] of transactionResponses.entries()) { + if (!transactionResponse) { + console.log("No transaction response"); + continue; + } + + const signature = eligibleSignatures[index].signature; + const events = parseEvents(ammClient.program, transactionResponse as VersionedTransactionResponse); + + for (const event of events) { + await processAmmEvent(event, signature, transactionResponse); + } + } + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in indexAmmEvents: ${error.message}` + : "Unknown error in indexAmmEvents" + ]); + } +} + +async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "CreateAmmEvent": + await handleCreateAmmEvent(event.data as CreateAmmEvent); + break; + case "AddLiquidityEvent": + await handleAddLiquidityEvent(event.data as AddLiquidityEvent); + break; + case "RemoveLiquidityEvent": + await handleRemoveLiquidityEvent(event.data as RemoveLiquidityEvent); + break; + case "SwapEvent": + await handleSwapEvent(event.data as SwapEvent, signature, transactionResponse); + break; + default: + console.log("Unknown event", event); + } +} +async function handleCreateAmmEvent(event: CreateAmmEvent) { + await usingDb(async (db: DBConnection) => { + await insertTokenIfNotExists(db, event.lpMint); + await insertTokenIfNotExists(db, event.baseMint); + await insertTokenIfNotExists(db, event.quoteMint); + await insertMarketIfNotExists(db, { + marketAcct: event.common.amm.toBase58(), + baseMint: event.baseMint.toString(), + quoteMint: event.quoteMint.toString(), + }); + + await db.insert(schema.v0_4_amms).values({ + ammAddr: event.common.amm.toString(), + lpMintAddr: event.lpMint.toString(), + createdAtSlot: BigInt(event.common.slot.toString()), + baseMintAddr: event.baseMint.toString(), + quoteMintAddr: event.quoteMint.toString(), + latestAmmSeqNumApplied: 0n, + baseReserves: 0n, + quoteReserves: 0n, + }).onConflictDoNothing(); + }); +} + +async function handleAddLiquidityEvent(event: AddLiquidityEvent) { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); +} + +async function handleRemoveLiquidityEvent(event: RemoveLiquidityEvent) { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); +} + +async function handleSwapEvent(event: SwapEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + if (transactionResponse.blockTime === null || transactionResponse.blockTime === undefined) { + return; + }; + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_swaps).values({ + signature: signature, + slot: BigInt(transactionResponse.slot), + // @ts-ignore - fixed above in the if statement + blockTime: new Date(transactionResponse.blockTime * 1000), + swapType: event.swapType.buy ? V04SwapType.Buy : V04SwapType.Sell, + ammAddr: event.common.amm.toString(), + userAddr: event.common.user.toString(), + inputAmount: event.inputAmount.toString(), + outputAmount: event.outputAmount.toString(), + ammSeqNum: BigInt(event.common.seqNum.toString()) + }).onConflictDoNothing(); + + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + }); +} + +async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_splits).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); +} + +async function handleMergeEvent(event: MergeTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_merges).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); +} + +async function insertTokenIfNotExists(db: DBConnection, mintAcct: PublicKey) { + const existingToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, mintAcct.toString())).limit(1); + if (existingToken.length === 0) { + console.log("Inserting token", mintAcct.toString()); + const mint: token.Mint = await token.getMint(connection, mintAcct); + await db.insert(schema.tokens).values({ + mintAcct: mintAcct.toString(), + symbol: mintAcct.toString().slice(0, 3), + name: mintAcct.toString().slice(0, 3), + decimals: mint.decimals, + supply: mint.supply, + updatedAt: new Date(), + }).onConflictDoNothing(); + } +} + +export async function indexVaultEvents() { + try { + const eligibleSignatures = await fetchEligibleSignatures(CONDITIONAL_VAULT_PROGRAM_ID.toString(), 1000); + + if (eligibleSignatures.length === 0) { + console.log("No signatures for Vault events"); + return; + } + + const transactionResponses = await fetchTransactionResponses(eligibleSignatures); + + for (const [index, transactionResponse] of transactionResponses.entries()) { + if (!transactionResponse) { + console.log("No transaction response"); + continue; + } + + const signature = eligibleSignatures[index].signature; + const events = parseEvents(conditionalVaultClient.vaultProgram, transactionResponse as VersionedTransactionResponse); + + for (const event of events) { + await processVaultEvent(event, signature, transactionResponse); + } + } + + //set last process slot + await setLatestProcessedSlot(Number(eligibleSignatures[0].slot)); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in indexVaultEvents: ${error.message}` + : "Unknown error in indexVaultEvents" + ]); + } +} + +async function processVaultEvent(event: { name: string; data: ConditionalVaultEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "InitializeQuestionEvent": + await handleInitializeQuestionEvent(event.data as InitializeQuestionEvent); + break; + case "InitializeConditionalVaultEvent": + await handleInitializeConditionalVaultEvent(event.data as InitializeConditionalVaultEvent); + break; + case "SplitTokensEvent": + await handleSplitEvent(event.data as SplitTokensEvent, signature, transactionResponse); + break; + case "MergeTokensEvent": + await handleMergeEvent(event.data as MergeTokensEvent, signature, transactionResponse); + break; + default: + console.log("Unknown Vault event", event.name); + } +} + +async function handleInitializeQuestionEvent(event: InitializeQuestionEvent) { + await usingDb(async (db) => { + await db.insert(schema.v0_4_questions).values({ + questionAddr: event.question.toString(), + isResolved: false, + oracleAddr: event.oracle.toString(), + numOutcomes: event.numOutcomes, + payoutNumerators: Array(event.numOutcomes).fill(0), + payoutDenominator: 0n, + questionId: event.questionId, + }).onConflictDoNothing(); + }); +} + +async function handleInitializeConditionalVaultEvent(event: InitializeConditionalVaultEvent) { + const vaultAddr = getVaultAddr(conditionalVaultClient.vaultProgram.programId, event.question, event.underlyingTokenMint)[0]; + await usingDb(async (db) => { + await db.transaction(async (trx) => { + if (!await doesQuestionExist(trx, event)) { + return; + } + await insertTokenIfNotExists(trx, event.underlyingTokenMint); + await insertTokenAccountIfNotExists(trx, event); + await insertConditionalVault(trx, event, vaultAddr); + }); + }); +} + +async function doesQuestionExist(db: DBConnection, event: InitializeConditionalVaultEvent): Promise { + const existingQuestion = await db.select().from(schema.v0_4_questions).where(eq(schema.v0_4_questions.questionAddr, event.question.toString())).limit(1); + return existingQuestion.length > 0; + // if (existingQuestion.length === 0) { + // await trx.insert(schema.v0_4_questions).values({ + // questionAddr: event.question.toString(), + // isResolved: false, + // oracleAddr: event.oracle.toString(), + // numOutcomes: event.numOutcomes, + // payoutNumerators: Array(event.numOutcomes).fill(0), + // payoutDenominator: 0n, + // questionId: event.questionId, + // }); + // } +} + +async function insertTokenAccountIfNotExists(db: DBConnection, event: InitializeConditionalVaultEvent) { + const existingTokenAcct = await db.select().from(schema.tokenAccts).where(eq(schema.tokenAccts.tokenAcct, event.vaultUnderlyingTokenAccount.toString())).limit(1); + if (existingTokenAcct.length === 0) { + await db.insert(schema.tokenAccts).values({ + tokenAcct: event.vaultUnderlyingTokenAccount.toString(), + mintAcct: event.underlyingTokenMint.toString(), + ownerAcct: event.vaultUnderlyingTokenAccount.toString(), + amount: 0n, + // Add other required fields for token_accts table + }); + } +} + +async function insertMarketIfNotExists(db: DBConnection, market: Market) { + const existingMarket = await db.select().from(schema.markets).where(eq(schema.markets.marketAcct, market.marketAcct)).limit(1); + if (existingMarket.length === 0) { + await db.insert(schema.markets).values({ + marketAcct: market.marketAcct, + baseMintAcct: market.baseMint, + quoteMintAcct: market.quoteMint, + marketType: 'amm', + createTxSig: '', + baseLotSize: 0n, + quoteLotSize: 0n, + quoteTickSize: 0n, + baseMakerFee: 0, + quoteMakerFee: 0, + baseTakerFee: 0, + quoteTakerFee: 0 + }).onConflictDoNothing(); + // TODO: I don't like this on Conflict.... + } +} + +async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { + const existingPrice = await db.select().from(schema.prices).where(and(eq(schema.prices.marketAcct, event.common.amm.toBase58()), eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())))).limit(1); + if (existingPrice.length > 0) { + console.log("Price already exists", event.common.amm.toBase58(), BigInt(event.common.slot.toString())); + return; + } + // Get's the AMM details for the current price from liquidity event or swap event + const ammPrice = PriceMath.getAmmPriceFromReserves(event.common.postBaseReserves, event.common.postQuoteReserves); + const baseToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].baseMintAddr)).limit(1); + const quoteToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].quoteMintAddr)).limit(1); + const humanPrice = PriceMath.getHumanPrice(ammPrice, baseToken[0].decimals, quoteToken[0].decimals); + + // Inserts the price into the prices table + await db.insert(schema.prices).values({ + marketAcct: event.common.amm.toBase58(), + baseAmount: BigInt(event.common.postBaseReserves.toString()), + quoteAmount: BigInt(event.common.postQuoteReserves.toString()), + price: humanPrice.toString(), + updatedSlot: BigInt(event.common.slot.toString()), + createdBy: 'amm-market-indexer', + pricesType: PricesType.Conditional, + }).onConflictDoNothing(); +} + +async function insertConditionalVault(db: DBConnection, event: InitializeConditionalVaultEvent, vaultAddr: PublicKey) { + await db.insert(schema.v0_4_conditional_vaults).values({ + conditionalVaultAddr: vaultAddr.toString(), + questionAddr: event.question.toString(), + underlyingMintAcct: event.underlyingTokenMint.toString(), + underlyingTokenAcct: event.vaultUnderlyingTokenAccount.toString(), + pdaBump: event.pdaBump, + latestVaultSeqNumApplied: 0n, + }).onConflictDoNothing(); +} \ No newline at end of file diff --git a/packages/v4_indexer/src/logger.ts b/packages/v4_indexer/src/logger.ts new file mode 100644 index 00000000..f9315a0b --- /dev/null +++ b/packages/v4_indexer/src/logger.ts @@ -0,0 +1,83 @@ +import { Counter } from "@lukasdeco/prom-client"; +import { AlertChatBotInterface, TelegramBotAPI } from "./adapters/telegram-bot"; + +const TELEGRAM_ALERT_CHAT_ID = process.env.TELEGRAM_ALERT_CHAT_ID ?? ""; + +export class Logger { + // private errorCounter; + // private warnCounter; + private chatBotApi: AlertChatBotInterface; + + constructor(chatBotApi: AlertChatBotInterface) { + // this.errorCounter = new Counter({ + // name: "errors", + // help: "number of errors", + // }); + + // this.warnCounter = new Counter({ + // name: "warnings", + // help: "number of warnings", + // }); + this.chatBotApi = chatBotApi; + } + + private formatData(data: any[]): string { + return data + .map((item) => { + if (typeof item === "object") { + try { + const jsonItem = JSON.stringify(item); + if (item.message && !jsonItem.includes(item.message)) { + return jsonItem + " " + item.message; + } + return jsonItem; + } catch (error) { + return "[Circular]"; + } + } + if (typeof item === "undefined") { + return "undefined"; + } + try { + return item.toString(); + } catch (e) { + return ""; + } + }) + .join(" "); + } + + log(...data: any[]): void { + console.log(this.formatData(data)); + } + + info(...data: any[]): void { + console.info(this.formatData(data)); + } + + error(...data: any[]): void { + console.error(this.formatData(data)); + // this.errorCounter.inc(); + } + + errorWithChatBotAlert(...data: any[]): void { + const formattedData = this.formatData(data); + console.error(formattedData); + // this.errorCounter.inc(); + if (TELEGRAM_ALERT_CHAT_ID) { + this.chatBotApi.sendMessage(TELEGRAM_ALERT_CHAT_ID, formattedData); + } + } + + warn(message: string): void { + console.warn(message); + // this.warnCounter.inc(); + } +} + +// TODO: add lint rule preventing default exports (default exports are antithetical to IDE auto refactors) +const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; +const telegramBotAPI = new TelegramBotAPI({ + token: TELEGRAM_BOT_TOKEN ?? "", +}); +export const logger = new Logger(telegramBotAPI); diff --git a/packages/v4_indexer/src/populateSignatures.ts b/packages/v4_indexer/src/populateSignatures.ts new file mode 100644 index 00000000..b47cdfe6 --- /dev/null +++ b/packages/v4_indexer/src/populateSignatures.ts @@ -0,0 +1,155 @@ +import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; +import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + + +const RPC_ENDPOINT = process.env.RPC_ENDPOINT; + +if (!RPC_ENDPOINT) { + throw new Error("RPC_ENDPOINT is not set"); +} +const connection = new Connection(RPC_ENDPOINT); +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +// it's possible that there are signatures BEFORE the oldest signature +// because the indexer may not have been running when those signatures were created + +// it's also possible that there are signatures AFTER the newest signature + +// we assume that there aren't signatures between the oldest and newest signatures + +// we split these into two functions: +// - backfillHistoricalSignatures +// - insertNewSignatures + +const backfillHistoricalSignatures = async ( + programId: PublicKey, +) => { + let backfilledSignatures: ConfirmedSignatureInfo[] = []; + let oldestSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature }) + .from(schema.signatures) + .orderBy(asc(schema.signatures.slot)) + .limit(1) + .then(signatures => signatures[0] ? signatures[0].signature : undefined); + }); + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { before: oldestSignature, limit: 1000 }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + backfilledSignatures = backfilledSignatures.concat(signatures); + oldestSignature = signatures[signatures.length - 1].signature; + + console.log(`backfilled ${backfilledSignatures.length} historical signatures so far...`); + } + + console.log(`now done backfilling. backfilled ${backfilledSignatures.length} historical signatures`); + return backfilledSignatures; +}; + +const insertNewSignatures = async (programId: PublicKey) => { + let allSignatures: ConfirmedSignatureInfo[] = []; + let latestRecordedSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) + .from(schema.signatures) + .orderBy(desc(schema.signatures.slot)) + .limit(100) + .then(signatures => { + if (signatures.length === 0) return undefined; + + const latestSlot = signatures[0].slot; + for (let i = 1; i < signatures.length; i++) { + if (signatures[i].slot < latestSlot) { + return signatures[i].signature; + } + } + return signatures[signatures.length - 1].signature; + }); + }); + + let oldestSignatureInserted: string | undefined; + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { limit: 1000, until: latestRecordedSignature, before: oldestSignatureInserted }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + allSignatures = allSignatures.concat(signatures); + oldestSignatureInserted = signatures[signatures.length - 1].signature; + } + + return allSignatures; +} + +const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAddr: PublicKey) => { + await usingDb(async (db) => { + await db.insert(schema.signatures).values(signatures.map(tx => ({ + signature: tx.signature, + slot: BigInt(tx.slot), + didErr: tx.err !== null, + err: tx.err ? JSON.stringify(tx.err) : null, + blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, + }))).onConflictDoNothing().execute(); + await db.insert(schema.signature_accounts).values(signatures.map(tx => ({ + signature: tx.signature, + account: queriedAddr.toString() + }))).onConflictDoNothing().execute(); + }); +} + +const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; + +export const backfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + const backfilledSignatures = await backfillHistoricalSignatures(programId); + console.log(`backfilled ${backfilledSignatures.length} signatures for ${programId.toString()}`); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} + +export const frontfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + setInterval(async () => { + const newSignatures = await insertNewSignatures(programId); + console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); + }, 1000); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} + +// export const populateSignatures = async () => { + +// // use promise.all so they all run concurrently +// await Promise.all(programIds.map(programId => backfillAndSubscribe(programId))); +// }; \ No newline at end of file diff --git a/packages/v4_indexer/tsconfig.json b/packages/v4_indexer/tsconfig.json new file mode 100644 index 00000000..c69e542e --- /dev/null +++ b/packages/v4_indexer/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "bundler", + "types": ["node", "bun-types", "inquirer"] + } +} From a0f7595c50642e4623f0d7c73237fcb79ad97828 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 30 Oct 2024 15:31:28 -0400 Subject: [PATCH 02/29] wip: stream signatures, consolidate v3+v4 txns --- packages/new_indexer/readme.md | 6 +- packages/new_indexer/src/backfiller.ts | 0 packages/new_indexer/src/frontfiller.ts | 0 packages/new_indexer/src/processLogs.ts | 5 + packages/new_indexer/src/subscriber.ts | 60 ++ .../amm-market/amm-market-account-indexer.ts | 37 + .../amm-market-account-interval-indexer.ts | 65 ++ .../amm-market-instruction-indexer.ts | 66 ++ .../amm-market-logs-subscribe-indexer.ts | 46 + .../src/v3_indexer/amm-market/utils.ts | 158 +++ .../autocrat/autocrat-dao-indexer.ts | 134 +++ .../autocrat/autocrat-proposal-indexer.ts | 946 ++++++++++++++++++ .../autocrat/autocrat-v0-indexer.ts | 21 + .../autocrat/autocrat-v0_1-indexer.ts | 21 + .../autocrat/autocrat-v0_2-indexer.ts | 21 + .../birdeye/birdeye-prices-indexer.ts | 102 ++ .../jupiter/jupiter-quotes-indexer.ts | 224 +++++ .../openbook-twap-instruction-indexer.ts | 26 + .../openbook-v2-account-indexer.ts | 98 ++ .../openbook-v2/openbook-v2-indexer.ts | 11 + .../v3_indexer/token/token-mint-indexer.ts | 70 ++ .../src/{ => v4_indexer}/indexEvents.ts | 75 +- .../{ => v4_indexer}/populateSignatures.ts | 0 23 files changed, 2173 insertions(+), 19 deletions(-) create mode 100644 packages/new_indexer/src/backfiller.ts create mode 100644 packages/new_indexer/src/frontfiller.ts create mode 100644 packages/new_indexer/src/processLogs.ts create mode 100644 packages/new_indexer/src/subscriber.ts create mode 100644 packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/amm-market/utils.ts create mode 100644 packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts rename packages/new_indexer/src/{ => v4_indexer}/indexEvents.ts (89%) rename packages/new_indexer/src/{ => v4_indexer}/populateSignatures.ts (100%) diff --git a/packages/new_indexer/readme.md b/packages/new_indexer/readme.md index 4ed7b1fc..2ce87d01 100644 --- a/packages/new_indexer/readme.md +++ b/packages/new_indexer/readme.md @@ -6,14 +6,16 @@ Transaction Indexer Indexes all transactions across all programs v3 and v4. Populates transactions table where the signature is the pk and transaction_accounts, which links each signature to an account_id (program) -Split into 2 parts - frontfiller and backfiller +Split into 2 parts - subscriber, frontfiller, and backfiller + +Subscriber - subscribes to txns on each program, and asynchrounously triggers processTransaction() everytime a new tx is picked up Frontfiller - checks for new transactions every second, and when a new txn is detected, first inserts into transactions table, then asynchronously triggers processTransaction() if there is no conflict in the insert (which implies the txn has already been processed) to process the transaction and populate other tables as necessary. This way, we process transactions as soon as they are detected, minimizing latency as compared to having seperate workers that track the transactions table and process transactions (such as fetchEligibleSignatures in v4 indexer). -Backfiller - the purpose of this is a failsafe in case a transaction fails to be picked up by the RPC or indexer. +Backfiller - the purpose of this is a failsafe in case a transaction fails to be picked up by the subscriber or frontfiller. Runs every 15 mins and fetches all signatures within the last 15 mins and adds to transactions table. If the txn doesn't already exist in the transaction table, we process the transaction as it hasn't been indexed. diff --git a/packages/new_indexer/src/backfiller.ts b/packages/new_indexer/src/backfiller.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/new_indexer/src/frontfiller.ts b/packages/new_indexer/src/frontfiller.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/new_indexer/src/processLogs.ts b/packages/new_indexer/src/processLogs.ts new file mode 100644 index 00000000..2f71b1ec --- /dev/null +++ b/packages/new_indexer/src/processLogs.ts @@ -0,0 +1,5 @@ + + +export async function processLogs(logs) { + +} \ No newline at end of file diff --git a/packages/new_indexer/src/subscriber.ts b/packages/new_indexer/src/subscriber.ts new file mode 100644 index 00000000..bc0b26cd --- /dev/null +++ b/packages/new_indexer/src/subscriber.ts @@ -0,0 +1,60 @@ +import { connection } from "./connection"; +import { Logs, PublicKey } from "@solana/web3.js"; +import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; +import { AccountLogsIndexer } from "./account-logs-indexer"; +import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; +import { logger } from "../logger"; +import { processLogs } from "./processLogs"; + +async function processLogs(logs: Logs, programId: PublicKey) { + //check if programId is v3 or v4 + if (programId.equals(V4_AMM_PROGRAM_ID) || programId.equals(V4_AUTOCRAT_PROGRAM_ID) || programId.equals(V4_CONDITIONAL_VAULT_PROGRAM_ID)) { + await processLogsV4(logs, programId); + } else if (programId.equals(V3_AMM_PROGRAM_ID) || programId.equals(V3_AUTOCRAT_PROGRAM_ID) || programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { + await processLogsV3(logs, programId); + } else { + logger.error(`Unknown programId ${programId.toString()}`); + } +} + +async function processLogsV4(logs: Logs, programId: PublicKey) { + let signature = logs.signature; + +} + +async function processLogsV3(logs: Logs, programId: PublicKey) { + +} + +//subscribes to logs for a given account +async function subscribe(accountPubKey: PublicKey) { + connection.onLogs(accountPubKey, async (logs: Logs) => { //TODO: maybe add commitment "confirmed" (rpc docs doesnt say if this is default) + try { + // wait here because we need to fetch the txn from RPC + // and often we get no response if we try right after recieving the logs notification + await new Promise((resolve) => setTimeout(resolve, 1500)); + processLogs(logs, accountPubKey); //trigger processing of logs + } catch (error) { + logger.errorWithChatBotAlert(`Error processing logs for account ${accountPubKey.toString()}`, error); + } + }); +} + +//asynchronously subscribes to logs for all programs +export async function subscribeAll() { + const programIds = [ + V4_AMM_PROGRAM_ID, + V4_AUTOCRAT_PROGRAM_ID, + V4_CONDITIONAL_VAULT_PROGRAM_ID, + V3_AMM_PROGRAM_ID, + V3_AUTOCRAT_PROGRAM_ID, + V3_CONDITIONAL_VAULT_PROGRAM_ID + ]; + Promise.all(programIds.map(async (programId) => subscribe(programId))); +} + + + + diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts new file mode 100644 index 00000000..d54a4c28 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts @@ -0,0 +1,37 @@ +import { AccountInfoIndexer } from "../account-info-indexer"; +import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; +import { Err, Ok } from "../../match"; +import { indexAmmMarketAccountWithContext } from "./utils"; +import { logger } from "../../logger"; + +export enum AmmAccountIndexerError { + GeneralError = "GeneralError", +} + +export const AmmMarketAccountUpdateIndexer: AccountInfoIndexer = { + index: async ( + accountInfo: AccountInfo, + account: PublicKey, + context: Context + ) => { + try { + const res = await indexAmmMarketAccountWithContext( + accountInfo, + account, + context + ); + + if (res.success) { + logger.log(res.ok); + return Ok({ acct: account.toBase58() }); + } + return res; + } catch (e) { + logger.errorWithChatBotAlert( + "general error with indexing amm market account info:", + e + ); + return Err({ type: AmmAccountIndexerError.GeneralError }); + } + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts new file mode 100644 index 00000000..ad3b511b --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts @@ -0,0 +1,65 @@ +import { PublicKey } from "@solana/web3.js"; +import { Err, Ok, Result } from "../../match"; +import { indexAmmMarketAccountWithContext } from "./utils"; +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { connection } from "../../connection"; +import { logger } from "../../logger"; +import { AmmMarketAccountIndexingErrors } from "./utils"; + +export enum AmmAccountIntervalIndexerError { + General = "General", + InvalidRPCResponse = "InvalidRPCResponse", + BlankAccountAddr = "BlankAccountAddr", +} + +export const AmmMarketAccountIntervalFetchIndexer: IntervalFetchIndexer = { + cronExpression: "50 * * * * *", + retries: 3, + index: async (acct: string) => { + if (acct === "") { + return Err({ + type: AmmAccountIntervalIndexerError.BlankAccountAddr, + }); + } + try { + const account = new PublicKey(acct); + const resWithContext = await connection.getAccountInfoAndContext(account); + if (!resWithContext.value) { + return Err({ + type: AmmAccountIntervalIndexerError.InvalidRPCResponse, + }); + } + + const res = await indexAmmMarketAccountWithContext( + resWithContext.value, + account, + resWithContext.context + ); + + if (res.success) { + logger.log(res.ok); + return Ok({ acct: account.toBase58() }); + } + return res; + } catch (e) { + if ( + e instanceof Object && + 'success' in e && + !e.success && + 'error' in e && + typeof e.error === 'object' && + e.error !== null && + 'type' in e.error + ) { + if (e.error.type === AmmMarketAccountIndexingErrors.AmmV4TwapIndexError) { + logger.error("failed to index amm twap for v4 amm", acct); + } else { + logger.errorWithChatBotAlert("general error with indexing amm market account info interval fetcher:", e); + } + } else { + logger.errorWithChatBotAlert("general error with indexing amm market account info interval fetcher:", e); + } + return Err({ type: AmmAccountIntervalIndexerError.General }); + } + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts new file mode 100644 index 00000000..7f833a41 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts @@ -0,0 +1,66 @@ +import { VersionedTransactionResponse } from "@solana/web3.js"; +import { Err, Ok, Result, TaggedUnion } from "../../match"; +import { TransactionRecord } from "@metadaoproject/indexer-db/lib/schema"; +import { AMM_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { InstructionIndexer } from "../instruction-indexer"; +import { + AmmInstructionIndexerError, + SwapPersistableError, +} from "../../types/errors"; +import { ammClient, IDL } from "../common"; +import { SwapBuilder } from "../../builders/swaps"; +import { logger } from "../../logger"; +import { GetTransactionErrorType } from "../../transaction/serializer"; + +export const AmmMarketInstructionsIndexer: InstructionIndexer = { + PROGRAM_ID: AMM_PROGRAM_ID.toString(), + PROGRAM_IDL: ammClient.program.idl, + PROGRAM_NAME: "amm", + indexInstruction: async ( + transactionIndex: number, + transactionResponse: VersionedTransactionResponse, + instructionIndex: number, + decodedInstruction: IDL["instructions"][number] + ) => { + return Ok({ txSig: "" }); + }, + async indexTransactionSig(transaction: TransactionRecord): Promise< + Result< + { + txSig: string; + }, + TaggedUnion + > + > { + const builder = new SwapBuilder(); + const buildRes = await builder.withSignatureAndCtx(transaction.txSig, { + slot: Number(transaction.slot), + }); + if (!buildRes.success) { + if ( + buildRes.error.type === SwapPersistableError.NonSwapTransaction || + buildRes.error.type === SwapPersistableError.AlreadyPersistedSwap || + buildRes.error.type === SwapPersistableError.ArbTransactionError || + buildRes.error.type === AmmInstructionIndexerError.FailedSwap || + (buildRes.error.type === SwapPersistableError.TransactionParseError && + buildRes.error.value?.type === + GetTransactionErrorType.NullGetTransactionResponse) || + buildRes.error.type === SwapPersistableError.PriceError + ) { + logger.error( + `error with indexing amm transaction ${transaction.txSig}`, + buildRes.error + ); + } else { + logger.errorWithChatBotAlert( + `error with indexing amm transaction ${transaction.txSig}`, + buildRes.error + ); + } + return Err({ type: AmmInstructionIndexerError.GeneralError }); + } + const persistable = buildRes.ok; + await persistable.persist(); + return Ok({ txSig: transaction.txSig }); + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts new file mode 100644 index 00000000..1946b6bc --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts @@ -0,0 +1,46 @@ +import { Context, Logs, PublicKey } from "@solana/web3.js"; +import { Err, Ok } from "../../match"; +import { AccountLogsIndexer } from "../account-logs-indexer"; +import { SwapBuilder } from "../../builders/swaps"; +import { logger } from "../../logger"; +import { SwapPersistableError } from "../../types/errors"; +import { GetTransactionErrorType } from "../../transaction/serializer"; + +export enum AmmAccountLogsIndexerError { + GeneralError = "GeneralError", +} + +export const AmmMarketLogsSubscribeIndexer: AccountLogsIndexer = { + index: async (logs: Logs, account: PublicKey, context: Context) => { + const builder = new SwapBuilder(); + const buildRes = await builder.withSignatureAndCtx(logs.signature, context); + if (!buildRes.success) { + if ( + buildRes.error.type === SwapPersistableError.NonSwapTransaction || + buildRes.error.type === SwapPersistableError.AlreadyPersistedSwap || + (buildRes.error.type === SwapPersistableError.TransactionParseError && + buildRes.error.value?.type === + GetTransactionErrorType.NullGetTransactionResponse) || + buildRes.error.type === SwapPersistableError.PriceError || + buildRes.error.type === SwapPersistableError.ArbTransactionError + ) { + logger.error( + `error with indexing amm logs, signature: ${logs.signature}`, + buildRes.error + ); + } else { + logger.errorWithChatBotAlert( + `error with indexing amm logs, signature: ${logs.signature}`, + buildRes.error + ); + } + return Err({ + type: AmmAccountLogsIndexerError.GeneralError, + value: buildRes.error.type + " " + buildRes.error.value, + }); + } + const persistable = buildRes.ok; + await persistable.persist(); + return Ok({ acct: account.toBase58() }); + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/amm-market/utils.ts b/packages/new_indexer/src/v3_indexer/amm-market/utils.ts new file mode 100644 index 00000000..eeb11945 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/amm-market/utils.ts @@ -0,0 +1,158 @@ +import { BN } from "@coral-xyz/anchor"; +import { BN_0, enrichTokenMetadata } from "@metadaoproject/futarchy-sdk"; +import { PriceMath } from "@metadaoproject/futarchy/v0.4"; +import { schema, usingDb, eq } from "@metadaoproject/indexer-db"; +import { PricesType } from "@metadaoproject/indexer-db/lib/schema"; +import { + TwapRecord, + PricesRecord, +} from "@metadaoproject/indexer-db/lib/schema"; +import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; +import { provider, rpcReadClient } from "../../connection"; +import { Err, Ok, Result, TaggedUnion } from "../../match"; +import { logger } from "../../logger"; +import { getHumanPrice } from "../../usecases/math"; + +export enum AmmMarketAccountIndexingErrors { + AmmTwapIndexError = "AmmTwapIndexError", + MarketMissingError = "MarketMissingError", + AmmV4TwapIndexError = "AmmV4TwapIndexError", + AmmTwapPriceError = "AmmTwapPriceError", + AmmTwapNoInsertError = "AmmTwapNoInsertError", +} + +export async function indexAmmMarketAccountWithContext( + accountInfo: AccountInfo, + account: PublicKey, + context: Context +): Promise> { + const ammMarketAccount = await rpcReadClient.markets.amm.decodeMarket( + accountInfo + ); + const baseToken = await enrichTokenMetadata( + ammMarketAccount.baseMint, + provider + ); + const quoteToken = await enrichTokenMetadata( + ammMarketAccount.quoteMint, + provider + ); + + // if we don't have an oracle.aggregator of 0 let's run this mf + if (ammMarketAccount.oracle.aggregator.toString() !== BN_0.toString()) { + // indexing the twap + const market = await usingDb((db) => + db + .select() + .from(schema.markets) + .where(eq(schema.markets.marketAcct, account.toBase58())) + .execute() + ); + if (market === undefined || market.length === 0) { + return Err({ type: AmmMarketAccountIndexingErrors.MarketMissingError }); + } + + const twapCalculation: BN = ammMarketAccount.oracle.aggregator.div( + ammMarketAccount.oracle.lastUpdatedSlot.sub( + ammMarketAccount.createdAtSlot + ) + ); + + const proposalAcct = market[0].proposalAcct; + + // if (proposalAcct === null) { + // logger.error("failed to index amm twap for v4 amm", account.toBase58()); + // return Err({ type: AmmMarketAccountIndexingErrors.AmmV4TwapIndexError }); + // } + const twapNumber: string = twapCalculation.toString(); + const newTwap: TwapRecord = { + curTwap: twapNumber, + marketAcct: account.toBase58(), + observationAgg: ammMarketAccount.oracle.aggregator.toString(), + proposalAcct: proposalAcct, + // alternatively, we could pass in the context of the update here + updatedSlot: context + ? context.slot.toString() + : ammMarketAccount.oracle.lastUpdatedSlot.toString(), + lastObservation: ammMarketAccount.oracle.lastObservation.toString(), + lastPrice: ammMarketAccount.oracle.lastPrice.toString(), + }; + + try{ + // TODO batch commits across inserts - maybe with event queue + const twapUpsertResult = await usingDb((db) => + db + .insert(schema.twaps) + .values(newTwap) + .onConflictDoNothing() + .returning({ marketAcct: schema.twaps.marketAcct }) + ); + + if (twapUpsertResult === undefined || twapUpsertResult.length === 0) { + logger.error("failed to upsert twap", newTwap); + // return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapNoInsertError }); + } + } catch (e) { + logger.error("failed to upsert twap", e); + return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapNoInsertError }); + } + } + + let priceFromReserves: BN; + + if (ammMarketAccount.baseAmount.toNumber() === 0 || ammMarketAccount.baseAmount.toNumber() === 0) { + logger.error("NO RESERVES", ammMarketAccount); + return Ok("no price from reserves"); + } + + try { + priceFromReserves = PriceMath.getAmmPriceFromReserves( + ammMarketAccount.baseAmount, + ammMarketAccount.quoteAmount + ); + } catch (e) { + logger.error("failed to get price from reserves", e); + return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); + } + + let conditionalMarketSpotPrice: number; + try { + conditionalMarketSpotPrice = getHumanPrice( + priceFromReserves, + baseToken.decimals!!, + quoteToken.decimals!! + ); + } catch (e) { + logger.error("failed to get human price", e); + return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); + } + + const newAmmConditionaPrice: PricesRecord = { + marketAcct: account.toBase58(), + updatedSlot: context + ? context.slot.toString() + : ammMarketAccount.oracle.lastUpdatedSlot.toString(), + price: conditionalMarketSpotPrice.toString(), + pricesType: PricesType.Conditional, + createdBy: "amm-market-indexer", + baseAmount: ammMarketAccount.baseAmount.toString(), + quoteAmount: ammMarketAccount.quoteAmount.toString(), + }; + + const pricesInsertResult = await usingDb((db) => + db + .insert(schema.prices) + .values(newAmmConditionaPrice) + .onConflictDoUpdate({ + target: [schema.prices.createdAt, schema.prices.marketAcct], + set: newAmmConditionaPrice, + }) + .returning({ marketAcct: schema.prices.marketAcct }) + ); + if (pricesInsertResult === undefined || pricesInsertResult.length === 0) { + logger.error("failed to index amm price", newAmmConditionaPrice.marketAcct); + return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); + } + + return Ok(`successfully indexed amm: ${account.toBase58()}`); +} diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts new file mode 100644 index 00000000..3deb8588 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts @@ -0,0 +1,134 @@ +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { rpcReadClient, connection } from "../../connection"; +import { usingDb, schema } from "@metadaoproject/indexer-db"; +import { Dao } from "@metadaoproject/futarchy-sdk"; +import { Err, Ok } from "../../match"; +import { PublicKey } from "@solana/web3.js"; +import { DaoRecord, TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; +import { getMint } from "@solana/spl-token"; +import { logger } from "../../logger"; + +export enum AutocratDaoIndexerError { + GeneralError = "GeneralError", + DuplicateError = "DuplicateError", + MissingParamError = "MissingParamError", + NotFoundError = "NotFoundError", + MissingChainResponseError = "MissingChainResponseError", + NothingToInsertError = "NothingToInsertError", +} + +export const AutocratDaoIndexer: IntervalFetchIndexer = { + cronExpression: "*/20 * * * * *", + index: async () => { + try { + // Fetches all daos from the database + const dbDaos: DaoRecord[] = + (await usingDb((db) => db.select().from(schema.daos).execute())) ?? []; + const onChainDaos = await rpcReadClient.daos.fetchAllDaos(); + + const daosToInsert: Dao[] = []; + for (const daoAggregate of onChainDaos) { + for (const dao of daoAggregate.daos) { + // if ( + // !dbDaos.find((dbDao) => + // new PublicKey(dbDao.daoAcct).equals(dao.publicKey) + // ) + // ) { + // daosToInsert.push(dao); + // } + daosToInsert.push(dao); + } + } + + console.log("DAOS to insert"); + console.log(daosToInsert.map((dao) => dao.publicKey.toString())); + + daosToInsert.map(async (dao) => { + if ( + dao.baseToken.publicKey == null || + dao.quoteToken.publicKey == null + ) { + logger.error("Unable to determine public key for dao tokens"); + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + // const baseTokenData = await enrichTokenMetadata( + // new PublicKey(dao.baseToken.publicKey), + // provider + // ); + const baseTokenMint = await getMint( + connection, + new PublicKey(dao.baseToken.publicKey) + ); + + // Puts the base tokens into the DB before we try to insert the dao + let token: TokenRecord = { + symbol: dao.baseToken.symbol, + name: dao.baseToken.name ? dao.baseToken.name : dao.baseToken.symbol, + decimals: dao.baseToken.decimals, + mintAcct: dao.baseToken.publicKey, + supply: baseTokenMint.supply.toString(), + updatedAt: new Date(), + }; + + await usingDb((db) => + db.insert(schema.tokens).values(token).onConflictDoNothing().execute() + ); + + let daoToInsert: DaoRecord = { + daoAcct: dao.publicKey.toBase58(), + programAcct: dao.protocol.autocrat.programId.toString(), + baseAcct: dao.baseToken.publicKey, + quoteAcct: dao.quoteToken.publicKey, + slotsPerProposal: dao.daoAccount.slotsPerProposal.toString(), + treasuryAcct: dao.daoAccount.treasury.toBase58(), + minBaseFutarchicLiquidity: + dao.daoAccount.minBaseFutarchicLiquidity + ? dao.daoAccount.minBaseFutarchicLiquidity.toString() + : 0 + , + minQuoteFutarchicLiquidity: + dao.daoAccount.minQuoteFutarchicLiquidity + ? dao.daoAccount.minQuoteFutarchicLiquidity.toString() + : 0 + , + passThresholdBps: BigInt(dao.daoAccount.passThresholdBps), + twapInitialObservation: + dao.daoAccount.twapInitialObservation + ? dao.daoAccount.twapInitialObservation.toString() + : 0 + , + twapMaxObservationChangePerUpdate: + dao.daoAccount.twapMaxObservationChangePerUpdate + ? dao.daoAccount.twapMaxObservationChangePerUpdate.toString() + : 0 + , + }; + // After we have the token in the DB, we can now insert the dao + await usingDb((db) => + db + .insert(schema.daos) + .values(daoToInsert) + .onConflictDoUpdate({ + set: { + minBaseFutarchicLiquidity: + daoToInsert.minBaseFutarchicLiquidity, + minQuoteFutarchicLiquidity: + daoToInsert.minQuoteFutarchicLiquidity, + twapInitialObservation: daoToInsert.twapInitialObservation, + twapMaxObservationChangePerUpdate: + daoToInsert.twapMaxObservationChangePerUpdate, + passThresholdBps: daoToInsert.passThresholdBps, + }, + target: schema.daos.daoAcct, + }) + .execute() + ); + }); + + return Ok({ acct: "Updated daos" }); + } catch (err) { + logger.errorWithChatBotAlert(err); + return Err({ type: AutocratDaoIndexerError.GeneralError }); + } + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts new file mode 100644 index 00000000..84047d27 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts @@ -0,0 +1,946 @@ +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { + rpcReadClient, + conditionalVaultClient, + provider, +} from "../../connection"; +import { + usingDb, + schema, + eq, + or, + gt, + lte, + and, + isNull, + sql, + inArray, +} from "@metadaoproject/indexer-db"; +import { Err, Ok } from "../../match"; +import { PublicKey } from "@solana/web3.js"; +import { + ConditionalVaultRecord, + DaoRecord, + MarketRecord, + MarketType, + ProposalRecord, + ProposalStatus, + TokenAcctRecord, + TokenRecord, + UserPerformanceRecord, +} from "@metadaoproject/indexer-db/lib/schema"; +import { + getAccount, + getAssociatedTokenAddressSync, + getMint, +} from "@solana/spl-token"; +import { + ProposalAccountWithKey, + enrichTokenMetadata, +} from "@metadaoproject/futarchy-sdk"; +import { BN } from "@coral-xyz/anchor"; +import { gte } from "drizzle-orm"; +import { desc } from "drizzle-orm"; +import { logger } from "../../logger"; +import { PriceMath, ProposalAccount } from "@metadaoproject/futarchy/v0.3"; +import { UserPerformance, UserPerformanceTotals } from "../../types"; +import { alias } from "drizzle-orm/pg-core"; +import { bigint } from "drizzle-orm/mysql-core"; + +export enum AutocratDaoIndexerError { + GeneralError = "GeneralError", + DuplicateError = "DuplicateError", + MissingParamError = "MissingParamError", + MissingProtocolError = "MissingProtocolError", + NotFoundError = "NotFoundError", + MissingChainResponseError = "MissingChainResponseError", + NothingToInsertError = "NothingToInsertError", +} + +export const AutocratProposalIndexer: IntervalFetchIndexer = { + cronExpression: "5 * * * * *", + index: async () => { + try { + const { currentSlot, currentTime } = + ( + await usingDb((db) => + db + .select({ + currentSlot: schema.prices.updatedSlot, + currentTime: schema.prices.createdAt, + }) + .from(schema.prices) + .orderBy(sql`${schema.prices.updatedSlot} DESC`) + .limit(1) + .execute() + ) + )?.[0] ?? {}; + + console.log("currentSlot", currentSlot); + if (!currentSlot || !currentTime) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + logger.log("Autocrat proposal indexer"); + const dbProposals: ProposalRecord[] = + (await usingDb((db) => db.select().from(schema.proposals).execute())) ?? + []; + + const protocolV0_3 = rpcReadClient.futarchyProtocols.find( + (protocol) => protocol.deploymentVersion == "V0.3" + ); + + const onChainProposals = + (await protocolV0_3?.autocrat.account.proposal.all()!!) as ProposalAccountWithKey[]; + + const proposalsToInsert = []; + for (const proposal of onChainProposals) { + if ( + !dbProposals.find((dbProposal) => + new PublicKey(dbProposal.proposalAcct).equals(proposal.publicKey) && + dbProposal.endedAt === null + ) + ) { + proposalsToInsert.push(proposal); + } + } + + logger.log("Proposals to insert"); + logger.log( + proposalsToInsert.map((proposal) => proposal.publicKey.toString()) + ); + + if(!onChainProposals.length) return Err({ type: AutocratDaoIndexerError.NothingToInsertError }); + + if(!proposalsToInsert.length) return Ok({ acct: "Nothing to insert, we're okay" }); + + proposalsToInsert.map(async (proposal) => { + const storedBaseVault = await conditionalVaultClient.getVault( + proposal.account.baseVault + ); + const storedQuoteVault = await conditionalVaultClient.getVault( + proposal.account.quoteVault + ); + + + const basePass: PublicKey = + storedBaseVault.conditionalOnFinalizeTokenMint; + const baseFail: PublicKey = + storedBaseVault.conditionalOnRevertTokenMint; + const quotePass: PublicKey = + storedQuoteVault.conditionalOnFinalizeTokenMint; + const quoteFail: PublicKey = + storedQuoteVault.conditionalOnRevertTokenMint; + + let baseVault: ConditionalVaultRecord = { + condVaultAcct: proposal.account.baseVault.toString(), + settlementAuthority: storedBaseVault.settlementAuthority.toString(), + underlyingMintAcct: storedBaseVault.underlyingTokenMint.toString(), + underlyingTokenAcct: + storedBaseVault.underlyingTokenAccount.toString(), + condFinalizeTokenMintAcct: basePass.toString(), + condRevertTokenMintAcct: baseFail.toString(), + status: "active", + }; + + let quoteVault: ConditionalVaultRecord = { + condVaultAcct: proposal.account.quoteVault.toString(), + settlementAuthority: storedQuoteVault.settlementAuthority.toString(), + underlyingMintAcct: storedQuoteVault.underlyingTokenMint.toString(), + underlyingTokenAcct: + storedQuoteVault.underlyingTokenAccount.toString(), + condFinalizeTokenMintAcct: quotePass.toString(), + condRevertTokenMintAcct: quoteFail.toString(), + status: "active", + }; + + await usingDb((db) => + db + .insert(schema.conditionalVaults) + .values([baseVault, quoteVault]) + .onConflictDoNothing() + .execute() + ); + + const proposalAcct = proposal.account; + const daoAcct = proposalAcct.dao; + if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + const passAmm = proposalAcct.passAmm; + const failAmm = proposalAcct.failAmm; + if(!passAmm || !failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + + const dbDao: DaoRecord | undefined = ( + await usingDb((db) => + db + .select() + .from(schema.daos) + .where(eq(schema.daos.daoAcct, daoAcct.toBase58())) + .execute() + ) + )?.[0]; + + if (!dbDao) return; + + const dbProposal: ProposalRecord = { + proposalAcct: proposal.publicKey.toString(), + proposalNum: BigInt(proposal.account.number.toString()), + autocratVersion: 0.3, + daoAcct: daoAcct.toString(), + proposerAcct: proposal.account.proposer.toString(), + status: ProposalStatus.Pending, + descriptionURL: proposal.account.descriptionUrl, + initialSlot: proposal.account.slotEnqueued.toString(), + passMarketAcct: passAmm.toString(), + failMarketAcct: failAmm.toString(), + baseVault: proposal.account.baseVault.toString(), + quoteVault: proposal.account.quoteVault.toString(), + endSlot: + proposal.account.slotEnqueued + .add(new BN(dbDao.slotsPerProposal?.toString())) + .toString() + , + durationInSlots: dbDao.slotsPerProposal, + minBaseFutarchicLiquidity: dbDao.minBaseFutarchicLiquidity ?? null, + minQuoteFutarchicLiquidity: dbDao.minQuoteFutarchicLiquidity ?? null, + passThresholdBps: dbDao.passThresholdBps, + twapInitialObservation: dbDao.twapInitialObservation ?? null, + twapMaxObservationChangePerUpdate: + dbDao.twapMaxObservationChangePerUpdate ?? null, + }; + + await usingDb((db) => + db + .insert(schema.proposals) + .values([dbProposal]) + .onConflictDoNothing() + .execute() + ); + await insertAssociatedAccountsDataForProposal(proposal, currentTime); + }); + + logger.log("inserted proposals"); + + for (const onChainProposal of onChainProposals) { + if (onChainProposal.account.state.pending) { + + const daoAcct = onChainProposal.account.dao; + if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + const dbDao: DaoRecord | undefined = ( + await usingDb((db) => + db + .select() + .from(schema.daos) + .where( + eq( + schema.daos.daoAcct, + daoAcct.toBase58() + ) + ) + .execute() + ) + )?.[0]; + + if (!dbDao) continue; + + // Setup for calculating time left + const initialSlot = new BN(onChainProposal.account.slotEnqueued.toString()); + + const slotsPerProposal = new BN(dbDao.slotsPerProposal?.toString()); + + //const endSlot: BN = initialSlot.add(slotsPerProposal); + + const currentSlotBN = new BN(currentSlot.toString()); + + const slotDifference = initialSlot + .add(slotsPerProposal) + .sub(currentSlotBN); + + // Setup time to add to the date.. + const timeLeftSecondsEstimate = (slotDifference.toNumber() * 400) / 1000 // MS to seconds + // const timeLeftMinutesEstimate = timeLeftSecondsEstimate / 60 // MS to seconds to minutes + // const timeLeftHoursEstimate = timeLeftMinutesEstimate / 60 + + const endedAt = new Date(currentTime.toUTCString()); + // endedAt.setHours(endedAt.getHours() + timeLeftHoursEstimate); + // endedAt.setMinutes(endedAt.getMinutes() + timeLeftMinutesEstimate); + endedAt.setSeconds(endedAt.getSeconds() + timeLeftSecondsEstimate); // setSeconds accepts float and will increase to hours etc. + + await usingDb((db) => + db + .update(schema.proposals) + .set({ + endedAt, + proposalAcct: onChainProposal.publicKey.toString(), + proposalNum: BigInt(onChainProposal.account.number.toString()), + autocratVersion: 0.3, + status: ProposalStatus.Pending, + descriptionURL: onChainProposal.account.descriptionUrl, + initialSlot: + onChainProposal.account.slotEnqueued.toString() + , + endSlot: + onChainProposal.account.slotEnqueued + .add(new BN(dbDao.slotsPerProposal?.toString())) + .toString() + , + updatedAt: sql`NOW()`, + }) + .where( + and( + eq( + schema.proposals.proposalAcct, + onChainProposal.publicKey.toString() + ), + sql`CAST(${schema.proposals.endSlot} AS NUMERIC) >= CAST(${currentSlot.toString()} AS NUMERIC)`, + isNull(schema.proposals.completedAt) + ) + ) + .execute() + ); + } + if (onChainProposal.account.state.passed) { + await usingDb((db) => + db + .update(schema.proposals) + .set({ status: ProposalStatus.Passed, completedAt: currentTime }) + .where( + and( + eq( + schema.proposals.proposalAcct, + onChainProposal.publicKey.toString() + ), + isNull(schema.proposals.completedAt) + ) + ) + .execute() + ); + + await usingDb((db) => + db + .update(schema.conditionalVaults) + .set({ status: "finalized" }) + .where( + eq( + schema.conditionalVaults.condVaultAcct, + onChainProposal.account.baseVault.toString() + ) + ) + .execute() + ); + + await usingDb((db) => + db + .update(schema.conditionalVaults) + .set({ status: "finalized" }) + .where( + eq( + schema.conditionalVaults.condVaultAcct, + onChainProposal.account.quoteVault.toString() + ) + ) + .execute() + ); + + await calculateUserPerformance(onChainProposal); + } + if (onChainProposal.account.state.failed) { + await usingDb((db) => + db + .update(schema.proposals) + .set({ status: ProposalStatus.Failed, completedAt: currentTime }) + .where( + and( + eq( + schema.proposals.proposalAcct, + onChainProposal.publicKey.toString() + ), + isNull(schema.proposals.completedAt) + ) + ) + .execute() + ); + + await usingDb((db) => + db + .update(schema.conditionalVaults) + .set({ status: "reverted" }) + .where( + eq( + schema.conditionalVaults.condVaultAcct, + onChainProposal.account.baseVault.toString() + ) + ) + .execute() + ); + + await usingDb((db) => + db + .update(schema.conditionalVaults) + .set({ status: "reverted" }) + .where( + eq( + schema.conditionalVaults.condVaultAcct, + onChainProposal.account.quoteVault.toString() + ) + ) + .execute() + ); + await calculateUserPerformance(onChainProposal); + } + + // check if markets are there, if they aren't insert them + // Check if markets are there, if they aren't, insert them + const passAmm = onChainProposal.account.passAmm; + const failAmm = onChainProposal.account.failAmm; + if(!passAmm || !failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + const existingMarkets = + (await usingDb((db) => + db + .select() + .from(schema.markets) + .where( + or( + eq( + schema.markets.marketAcct, + passAmm.toString() + ), + eq( + schema.markets.marketAcct, + failAmm.toString() + ) + ) + ) + .execute() + )) ?? []; + + if ( + !existingMarkets.some( + (market) => + market.marketAcct === passAmm.toString() + ) || + !existingMarkets.some( + (market) => + market.marketAcct === failAmm.toString() + ) + ) { + await insertAssociatedAccountsDataForProposal( + onChainProposal, + currentTime + ); + } + } + + logger.log("updated proposal and vault states"); + + return Ok({ acct: "Update proposal and vault states" }); + } catch (err) { + logger.error("error with proposal indexer:", err); + return Err({ type: AutocratDaoIndexerError.GeneralError }); + } + }, +}; + +async function insertAssociatedAccountsDataForProposal( + proposal: ProposalAccountWithKey, + currentTime: Date +) { + + const daoAcct = proposal.account.dao; + if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + const dao = + (await usingDb((db) => + db + .select() + .from(schema.daos) + .where(eq(schema.daos.daoAcct, daoAcct.toBase58())) + .execute() + )) ?? []; + + let daoDetails; + if (dao.length > 0) { + const daoId = dao[0].daoId; + if (daoId) { + daoDetails = await usingDb((db) => + db + .select() + .from(schema.daoDetails) + .where(eq(schema.daoDetails.daoId, daoId)) + .execute() + ); + } + } + + const baseTokenMetadata = await enrichTokenMetadata( + new PublicKey(dao[0].baseAcct), + provider + ); + + const storedBaseVault = await conditionalVaultClient.getVault( + proposal.account.baseVault + ); + const storedQuoteVault = await conditionalVaultClient.getVault( + proposal.account.quoteVault + ); + + const basePass: PublicKey = storedBaseVault.conditionalOnFinalizeTokenMint; + const baseFail: PublicKey = storedBaseVault.conditionalOnRevertTokenMint; + const quotePass: PublicKey = storedQuoteVault.conditionalOnFinalizeTokenMint; + const quoteFail: PublicKey = storedQuoteVault.conditionalOnRevertTokenMint; + + let baseVault: ConditionalVaultRecord = { + condVaultAcct: proposal.account.baseVault.toString(), + settlementAuthority: storedBaseVault.settlementAuthority.toString(), + underlyingMintAcct: storedBaseVault.underlyingTokenMint.toString(), + underlyingTokenAcct: storedBaseVault.underlyingTokenAccount.toString(), + condFinalizeTokenMintAcct: basePass.toString(), + condRevertTokenMintAcct: baseFail.toString(), + status: "active", + }; + + let quoteVault: ConditionalVaultRecord = { + condVaultAcct: proposal.account.quoteVault.toString(), + settlementAuthority: storedQuoteVault.settlementAuthority.toString(), + underlyingMintAcct: storedQuoteVault.underlyingTokenMint.toString(), + underlyingTokenAcct: storedQuoteVault.underlyingTokenAccount.toString(), + condFinalizeTokenMintAcct: quotePass.toString(), + condRevertTokenMintAcct: quoteFail.toString(), + status: "active", + }; + + await usingDb((db) => + db + .insert(schema.conditionalVaults) + .values([baseVault, quoteVault]) + .onConflictDoNothing() + .execute() + ); + + let tokensToInsert: TokenRecord[] = []; + for (const token of [basePass, baseFail, quotePass, quoteFail]) { + const metadata = await enrichTokenMetadata(token, provider); + const storedMint = await getMint(provider.connection, token); + + // NOTE: THIS IS ONLY FOR PROPOSALS AND ONLY FOR BASE / QUOTE CONDITIONAL + const isQuote = [quoteFail, quotePass].includes(token); + const isFail = [quoteFail, baseFail].includes(token); + let imageUrl, defaultSymbol, defaultName; + + let passOrFailPrefix = isFail ? "f" : "p"; + // TODO: This MAY have issue with devnet... + let baseSymbol = isQuote ? "USDC" : baseTokenMetadata.symbol; + defaultSymbol = passOrFailPrefix + baseSymbol; + defaultName = `Proposal ${proposal.account.number}: ${defaultSymbol}`; + + if (dao && daoDetails) { + if (isQuote) { + // Fail / Pass USDC + imageUrl = !isFail + ? "https://imagedelivery.net/HYEnlujCFMCgj6yA728xIw/f38677ab-8ec6-4706-6606-7d4e0a3cfc00/public" + : "https://imagedelivery.net/HYEnlujCFMCgj6yA728xIw/d9bfd8de-2937-419a-96f6-8d6a3a76d200/public"; + } else { + // Base Token + imageUrl = isFail + ? daoDetails[0].fail_token_image_url + : daoDetails[0].pass_token_image_url; + } + } + let tokenToInsert: TokenRecord = { + symbol: + metadata.name && !metadata.isFallback ? metadata.symbol : defaultSymbol, + name: metadata.name && !metadata.isFallback ? metadata.name : defaultName, + decimals: metadata.decimals, + mintAcct: token.toString(), + supply: storedMint.supply.toString(), + imageUrl: imageUrl ? imageUrl : "", + updatedAt: currentTime, + }; + tokensToInsert.push(tokenToInsert); + } + + await usingDb((db) => + db + .insert(schema.tokens) + .values(tokensToInsert) + .onConflictDoNothing() + .execute() + ); + + let tokenAcctsToInsert: TokenAcctRecord[] = []; + for (const [mint, owner] of [ + [basePass, proposal.account.passAmm], + [baseFail, proposal.account.failAmm], + [quotePass, proposal.account.passAmm], + [quoteFail, proposal.account.failAmm], + ]) { + if(!mint || !owner) continue; + let tokenAcct: TokenAcctRecord = { + mintAcct: mint.toString(), + updatedAt: currentTime, + tokenAcct: getAssociatedTokenAddressSync(mint, owner, true).toString(), + ownerAcct: owner.toString(), + amount: await getAccount( + provider.connection, + getAssociatedTokenAddressSync(mint, owner, true) + ).then((account) => account.amount.toString()), + }; + tokenAcctsToInsert.push(tokenAcct); + } + + await usingDb((db) => + db + .insert(schema.tokenAccts) + .values(tokenAcctsToInsert) + .onConflictDoNothing() + .execute() + ); + + for (const [mint, owner] of [ + [basePass, proposal.account.passAmm], + [baseFail, proposal.account.failAmm], + [quotePass, proposal.account.passAmm], + [quoteFail, proposal.account.failAmm], + ]) { + if(!mint || !owner) continue; + let tokenAcct: TokenAcctRecord = { + mintAcct: mint.toString(), + updatedAt: currentTime, + tokenAcct: getAssociatedTokenAddressSync(mint, owner, true).toString(), + ownerAcct: owner.toString(), + amount: await getAccount( + provider.connection, + getAssociatedTokenAddressSync(mint, owner, true) + ).then((account) => account.amount.toString()), + }; + tokenAcctsToInsert.push(tokenAcct); + } + + await usingDb((db) => + db + .insert(schema.tokenAccts) + .values(tokenAcctsToInsert) + .onConflictDoNothing() + .execute() + ); + + if(!proposal.account.passAmm || !proposal.account.failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); + + let passMarket: MarketRecord = { + marketAcct: proposal.account.passAmm.toString(), + proposalAcct: proposal.publicKey.toString(), + marketType: MarketType.FUTARCHY_AMM, + createTxSig: "", + baseMintAcct: storedBaseVault.conditionalOnFinalizeTokenMint.toString(), + quoteMintAcct: storedQuoteVault.conditionalOnFinalizeTokenMint.toString(), + baseLotSize: "1", + quoteLotSize: "1", + quoteTickSize: "1", + bidsTokenAcct: getAssociatedTokenAddressSync( + quotePass, + proposal.account.passAmm, + true + ).toString(), + asksTokenAcct: getAssociatedTokenAddressSync( + basePass, + proposal.account.passAmm, + true + ).toString(), + baseMakerFee: 0, + baseTakerFee: 100, + quoteMakerFee: 0, + quoteTakerFee: 100, + }; + + let failMarket: MarketRecord = { + marketAcct: proposal.account.failAmm.toString(), + proposalAcct: proposal.publicKey.toString(), + marketType: MarketType.FUTARCHY_AMM, + createTxSig: "", + baseMintAcct: storedBaseVault.conditionalOnRevertTokenMint.toString(), + quoteMintAcct: storedQuoteVault.conditionalOnRevertTokenMint.toString(), + baseLotSize: "1", + quoteLotSize: "1", + quoteTickSize: "1", + bidsTokenAcct: getAssociatedTokenAddressSync( + quoteFail, + proposal.account.failAmm, + true + ).toString(), + asksTokenAcct: getAssociatedTokenAddressSync( + baseFail, + proposal.account.failAmm, + true + ).toString(), + baseMakerFee: 0, + baseTakerFee: 100, + quoteMakerFee: 0, + quoteTakerFee: 100, + }; + + await usingDb((db) => + db + .insert(schema.markets) + .values([passMarket, failMarket]) + .onConflictDoNothing() + .execute() + ); +} + +async function calculateUserPerformance( + onChainProposal: ProposalAccountWithKey +) { + const quoteTokens = alias(schema.tokens, "quote_tokens"); // NOTE: This should be USDC for now + const baseTokens = alias(schema.tokens, "base_tokens"); + // calculate performance + const [proposal] = + (await usingDb((db) => { + return db + .select() + .from(schema.proposals) + .where( + eq( + schema.proposals.proposalAcct, + onChainProposal.publicKey.toString() + ) + ) + .leftJoin( + schema.daos, + eq(schema.proposals.daoAcct, schema.daos.daoAcct) + ) + .leftJoin(quoteTokens, eq(schema.daos.quoteAcct, quoteTokens.mintAcct)) + .leftJoin(baseTokens, eq(schema.daos.baseAcct, baseTokens.mintAcct)) + .limit(1) + .execute(); + })) ?? []; + + if (!proposal) return; + + const { proposals, daos, quote_tokens, base_tokens } = proposal; + + let proposalDaoAcct = daos?.daoAcct; + + if (!proposals) return; + + if (!proposalDaoAcct) { + proposalDaoAcct = proposals.daoAcct; + } + + if (!proposalDaoAcct) { + console.error("No daoAcct found"); + } + + const allOrders = + (await usingDb((db) => { + return db + .select() + .from(schema.orders) + .where( + inArray(schema.orders.marketAcct, [ + proposals.passMarketAcct, + proposals.failMarketAcct, + ]) + ) + .execute(); + })) ?? []; + + // Get the time for us to search across the price space for spot + const proposalFinalizedAt = proposals.completedAt ?? new Date(); + const proposalFinalizedAtMinus2Minutes = new Date(proposalFinalizedAt); + proposalFinalizedAtMinus2Minutes.setMinutes( + proposalFinalizedAt.getMinutes() - 2 + ); + + const resolvingMarket = + proposals.status === ProposalStatus.Passed + ? proposals.passMarketAcct + : proposals.failMarketAcct; + // TODO: Get spot price at proposal finalization or even current spot price + // if the proposal is still active (this would be UNREALISED P&L) + // TODO: If this is 0 we really need to throw and error and alert someone, we shouldn't have missing spot data + const spotPrice = + (await usingDb((db) => { + return db + .select() + .from(schema.prices) + .where( + and( + eq(schema.prices.marketAcct, base_tokens.mintAcct), + lte(schema.prices.createdAt, proposalFinalizedAt), + gt(schema.prices.createdAt, proposalFinalizedAtMinus2Minutes) + ) + ) + .limit(1) + .orderBy(desc(schema.prices.createdAt)) + .execute(); + })) ?? []; + + let actors = allOrders.reduce((current, next) => { + const actor = next.actorAcct; + let totals = current.get(actor); + + if (!totals) { + totals = { + tokensBought: 0, // Aggregate value for reporting + tokensSold: 0, + volumeBought: 0, + volumeSold: 0, + tokensBoughtResolvingMarket: 0, // P/F market buy quantity + tokensSoldResolvingMarket: 0, // P/F market sell quantity + volumeBoughtResolvingMarket: 0, // P/F market buy volume + volumeSoldResolvingMarket: 0, // P/F market sell volume + buyOrderCount: 0, + sellOrderCount: 0, + }; + } + + // Token Decimals used for nomalizing results + const baseTokenDecimals = base_tokens?.decimals; + const quoteTokenDecimals = quote_tokens?.decimals ?? 6; // NOTE: Safe for now + + if (!baseTokenDecimals || !quoteTokenDecimals) { + return current; + } + + // Debatable size or quantity, often used interchangably + const size = PriceMath.getHumanAmount( + new BN(next.filledBaseAmount), + baseTokenDecimals + ); + + // Amount or notional + const amount = Number(next.quotePrice).valueOf() * size; + + // Buy Side + if (next.side === "BID") { + totals.tokensBought = totals.tokensBought + size; + totals.volumeBought = totals.volumeBought + amount; + totals.buyOrderCount = totals.buyOrderCount + 1; + // If this is the resolving market then we want to keep a running tally for that for P&L + if (next.marketAcct === resolvingMarket) { + totals.tokensBoughtResolvingMarket = + totals.tokensBoughtResolvingMarket + size; + totals.volumeBoughtResolvingMarket = + totals.volumeBoughtResolvingMarket + amount; + } + // Sell Side + } else if (next.side === "ASK") { + totals.tokensSold = totals.tokensSold + size; + totals.volumeSold = totals.volumeSold + amount; + totals.sellOrderCount = totals.sellOrderCount + 1; + // If this is the resolving market then we want to keep a running tally for that for P&L + if (next.marketAcct === resolvingMarket) { + totals.tokensSoldResolvingMarket = + totals.tokensSoldResolvingMarket + size; + totals.volumeSoldResolvingMarket = + totals.volumeSoldResolvingMarket + amount; + } + } + + current.set(actor, totals); + + return current; + }, new Map()); + + const toInsert: Array = Array.from( + actors.entries() + ).map((k) => { + const [actor, values] = k; + + // NOTE: this gets us the delta, whereas we need to know the direction at the very end + const tradeSizeDelta = Math.abs( + values.tokensBoughtResolvingMarket - values.tokensSoldResolvingMarket + ); + + // NOTE: Directionally orients our last leg + const needsSellToExit = + values.tokensBoughtResolvingMarket > values.tokensSoldResolvingMarket; // boolean + + // We need to complete the round trip / final leg + if (tradeSizeDelta !== 0) { + // TODO: This needs to be revised given the spot price can't be null or 0 if we want to really do this + const lastLegNotional = + tradeSizeDelta * Number(spotPrice[0]?.price ?? "0"); + + if (needsSellToExit) { + // We've bought more than we've sold, therefore when we exit the position calulcation + // we need to count the remaining volume as a sell at spot price when conditional + // market is finalized. + values.volumeSoldResolvingMarket = + values.volumeSoldResolvingMarket + lastLegNotional; + } else { + values.volumeBoughtResolvingMarket = + values.volumeBoughtResolvingMarket + lastLegNotional; + } + } + + return { + proposalAcct: onChainProposal.publicKey.toString(), + daoAcct: proposalDaoAcct, + userAcct: actor, + tokensBought: values.tokensBought.toString(), + tokensSold: values.tokensSold.toString(), + volumeBought: values.volumeBought.toString(), + volumeSold: values.volumeSold.toString(), + tokensBoughtResolvingMarket: + values.tokensBoughtResolvingMarket.toString(), + tokensSoldResolvingMarket: values.tokensSoldResolvingMarket.toString(), + volumeBoughtResolvingMarket: + values.volumeBoughtResolvingMarket.toString(), + volumeSoldResolvingMarket: values.volumeSoldResolvingMarket.toString(), + buyOrdersCount: values.buyOrderCount as unknown as bigint, + sellOrdersCount: values.sellOrderCount as unknown as bigint, + }; + }); + + if (toInsert.length > 0) { + await usingDb((db) => { + return db.transaction(async (tx) => { + await tx + .insert(schema.users) + .values( + toInsert.map((i) => { + return { + userAcct: i.userAcct, + }; + }) + ) + .onConflictDoNothing(); + + await Promise.all( + toInsert.map(async (insert) => { + try { + await tx + .insert(schema.userPerformance) + .values(insert) + .onConflictDoUpdate({ + target: [ + schema.userPerformance.proposalAcct, + schema.userPerformance.userAcct, + ], + set: { + tokensBought: insert.tokensBought, + tokensSold: insert.tokensSold, + volumeBought: insert.volumeBought, + volumeSold: insert.volumeSold, + tokensBoughtResolvingMarket: + insert.tokensBoughtResolvingMarket, + tokensSoldResolvingMarket: insert.tokensSoldResolvingMarket, + volumeBoughtResolvingMarket: + insert.volumeBoughtResolvingMarket, + volumeSoldResolvingMarket: insert.volumeSoldResolvingMarket, + buyOrdersCount: insert.buyOrdersCount, + sellOrdersCount: insert.sellOrdersCount, + }, + }); + } catch (e) { + logger.error("error inserting user_performance record", e); + } + }) + ); + }); + }); + } +} + diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts new file mode 100644 index 00000000..9a31a557 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts @@ -0,0 +1,21 @@ +import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; +import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0"; +import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; +import { logger } from "../../logger"; + +const AUTOCRAT_V0 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; + +if (AUTOCRAT_V0.label !== "V0") { + const error = new Error(`Mistook autocrat ${AUTOCRAT_V0.label} for V0`); + logger.error(error.message); + throw error; +} + +export const AutocratV0Indexer: InstructionIndexer = { + PROGRAM_NAME: "AutocrateV0", + PROGRAM_ID: AUTOCRAT_V0.programId.toBase58(), + PROGRAM_IDL: AUTOCRAT_V0.idl as any, + indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { + return Ok; + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts new file mode 100644 index 00000000..95d51d60 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts @@ -0,0 +1,21 @@ +import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; +import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.1"; +import { InstructionIndexer, Ok } from "../instruction-indexer"; +import { logger } from "../../logger"; + +const AUTOCRAT_V0_1 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 2]; + +if (AUTOCRAT_V0_1.label !== "V0.1") { + const error = new Error(`Mistook autocrat ${AUTOCRAT_V0_1.label} for V0.1`); + logger.error(error.message); + throw error; +} + +export const AutocratV0_1Indexer: InstructionIndexer = { + PROGRAM_NAME: "AutocratV0.1", + PROGRAM_ID: AUTOCRAT_V0_1.programId.toBase58(), + PROGRAM_IDL: IDL, + indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { + return Ok; + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts new file mode 100644 index 00000000..ce56b9bf --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts @@ -0,0 +1,21 @@ +import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; +import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.2"; +import { InstructionIndexer, Ok } from "../instruction-indexer"; +import { logger } from "../../logger"; + +const AUTOCRAT_V0_2 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; + +if (AUTOCRAT_V0_2.label !== "V0.2") { + const error = new Error(`Mistook autocrat ${AUTOCRAT_V0_2.label} for V0.2`); + logger.error(error.message); + throw error; +} + +export const AutocratV0_1Indexer: InstructionIndexer = { + PROGRAM_NAME: "AutocratV0.2", + PROGRAM_ID: AUTOCRAT_V0_2.programId.toBase58(), + PROGRAM_IDL: IDL, + indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { + return Ok; + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts b/packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts new file mode 100644 index 00000000..cf0515e3 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts @@ -0,0 +1,102 @@ +import { and, eq, schema, usingDb } from "@metadaoproject/indexer-db"; +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { Err, Ok } from "../../match"; +import { + IndexerAccountDependencyStatus, + PricesRecord, + PricesType, +} from "@metadaoproject/indexer-db/lib/schema"; +import { logger } from "../../logger"; + +const apiKey = process.env.BIRDEYE_API_KEY ?? ""; + +enum BirdeyePricesIndexingError { + BirdeyeFetchError = "BirdeyeFetchError", + BirdeyeFetchMissingResponse = "BirdeyeFetchMissingResponse", + GeneralBirdeyePricesIndexError = "GeneralBirdeyePricesIndexError", +} + +export const BirdeyePricesIndexer: IntervalFetchIndexer = { + cronExpression: "* * * * *", + retries: 12, + index: async (acct: string) => { + try { + const url = `https://public-api.birdeye.so/defi/price?address=${acct}`; + const tokenPriceRes = await fetch(url, { + headers: { + "X-API-KEY": apiKey, + }, + }); + + if (tokenPriceRes.status !== 200) { + logger.error( + "non-200 response from birdeye:", + tokenPriceRes.status, + tokenPriceRes.statusText + ); + } + + const tokenPriceJson = (await tokenPriceRes.json()) as BirdeyePricesRes; + + if (!tokenPriceJson.success) { + logger.error( + "error fetching from birdeye tokenPriceJson:", + tokenPriceJson + ); + if (tokenPriceJson.message === "Unauthorized") { + logger.error("birdeye api key is incorrect"); + const stopBirdeyeRes = await usingDb((db) => + db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "birdeye-prices"))).execute() + ); + if((stopBirdeyeRes?.rowCount ?? 0) > 0) { + logger.error("birdeye dependency disabled"); + } + } + return Err({ type: BirdeyePricesIndexingError.BirdeyeFetchError }); + } + + if (!tokenPriceJson.data) { + logger.error("bird eye prices fetch missing data"); + return Err({ + type: BirdeyePricesIndexingError.BirdeyeFetchMissingResponse, + }); + } + + const newPrice: PricesRecord = { + marketAcct: acct, + price: tokenPriceJson.data?.value.toString() ?? "", + pricesType: PricesType.Spot, + createdBy: "birdeye-prices-indexer", + // TODO: Fudge, birdeye doesn't have this so we might need to figure out something.. maybe just call the RPC + updatedSlot: "0", + }; + + const insertPriceRes = await usingDb((db) => + db + .insert(schema.prices) + .values(newPrice) + .onConflictDoNothing() + .execute() + ); + if ((insertPriceRes?.rowCount ?? 0) > 0) { + console.log("inserted new birdeye price", acct); + } + return Ok({ acct }); + } catch (e) { + logger.error("general error with birdeye prices indexer:", e); + return Err({ + type: BirdeyePricesIndexingError.GeneralBirdeyePricesIndexError, + }); + } + }, +}; + +type BirdeyePricesRes = { + data?: { + value: number; + updateUnixTime: number; + updateHumanTime: string; + }; + success: boolean; + message?: string; +}; diff --git a/packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts b/packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts new file mode 100644 index 00000000..743529d7 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts @@ -0,0 +1,224 @@ +import { schema, usingDb, eq, and } from "@metadaoproject/indexer-db"; +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { Err, Ok } from "../../match"; +import { + IndexerAccountDependencyStatus, + PricesRecord, + PricesType, +} from "@metadaoproject/indexer-db/lib/schema"; +import { logger } from "../../logger"; + +export enum JupiterQuoteIndexingError { + JupiterFetchError = "JupiterFetchError", + GeneralJupiterQuoteIndexError = "GeneralJupiterQuoteIndexError", +} + +export const JupiterQuotesIndexer: IntervalFetchIndexer = { + cronExpression: "* * * * *", + retries: 12, + index: async (acct: string) => { + // get decimals from our DB + try { + const fetchQuoteRes = await fetchQuoteFromJupe(acct); + if (!fetchQuoteRes) { + return Err({ + type: JupiterQuoteIndexingError.JupiterFetchError, + }); + } + const [price, slot] = fetchQuoteRes; + const newPrice: PricesRecord = { + marketAcct: acct, + price: price.toString(), + pricesType: PricesType.Spot, + createdBy: "jupiter-quotes-indexer", + updatedSlot: slot?.toString() ?? "0", + }; + + const insertPriceRes = await usingDb((db) => + db + .insert(schema.prices) + .values(newPrice) + .onConflictDoNothing() + .execute() + ); + if ((insertPriceRes?.rowCount ?? 0) > 0) { + console.log("inserted new jup quote price", acct); + } + return Ok({ acct }); + } catch (e) { + logger.error("general error indexing jupiter quote: ", e); + return Err({ + type: JupiterQuoteIndexingError.GeneralJupiterQuoteIndexError, + }); + } + }, +}; + +type JupTokenQuoteRes = { + outAmount?: string; + inAmount?: string; + contextSlot?: number; + error?: string; +}; + +const convertJupTokenPrice = ( + data: JupTokenQuoteRes, + inputTokenDecimals: number, + outputTokenDecimals: number +): number => { + const price = + Number(data.outAmount ?? "0") / + 10 ** outputTokenDecimals / + (Number(data.inAmount ?? "0") / 10 ** inputTokenDecimals); + return price; +}; + +const convertJupBaseOutTokenPrice = ( + data: JupTokenQuoteRes, + quoteTokenDecimals: number, + baseTokenDecimals: number +): number => { + const inPrice = Number(data.inAmount ?? "0") / 10 ** quoteTokenDecimals; + const outPrice = Number(data.outAmount ?? "0") / 10 ** baseTokenDecimals; + return inPrice / outPrice; +}; + +export const fetchQuoteFromJupe = async ( + acct: string +): Promise<[number, number | undefined] | null> => { + try { + const baseToken = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, acct)) + .execute() + )) ?? []; + + // Define the output mint based on the input token + const quoteMint = + acct === "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" + ? "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" + : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + + const quoteToken = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, quoteMint)) + .execute() + )) ?? []; + + if (baseToken.length === 0 || quoteToken.length === 0) { + console.log("quote or base token not found in db for jupiter quotes indexer", acct); + return null; + } + + const amountVal = 1 * 10 ** baseToken[0].decimals; + + // Fetch ASK price (original fetch) + const askUrl = + `https://public.jupiterapi.com/quote?inputMint=${acct}&` + + `outputMint=${quoteMint}&` + + `amount=${amountVal.toString()}&` + + "slippageBps=30&" + + "swapMode=ExactIn&" + + "onlyDirectRoutes=false&" + + "maxAccounts=64&" + + "experimentalDexes=Jupiter%20LO"; + const askRes = await fetch(askUrl); + + if (askRes.status !== 200) { + logger.error( + "non-200 response from Jupiter ASK quote:", + askRes.status, + askRes.statusText + ); + if (askRes.status === 400) { + logger.error("jupiter request is malformed"); + const stopJupiterRes = await usingDb((db) => + db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "jupiter-quotes"))).execute() + ); + if((stopJupiterRes?.rowCount ?? 0) > 0) { + logger.error("jupiter dependency disabled"); + } + } + return null; + } + + const askJson = (await askRes.json()) as JupTokenQuoteRes; + + if (askJson.error || !askJson.outAmount || !askJson.inAmount) { + logger.error("Error with ASK quote response:", askJson); + return null; + } + + const askPrice = convertJupTokenPrice( + askJson, + baseToken[0].decimals, + quoteToken[0].decimals + ); + + // Fetch BID price (swapped input/output) + const bidUrl = + `https://public.jupiterapi.com/quote?inputMint=${quoteMint}&` + + `outputMint=${acct}&` + + `amount=${(1 * 10 ** quoteToken[0].decimals).toString()}&` + + "slippageBps=30&" + + "swapMode=ExactIn&" + + "onlyDirectRoutes=false&" + + "maxAccounts=64&" + + "experimentalDexes=Jupiter%20LO"; + const bidRes = await fetch(bidUrl); + + if (bidRes.status !== 200) { + logger.error( + "non-200 response from Jupiter BID quote:", + bidRes.status, + bidRes.statusText + ); + if (bidRes.status === 400) { + logger.error("jupiter request is malformed"); + const stopJupiterRes = await usingDb((db) => + db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "jupiter-quotes"))).execute() + ); + if((stopJupiterRes?.rowCount ?? 0) > 0) { + logger.error("jupiter dependency disabled"); + } + } + // TODO: We should really back the f-off here after like 10 times... + return null; + } + + const bidJson = (await bidRes.json()) as JupTokenQuoteRes; + + if (bidJson.error || !bidJson.outAmount || !bidJson.inAmount) { + logger.error("Error with BID quote response:", bidJson); + return null; + } + + const bidPrice = convertJupBaseOutTokenPrice( + bidJson, + quoteToken[0].decimals, + baseToken[0].decimals + ); + + if (!askPrice) { + return [bidPrice, askJson.contextSlot]; + } + if (!bidPrice) { + return [askPrice, askJson.contextSlot]; + } + + // Calculate the mid-price + const midPrice = (askPrice + bidPrice) / 2; + + // Return the mid-price and the context slot from the ASK response + return [midPrice, askJson.contextSlot]; + } catch (e) { + logger.error("error getting price from Jupiter: ", e); + return null; + } +}; diff --git a/packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts b/packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts new file mode 100644 index 00000000..894a9013 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts @@ -0,0 +1,26 @@ +import { IDL, OpenbookTwap } from "@metadaoproject/futarchy-sdk/lib/idl/openbook_twap"; +import { OPENBOOK_TWAP_PROGRAM_ID } from "@metadaoproject/futarchy-sdk/lib/constants"; +import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; + +// Doing this rather than class implements pattern due to +// https://github.com/microsoft/TypeScript/issues/41399 +export const OpenbookTwapIndexer: InstructionIndexer = { + PROGRAM_NAME: "OpenbookTwap", + PROGRAM_ID: OPENBOOK_TWAP_PROGRAM_ID.toBase58(), + PROGRAM_IDL: IDL, + indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { + // TODO: in the future we want to switch on the instruction name and index the openbook program instruction + // build the order book, then from that deduce the twap change. + + // For now though, we're going to take a shortcut by just reading the logs. + // We get initial weighted observation aggregator via the createTwapMarket expected value + // see https://github.com/metaDAOproject/openbook-twap/blob/82690c33a091b82e908843a14ad1a571dfba12b1/programs/openbook-twap/src/lib.rs#L68 + // Afterwards we can extract the log line here + // and use it to increment the observation aggregator + // https://github.com/metaDAOproject/openbook-twap/blob/82690c33a091b82e908843a14ad1a571dfba12b1/programs/openbook-twap/src/lib.rs#L120 + // we simply take difference between transaction slot and proposal enqueued slot then divide the obs agg by this + // https://github.com/metaDAOproject/futarchy/blob/d5b91dc103e23d72900817e93b450e42274469c9/programs/autocrat_v0/src/lib.rs#L335 + + return Ok; + } +}; diff --git a/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts b/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts new file mode 100644 index 00000000..6edec736 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts @@ -0,0 +1,98 @@ +import { AccountInfoIndexer } from "../account-info-indexer"; +import { rpcReadClient } from "../../connection"; +import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; +import { schema, usingDb } from "@metadaoproject/indexer-db"; +import { Err, Ok } from "../../match"; +import { + OpenbookMarketFetchRequest, + getMidPrice, +} from "@metadaoproject/futarchy-sdk"; +import { + PricesRecord, + PricesType, +} from "@metadaoproject/indexer-db/lib/schema"; +import { logger } from "../../logger"; + +export enum OpenbookV2MarketAccountIndexerError { + MarketNotFound = "MarketNotFound", + GeneralError = "GeneralError", + OrderbookNotFound = "OrderbookNotFound", + MidPriceNotFound = "MidPriceNotFound", +} + +export const OpenbookV2MarketAccountUpdateIndexer: AccountInfoIndexer = { + index: async ( + _: AccountInfo, + account: PublicKey, + context: Context + ) => { + try { + const market = await rpcReadClient.markets.openbook.fetchMarket( + new OpenbookMarketFetchRequest(account, null as any) + ); + + if (!market) { + logger.error("Failed to fetch market"); + return Err({ + type: OpenbookV2MarketAccountIndexerError.MarketNotFound, + }); + } + + const orderbook = await rpcReadClient.markets.openbook.fetchOrderBook( + market + ); + if (!orderbook) { + logger.error("Failed to fetch order book"); + return Err({ + type: OpenbookV2MarketAccountIndexerError.OrderbookNotFound, + }); + } + + const midPrice = getMidPrice(orderbook); + if (!midPrice) { + logger.error("Failed to calculate mid price"); + return Err({ + type: OpenbookV2MarketAccountIndexerError.MidPriceNotFound, + }); + } + + // update the latest slot here + const newOpenbookConditionaPrice: PricesRecord = { + marketAcct: account.toString(), + updatedSlot: context.slot.toString(), + price: midPrice.toString(), + pricesType: PricesType.Conditional, + baseAmount: + market.marketInstance.account.baseDepositTotal.toString() + , + quoteAmount: + market.marketInstance.account.quoteDepositTotal.toString() + , + createdBy: "openbook-v2-account-indexer", + }; + + const pricesInsertResult = + (await usingDb((db) => + db + .insert(schema.prices) + .values(newOpenbookConditionaPrice) + .onConflictDoUpdate({ + target: [schema.prices.createdAt, schema.prices.marketAcct], + set: newOpenbookConditionaPrice, + }) + .returning({ marketAcct: schema.prices.marketAcct }) + )) ?? []; + + return Ok({ acct: pricesInsertResult[0].marketAcct }); + } catch (error) { + logger.error( + "Unexpected error in openbook v2 market info index function:", + error + ); + return Err({ + type: OpenbookV2MarketAccountIndexerError.GeneralError, + error, + }); + } + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts b/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts new file mode 100644 index 00000000..7cb48703 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts @@ -0,0 +1,11 @@ +import { OPENBOOK_PROGRAM_ID } from "@metadaoproject/futarchy-sdk"; +import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; + +export const OpenbookV2Indexer: InstructionIndexer = { + PROGRAM_NAME: "OpenBookV2", + PROGRAM_ID: OPENBOOK_PROGRAM_ID.toBase58(), + PROGRAM_IDL: null, + indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { + return Ok; + }, +}; diff --git a/packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts b/packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts new file mode 100644 index 00000000..cde88d49 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts @@ -0,0 +1,70 @@ +import { IntervalFetchIndexer } from "../interval-fetch-indexer"; +import { provider } from "../../connection"; +import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; +import { Err, Ok } from "../../match"; +import { PublicKey } from "@solana/web3.js"; +import { TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; +import { TokenAccountNotFoundError, getMint } from "@solana/spl-token"; +import { logger } from "../../logger"; + +export enum TokenMintIndexerError { + GeneralError = "GeneralError", + MissingParamError = "MissingParamError", + NotFoundError = "NotFoundError", + MissingChainResponseError = "MissingChainResponseError", + NothingToInsertError = "NothingToInsertError", +} + +export const TokenMintIndexer: IntervalFetchIndexer = { + cronExpression: "5 * * * * *", + retries: 10, + index: async (mintStr: string) => { + try { + let mint = new PublicKey(mintStr); + + let storedMint; + try { + storedMint = await getMint(provider.connection, mint); + } catch (err) { + if (err instanceof TokenAccountNotFoundError) { + logger.error(`Mint ${mint.toString()} not found`); + return Err({ type: TokenMintIndexerError.NotFoundError }); + } else { + throw err; + } + } + + const dbMint: TokenRecord | undefined = ( + await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, mint.toString())) + .execute() + ) + )?.[0]; + + if (!dbMint) return Err({ type: TokenMintIndexerError.NotFoundError }); + + if (dbMint.supply !== storedMint.supply.toString()) { + await usingDb((db) => + db + .update(schema.tokens) + .set({ supply: storedMint.supply.toString(), updatedAt: new Date() }) + .where(eq(schema.tokens.mintAcct, mint.toString())) + .execute() + ); + console.log( + `Updated supply for mint ${mint.toString()} from ${ + dbMint.supply + } to ${storedMint.supply}` + ); + } + + return Ok({ acct: "Update the token record" }); + } catch (err) { + logger.errorWithChatBotAlert(err); + return Err({ type: TokenMintIndexerError.GeneralError }); + } + }, +}; diff --git a/packages/new_indexer/src/indexEvents.ts b/packages/new_indexer/src/v4_indexer/indexEvents.ts similarity index 89% rename from packages/new_indexer/src/indexEvents.ts rename to packages/new_indexer/src/v4_indexer/indexEvents.ts index 0b576ed8..2b630f9f 100644 --- a/packages/new_indexer/src/indexEvents.ts +++ b/packages/new_indexer/src/v4_indexer/indexEvents.ts @@ -21,12 +21,14 @@ type DBConnection = any; // TODO: Fix typing.. const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); -const parseEvents = (program: Program, transactionResponse: VersionedTransactionResponse | TransactionResponse): { name: string; data: any }[] => { - const events: { name: string; data: any }[] = []; +const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { + const ammEvents: { name: string; data: any }[] = []; + const vaultEvents: { name: string; data: any }[] = []; try { const inner: CompiledInnerInstruction[] = transactionResponse?.meta?.innerInstructions ?? []; - const idlProgramId = program.programId; + const ammIdlProgramId = ammClient.programId; + const vaultIdlProgramId = conditionalVaultClient.vaultProgram.programId; for (let i = 0; i < inner.length; i++) { for (let j = 0; j < inner[i].instructions.length; j++) { const ix = inner[i].instructions[j]; @@ -34,22 +36,36 @@ const parseEvents = (program: Program, transactionRespo transactionResponse?.transaction.message.staticAccountKeys[ ix.programIdIndex ]; - if ( - programPubkey === undefined || - !programPubkey.equals(idlProgramId) - ) { - // we are at instructions that does not match the linked program + if (!programPubkey) { + console.log("No program pubkey"); continue; } - const ixData = anchor.utils.bytes.bs58.decode( - ix.data - ); - const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); - const event = program.coder.events.decode(eventData); - // console.log(event) - if (event) { - events.push(event); + // get which program the instruction belongs to + let program: Program; + if (programPubkey.equals(ammIdlProgramId)) { + program = ammClient.program; + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + ammEvents.push(event); + } + } else if (programPubkey.equals(vaultIdlProgramId)) { + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + vaultEvents.push(event); + } + } else { + console.log("Unknown program pubkey", programPubkey.toBase58()); } } } @@ -61,7 +77,10 @@ const parseEvents = (program: Program, transactionRespo ]); } - return events; + return { + ammEvents, + vaultEvents + }; } async function fetchEligibleSignatures(programId: string, limit: number) { @@ -162,6 +181,28 @@ export async function indexAmmEvents() { } } +export async function processSignature(signature: string, programId: PublicKey) { + if (programId.equals(AMM_PROGRAM_ID) || programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { + const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); + if (!transactionResponse) { + console.log("No transaction response"); + return; + } + + const events = parseEvents(transactionResponse); + const ammEvents = events.ammEvents; + const vaultEvents = events.vaultEvents; + + Promise.all(ammEvents.map(async (event) => { + await processAmmEvent(event, signature, transactionResponse); + })); + + Promise.all(vaultEvents.map(async (event) => { + await processVaultEvent(event, signature, transactionResponse); + })); + } +} + async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { switch (event.name) { case "CreateAmmEvent": diff --git a/packages/new_indexer/src/populateSignatures.ts b/packages/new_indexer/src/v4_indexer/populateSignatures.ts similarity index 100% rename from packages/new_indexer/src/populateSignatures.ts rename to packages/new_indexer/src/v4_indexer/populateSignatures.ts From dbd018c0666d4000b4c98a240fe0ad863b69516e Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 30 Oct 2024 19:03:10 -0400 Subject: [PATCH 03/29] v4 logsSubscribe --- packages/new_indexer/src/subscriber.ts | 4 +- .../new_indexer/src/v3_indexer/indexer.ts | 0 .../new_indexer/src/v3_indexer/processor.ts | 0 .../new_indexer/src/v4_indexer/indexEvents.ts | 546 ------------------ .../new_indexer/src/v4_indexer/indexer.ts | 106 ++++ .../src/v4_indexer/populateSignatures.ts | 154 ----- .../new_indexer/src/v4_indexer/processor.ts | 451 +++++++++++++++ 7 files changed, 559 insertions(+), 702 deletions(-) create mode 100644 packages/new_indexer/src/v3_indexer/indexer.ts create mode 100644 packages/new_indexer/src/v3_indexer/processor.ts delete mode 100644 packages/new_indexer/src/v4_indexer/indexEvents.ts create mode 100644 packages/new_indexer/src/v4_indexer/indexer.ts delete mode 100644 packages/new_indexer/src/v4_indexer/populateSignatures.ts create mode 100644 packages/new_indexer/src/v4_indexer/processor.ts diff --git a/packages/new_indexer/src/subscriber.ts b/packages/new_indexer/src/subscriber.ts index bc0b26cd..0ec49f18 100644 --- a/packages/new_indexer/src/subscriber.ts +++ b/packages/new_indexer/src/subscriber.ts @@ -6,7 +6,7 @@ import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; import { AccountLogsIndexer } from "./account-logs-indexer"; import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; import { logger } from "../logger"; -import { processLogs } from "./processLogs"; +import { processSignature } from "./v4_indexer/indexer"; async function processLogs(logs: Logs, programId: PublicKey) { //check if programId is v3 or v4 @@ -21,7 +21,7 @@ async function processLogs(logs: Logs, programId: PublicKey) { async function processLogsV4(logs: Logs, programId: PublicKey) { let signature = logs.signature; - + await processSignature(signature); } async function processLogsV3(logs: Logs, programId: PublicKey) { diff --git a/packages/new_indexer/src/v3_indexer/indexer.ts b/packages/new_indexer/src/v3_indexer/indexer.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/new_indexer/src/v3_indexer/processor.ts b/packages/new_indexer/src/v3_indexer/processor.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/new_indexer/src/v4_indexer/indexEvents.ts b/packages/new_indexer/src/v4_indexer/indexEvents.ts deleted file mode 100644 index 2b630f9f..00000000 --- a/packages/new_indexer/src/v4_indexer/indexEvents.ts +++ /dev/null @@ -1,546 +0,0 @@ -import { AddLiquidityEvent, AMM_PROGRAM_ID, AmmEvent, CONDITIONAL_VAULT_PROGRAM_ID, ConditionalVaultEvent, CreateAmmEvent, getVaultAddr, InitializeConditionalVaultEvent, InitializeQuestionEvent, SwapEvent, PriceMath, SplitTokensEvent, MergeTokensEvent, RemoveLiquidityEvent } from "@metadaoproject/futarchy/v0.4"; -import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; -import * as anchor from "@coral-xyz/anchor"; -import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; -import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; -import * as token from "@solana/spl-token"; - -import { connection, ammClient, conditionalVaultClient } from "./connection"; -import { Program } from "@coral-xyz/anchor"; - -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; - -type Market = { - marketAcct: string; - baseMint: string; - quoteMint: string; -} - -type DBConnection = any; // TODO: Fix typing.. - -const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); - -const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { - const ammEvents: { name: string; data: any }[] = []; - const vaultEvents: { name: string; data: any }[] = []; - try { - const inner: CompiledInnerInstruction[] = - transactionResponse?.meta?.innerInstructions ?? []; - const ammIdlProgramId = ammClient.programId; - const vaultIdlProgramId = conditionalVaultClient.vaultProgram.programId; - for (let i = 0; i < inner.length; i++) { - for (let j = 0; j < inner[i].instructions.length; j++) { - const ix = inner[i].instructions[j]; - const programPubkey = - transactionResponse?.transaction.message.staticAccountKeys[ - ix.programIdIndex - ]; - if (!programPubkey) { - console.log("No program pubkey"); - continue; - } - - // get which program the instruction belongs to - let program: Program; - if (programPubkey.equals(ammIdlProgramId)) { - program = ammClient.program; - const ixData = anchor.utils.bytes.bs58.decode( - ix.data - ); - const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); - const event = program.coder.events.decode(eventData); - // console.log(event) - if (event) { - ammEvents.push(event); - } - } else if (programPubkey.equals(vaultIdlProgramId)) { - const ixData = anchor.utils.bytes.bs58.decode( - ix.data - ); - const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); - const event = program.coder.events.decode(eventData); - // console.log(event) - if (event) { - vaultEvents.push(event); - } - } else { - console.log("Unknown program pubkey", programPubkey.toBase58()); - } - } - } - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error parsing events: ${error.message}` - : "Unknown error parsing events" - ]); - } - - return { - ammEvents, - vaultEvents - }; -} - -async function fetchEligibleSignatures(programId: string, limit: number) { - try { - return await usingDb(async (db) => { - let lastSlotIndexerQuery = await db.select() - .from(schema.indexers) - .where(eq(schema.indexers.name, "v0_4_amm_indexer")); - const indexerResult = await lastSlotIndexerQuery; - if (indexerResult.length === 0) throw Error("Indexer not found in indexers table"); - const lastSlotProcessed = indexerResult[0].latestSlotProcessed; - - return db.select({signature: schema.signatures.signature, slot: schema.signatures.slot}) - .from(schema.signatures) - .innerJoin(schema.signature_accounts, eq(schema.signatures.signature, schema.signature_accounts.signature)) - .where( - and( - eq(schema.signature_accounts.account, programId), - gt(schema.signatures.slot, lastSlotProcessed) - ) - ) - .orderBy(desc(schema.signatures.slot)) - .limit(limit); - }); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error fetching eligible signatures: ${error.message}` - : "Unknown error fetching eligible signatures" - ]); - return []; - } -} - -async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { - try { - return await connection.getTransactions( - eligibleSignatures.map(s => s.signature), - { commitment: "confirmed", maxSupportedTransactionVersion: 1 } - ); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error fetching transaction responses: ${error.message}` - : "Unknown error fetching transaction responses" - ]); - return []; - } -} - -//set latestProcessedSlot in db -async function setLatestProcessedSlot(slot: number) { - try { - await usingDb(async (db) => { - await db.update(schema.indexers) - .set({ latestSlotProcessed: BigInt(slot) }) - .where(eq(schema.indexers.name, "v0_4_amm_indexer")) - .execute(); - }); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error setting latest processed slot: ${error.message}` - : "Unknown error setting latest processed slot" - ]); - } -} - -export async function indexAmmEvents() { - try { - const eligibleSignatures = await fetchEligibleSignatures(AMM_PROGRAM_ID.toString(), 100); - if (eligibleSignatures.length === 0) { - console.log("No signatures for AMM events"); - return; - } - - const transactionResponses = await fetchTransactionResponses(eligibleSignatures); - - for (const [index, transactionResponse] of transactionResponses.entries()) { - if (!transactionResponse) { - console.log("No transaction response"); - continue; - } - - const signature = eligibleSignatures[index].signature; - const events = parseEvents(ammClient.program, transactionResponse as VersionedTransactionResponse); - - for (const event of events) { - await processAmmEvent(event, signature, transactionResponse); - } - } - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error in indexAmmEvents: ${error.message}` - : "Unknown error in indexAmmEvents" - ]); - } -} - -export async function processSignature(signature: string, programId: PublicKey) { - if (programId.equals(AMM_PROGRAM_ID) || programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { - const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); - if (!transactionResponse) { - console.log("No transaction response"); - return; - } - - const events = parseEvents(transactionResponse); - const ammEvents = events.ammEvents; - const vaultEvents = events.vaultEvents; - - Promise.all(ammEvents.map(async (event) => { - await processAmmEvent(event, signature, transactionResponse); - })); - - Promise.all(vaultEvents.map(async (event) => { - await processVaultEvent(event, signature, transactionResponse); - })); - } -} - -async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { - switch (event.name) { - case "CreateAmmEvent": - await handleCreateAmmEvent(event.data as CreateAmmEvent); - break; - case "AddLiquidityEvent": - await handleAddLiquidityEvent(event.data as AddLiquidityEvent); - break; - case "RemoveLiquidityEvent": - await handleRemoveLiquidityEvent(event.data as RemoveLiquidityEvent); - break; - case "SwapEvent": - await handleSwapEvent(event.data as SwapEvent, signature, transactionResponse); - break; - default: - console.log("Unknown event", event); - } -} -async function handleCreateAmmEvent(event: CreateAmmEvent) { - await usingDb(async (db: DBConnection) => { - await insertTokenIfNotExists(db, event.lpMint); - await insertTokenIfNotExists(db, event.baseMint); - await insertTokenIfNotExists(db, event.quoteMint); - await insertMarketIfNotExists(db, { - marketAcct: event.common.amm.toBase58(), - baseMint: event.baseMint.toString(), - quoteMint: event.quoteMint.toString(), - }); - - await db.insert(schema.v0_4_amms).values({ - ammAddr: event.common.amm.toString(), - lpMintAddr: event.lpMint.toString(), - createdAtSlot: BigInt(event.common.slot.toString()), - baseMintAddr: event.baseMint.toString(), - quoteMintAddr: event.quoteMint.toString(), - latestAmmSeqNumApplied: 0n, - baseReserves: 0n, - quoteReserves: 0n, - }).onConflictDoNothing(); - }); -} - -async function handleAddLiquidityEvent(event: AddLiquidityEvent) { - await usingDb(async (db: DBConnection) => { - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - - console.log("Updated AMM", event.common.amm.toString()); - }); -} - -async function handleRemoveLiquidityEvent(event: RemoveLiquidityEvent) { - await usingDb(async (db: DBConnection) => { - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - - console.log("Updated AMM", event.common.amm.toString()); - }); -} - -async function handleSwapEvent(event: SwapEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - if (transactionResponse.blockTime === null || transactionResponse.blockTime === undefined) { - return; - }; - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_swaps).values({ - signature: signature, - slot: BigInt(transactionResponse.slot), - // @ts-ignore - fixed above in the if statement - blockTime: new Date(transactionResponse.blockTime * 1000), - swapType: event.swapType.buy ? V04SwapType.Buy : V04SwapType.Sell, - ammAddr: event.common.amm.toString(), - userAddr: event.common.user.toString(), - inputAmount: event.inputAmount.toString(), - outputAmount: event.outputAmount.toString(), - ammSeqNum: BigInt(event.common.seqNum.toString()) - }).onConflictDoNothing(); - - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - }); -} - -async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_splits).values({ - vaultAddr: event.vault.toString(), - vaultSeqNum: BigInt(event.seqNum.toString()), - signature: signature, - slot: BigInt(transactionResponse.slot), - amount: BigInt(event.amount.toString()) - }).onConflictDoNothing(); - }); -} - -async function handleMergeEvent(event: MergeTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_merges).values({ - vaultAddr: event.vault.toString(), - vaultSeqNum: BigInt(event.seqNum.toString()), - signature: signature, - slot: BigInt(transactionResponse.slot), - amount: BigInt(event.amount.toString()) - }).onConflictDoNothing(); - }); -} - -async function insertTokenIfNotExists(db: DBConnection, mintAcct: PublicKey) { - const existingToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, mintAcct.toString())).limit(1); - if (existingToken.length === 0) { - console.log("Inserting token", mintAcct.toString()); - const mint: token.Mint = await token.getMint(connection, mintAcct); - await db.insert(schema.tokens).values({ - mintAcct: mintAcct.toString(), - symbol: mintAcct.toString().slice(0, 3), - name: mintAcct.toString().slice(0, 3), - decimals: mint.decimals, - supply: mint.supply, - updatedAt: new Date(), - }).onConflictDoNothing(); - } -} - -export async function indexVaultEvents() { - try { - const eligibleSignatures = await fetchEligibleSignatures(CONDITIONAL_VAULT_PROGRAM_ID.toString(), 1000); - - if (eligibleSignatures.length === 0) { - console.log("No signatures for Vault events"); - return; - } - - const transactionResponses = await fetchTransactionResponses(eligibleSignatures); - - for (const [index, transactionResponse] of transactionResponses.entries()) { - if (!transactionResponse) { - console.log("No transaction response"); - continue; - } - - const signature = eligibleSignatures[index].signature; - const events = parseEvents(conditionalVaultClient.vaultProgram, transactionResponse as VersionedTransactionResponse); - - for (const event of events) { - await processVaultEvent(event, signature, transactionResponse); - } - } - - //set last process slot - await setLatestProcessedSlot(Number(eligibleSignatures[0].slot)); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error in indexVaultEvents: ${error.message}` - : "Unknown error in indexVaultEvents" - ]); - } -} - -async function processVaultEvent(event: { name: string; data: ConditionalVaultEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { - switch (event.name) { - case "InitializeQuestionEvent": - await handleInitializeQuestionEvent(event.data as InitializeQuestionEvent); - break; - case "InitializeConditionalVaultEvent": - await handleInitializeConditionalVaultEvent(event.data as InitializeConditionalVaultEvent); - break; - case "SplitTokensEvent": - await handleSplitEvent(event.data as SplitTokensEvent, signature, transactionResponse); - break; - case "MergeTokensEvent": - await handleMergeEvent(event.data as MergeTokensEvent, signature, transactionResponse); - break; - default: - console.log("Unknown Vault event", event.name); - } -} - -async function handleInitializeQuestionEvent(event: InitializeQuestionEvent) { - await usingDb(async (db) => { - await db.insert(schema.v0_4_questions).values({ - questionAddr: event.question.toString(), - isResolved: false, - oracleAddr: event.oracle.toString(), - numOutcomes: event.numOutcomes, - payoutNumerators: Array(event.numOutcomes).fill(0), - payoutDenominator: 0n, - questionId: event.questionId, - }).onConflictDoNothing(); - }); -} - -async function handleInitializeConditionalVaultEvent(event: InitializeConditionalVaultEvent) { - const vaultAddr = getVaultAddr(conditionalVaultClient.vaultProgram.programId, event.question, event.underlyingTokenMint)[0]; - await usingDb(async (db) => { - await db.transaction(async (trx) => { - if (!await doesQuestionExist(trx, event)) { - return; - } - await insertTokenIfNotExists(trx, event.underlyingTokenMint); - await insertTokenAccountIfNotExists(trx, event); - await insertConditionalVault(trx, event, vaultAddr); - }); - }); -} - -async function doesQuestionExist(db: DBConnection, event: InitializeConditionalVaultEvent): Promise { - const existingQuestion = await db.select().from(schema.v0_4_questions).where(eq(schema.v0_4_questions.questionAddr, event.question.toString())).limit(1); - return existingQuestion.length > 0; - // if (existingQuestion.length === 0) { - // await trx.insert(schema.v0_4_questions).values({ - // questionAddr: event.question.toString(), - // isResolved: false, - // oracleAddr: event.oracle.toString(), - // numOutcomes: event.numOutcomes, - // payoutNumerators: Array(event.numOutcomes).fill(0), - // payoutDenominator: 0n, - // questionId: event.questionId, - // }); - // } -} - -async function insertTokenAccountIfNotExists(db: DBConnection, event: InitializeConditionalVaultEvent) { - const existingTokenAcct = await db.select().from(schema.tokenAccts).where(eq(schema.tokenAccts.tokenAcct, event.vaultUnderlyingTokenAccount.toString())).limit(1); - if (existingTokenAcct.length === 0) { - await db.insert(schema.tokenAccts).values({ - tokenAcct: event.vaultUnderlyingTokenAccount.toString(), - mintAcct: event.underlyingTokenMint.toString(), - ownerAcct: event.vaultUnderlyingTokenAccount.toString(), - amount: 0n, - // Add other required fields for token_accts table - }); - } -} - -async function insertMarketIfNotExists(db: DBConnection, market: Market) { - const existingMarket = await db.select().from(schema.markets).where(eq(schema.markets.marketAcct, market.marketAcct)).limit(1); - if (existingMarket.length === 0) { - await db.insert(schema.markets).values({ - marketAcct: market.marketAcct, - baseMintAcct: market.baseMint, - quoteMintAcct: market.quoteMint, - marketType: 'amm', - createTxSig: '', - baseLotSize: 0n, - quoteLotSize: 0n, - quoteTickSize: 0n, - baseMakerFee: 0, - quoteMakerFee: 0, - baseTakerFee: 0, - quoteTakerFee: 0 - }).onConflictDoNothing(); - // TODO: I don't like this on Conflict.... - } -} - -async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { - const existingPrice = await db.select().from(schema.prices).where(and(eq(schema.prices.marketAcct, event.common.amm.toBase58()), eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())))).limit(1); - if (existingPrice.length > 0) { - console.log("Price already exists", event.common.amm.toBase58(), BigInt(event.common.slot.toString())); - return; - } - // Get's the AMM details for the current price from liquidity event or swap event - const ammPrice = PriceMath.getAmmPriceFromReserves(event.common.postBaseReserves, event.common.postQuoteReserves); - const baseToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].baseMintAddr)).limit(1); - const quoteToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].quoteMintAddr)).limit(1); - const humanPrice = PriceMath.getHumanPrice(ammPrice, baseToken[0].decimals, quoteToken[0].decimals); - - // Inserts the price into the prices table - await db.insert(schema.prices).values({ - marketAcct: event.common.amm.toBase58(), - baseAmount: BigInt(event.common.postBaseReserves.toString()), - quoteAmount: BigInt(event.common.postQuoteReserves.toString()), - price: humanPrice.toString(), - updatedSlot: BigInt(event.common.slot.toString()), - createdBy: 'amm-market-indexer', - pricesType: PricesType.Conditional, - }).onConflictDoNothing(); -} - -async function insertConditionalVault(db: DBConnection, event: InitializeConditionalVaultEvent, vaultAddr: PublicKey) { - await db.insert(schema.v0_4_conditional_vaults).values({ - conditionalVaultAddr: vaultAddr.toString(), - questionAddr: event.question.toString(), - underlyingMintAcct: event.underlyingTokenMint.toString(), - underlyingTokenAcct: event.vaultUnderlyingTokenAccount.toString(), - pdaBump: event.pdaBump, - latestVaultSeqNumApplied: 0n, - }).onConflictDoNothing(); -} \ No newline at end of file diff --git a/packages/new_indexer/src/v4_indexer/indexer.ts b/packages/new_indexer/src/v4_indexer/indexer.ts new file mode 100644 index 00000000..2c102ea0 --- /dev/null +++ b/packages/new_indexer/src/v4_indexer/indexer.ts @@ -0,0 +1,106 @@ +import { AMM_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import * as anchor from "@coral-xyz/anchor"; +import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; + +import { connection, ammClient, conditionalVaultClient } from "./connection"; +import { Program } from "@coral-xyz/anchor"; + +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + +import { processAmmEvent, processVaultEvent } from "./processor"; + +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { + const ammEvents: { name: string; data: any }[] = []; + const vaultEvents: { name: string; data: any }[] = []; + try { + const inner: CompiledInnerInstruction[] = + transactionResponse?.meta?.innerInstructions ?? []; + const ammIdlProgramId = ammClient.programId; + const vaultIdlProgramId = conditionalVaultClient.vaultProgram.programId; + for (let i = 0; i < inner.length; i++) { + for (let j = 0; j < inner[i].instructions.length; j++) { + const ix = inner[i].instructions[j]; + const programPubkey = + transactionResponse?.transaction.message.staticAccountKeys[ + ix.programIdIndex + ]; + if (!programPubkey) { + console.log("No program pubkey"); + continue; + } + + // get which program the instruction belongs to + let program: Program; + if (programPubkey.equals(ammIdlProgramId)) { + program = ammClient.program; + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + ammEvents.push(event); + } + } else if (programPubkey.equals(vaultIdlProgramId)) { + const ixData = anchor.utils.bytes.bs58.decode( + ix.data + ); + const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); + const event = program.coder.events.decode(eventData); + // console.log(event) + if (event) { + vaultEvents.push(event); + } + } else { + console.log("Unknown program pubkey", programPubkey.toBase58()); + } + } + } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error parsing events: ${error.message}` + : "Unknown error parsing events" + ]); + } + + return { + ammEvents, + vaultEvents + }; +} + +export async function processSignature(signature: string, programId: PublicKey) { + try { + if (programId.equals(AMM_PROGRAM_ID) || programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { + const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); + if (!transactionResponse) { + console.log("No transaction response"); + return; + } + + const events = parseEvents(transactionResponse); + const ammEvents = events.ammEvents; + const vaultEvents = events.vaultEvents; + + Promise.all(ammEvents.map(async (event) => { + await processAmmEvent(event, signature, transactionResponse); + })); + + Promise.all(vaultEvents.map(async (event) => { + await processVaultEvent(event, signature, transactionResponse); + })); + } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error processing signature: ${error.message}` + : "Unknown error processing signature" + ]); + } +} + diff --git a/packages/new_indexer/src/v4_indexer/populateSignatures.ts b/packages/new_indexer/src/v4_indexer/populateSignatures.ts deleted file mode 100644 index 0890b9df..00000000 --- a/packages/new_indexer/src/v4_indexer/populateSignatures.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; -import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; -import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; -import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; - - -const RPC_ENDPOINT = process.env.RPC_ENDPOINT; - -if (!RPC_ENDPOINT) { - throw new Error("RPC_ENDPOINT is not set"); -} -const connection = new Connection(RPC_ENDPOINT); -const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); - -// it's possible that there are signatures BEFORE the oldest signature -// because the indexer may not have been running when those signatures were created - -// it's also possible that there are signatures AFTER the newest signature - -// we assume that there aren't signatures between the oldest and newest signatures - -// we split these into two functions: -// - backfillHistoricalSignatures -// - insertNewSignatures - -const backfillHistoricalSignatures = async ( - programId: PublicKey, -) => { - let backfilledSignatures: ConfirmedSignatureInfo[] = []; - let oldestSignature = await usingDb(async (db) => { - return await db.select({ signature: schema.signatures.signature }) - .from(schema.signatures) - .orderBy(asc(schema.signatures.slot)) - .limit(1) - .then(signatures => signatures[0] ? signatures[0].signature : undefined); - }); - - while (true) { - const signatures = await connection.getSignaturesForAddress( - programId, - { before: oldestSignature, limit: 1000 }, - "confirmed" - ); - - if (signatures.length === 0) break; - - await insertSignatures(signatures, programId); - - backfilledSignatures = backfilledSignatures.concat(signatures); - oldestSignature = signatures[signatures.length - 1].signature; - - console.log(`backfilled ${backfilledSignatures.length} historical signatures so far...`); - } - - console.log(`now done backfilling. backfilled ${backfilledSignatures.length} historical signatures`); - return backfilledSignatures; -}; - -const insertNewSignatures = async (programId: PublicKey) => { - let allSignatures: ConfirmedSignatureInfo[] = []; - let latestRecordedSignature = await usingDb(async (db) => { - return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) - .from(schema.signatures) - .orderBy(desc(schema.signatures.slot)) - .limit(100) - .then(signatures => { - if (signatures.length === 0) return undefined; - - const latestSlot = signatures[0].slot; - for (let i = 1; i < signatures.length; i++) { - if (signatures[i].slot < latestSlot) { - return signatures[i].signature; - } - } - return signatures[signatures.length - 1].signature; - }); - }); - - let oldestSignatureInserted: string | undefined; - - while (true) { - const signatures = await connection.getSignaturesForAddress( - programId, - { limit: 1000, until: latestRecordedSignature, before: oldestSignatureInserted }, - "confirmed" - ); - - if (signatures.length === 0) break; - - await insertSignatures(signatures, programId); - - allSignatures = allSignatures.concat(signatures); - oldestSignatureInserted = signatures[signatures.length - 1].signature; - } - - return allSignatures; -} - -const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAddr: PublicKey) => { - await usingDb(async (db) => { - await db.insert(schema.transactions).values(signatures.map(tx => ({ - signature: tx.signature, - slot: BigInt(tx.slot), - failed: tx.err !== null, - blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, - }))).onConflictDoNothing().execute(); - await db.insert(schema.signature_accounts).values(signatures.map(tx => ({ - signature: tx.signature, - account: queriedAddr.toString() - }))).onConflictDoNothing().execute(); - }); -} - -const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; - -export const backfill = async () => { - await Promise.all(programIds.map(async (programId) => { - try { - const backfilledSignatures = await backfillHistoricalSignatures(programId); - console.log(`backfilled ${backfilledSignatures.length} signatures for ${programId.toString()}`); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error ? - `Error in backfill for ${programId.toString()}: ${error.message}` : - `Unknown error in backfill for ${programId.toString()}` - ]); - } - })); -} - -export const frontfill = async () => { - await Promise.all(programIds.map(async (programId) => { - try { - setInterval(async () => { - const newSignatures = await insertNewSignatures(programId); - console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); - }, 1000); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error ? - `Error in backfill for ${programId.toString()}: ${error.message}` : - `Unknown error in backfill for ${programId.toString()}` - ]); - } - })); -} - -// export const populateSignatures = async () => { - -// // use promise.all so they all run concurrently -// await Promise.all(programIds.map(programId => backfillAndSubscribe(programId))); -// }; \ No newline at end of file diff --git a/packages/new_indexer/src/v4_indexer/processor.ts b/packages/new_indexer/src/v4_indexer/processor.ts new file mode 100644 index 00000000..00779f47 --- /dev/null +++ b/packages/new_indexer/src/v4_indexer/processor.ts @@ -0,0 +1,451 @@ +import { AddLiquidityEvent, AmmEvent, ConditionalVaultEvent, CreateAmmEvent, getVaultAddr, InitializeConditionalVaultEvent, InitializeQuestionEvent, SwapEvent, PriceMath, SplitTokensEvent, MergeTokensEvent, RemoveLiquidityEvent } from "@metadaoproject/futarchy/v0.4"; +import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; +import { PublicKey, VersionedTransactionResponse } from "@solana/web3.js"; +import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; +import * as token from "@solana/spl-token"; + +import { connection, conditionalVaultClient } from "./connection"; + +import { TelegramBotAPI } from "./adapters/telegram-bot"; +import { Logger } from "./logger"; + +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +type Market = { + marketAcct: string; + baseMint: string; + quoteMint: string; +} + +type DBConnection = any; // TODO: Fix typing.. + + +export async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "CreateAmmEvent": + await handleCreateAmmEvent(event.data as CreateAmmEvent); + break; + case "AddLiquidityEvent": + await handleAddLiquidityEvent(event.data as AddLiquidityEvent); + break; + case "RemoveLiquidityEvent": + await handleRemoveLiquidityEvent(event.data as RemoveLiquidityEvent); + break; + case "SwapEvent": + await handleSwapEvent(event.data as SwapEvent, signature, transactionResponse); + break; + default: + console.log("Unknown event", event); + } +} + +async function handleCreateAmmEvent(event: CreateAmmEvent) { + try { + await usingDb(async (db: DBConnection) => { + await insertTokenIfNotExists(db, event.lpMint); + await insertTokenIfNotExists(db, event.baseMint); + await insertTokenIfNotExists(db, event.quoteMint); + await insertMarketIfNotExists(db, { + marketAcct: event.common.amm.toBase58(), + baseMint: event.baseMint.toString(), + quoteMint: event.quoteMint.toString(), + }); + + await db.insert(schema.v0_4_amms).values({ + ammAddr: event.common.amm.toString(), + lpMintAddr: event.lpMint.toString(), + createdAtSlot: BigInt(event.common.slot.toString()), + baseMintAddr: event.baseMint.toString(), + quoteMintAddr: event.quoteMint.toString(), + latestAmmSeqNumApplied: 0n, + baseReserves: 0n, + quoteReserves: 0n, + }).onConflictDoNothing(); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleCreateAmmEvent: ${error.message}` + : "Unknown error in handleCreateAmmEvent" + ]); + } +} + +async function handleAddLiquidityEvent(event: AddLiquidityEvent) { + try { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleAddLiquidityEvent: ${error.message}` + : "Unknown error in handleAddLiquidityEvent" + ]); + } +} + +async function handleRemoveLiquidityEvent(event: RemoveLiquidityEvent) { + try { + await usingDb(async (db: DBConnection) => { + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + + console.log("Updated AMM", event.common.amm.toString()); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleRemoveLiquidityEvent: ${error.message}` + : "Unknown error in handleRemoveLiquidityEvent" + ]); + } +} + +async function handleSwapEvent(event: SwapEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + try { + if (transactionResponse.blockTime === null || transactionResponse.blockTime === undefined) { + return; + }; + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_swaps).values({ + signature: signature, + slot: BigInt(transactionResponse.slot), + // @ts-ignore - fixed above in the if statement + blockTime: new Date(transactionResponse.blockTime * 1000), + swapType: event.swapType.buy ? V04SwapType.Buy : V04SwapType.Sell, + ammAddr: event.common.amm.toString(), + userAddr: event.common.user.toString(), + inputAmount: event.inputAmount.toString(), + outputAmount: event.outputAmount.toString(), + ammSeqNum: BigInt(event.common.seqNum.toString()) + }).onConflictDoNothing(); + + const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); + + if (amm.length === 0) { + console.log("AMM not found", event.common.amm.toString()); + return; + } + + if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { + console.log("Already applied", event.common.seqNum.toString()); + return; + } + + await insertPriceIfNotDuplicate(db, amm, event); + + await db.update(schema.v0_4_amms).set({ + baseReserves: BigInt(event.common.postBaseReserves.toString()), + quoteReserves: BigInt(event.common.postQuoteReserves.toString()), + latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), + }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleSwapEvent: ${error.message}` + : "Unknown error in handleSwapEvent" + ]); + } +} + +async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + try { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_splits).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleSplitEvent: ${error.message}` + : "Unknown error in handleSplitEvent" + ]); + } +} + +async function handleMergeEvent(event: MergeTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { + try { + await usingDb(async (db: DBConnection) => { + await db.insert(schema.v0_4_merges).values({ + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + }).onConflictDoNothing(); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleMergeEvent: ${error.message}` + : "Unknown error in handleMergeEvent" + ]); + } +} + +async function insertTokenIfNotExists(db: DBConnection, mintAcct: PublicKey) { + const existingToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, mintAcct.toString())).limit(1); + if (existingToken.length === 0) { + console.log("Inserting token", mintAcct.toString()); + const mint: token.Mint = await token.getMint(connection, mintAcct); + await db.insert(schema.tokens).values({ + mintAcct: mintAcct.toString(), + symbol: mintAcct.toString().slice(0, 3), + name: mintAcct.toString().slice(0, 3), + decimals: mint.decimals, + supply: mint.supply, + updatedAt: new Date(), + }).onConflictDoNothing(); + } +} + + +export async function processVaultEvent(event: { name: string; data: ConditionalVaultEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { + switch (event.name) { + case "InitializeQuestionEvent": + await handleInitializeQuestionEvent(event.data as InitializeQuestionEvent); + break; + case "InitializeConditionalVaultEvent": + await handleInitializeConditionalVaultEvent(event.data as InitializeConditionalVaultEvent); + break; + case "SplitTokensEvent": + await handleSplitEvent(event.data as SplitTokensEvent, signature, transactionResponse); + break; + case "MergeTokensEvent": + await handleMergeEvent(event.data as MergeTokensEvent, signature, transactionResponse); + break; + default: + console.log("Unknown Vault event", event.name); + } +} + +async function handleInitializeQuestionEvent(event: InitializeQuestionEvent) { + try { + await usingDb(async (db) => { + await db.insert(schema.v0_4_questions).values({ + questionAddr: event.question.toString(), + isResolved: false, + oracleAddr: event.oracle.toString(), + numOutcomes: event.numOutcomes, + payoutNumerators: Array(event.numOutcomes).fill(0), + payoutDenominator: 0n, + questionId: event.questionId, + }).onConflictDoNothing(); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleInitializeQuestionEvent: ${error.message}` + : "Unknown error in handleInitializeQuestionEvent" + ]); + } +} + +async function handleInitializeConditionalVaultEvent(event: InitializeConditionalVaultEvent) { + try { + const vaultAddr = getVaultAddr(conditionalVaultClient.vaultProgram.programId, event.question, event.underlyingTokenMint)[0]; + await usingDb(async (db) => { + await db.transaction(async (trx) => { + if (!await doesQuestionExist(trx, event)) { + return; + } + await insertTokenIfNotExists(trx, event.underlyingTokenMint); + await insertTokenAccountIfNotExists(trx, event); + await insertConditionalVault(trx, event, vaultAddr); + }); + }); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error in handleInitializeConditionalVaultEvent: ${error.message}` + : "Unknown error in handleInitializeConditionalVaultEvent" + ]); + } +} + +async function doesQuestionExist(db: DBConnection, event: InitializeConditionalVaultEvent): Promise { + const existingQuestion = await db.select().from(schema.v0_4_questions).where(eq(schema.v0_4_questions.questionAddr, event.question.toString())).limit(1); + return existingQuestion.length > 0; + // if (existingQuestion.length === 0) { + // await trx.insert(schema.v0_4_questions).values({ + // questionAddr: event.question.toString(), + // isResolved: false, + // oracleAddr: event.oracle.toString(), + // numOutcomes: event.numOutcomes, + // payoutNumerators: Array(event.numOutcomes).fill(0), + // payoutDenominator: 0n, + // questionId: event.questionId, + // }); + // } +} + +async function insertTokenAccountIfNotExists(db: DBConnection, event: InitializeConditionalVaultEvent) { + const existingTokenAcct = await db.select() + .from(schema.tokenAccts) + .where(eq(schema.tokenAccts.tokenAcct, event.vaultUnderlyingTokenAccount.toString())) + .limit(1); + + if (existingTokenAcct.length === 0) { + await db.insert(schema.tokenAccts).values({ + tokenAcct: event.vaultUnderlyingTokenAccount.toString(), + mintAcct: event.underlyingTokenMint.toString(), + ownerAcct: event.vaultUnderlyingTokenAccount.toString(), + amount: 0n, + }); + } +} + +async function insertMarketIfNotExists(db: DBConnection, market: Market) { + const existingMarket = await db.select() + .from(schema.markets) + .where(eq(schema.markets.marketAcct, market.marketAcct)) + .limit(1); + + if (existingMarket.length === 0) { + await db.insert(schema.markets).values({ + marketAcct: market.marketAcct, + baseMintAcct: market.baseMint, + quoteMintAcct: market.quoteMint, + marketType: 'amm', + createTxSig: '', + baseLotSize: 0n, + quoteLotSize: 0n, + quoteTickSize: 0n, + baseMakerFee: 0, + quoteMakerFee: 0, + baseTakerFee: 0, + quoteTakerFee: 0 + }).onConflictDoNothing(); + } +} + +async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { + const existingPrice = await db.select() + .from(schema.prices) + .where(and( + eq(schema.prices.marketAcct, event.common.amm.toBase58()), + eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())) + )) + .limit(1); + + if (existingPrice.length > 0) { + console.log("Price already exists", event.common.amm.toBase58(), BigInt(event.common.slot.toString())); + return; + } + + const ammPrice = PriceMath.getAmmPriceFromReserves(event.common.postBaseReserves, event.common.postQuoteReserves); + const baseToken = await db.select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, amm[0].baseMintAddr)) + .limit(1); + const quoteToken = await db.select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, amm[0].quoteMintAddr)) + .limit(1); + + if (!baseToken.length || !quoteToken.length) { + throw new Error(`Token not found: base=${!!baseToken.length}, quote=${!!quoteToken.length}`); + } + + const humanPrice = PriceMath.getHumanPrice(ammPrice, baseToken[0].decimals, quoteToken[0].decimals); + + await db.insert(schema.prices).values({ + marketAcct: event.common.amm.toBase58(), + baseAmount: BigInt(event.common.postBaseReserves.toString()), + quoteAmount: BigInt(event.common.postQuoteReserves.toString()), + price: humanPrice.toString(), + updatedSlot: BigInt(event.common.slot.toString()), + createdBy: 'amm-market-indexer', + pricesType: PricesType.Conditional, + }).onConflictDoNothing(); +} + +async function insertConditionalVault(db: DBConnection, event: InitializeConditionalVaultEvent, vaultAddr: PublicKey) { + await db.insert(schema.v0_4_conditional_vaults).values({ + conditionalVaultAddr: vaultAddr.toString(), + questionAddr: event.question.toString(), + underlyingMintAcct: event.underlyingTokenMint.toString(), + underlyingTokenAcct: event.vaultUnderlyingTokenAccount.toString(), + pdaBump: event.pdaBump, + latestVaultSeqNumApplied: 0n, + }).onConflictDoNothing(); +} + + +async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { + try { + return await connection.getTransactions( + eligibleSignatures.map(s => s.signature), + { commitment: "confirmed", maxSupportedTransactionVersion: 1 } + ); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error fetching transaction responses: ${error.message}` + : "Unknown error fetching transaction responses" + ]); + return []; + } +} + +//set latestProcessedSlot in db +async function setLatestProcessedSlot(slot: number) { + try { + await usingDb(async (db) => { + await db.update(schema.indexers) + .set({ latestSlotProcessed: BigInt(slot) }) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .execute(); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error setting latest processed slot: ${error.message}` + : "Unknown error setting latest processed slot" + ]); + } +} \ No newline at end of file From b0f4678a1af2cf6895590769cea0a4be292bdf04 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 30 Oct 2024 19:35:18 -0400 Subject: [PATCH 04/29] organizing v3 stuff... --- packages/new_indexer/src/processLogs.ts | 5 - packages/new_indexer/src/subscriber.ts | 8 +- .../src/v3_indexer}/builders/swaps.ts | 0 .../src/v3_indexer}/connection.ts | 0 .../src/v3_indexer}/constants.ts | 0 .../new_indexer/src/v3_indexer/indexer.ts | 6 + .../indexers/account-info-indexer.ts | 0 .../indexers/account-logs-indexer.ts | 0 .../amm-market/amm-market-account-indexer.ts | 2 +- .../amm-market-account-interval-indexer.ts | 2 +- .../amm-market-instruction-indexer.ts | 2 +- .../amm-market-logs-subscribe-indexer.ts | 2 +- .../{ => indexers}/amm-market/utils.ts | 2 +- .../autocrat/autocrat-dao-indexer.ts | 4 +- .../autocrat/autocrat-proposal-indexer.ts | 2 +- .../autocrat/autocrat-v0-indexer.ts | 2 +- .../autocrat/autocrat-v0_1-indexer.ts | 2 +- .../autocrat/autocrat-v0_2-indexer.ts | 2 +- .../birdeye/birdeye-prices-indexer.ts | 2 +- .../src/v3_indexer}/indexers/common.ts | 0 .../src/v3_indexer/indexers/index.ts | 119 +++ .../indexers/instruction-indexer.ts | 0 .../indexers/interval-fetch-indexer.ts | 0 .../jupiter/jupiter-quotes-indexer.ts | 2 +- .../openbook-twap-instruction-indexer.ts | 0 .../openbook-v2-account-indexer.ts | 2 +- .../openbook-v2/openbook-v2-indexer.ts | 0 .../indexers/start-account-info-indexers.ts | 63 ++ .../indexers/start-interval-fetch-indexers.ts | 187 ++++ .../indexers/start-logs-subscribe-indexer.ts | 46 + .../start-transaction-history-indexers.ts | 0 .../token/token-mint-indexer.ts | 2 +- .../src/v3_indexer}/instruction-dispatch.ts | 0 .../src/v3_indexer}/match.ts | 0 .../src/v3_indexer}/proposal-indexer.ts | 0 .../transaction/account-resolver.ts | 0 .../src/v3_indexer}/transaction/history.ts | 0 .../transaction/serializer.test.ts | 0 .../src/v3_indexer}/transaction/serializer.ts | 0 .../src/v3_indexer}/transaction/watcher.ts | 0 .../src/v3_indexer}/types/errors.ts | 0 .../src/v3_indexer}/types/index.ts | 0 .../src/v3_indexer}/types/swaps.ts | 0 .../new_indexer/src/v4_indexer/indexer.ts | 39 +- packages/{indexer => old_indexer}/Dockerfile | 0 .../{indexer => old_indexer}/package.json | 0 .../src/adapters/telegram-bot.ts | 0 packages/old_indexer/src/builders/swaps.ts | 428 +++++++++ .../{indexer => old_indexer}/src/cli/index.ts | 0 .../src/cli/txw/common/select-account.ts | 0 .../src/cli/txw/create.ts | 0 .../src/cli/txw/index.ts | 0 .../src/cli/txw/populate.ts | 0 .../src/cli/txw/reset.ts | 0 .../src/cli/txw/validate.ts | 0 packages/old_indexer/src/connection.ts | 30 + packages/old_indexer/src/constants.ts | 21 + .../src/endpoints/get-metrics.ts | 0 .../{indexer => old_indexer}/src/index.ts | 0 .../src/indexers/account-info-indexer.ts | 16 + .../src/indexers/account-logs-indexer.ts | 16 + .../amm-market/amm-market-account-indexer.ts | 0 .../amm-market-account-interval-indexer.ts | 0 .../amm-market-instruction-indexer.ts | 0 .../amm-market-logs-subscribe-indexer.ts | 0 .../src/indexers/amm-market/utils.ts | 0 .../indexers/autocrat/autocrat-dao-indexer.ts | 0 .../autocrat/autocrat-proposal-indexer.ts | 0 .../indexers/autocrat/autocrat-v0-indexer.ts | 0 .../autocrat/autocrat-v0_1-indexer.ts | 0 .../autocrat/autocrat-v0_2-indexer.ts | 0 .../birdeye/birdeye-prices-indexer.ts | 0 packages/old_indexer/src/indexers/common.ts | 12 + .../src/indexers/index.ts | 0 .../src/indexers/instruction-indexer.ts | 44 + .../src/indexers/interval-fetch-indexer.ts | 13 + .../jupiter/jupiter-quotes-indexer.ts | 0 .../openbook-twap-instruction-indexer.ts | 0 .../openbook-v2-account-indexer.ts | 0 .../openbook-v2/openbook-v2-indexer.ts | 0 .../indexers/start-account-info-indexers.ts | 0 .../indexers/start-interval-fetch-indexers.ts | 0 .../indexers/start-logs-subscribe-indexer.ts | 0 .../start-transaction-history-indexers.ts | 156 +++ .../src/indexers/token/token-mint-indexer.ts | 0 .../old_indexer/src/instruction-dispatch.ts | 220 +++++ .../src/local-cache.ts | 0 .../{indexer => old_indexer}/src/logger.ts | 0 packages/old_indexer/src/match.ts | 19 + packages/old_indexer/src/proposal-indexer.ts | 46 + .../{indexer => old_indexer}/src/server.ts | 0 .../src/transaction/account-resolver.ts | 55 ++ .../old_indexer/src/transaction/history.ts | 108 +++ .../src/transaction/serializer.test.ts | 40 + .../old_indexer/src/transaction/serializer.ts | 907 ++++++++++++++++++ .../old_indexer/src/transaction/watcher.ts | 619 ++++++++++++ packages/old_indexer/src/types/errors.ts | 14 + packages/old_indexer/src/types/index.ts | 41 + packages/old_indexer/src/types/swaps.ts | 9 + .../src/usecases/math.test.ts | 0 .../src/usecases/math.ts | 0 .../{indexer => old_indexer}/tsconfig.json | 0 102 files changed, 3277 insertions(+), 40 deletions(-) delete mode 100644 packages/new_indexer/src/processLogs.ts rename packages/{indexer/src => new_indexer/src/v3_indexer}/builders/swaps.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/connection.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/constants.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/account-info-indexer.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/account-logs-indexer.ts (100%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/amm-market/amm-market-account-indexer.ts (95%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/amm-market/amm-market-account-interval-indexer.ts (98%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/amm-market/amm-market-instruction-indexer.ts (98%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/amm-market/amm-market-logs-subscribe-indexer.ts (97%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/amm-market/utils.ts (99%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/autocrat/autocrat-dao-indexer.ts (97%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/autocrat/autocrat-proposal-indexer.ts (99%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/autocrat/autocrat-v0-indexer.ts (94%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/autocrat/autocrat-v0_1-indexer.ts (94%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/autocrat/autocrat-v0_2-indexer.ts (94%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/birdeye/birdeye-prices-indexer.ts (98%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/common.ts (100%) create mode 100644 packages/new_indexer/src/v3_indexer/indexers/index.ts rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/instruction-indexer.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/interval-fetch-indexer.ts (100%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/jupiter/jupiter-quotes-indexer.ts (99%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/openbook-twap/openbook-twap-instruction-indexer.ts (100%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/openbook-v2/openbook-v2-account-indexer.ts (98%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/openbook-v2/openbook-v2-indexer.ts (100%) create mode 100644 packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts create mode 100644 packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts create mode 100644 packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts rename packages/{indexer/src => new_indexer/src/v3_indexer}/indexers/start-transaction-history-indexers.ts (100%) rename packages/new_indexer/src/v3_indexer/{ => indexers}/token/token-mint-indexer.ts (98%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/instruction-dispatch.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/match.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/proposal-indexer.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/transaction/account-resolver.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/transaction/history.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/transaction/serializer.test.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/transaction/serializer.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/transaction/watcher.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/types/errors.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/types/index.ts (100%) rename packages/{indexer/src => new_indexer/src/v3_indexer}/types/swaps.ts (100%) rename packages/{indexer => old_indexer}/Dockerfile (100%) rename packages/{indexer => old_indexer}/package.json (100%) rename packages/{indexer => old_indexer}/src/adapters/telegram-bot.ts (100%) create mode 100644 packages/old_indexer/src/builders/swaps.ts rename packages/{indexer => old_indexer}/src/cli/index.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/common/select-account.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/create.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/index.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/populate.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/reset.ts (100%) rename packages/{indexer => old_indexer}/src/cli/txw/validate.ts (100%) create mode 100644 packages/old_indexer/src/connection.ts create mode 100644 packages/old_indexer/src/constants.ts rename packages/{indexer => old_indexer}/src/endpoints/get-metrics.ts (100%) rename packages/{indexer => old_indexer}/src/index.ts (100%) create mode 100644 packages/old_indexer/src/indexers/account-info-indexer.ts create mode 100644 packages/old_indexer/src/indexers/account-logs-indexer.ts rename packages/{indexer => old_indexer}/src/indexers/amm-market/amm-market-account-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/amm-market/amm-market-account-interval-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/amm-market/amm-market-instruction-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/amm-market/utils.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/autocrat/autocrat-dao-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/autocrat/autocrat-proposal-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/autocrat/autocrat-v0-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/autocrat/autocrat-v0_1-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/autocrat/autocrat-v0_2-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/birdeye/birdeye-prices-indexer.ts (100%) create mode 100644 packages/old_indexer/src/indexers/common.ts rename packages/{indexer => old_indexer}/src/indexers/index.ts (100%) create mode 100644 packages/old_indexer/src/indexers/instruction-indexer.ts create mode 100644 packages/old_indexer/src/indexers/interval-fetch-indexer.ts rename packages/{indexer => old_indexer}/src/indexers/jupiter/jupiter-quotes-indexer.ts (100%) rename packages/{new_indexer/src/v3_indexer => old_indexer/src/indexers}/openbook-twap/openbook-twap-instruction-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/openbook-v2/openbook-v2-account-indexer.ts (100%) rename packages/{new_indexer/src/v3_indexer => old_indexer/src/indexers}/openbook-v2/openbook-v2-indexer.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/start-account-info-indexers.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/start-interval-fetch-indexers.ts (100%) rename packages/{indexer => old_indexer}/src/indexers/start-logs-subscribe-indexer.ts (100%) create mode 100644 packages/old_indexer/src/indexers/start-transaction-history-indexers.ts rename packages/{indexer => old_indexer}/src/indexers/token/token-mint-indexer.ts (100%) create mode 100644 packages/old_indexer/src/instruction-dispatch.ts rename packages/{indexer => old_indexer}/src/local-cache.ts (100%) rename packages/{indexer => old_indexer}/src/logger.ts (100%) create mode 100644 packages/old_indexer/src/match.ts create mode 100644 packages/old_indexer/src/proposal-indexer.ts rename packages/{indexer => old_indexer}/src/server.ts (100%) create mode 100644 packages/old_indexer/src/transaction/account-resolver.ts create mode 100644 packages/old_indexer/src/transaction/history.ts create mode 100644 packages/old_indexer/src/transaction/serializer.test.ts create mode 100644 packages/old_indexer/src/transaction/serializer.ts create mode 100644 packages/old_indexer/src/transaction/watcher.ts create mode 100644 packages/old_indexer/src/types/errors.ts create mode 100644 packages/old_indexer/src/types/index.ts create mode 100644 packages/old_indexer/src/types/swaps.ts rename packages/{indexer => old_indexer}/src/usecases/math.test.ts (100%) rename packages/{indexer => old_indexer}/src/usecases/math.ts (100%) rename packages/{indexer => old_indexer}/tsconfig.json (100%) diff --git a/packages/new_indexer/src/processLogs.ts b/packages/new_indexer/src/processLogs.ts deleted file mode 100644 index 2f71b1ec..00000000 --- a/packages/new_indexer/src/processLogs.ts +++ /dev/null @@ -1,5 +0,0 @@ - - -export async function processLogs(logs) { - -} \ No newline at end of file diff --git a/packages/new_indexer/src/subscriber.ts b/packages/new_indexer/src/subscriber.ts index 0ec49f18..f165edea 100644 --- a/packages/new_indexer/src/subscriber.ts +++ b/packages/new_indexer/src/subscriber.ts @@ -6,7 +6,9 @@ import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; import { AccountLogsIndexer } from "./account-logs-indexer"; import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; import { logger } from "../logger"; -import { processSignature } from "./v4_indexer/indexer"; +import { index as indexV4 } from "./v4_indexer/indexer"; +import { index as indexV3 } from "./v3_indexer/indexer"; + async function processLogs(logs: Logs, programId: PublicKey) { //check if programId is v3 or v4 @@ -21,11 +23,11 @@ async function processLogs(logs: Logs, programId: PublicKey) { async function processLogsV4(logs: Logs, programId: PublicKey) { let signature = logs.signature; - await processSignature(signature); + await indexV4(signature, programId); } async function processLogsV3(logs: Logs, programId: PublicKey) { - + await indexV3(logs, programId); } //subscribes to logs for a given account diff --git a/packages/indexer/src/builders/swaps.ts b/packages/new_indexer/src/v3_indexer/builders/swaps.ts similarity index 100% rename from packages/indexer/src/builders/swaps.ts rename to packages/new_indexer/src/v3_indexer/builders/swaps.ts diff --git a/packages/indexer/src/connection.ts b/packages/new_indexer/src/v3_indexer/connection.ts similarity index 100% rename from packages/indexer/src/connection.ts rename to packages/new_indexer/src/v3_indexer/connection.ts diff --git a/packages/indexer/src/constants.ts b/packages/new_indexer/src/v3_indexer/constants.ts similarity index 100% rename from packages/indexer/src/constants.ts rename to packages/new_indexer/src/v3_indexer/constants.ts diff --git a/packages/new_indexer/src/v3_indexer/indexer.ts b/packages/new_indexer/src/v3_indexer/indexer.ts index e69de29b..f272dc23 100644 --- a/packages/new_indexer/src/v3_indexer/indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexer.ts @@ -0,0 +1,6 @@ +import { Logs, PublicKey } from "@solana/web3.js"; + + +export async function index(logs: Logs, programId: PublicKey) { + +} \ No newline at end of file diff --git a/packages/indexer/src/indexers/account-info-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/account-info-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/account-info-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/account-info-indexer.ts diff --git a/packages/indexer/src/indexers/account-logs-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/account-logs-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/account-logs-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/account-logs-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts similarity index 95% rename from packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts index d54a4c28..36b323c5 100644 --- a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts @@ -2,7 +2,7 @@ import { AccountInfoIndexer } from "../account-info-indexer"; import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; import { Err, Ok } from "../../match"; import { indexAmmMarketAccountWithContext } from "./utils"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; export enum AmmAccountIndexerError { GeneralError = "GeneralError", diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts similarity index 98% rename from packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts index ad3b511b..d935d7ec 100644 --- a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-account-interval-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts @@ -3,7 +3,7 @@ import { Err, Ok, Result } from "../../match"; import { indexAmmMarketAccountWithContext } from "./utils"; import { IntervalFetchIndexer } from "../interval-fetch-indexer"; import { connection } from "../../connection"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; import { AmmMarketAccountIndexingErrors } from "./utils"; export enum AmmAccountIntervalIndexerError { diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts similarity index 98% rename from packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts index 7f833a41..dfd0c879 100644 --- a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-instruction-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts @@ -9,7 +9,7 @@ import { } from "../../types/errors"; import { ammClient, IDL } from "../common"; import { SwapBuilder } from "../../builders/swaps"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; import { GetTransactionErrorType } from "../../transaction/serializer"; export const AmmMarketInstructionsIndexer: InstructionIndexer = { diff --git a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts similarity index 97% rename from packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts index 1946b6bc..b559378c 100644 --- a/packages/new_indexer/src/v3_indexer/amm-market/amm-market-logs-subscribe-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts @@ -2,7 +2,7 @@ import { Context, Logs, PublicKey } from "@solana/web3.js"; import { Err, Ok } from "../../match"; import { AccountLogsIndexer } from "../account-logs-indexer"; import { SwapBuilder } from "../../builders/swaps"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; import { SwapPersistableError } from "../../types/errors"; import { GetTransactionErrorType } from "../../transaction/serializer"; diff --git a/packages/new_indexer/src/v3_indexer/amm-market/utils.ts b/packages/new_indexer/src/v3_indexer/indexers/amm-market/utils.ts similarity index 99% rename from packages/new_indexer/src/v3_indexer/amm-market/utils.ts rename to packages/new_indexer/src/v3_indexer/indexers/amm-market/utils.ts index eeb11945..01829792 100644 --- a/packages/new_indexer/src/v3_indexer/amm-market/utils.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/amm-market/utils.ts @@ -10,7 +10,7 @@ import { import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; import { provider, rpcReadClient } from "../../connection"; import { Err, Ok, Result, TaggedUnion } from "../../match"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; import { getHumanPrice } from "../../usecases/math"; export enum AmmMarketAccountIndexingErrors { diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts similarity index 97% rename from packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts index 3deb8588..a055e517 100644 --- a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-dao-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts @@ -1,12 +1,12 @@ import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { rpcReadClient, connection } from "../../connection"; +import { rpcReadClient, connection } from "../../.connection"; import { usingDb, schema } from "@metadaoproject/indexer-db"; import { Dao } from "@metadaoproject/futarchy-sdk"; import { Err, Ok } from "../../match"; import { PublicKey } from "@solana/web3.js"; import { DaoRecord, TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; import { getMint } from "@solana/spl-token"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; export enum AutocratDaoIndexerError { GeneralError = "GeneralError", diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts similarity index 99% rename from packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts index 84047d27..ae20f316 100644 --- a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-proposal-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts @@ -41,7 +41,7 @@ import { import { BN } from "@coral-xyz/anchor"; import { gte } from "drizzle-orm"; import { desc } from "drizzle-orm"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; import { PriceMath, ProposalAccount } from "@metadaoproject/futarchy/v0.3"; import { UserPerformance, UserPerformanceTotals } from "../../types"; import { alias } from "drizzle-orm/pg-core"; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts similarity index 94% rename from packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts index 9a31a557..f23102f5 100644 --- a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts @@ -1,7 +1,7 @@ import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0"; import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; const AUTOCRAT_V0 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts similarity index 94% rename from packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts index 95d51d60..331c3519 100644 --- a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_1-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts @@ -1,7 +1,7 @@ import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.1"; import { InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; const AUTOCRAT_V0_1 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 2]; diff --git a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts similarity index 94% rename from packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts index ce56b9bf..68c70cbb 100644 --- a/packages/new_indexer/src/v3_indexer/autocrat/autocrat-v0_2-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts @@ -1,7 +1,7 @@ import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.2"; import { InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; const AUTOCRAT_V0_2 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; diff --git a/packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts similarity index 98% rename from packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts index cf0515e3..7142fac3 100644 --- a/packages/new_indexer/src/v3_indexer/birdeye/birdeye-prices-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts @@ -6,7 +6,7 @@ import { PricesRecord, PricesType, } from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; const apiKey = process.env.BIRDEYE_API_KEY ?? ""; diff --git a/packages/indexer/src/indexers/common.ts b/packages/new_indexer/src/v3_indexer/indexers/common.ts similarity index 100% rename from packages/indexer/src/indexers/common.ts rename to packages/new_indexer/src/v3_indexer/indexers/common.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/index.ts b/packages/new_indexer/src/v3_indexer/indexers/index.ts new file mode 100644 index 00000000..f3293924 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/indexers/index.ts @@ -0,0 +1,119 @@ +import { eq, getClient, schema, usingDb } from "@metadaoproject/indexer-db"; +import { + IndexerAccountDependencyReadRecord, + IndexerAccountDependencyStatus, + IndexerType, +} from "@metadaoproject/indexer-db/lib/schema"; +import { startIntervalFetchIndexer } from "./start-interval-fetch-indexers"; +import { startAccountInfoIndexer } from "./start-account-info-indexers"; +import { startTransactionHistoryIndexer } from "./start-transaction-history-indexers"; +import { startLogsSubscribeIndexer } from "./start-logs-subscribe-indexer"; +import { IndexerWithAccountDeps } from "../types"; +import { logger } from "../../logger"; + +export async function startIndexers() { + await startAllIndexers(); + await listenForNewAccountsToIndex(); + console.log("indexers successfully started"); +} + +export async function startAllIndexers() { + const allIndexers = + (await usingDb((db) => + db + .select() + .from(schema.indexers) + .fullJoin( + schema.indexerAccountDependencies, + eq(schema.indexerAccountDependencies.name, schema.indexers.name) + ) + .where( + eq( + schema.indexerAccountDependencies.status, + IndexerAccountDependencyStatus.Active + ) + ) + .execute() + )) ?? []; + + for (const indexerQueryRes of allIndexers) { + await startIndexer(indexerQueryRes); + } +} + +async function startIndexer(indexerQueryRes: any) { + switch (indexerQueryRes.indexers?.indexerType) { + case IndexerType.AccountInfo: + await startAccountInfoIndexer(indexerQueryRes); + break; + case IndexerType.IntervalFetch: + const job = await startIntervalFetchIndexer(indexerQueryRes); + if (job) { + console.log( + `scheduled to run account ${ + indexerQueryRes?.indexer_account_dependencies?.acct + } on the ${indexerQueryRes.indexers?.implementation} indexer at ${job + .nextRun() + ?.toISOString()} and on a pattern of ${job.getPattern()}` + ); + } + break; + case IndexerType.TXHistory: + startTransactionHistoryIndexer(indexerQueryRes); + break; + case IndexerType.LogSubscribe: + startLogsSubscribeIndexer(indexerQueryRes); + break; + default: + console.warn( + `Unknown indexer type: ${indexerQueryRes.indexers?.indexerType}` + ); + } +} + +async function listenForNewAccountsToIndex() { + const client = await getClient(); + client.query("LISTEN indexer_account_dependencies_insert_channel"); + + client.on("notification", async (msg) => { + const payload = JSON.parse(msg.payload ?? "{}"); + await handleNewAccountToIndex(payload); + }); +} + +async function handleNewAccountToIndex( + newRow: IndexerAccountDependencyReadRecord +) { + // Example function to handle the new row + try { + // skip disabled acct + if (newRow.status === IndexerAccountDependencyStatus.Disabled) return; + + const indexer = + (await usingDb((db) => + db + .select() + .from(schema.indexers) + .where(eq(schema.indexers.name, newRow.name)) + .execute() + )) ?? []; + if (!indexer[0]) { + console.warn( + "new indexer dependency inserted that does not tie to an indexer" + ); + return; + } + const indexerWithAccountDep: IndexerWithAccountDeps = { + indexer_account_dependencies: newRow, + indexers: indexer[0], + }; + await startIndexer(indexerWithAccountDep); + // Perform operations using Drizzle ORM + // For example, you could log the new row or trigger other indexers + } catch (e) { + logger.errorWithChatBotAlert( + "error with starting of indexing new account dependency", + e + ); + } +} diff --git a/packages/indexer/src/indexers/instruction-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/instruction-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/instruction-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/instruction-indexer.ts diff --git a/packages/indexer/src/indexers/interval-fetch-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/interval-fetch-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts similarity index 99% rename from packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts index 743529d7..076487d8 100644 --- a/packages/new_indexer/src/v3_indexer/jupiter/jupiter-quotes-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts @@ -6,7 +6,7 @@ import { PricesRecord, PricesType, } from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; export enum JupiterQuoteIndexingError { JupiterFetchError = "JupiterFetchError", diff --git a/packages/indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts similarity index 98% rename from packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts index 6edec736..8518760b 100644 --- a/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-account-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts @@ -11,7 +11,7 @@ import { PricesRecord, PricesType, } from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; export enum OpenbookV2MarketAccountIndexerError { MarketNotFound = "MarketNotFound", diff --git a/packages/indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts b/packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts new file mode 100644 index 00000000..a9eb65f3 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts @@ -0,0 +1,63 @@ +import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; +import { PublicKey } from "@solana/web3.js"; +import { connection } from "../connection"; +import { IndexerWithAccountDeps } from "../types"; +import { AccountInfoIndexer } from "./account-info-indexer"; +import { AmmMarketAccountUpdateIndexer } from "./amm-market/amm-market-account-indexer"; +import { OpenbookV2MarketAccountUpdateIndexer } from "./openbook-v2/openbook-v2-account-indexer"; +import { logger } from "../../logger"; + +export async function startAccountInfoIndexer( + indexerQueryRes: IndexerWithAccountDeps +) { + const { indexers: indexer, indexer_account_dependencies: dependentAccount } = + indexerQueryRes; + if (!indexer) return; + const implementation = getAccountInfoIndexerImplementation( + indexer.implementation + ); + if (implementation && dependentAccount && dependentAccount.acct) { + const accountPubKey = new PublicKey(dependentAccount.acct); + + const accountInfo = await connection.getAccountInfoAndContext( + accountPubKey + ); + + //index refresh on startup + if (accountInfo.value) { + const res = await implementation.index( + accountInfo.value, + accountPubKey, + accountInfo.context + ); + if (!res.success) { + logger.error( + "error indexing account initial fetch", + accountPubKey.toString() + ); + } + } + + connection.onAccountChange(accountPubKey, async (accountInfo, context) => { + const res = await implementation.index( + accountInfo, + accountPubKey, + context + ); + if (!res.success) { + logger.error("error indexing account update", accountPubKey.toString()); + } + }); + } +} +function getAccountInfoIndexerImplementation( + implementation: IndexerImplementation +): AccountInfoIndexer | null { + switch (implementation) { + case IndexerImplementation.AmmMarketIndexer: + return AmmMarketAccountUpdateIndexer; + case IndexerImplementation.OpenbookV2MarketIndexer: + return OpenbookV2MarketAccountUpdateIndexer; + } + return null; +} diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts b/packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts new file mode 100644 index 00000000..07037996 --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts @@ -0,0 +1,187 @@ +import { + IndexerAccountDependencyStatus, + IndexerImplementation, +} from "@metadaoproject/indexer-db/lib/schema"; + +import { IndexerWithAccountDeps } from "../types"; +import { BirdeyePricesIndexer } from "./birdeye/birdeye-prices-indexer"; +import { IntervalFetchIndexer } from "./interval-fetch-indexer"; +import { JupiterQuotesIndexer } from "./jupiter/jupiter-quotes-indexer"; +import { AmmMarketAccountIntervalFetchIndexer } from "./amm-market/amm-market-account-interval-indexer"; +import { AutocratDaoIndexer } from "./autocrat/autocrat-dao-indexer"; +import { AutocratProposalIndexer } from "./autocrat/autocrat-proposal-indexer"; +import { TokenMintIndexer } from "./token/token-mint-indexer"; +import { Cron } from "croner"; +import { and, eq, schema, usingDb } from "@metadaoproject/indexer-db"; +import { logger } from "../../logger"; + +// add croner for this +// instantiates new croner and returns in function, which could be potentially useful +// now we can stop the job if we have an error + +const maxResets = 5; + +export function startIntervalFetchIndexer( + indexerQueryRes: IndexerWithAccountDeps +): Cron | null { + let errorCount = 0; + let resets = 0; + const { indexers: indexer, indexer_account_dependencies: dependentAccount } = + indexerQueryRes; + if (!indexer) return null; + const implementation = getIntervalFetchIndexerImplementation( + indexer.implementation + ); + if (implementation && dependentAccount && dependentAccount.acct) { + const retries = implementation.retries ?? 3; // default 3 interval fetch retries + logger.log("setting interval fetch for:", dependentAccount.acct); + const job = new Cron( + implementation.cronExpression, + {}, + async (self: Cron) => { + const res = await implementation.index(dependentAccount.acct); + if (!res.success) { + logger.log( + `error with interval fetch indexer ${dependentAccount.acct}:`, + res.error + ); + errorCount += 1; + if (resets === maxResets) { + // we have already paused/reset this indexer the max times, we are stopping the whole thing for good + handleIntervalFetchFinalFailure(dependentAccount, self); + return; + } + if (errorCount > retries) { + handleIntervalFetchFailure(dependentAccount, self); + // now that the job has been paused for 100 minutes, we reset the error count to 0 + errorCount = 0; + resets += 1; + } + } else { + errorCount = 0; + logger.log( + `next run for ${dependentAccount.acct} with ${ + indexer.implementation + } at ${self.nextRun()}` + ); + } + } + ); + return job; + } + return null; +} +export function getIntervalFetchIndexerImplementation( + implementation: IndexerImplementation +): IntervalFetchIndexer | null { + switch (implementation) { + case IndexerImplementation.JupiterQuotesIndexer: + return JupiterQuotesIndexer; + case IndexerImplementation.BirdeyePricesIndexer: + return BirdeyePricesIndexer; + case IndexerImplementation.AmmMarketsAccountFetch: + return AmmMarketAccountIntervalFetchIndexer; + case IndexerImplementation.AutocratDaoIndexer: + return AutocratDaoIndexer; + case IndexerImplementation.AutocratProposalIndexer: + return AutocratProposalIndexer; + case IndexerImplementation.TokenMintIndexer: + return TokenMintIndexer; + } + return null; +} + +async function handleIntervalFetchFailure( + indexerWithAcct: IndexerWithAccountDeps["indexer_account_dependencies"], + job: Cron +) { + job.pause(); + const updateResult = + (await usingDb((db) => + db + .update(schema.indexerAccountDependencies) + .set({ + status: IndexerAccountDependencyStatus.Paused, + updatedAt: new Date(), + }) + .where( + and( + eq( + schema.indexerAccountDependencies.acct, + indexerWithAcct?.acct ?? "" + ), + eq( + schema.indexerAccountDependencies.name, + indexerWithAcct?.name ?? "" + ) + ) + ) + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + if (updateResult.length !== 1) { + logger.errorWithChatBotAlert( + `error with pausing interval fetch indexer ${indexerWithAcct?.acct}.` + ); + } + // we resume job after 100 minutes to try again + setTimeout(async () => { + job.resume(); + const updateResult = + (await usingDb((db) => + db + .update(schema.indexerAccountDependencies) + .set({ + status: IndexerAccountDependencyStatus.Active, + updatedAt: new Date(), + }) + .where( + and( + eq( + schema.indexerAccountDependencies.acct, + indexerWithAcct?.acct ?? "" + ), + eq( + schema.indexerAccountDependencies.name, + indexerWithAcct?.name ?? "" + ) + ) + ) + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + + if (updateResult.length !== 1) { + logger.errorWithChatBotAlert( + `failed to update indexer_account_dependency on acct ${indexerWithAcct?.acct} to Active even though the job has been resumed` + ); + } + }, 3600_000); +} + +async function handleIntervalFetchFinalFailure( + indexerWithAcct: IndexerWithAccountDeps["indexer_account_dependencies"], + job: Cron +) { + job.stop(); + const updateResult = + (await usingDb((db) => + db + .update(schema.indexerAccountDependencies) + .set({ + status: IndexerAccountDependencyStatus.Disabled, + updatedAt: new Date(), + }) + .where( + eq( + schema.indexerAccountDependencies.acct, + indexerWithAcct?.acct ?? "" + ) + ) + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + + if (updateResult.length !== 1) { + logger.errorWithChatBotAlert( + `final error with interval fetch indexer ${indexerWithAcct?.acct}. status set to disabled.` + ); + } +} diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts new file mode 100644 index 00000000..4c8f267a --- /dev/null +++ b/packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts @@ -0,0 +1,46 @@ +import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; +import { PublicKey } from "@solana/web3.js"; +import { connection } from "../connection"; +import { IndexerWithAccountDeps } from "../types"; +import { AccountLogsIndexer } from "./account-logs-indexer"; +import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; +import { logger } from "../../logger"; + +export async function startLogsSubscribeIndexer( + indexerQueryRes: IndexerWithAccountDeps +) { + const { indexers: indexer, indexer_account_dependencies: dependentAccount } = + indexerQueryRes; + if (!indexer) return; + const implementation = getLogsSubscribeIndexerImplementation( + indexer.implementation + ); + if (implementation && dependentAccount && dependentAccount.acct) { + const accountPubKey = new PublicKey(dependentAccount.acct); + + connection.onLogs(accountPubKey, async (logs, context) => { + // wait here because we need to fetch the txn from RPC + // and often we get no response if we try right after recieving the logs notification + await new Promise((resolve) => setTimeout(resolve, 1500)); + const res = await implementation.index(logs, accountPubKey, context); + if (!res.success) { + logger.error( + "error indexing account logs", + accountPubKey.toString(), + res.error.type, + JSON.stringify(res.error.value), + "logs: " + logs.signature + ); + } + }); + } +} +function getLogsSubscribeIndexerImplementation( + implementation: IndexerImplementation +): AccountLogsIndexer | null { + switch (implementation) { + case IndexerImplementation.AmmMarketsLogsSubscribe: + return AmmMarketLogsSubscribeIndexer; + } + return null; +} diff --git a/packages/indexer/src/indexers/start-transaction-history-indexers.ts b/packages/new_indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts similarity index 100% rename from packages/indexer/src/indexers/start-transaction-history-indexers.ts rename to packages/new_indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts diff --git a/packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts b/packages/new_indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts similarity index 98% rename from packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts rename to packages/new_indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts index cde88d49..c1e7a2be 100644 --- a/packages/new_indexer/src/v3_indexer/token/token-mint-indexer.ts +++ b/packages/new_indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts @@ -5,7 +5,7 @@ import { Err, Ok } from "../../match"; import { PublicKey } from "@solana/web3.js"; import { TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; import { TokenAccountNotFoundError, getMint } from "@solana/spl-token"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; export enum TokenMintIndexerError { GeneralError = "GeneralError", diff --git a/packages/indexer/src/instruction-dispatch.ts b/packages/new_indexer/src/v3_indexer/instruction-dispatch.ts similarity index 100% rename from packages/indexer/src/instruction-dispatch.ts rename to packages/new_indexer/src/v3_indexer/instruction-dispatch.ts diff --git a/packages/indexer/src/match.ts b/packages/new_indexer/src/v3_indexer/match.ts similarity index 100% rename from packages/indexer/src/match.ts rename to packages/new_indexer/src/v3_indexer/match.ts diff --git a/packages/indexer/src/proposal-indexer.ts b/packages/new_indexer/src/v3_indexer/proposal-indexer.ts similarity index 100% rename from packages/indexer/src/proposal-indexer.ts rename to packages/new_indexer/src/v3_indexer/proposal-indexer.ts diff --git a/packages/indexer/src/transaction/account-resolver.ts b/packages/new_indexer/src/v3_indexer/transaction/account-resolver.ts similarity index 100% rename from packages/indexer/src/transaction/account-resolver.ts rename to packages/new_indexer/src/v3_indexer/transaction/account-resolver.ts diff --git a/packages/indexer/src/transaction/history.ts b/packages/new_indexer/src/v3_indexer/transaction/history.ts similarity index 100% rename from packages/indexer/src/transaction/history.ts rename to packages/new_indexer/src/v3_indexer/transaction/history.ts diff --git a/packages/indexer/src/transaction/serializer.test.ts b/packages/new_indexer/src/v3_indexer/transaction/serializer.test.ts similarity index 100% rename from packages/indexer/src/transaction/serializer.test.ts rename to packages/new_indexer/src/v3_indexer/transaction/serializer.test.ts diff --git a/packages/indexer/src/transaction/serializer.ts b/packages/new_indexer/src/v3_indexer/transaction/serializer.ts similarity index 100% rename from packages/indexer/src/transaction/serializer.ts rename to packages/new_indexer/src/v3_indexer/transaction/serializer.ts diff --git a/packages/indexer/src/transaction/watcher.ts b/packages/new_indexer/src/v3_indexer/transaction/watcher.ts similarity index 100% rename from packages/indexer/src/transaction/watcher.ts rename to packages/new_indexer/src/v3_indexer/transaction/watcher.ts diff --git a/packages/indexer/src/types/errors.ts b/packages/new_indexer/src/v3_indexer/types/errors.ts similarity index 100% rename from packages/indexer/src/types/errors.ts rename to packages/new_indexer/src/v3_indexer/types/errors.ts diff --git a/packages/indexer/src/types/index.ts b/packages/new_indexer/src/v3_indexer/types/index.ts similarity index 100% rename from packages/indexer/src/types/index.ts rename to packages/new_indexer/src/v3_indexer/types/index.ts diff --git a/packages/indexer/src/types/swaps.ts b/packages/new_indexer/src/v3_indexer/types/swaps.ts similarity index 100% rename from packages/indexer/src/types/swaps.ts rename to packages/new_indexer/src/v3_indexer/types/swaps.ts diff --git a/packages/new_indexer/src/v4_indexer/indexer.ts b/packages/new_indexer/src/v4_indexer/indexer.ts index 2c102ea0..2ac4a39b 100644 --- a/packages/new_indexer/src/v4_indexer/indexer.ts +++ b/packages/new_indexer/src/v4_indexer/indexer.ts @@ -74,27 +74,32 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac }; } -export async function processSignature(signature: string, programId: PublicKey) { +//indexes signature +export async function index(signature: string, programId: PublicKey) { try { - if (programId.equals(AMM_PROGRAM_ID) || programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { - const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); - if (!transactionResponse) { - console.log("No transaction response"); - return; - } + if (!programId.equals(AMM_PROGRAM_ID) && !programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { + //autocrat program id, we aren't indexing these for now + console.log("Unknown program id: ", programId.toBase58()); + return; + } + const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); + if (!transactionResponse) { + console.log("No transaction response"); + return; + } - const events = parseEvents(transactionResponse); - const ammEvents = events.ammEvents; - const vaultEvents = events.vaultEvents; + const events = parseEvents(transactionResponse); + const ammEvents = events.ammEvents; + const vaultEvents = events.vaultEvents; - Promise.all(ammEvents.map(async (event) => { - await processAmmEvent(event, signature, transactionResponse); - })); + Promise.all(ammEvents.map(async (event) => { + await processAmmEvent(event, signature, transactionResponse); + })); - Promise.all(vaultEvents.map(async (event) => { - await processVaultEvent(event, signature, transactionResponse); - })); - } + Promise.all(vaultEvents.map(async (event) => { + await processVaultEvent(event, signature, transactionResponse); + })); + } catch (error) { logger.errorWithChatBotAlert([ error instanceof Error diff --git a/packages/indexer/Dockerfile b/packages/old_indexer/Dockerfile similarity index 100% rename from packages/indexer/Dockerfile rename to packages/old_indexer/Dockerfile diff --git a/packages/indexer/package.json b/packages/old_indexer/package.json similarity index 100% rename from packages/indexer/package.json rename to packages/old_indexer/package.json diff --git a/packages/indexer/src/adapters/telegram-bot.ts b/packages/old_indexer/src/adapters/telegram-bot.ts similarity index 100% rename from packages/indexer/src/adapters/telegram-bot.ts rename to packages/old_indexer/src/adapters/telegram-bot.ts diff --git a/packages/old_indexer/src/builders/swaps.ts b/packages/old_indexer/src/builders/swaps.ts new file mode 100644 index 00000000..8981a0bd --- /dev/null +++ b/packages/old_indexer/src/builders/swaps.ts @@ -0,0 +1,428 @@ +import { Context } from "@solana/web3.js"; +import { Err, Ok, Result, TaggedUnion } from "../match"; +import { + AmmInstructionIndexerError, + SwapPersistableError, +} from "../types/errors"; +import { schema, usingDb, eq } from "@metadaoproject/indexer-db"; +import { + OrderSide, + OrdersRecord, + // PricesRecord, + // PricesType, + TakesRecord, + TransactionRecord, +} from "@metadaoproject/indexer-db/lib/schema"; +import { BN } from "@coral-xyz/anchor"; +import { + Instruction, + SERIALIZED_TRANSACTION_LOGIC_VERSION, + Transaction, + getTransaction, + parseFormattedInstructionArgsData, + serialize, +} from "../transaction/serializer"; +import { logger } from "../logger"; +import { getMainIxTypeFromTransaction } from "../transaction/watcher"; +import { getHumanPrice } from "../usecases/math"; + +export class SwapPersistable { + private ordersRecord: OrdersRecord; + private takesRecord: TakesRecord; + private transactionRecord: TransactionRecord; + //private priceRecord: PricesRecord; + constructor( + ordersRecord: OrdersRecord, + takesRecord: TakesRecord, + transactionRecord: TransactionRecord, + //priceRecord: PricesRecord + ) { + this.ordersRecord = ordersRecord; + this.takesRecord = takesRecord; + this.transactionRecord = transactionRecord; + //this.priceRecord = priceRecord; + } + + async persist() { + try { + const upsertResult = + (await usingDb((db) => + db + .insert(schema.transactions) + .values(this.transactionRecord) + .onConflictDoUpdate({ + target: schema.transactions.txSig, + set: this.transactionRecord, + }) + .returning({ txSig: schema.transactions.txSig }) + )) ?? []; + if ( + upsertResult.length !== 1 || + upsertResult[0].txSig !== this.transactionRecord.txSig + ) { + logger.warn( + `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( + this.transactionRecord + )}` + ); + } + // Insert user if they aren't already in the database + const insertUsersResult = (await usingDb((db) => + db + .insert(schema.users) + .values({ userAcct: this.ordersRecord.actorAcct }) + .onConflictDoNothing() + .returning({ userAcct: schema.users.userAcct }) + )) ?? []; + if ( + insertUsersResult.length !== 1 || + insertUsersResult[0].userAcct !== this.ordersRecord.actorAcct + ) { + logger.warn( + `Failed to upsert user ${this.ordersRecord.actorAcct}. ${JSON.stringify( + this.ordersRecord + )}` + ); + if(insertUsersResult.length <= 0) { + logger.warn(`User already exists in db: ${this.ordersRecord.actorAcct}`); + } + } + + // const priceInsertRes = + // (await usingDb((db) => + // db + // .insert(schema.prices) + // .values(this.priceRecord) + // .onConflictDoNothing() + // .returning({ marketAcct: schema.prices.marketAcct, updatedSlot: schema.prices.updatedSlot }) + // )) ?? []; + // if ( + // priceInsertRes.length !== 1 || + // (priceInsertRes[0].marketAcct !== this.priceRecord.marketAcct && + // priceInsertRes[0].updatedSlot !== this.priceRecord.updatedSlot) + // ) { + // logger.warn( + // `Failed to insert price ${this.priceRecord.marketAcct}. ${JSON.stringify( + // this.priceRecord + // )}` + // ); + // } + const orderInsertRes = + (await usingDb((db) => + db + .insert(schema.orders) + .values(this.ordersRecord) + .onConflictDoNothing() + .returning({ txSig: schema.takes.orderTxSig }) + )) ?? []; + if (orderInsertRes.length > 0) { + console.log( + "successfully inserted swap order record", + orderInsertRes[0].txSig + ); + } else { + logger.warn( + `did not save swap order in persister. + ${this.ordersRecord.orderTxSig}` + ); + } + const takeInsertRes = + (await usingDb((db) => + db + .insert(schema.takes) + .values(this.takesRecord) + .onConflictDoNothing() + .returning({ txSig: schema.takes.orderTxSig }) + )) ?? []; + if (takeInsertRes.length > 0) { + logger.log( + `successfully inserted swap take record. + ${takeInsertRes[0].txSig}` + ); + } else { + logger.warn( + `did not save swap take record in persister. + ${this.takesRecord.orderTxSig}` + ); + } + } catch (e) { + logger.errorWithChatBotAlert(`error with persisting swap: ${e}`); + } + } +} + +export class SwapBuilder { + constructor() {} + async withSignatureAndCtx( + signature: string, + ctx: Context + ): Promise> { + try { + // first check to see if swap is already persisted + const swapOrder = + (await usingDb((db) => + db + .select() + .from(schema.orders) + .where(eq(schema.orders.orderTxSig, signature)) + .execute() + )) ?? []; + if (swapOrder.length > 0) { + return Err({ type: SwapPersistableError.AlreadyPersistedSwap }); + } + + const txRes = await getTransaction(signature); + if (!txRes.success) { + return Err({ + type: SwapPersistableError.TransactionParseError, + value: txRes.error, + }); + } + + const tx = txRes.ok; + const swapIx = tx.instructions.find((ix) => ix.name === "swap"); + if (!!swapIx) { + // sometimes we mint cond tokens for the user right before we do the swap ix + const mintIx = tx.instructions?.find( + (i) => i.name === "mintConditionalTokens" + ); + // What if there's more than one? + const mergeIx = tx.instructions?.find((i) => i.name === "mergeConditionalTokensForUnderlyingTokens"); + + if (mergeIx && mintIx) { + console.error("ARB TRANSACTION DETECTED") + return Err({ type: SwapPersistableError.ArbTransactionError }); + } + + const result = await this.buildOrderFromSwapIx(swapIx, tx, mintIx); + if (!result.success) { + return Err(result.error); + } + const { swapOrder, swapTake } = result.ok; + + // TODO: consider co-locating this logic so it can be shared + // TODO doing this twice... also doing this above + + const transactionRecord: TransactionRecord = { + txSig: signature, + slot: ctx.slot.toString(), + blockTime: new Date(tx.blockTime * 1000), // TODO need to verify if this is correct + failed: tx.err !== undefined, + payload: serialize(tx), + serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, + mainIxType: getMainIxTypeFromTransaction(tx), + }; + + // TODO: This needs smore work before it's ready + // const priceRecord: PricesRecord = { + // marketAcct: swapOrder.marketAcct, + // updatedSlot: ctx.slot.toString(), + // createdAt: transactionRecord.blockTime, + // // TODO: This doesn't have base and quote... So could be an issue.. + // price: swapTake.quotePrice, + // pricesType: PricesType.Conditional, + // } + + return Ok(new SwapPersistable(swapOrder, swapTake, transactionRecord)); // priceRecord + } + return Err({ type: SwapPersistableError.NonSwapTransaction }); + } catch (e: any) { + logger.errorWithChatBotAlert( + "swap peristable general error", + e.message + ? { + message: e.message, + stack: e.stack, + name: e.name, + cause: e.cause, + fileName: e.fileName, + lineNumber: e.lineNumber, + } + : e + ); + return Err({ type: SwapPersistableError.GeneralError }); + } + } + + async buildOrderFromSwapIx( + swapIx: Instruction, + tx: Transaction, + mintIx: Instruction | undefined + ): Promise< + Result<{ swapOrder: OrdersRecord; swapTake: TakesRecord }, TaggedUnion> + > { + if (!swapIx) return Err({ type: "missing data" }); + + const marketAcct = swapIx.accountsWithData.find((a) => a.name === "amm"); + if (!marketAcct) return Err({ type: "missing data" }); + const userAcct = swapIx.accountsWithData.find((a) => a.name === "user"); + if (!userAcct) return Err({ type: "missing data" }); + // TODO fix + const userBaseAcct = swapIx.accountsWithData.find( + (a) => a.name === "userBaseAccount" + ); + if (!userBaseAcct) return Err({ type: "missing data" }); + const userQuoteAcct = swapIx.accountsWithData.find( + (a) => a.name === "userQuoteAccount" + ); + if (!userQuoteAcct) return Err({ type: "missing data" }); + + if (!swapIx.args) return Err({ type: "missing data" }); + const swapArgs = swapIx.args.find((a) => a.type === "SwapArgs"); + if (!swapArgs) return Err({ type: "missing swap args" }); + const swapArgsParsed = parseFormattedInstructionArgsData<{ + swapType: string; + inputAmount: number; + outputAmount: number; + }>(swapArgs?.data ?? ""); + + const mintAmount = mintIx + ? mintIx.args.find((a) => a.name === "amount")?.data ?? "0" + : "0"; + // determine side + const side = + swapArgsParsed?.swapType === "Buy" ? OrderSide.BID : OrderSide.ASK; + + // get balances + const userBaseAcctWithBalances = tx.accounts.find( + (a) => a.pubkey === userBaseAcct.pubkey + ); + + const userBasePreBalance = + userBaseAcctWithBalances?.preTokenBalance?.amount ?? BigInt(0); + + const userBasePreBalanceWithPotentialMint = + side === OrderSide.ASK + ? userBasePreBalance +BigInt(Number(mintAmount)) + : userBaseAcctWithBalances?.preTokenBalance?.amount; + + const userBasePostBalance = + userBaseAcctWithBalances?.postTokenBalance?.amount; + + const userQuoteAcctWithBalances = tx.accounts.find( + (a) => a.pubkey === userQuoteAcct.pubkey + ); + + const userQuotePreBalance = + userQuoteAcctWithBalances?.preTokenBalance?.amount ?? BigInt(0); + + const userQuotePreBalanceWithPotentialMint = + side === OrderSide.BID + ? userQuotePreBalance + BigInt(Number(mintAmount)) + : userQuoteAcctWithBalances?.preTokenBalance?.amount; + + const userQuotePostBalance = + userQuoteAcctWithBalances?.postTokenBalance?.amount; + + const baseAmount = new BN( + (userBasePostBalance ?? BigInt(0)) - + (userBasePreBalanceWithPotentialMint ?? BigInt(0)) + ).abs(); + const quoteAmount = new BN( + (userQuotePostBalance ?? BigInt(0)) - + (userQuotePreBalanceWithPotentialMint ?? BigInt(0)) + ).abs(); + + if ( + !!tx.err && + quoteAmount.toString() === "0" && + baseAmount.toString() === "0" + ) { + return Err({ type: AmmInstructionIndexerError.FailedSwap }); + } + + // determine price + // NOTE: This is estimated given the output is a min expected value + // default is input / output (buying a token with USDC or whatever) + const marketAcctRecord = + (await usingDb((db) => + db + .select() + .from(schema.markets) + .where(eq(schema.markets.marketAcct, marketAcct.pubkey)) + .execute() + )) ?? []; + if (marketAcctRecord.length === 0) { + return Err({ type: AmmInstructionIndexerError.MissingMarket }); + } + const baseToken = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, marketAcctRecord[0].baseMintAcct)) + .execute() + )) ?? []; + if (baseToken.length === 0) { + return Err({ type: AmmInstructionIndexerError.MissingMarket }); + } + const quoteToken = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.mintAcct, marketAcctRecord[0].quoteMintAcct)) + .limit(1) + .execute() + )) ?? []; + if (baseToken.length === 0) { + return Err({ type: AmmInstructionIndexerError.MissingMarket }); + } + + let price: number | null = null; + + if (quoteAmount.toString() && baseAmount.toString()) { + console.log(quoteAmount.toString(), baseAmount.toString()); + try{ + const ammPrice = quoteAmount.mul(new BN(10).pow(new BN(12))).div(baseAmount) + + price = getHumanPrice( + ammPrice, + baseToken[0].decimals, + quoteToken[0].decimals + ); + } catch (e) { + logger.error("error getting price", e); + return Err({ type: SwapPersistableError.GeneralError }); + } + } + // TODO: Need to likely handle rounding..... + // index a swap here + + const signature = tx.signatures[0]; + const now = new Date(); + + const swapOrder: OrdersRecord = { + marketAcct: marketAcct.pubkey, + orderBlock: tx.slot.toString(), + orderTime: now, + orderTxSig: signature, + quotePrice: price?.toString() ?? "0", + actorAcct: userAcct.pubkey, + // TODO: If and only if the transaction is SUCCESSFUL does this value equal this.. + filledBaseAmount: baseAmount.toString(), + isActive: false, + side: side, + // TODO: If transaction is failed then this is the output amount... + unfilledBaseAmount: "0", + updatedAt: now, + }; + + const swapTake: TakesRecord = { + marketAcct: marketAcct.pubkey, + // This will always be the DAO / proposal base token, so while it may be NICE to have a key + // to use to reference on data aggregate, it's not directly necessary. + baseAmount: baseAmount.toString(), // NOTE: This is always the base token given we have a BASE / QUOTE relationship + orderBlock: tx.slot.toString(), + orderTime: now, + orderTxSig: signature, + quotePrice: price?.toString() ?? "0", + // TODO: this is coded into the market, in the case of our AMM, it's 1% + // this fee is based on the INPUT value (so if we're buying its USDC, selling its TOKEN) + takerBaseFee: BigInt(0), + takerQuoteFee: BigInt(0), + }; + + return Ok({ swapOrder, swapTake }); + } +} diff --git a/packages/indexer/src/cli/index.ts b/packages/old_indexer/src/cli/index.ts similarity index 100% rename from packages/indexer/src/cli/index.ts rename to packages/old_indexer/src/cli/index.ts diff --git a/packages/indexer/src/cli/txw/common/select-account.ts b/packages/old_indexer/src/cli/txw/common/select-account.ts similarity index 100% rename from packages/indexer/src/cli/txw/common/select-account.ts rename to packages/old_indexer/src/cli/txw/common/select-account.ts diff --git a/packages/indexer/src/cli/txw/create.ts b/packages/old_indexer/src/cli/txw/create.ts similarity index 100% rename from packages/indexer/src/cli/txw/create.ts rename to packages/old_indexer/src/cli/txw/create.ts diff --git a/packages/indexer/src/cli/txw/index.ts b/packages/old_indexer/src/cli/txw/index.ts similarity index 100% rename from packages/indexer/src/cli/txw/index.ts rename to packages/old_indexer/src/cli/txw/index.ts diff --git a/packages/indexer/src/cli/txw/populate.ts b/packages/old_indexer/src/cli/txw/populate.ts similarity index 100% rename from packages/indexer/src/cli/txw/populate.ts rename to packages/old_indexer/src/cli/txw/populate.ts diff --git a/packages/indexer/src/cli/txw/reset.ts b/packages/old_indexer/src/cli/txw/reset.ts similarity index 100% rename from packages/indexer/src/cli/txw/reset.ts rename to packages/old_indexer/src/cli/txw/reset.ts diff --git a/packages/indexer/src/cli/txw/validate.ts b/packages/old_indexer/src/cli/txw/validate.ts similarity index 100% rename from packages/indexer/src/cli/txw/validate.ts rename to packages/old_indexer/src/cli/txw/validate.ts diff --git a/packages/old_indexer/src/connection.ts b/packages/old_indexer/src/connection.ts new file mode 100644 index 00000000..47e2bd76 --- /dev/null +++ b/packages/old_indexer/src/connection.ts @@ -0,0 +1,30 @@ +import { Connection } from "@solana/web3.js"; +import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { + FutarchyRPCClient, + FutarchyIndexerClient, +} from "@metadaoproject/futarchy-sdk"; +import { ConditionalVaultClient } from "@metadaoproject/futarchy/v0.3"; + +export const RPC_ENDPOINT = process.env.RPC_ENDPOINT ?? ""; +export const INDEXER_URL = process.env.INDEXER_URL ?? ""; +export const INDEXER_WSS_URL = process.env.INDEXER_WSS_URL ?? ""; +export const connection: Connection = new Connection(RPC_ENDPOINT, "confirmed"); +// the indexer will only be reading, not writing +export const readonlyWallet: Wallet = undefined as unknown as Wallet; +export const provider = new AnchorProvider(connection, readonlyWallet, { + commitment: "confirmed", +}); + +export const rpcReadClient = FutarchyRPCClient.make(provider, undefined); + +export const indexerReadClient = FutarchyIndexerClient.make( + rpcReadClient, + INDEXER_URL, + INDEXER_WSS_URL, + "" +); + +export const conditionalVaultClient = ConditionalVaultClient.createClient({ + provider, +}); diff --git a/packages/old_indexer/src/constants.ts b/packages/old_indexer/src/constants.ts new file mode 100644 index 00000000..ad5bc692 --- /dev/null +++ b/packages/old_indexer/src/constants.ts @@ -0,0 +1,21 @@ +import { Idl } from "@coral-xyz/anchor"; +import { + AMM_PROGRAM_ID, + AUTOCRAT_PROGRAM_ID, + AmmIDL, + AutocratIDL, + CONDITIONAL_VAULT_PROGRAM_ID, + ConditionalVaultIDL, +} from "@metadaoproject/futarchy/v0.3"; + +export const SLOTS_TO_DAYS: Record = { + "648000": 3, + "2160000": 10, + "1080000": 5, +}; + +export const PROGRAM_ID_TO_IDL_MAP: Record = { + [AMM_PROGRAM_ID.toBase58()]: AmmIDL as Idl, + [AUTOCRAT_PROGRAM_ID.toBase58()]: AutocratIDL as Idl, + [CONDITIONAL_VAULT_PROGRAM_ID.toBase58()]: ConditionalVaultIDL as Idl, +}; diff --git a/packages/indexer/src/endpoints/get-metrics.ts b/packages/old_indexer/src/endpoints/get-metrics.ts similarity index 100% rename from packages/indexer/src/endpoints/get-metrics.ts rename to packages/old_indexer/src/endpoints/get-metrics.ts diff --git a/packages/indexer/src/index.ts b/packages/old_indexer/src/index.ts similarity index 100% rename from packages/indexer/src/index.ts rename to packages/old_indexer/src/index.ts diff --git a/packages/old_indexer/src/indexers/account-info-indexer.ts b/packages/old_indexer/src/indexers/account-info-indexer.ts new file mode 100644 index 00000000..29f127e6 --- /dev/null +++ b/packages/old_indexer/src/indexers/account-info-indexer.ts @@ -0,0 +1,16 @@ +import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; +import { Result, TaggedUnion } from "../match"; +export type AccountInfoIndexer = { + index( + accountInfo: AccountInfo, + account: PublicKey, + context: Context + ): Promise< + Result< + { + acct: string; + }, + TaggedUnion + > + >; +}; diff --git a/packages/old_indexer/src/indexers/account-logs-indexer.ts b/packages/old_indexer/src/indexers/account-logs-indexer.ts new file mode 100644 index 00000000..fcc2950f --- /dev/null +++ b/packages/old_indexer/src/indexers/account-logs-indexer.ts @@ -0,0 +1,16 @@ +import { Context, Logs, PublicKey } from "@solana/web3.js"; +import { Result, TaggedUnion } from "../match"; +export type AccountLogsIndexer = { + index( + logs: Logs, + account: PublicKey, + context: Context + ): Promise< + Result< + { + acct: string; + }, + TaggedUnion + > + >; +}; diff --git a/packages/indexer/src/indexers/amm-market/amm-market-account-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/amm-market/amm-market-account-indexer.ts rename to packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts diff --git a/packages/indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts rename to packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts diff --git a/packages/indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts rename to packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts diff --git a/packages/indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts rename to packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts diff --git a/packages/indexer/src/indexers/amm-market/utils.ts b/packages/old_indexer/src/indexers/amm-market/utils.ts similarity index 100% rename from packages/indexer/src/indexers/amm-market/utils.ts rename to packages/old_indexer/src/indexers/amm-market/utils.ts diff --git a/packages/indexer/src/indexers/autocrat/autocrat-dao-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/autocrat/autocrat-dao-indexer.ts rename to packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts diff --git a/packages/indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts rename to packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts diff --git a/packages/indexer/src/indexers/autocrat/autocrat-v0-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/autocrat/autocrat-v0-indexer.ts rename to packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts diff --git a/packages/indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts rename to packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts diff --git a/packages/indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts rename to packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts diff --git a/packages/indexer/src/indexers/birdeye/birdeye-prices-indexer.ts b/packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/birdeye/birdeye-prices-indexer.ts rename to packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts diff --git a/packages/old_indexer/src/indexers/common.ts b/packages/old_indexer/src/indexers/common.ts new file mode 100644 index 00000000..4462a0dc --- /dev/null +++ b/packages/old_indexer/src/indexers/common.ts @@ -0,0 +1,12 @@ +import { SolanaParser } from "@debridge-finance/solana-transaction-parser"; +import { AmmClient, AMM_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { provider } from "../connection"; + +export const ammClient = new AmmClient(provider, AMM_PROGRAM_ID, []); +export type IDL = typeof ammClient.program.idl; +export const ammParser = new SolanaParser([ + { + idl: ammClient.program.idl, + programId: AMM_PROGRAM_ID, + }, +]); diff --git a/packages/indexer/src/indexers/index.ts b/packages/old_indexer/src/indexers/index.ts similarity index 100% rename from packages/indexer/src/indexers/index.ts rename to packages/old_indexer/src/indexers/index.ts diff --git a/packages/old_indexer/src/indexers/instruction-indexer.ts b/packages/old_indexer/src/indexers/instruction-indexer.ts new file mode 100644 index 00000000..39d5ea8a --- /dev/null +++ b/packages/old_indexer/src/indexers/instruction-indexer.ts @@ -0,0 +1,44 @@ +import { VersionedTransactionResponse } from "@solana/web3.js"; +import { Idl } from "@coral-xyz/anchor"; +import { Result, TaggedUnion } from "../match"; +import { IDL } from "./common"; + +export const Ok = { indexed: true }; +export const Err = { indexed: false }; + +type InstructionIDL = Idl | IDL; + +export type InstructionIndexer = { + readonly PROGRAM_NAME: string; + readonly PROGRAM_ID: string; + readonly PROGRAM_IDL: IDL; + + indexInstruction( + transactionIndex: number, + transactionResponse: VersionedTransactionResponse, + instructionIndex: number, + decodedInstruction?: IDL["instructions"][number] + ): Promise< + Result< + { + txSig: string; + }, + TaggedUnion + > + >; + indexTransactionSig(transaction: { + txSig: string; + slot: string; + blockTime: Date; + failed: boolean; + payload: string; + serializerLogicVersion: number; + }): Promise< + Result< + { + txSig: string; + }, + TaggedUnion + > + >; +}; diff --git a/packages/old_indexer/src/indexers/interval-fetch-indexer.ts b/packages/old_indexer/src/indexers/interval-fetch-indexer.ts new file mode 100644 index 00000000..ce983ffc --- /dev/null +++ b/packages/old_indexer/src/indexers/interval-fetch-indexer.ts @@ -0,0 +1,13 @@ +import { Result, TaggedUnion } from "../match"; +export type IntervalFetchIndexer = { + cronExpression: string; + retries?: number; + index(acct: string): Promise< + Result< + { + acct: string; + }, + TaggedUnion + > + >; +}; diff --git a/packages/indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts b/packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts rename to packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts b/packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/openbook-twap/openbook-twap-instruction-indexer.ts rename to packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts diff --git a/packages/indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts b/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts rename to packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts b/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/openbook-v2/openbook-v2-indexer.ts rename to packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts diff --git a/packages/indexer/src/indexers/start-account-info-indexers.ts b/packages/old_indexer/src/indexers/start-account-info-indexers.ts similarity index 100% rename from packages/indexer/src/indexers/start-account-info-indexers.ts rename to packages/old_indexer/src/indexers/start-account-info-indexers.ts diff --git a/packages/indexer/src/indexers/start-interval-fetch-indexers.ts b/packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts similarity index 100% rename from packages/indexer/src/indexers/start-interval-fetch-indexers.ts rename to packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts diff --git a/packages/indexer/src/indexers/start-logs-subscribe-indexer.ts b/packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/start-logs-subscribe-indexer.ts rename to packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts diff --git a/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts b/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts new file mode 100644 index 00000000..55a45df4 --- /dev/null +++ b/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts @@ -0,0 +1,156 @@ +import { + IndexerImplementation, + IndexerRecord, + TransactionRecord, + TransactionWatcherTransactionRecord, +} from "@metadaoproject/indexer-db/lib/schema"; + +import { IndexerWithAccountDeps } from "../types"; +import { AmmMarketInstructionsIndexer } from "./amm-market/amm-market-instruction-indexer"; +import { InstructionIndexer } from "./instruction-indexer"; +import { Idl } from "@coral-xyz/anchor"; +import { schema, usingDb, eq, and, gte } from "@metadaoproject/indexer-db"; +import * as fastq from "fastq"; +import type { queueAsPromised } from "fastq"; + +// it is stored as base58 but the + +export async function startTransactionHistoryIndexer( + indexerQueryRes: IndexerWithAccountDeps +) { + const { indexers: indexer, indexer_account_dependencies: dependentAccount } = + indexerQueryRes; + if (!indexer) return; + const implementation = getTransactionHistoryImplementation( + indexer.implementation + ); + if (implementation && dependentAccount && dependentAccount.acct) { + // query for all transactions for this acct with slots higher than this indexer + const transactions = + (await usingDb((db) => { + return db + .select() + .from(schema.transactions) + .fullJoin( + schema.transactionWatcherTransactions, + eq( + schema.transactionWatcherTransactions.txSig, + schema.transactions.txSig + ) + ) + .where( + and( + eq( + schema.transactionWatcherTransactions.watcherAcct, + dependentAccount.acct + ), + gte(schema.transactions.slot, indexer.latestSlotProcessed) + ) + ) + .execute(); + })) ?? []; + + await indexExistingTxs(transactions, implementation, indexer); + } +} + +async function indexExistingTxs( + transactions: { + transactions: TransactionRecord | null; + transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; + }[], + implementation: InstructionIndexer, + indexer: IndexerRecord +) { + for (const tx of transactions) { + if (tx.transactions?.txSig) { + const res = await implementation.indexTransactionSig(tx.transactions); + if (res.success) { + // update latest slot for indexer + const updateResult = + (await usingDb((db) => + db + .update(schema.indexers) + .set({ + latestSlotProcessed: tx.transactions?.slot, + }) + .where(eq(schema.indexers.name, indexer.name)) + .returning({ + latestSlotProcessed: schema.indexers.latestSlotProcessed, + }) + )) ?? []; + if (updateResult.length > 0) { + console.log( + `successfully updated indexer "${indexer.name}" to slot ${updateResult[0].latestSlotProcessed}` + ); + } + } + } + } +} + +export const newTxQueue: queueAsPromised<{ + transactions: TransactionRecord | null; + transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; +}> = fastq.promise(handleNewTxs, 1); + +async function handleNewTxs(msg: { + transactions: TransactionRecord | null; + transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; +}) { + const { transactions: tx, transaction_watcher_transactions: watcherTx } = msg; + // query for the any indexer account dependencies based on the watcher acct, and then query for the indexer implementation based on that, then you are up and running + const indexerQueryRes = + (await usingDb((db) => { + return db + .select() + .from(schema.indexerAccountDependencies) + .fullJoin( + schema.indexers, + eq(schema.indexers.name, schema.indexerAccountDependencies.name) + ) + .where( + eq( + schema.indexerAccountDependencies.acct, + watcherTx?.watcherAcct ?? "" + ) + ) + .execute(); + })) ?? []; + if (indexerQueryRes.length === 0) { + console.log( + "skipping processing new tx, no indexer query result. Tx Sig:", + tx?.txSig + ); + return; + } + const { indexers: indexer } = indexerQueryRes[0]; + if (!indexer) { + console.log( + "skipping processing new tx, no indexer tied to query result. Tx Sig:", + tx?.txSig + ); + return; + } + const implementation = getTransactionHistoryImplementation( + indexer.implementation + ); + if (!implementation) { + console.log( + "skipping processing new tx, no implementation found. Tx Sig:", + tx?.txSig + ); + return; + } + indexExistingTxs([msg], implementation, indexer); +} + +export function getTransactionHistoryImplementation( + implementation: IndexerImplementation +): InstructionIndexer | null { + switch (implementation) { + case IndexerImplementation.AmmMarketInstructionsIndexer: + return AmmMarketInstructionsIndexer; + } + return null; +} diff --git a/packages/indexer/src/indexers/token/token-mint-indexer.ts b/packages/old_indexer/src/indexers/token/token-mint-indexer.ts similarity index 100% rename from packages/indexer/src/indexers/token/token-mint-indexer.ts rename to packages/old_indexer/src/indexers/token/token-mint-indexer.ts diff --git a/packages/old_indexer/src/instruction-dispatch.ts b/packages/old_indexer/src/instruction-dispatch.ts new file mode 100644 index 00000000..1821f3c9 --- /dev/null +++ b/packages/old_indexer/src/instruction-dispatch.ts @@ -0,0 +1,220 @@ +import { connection } from "./connection"; +import { InstructionIndexer } from "./indexers/instruction-indexer"; +import { BorshCoder } from "@coral-xyz/anchor"; +import { OpenbookTwapIndexer } from "./indexers/openbook-twap/openbook-twap-instruction-indexer"; +import { OpenbookV2Indexer } from "./indexers/openbook-v2/openbook-v2-indexer"; +import { AutocratV0Indexer } from "./indexers/autocrat/autocrat-v0-indexer"; +import { AutocratV0_1Indexer } from "./indexers/autocrat/autocrat-v0_1-indexer"; +import { red, yellow } from "ansicolor"; +import { + AddressLookupTableAccount, + Message, + MessageAccountKeys, +} from "@solana/web3.js"; + +export type IndexTransactionResult = + | { indexed: true } + | { indexed: false; error: { type: E; details: ErrorDetails[E] } }; + +export enum IndexTransactionError { + NoTxReturned = "NoTxReturned", + NoKnownProgram = "NoKnownProgram", + MoreSignaturesThanExpected = "MoreSignaturesThanExpected", + WrongSignature = "WrongSignature", + FailedToIndexInstruction = "FailedToIndexInstruction", + InvalidVersion = "InvalidVersion", + VersionLookupTableMismatch = "VersionLookupTableMismatch", + InvalidLookupTable = "InvalidLookupTable", +} + +export type MessageAddressTableLookup = Message["addressTableLookups"][0]; + +export type ErrorDetails = { + [IndexTransactionError.NoTxReturned]: undefined; + [IndexTransactionError.NoKnownProgram]: { programs: string[] }; + [IndexTransactionError.MoreSignaturesThanExpected]: { signatures: string[] }; + [IndexTransactionError.WrongSignature]: { signature: string }; + [IndexTransactionError.FailedToIndexInstruction]: undefined; + [IndexTransactionError.InvalidVersion]: { version: any }; + [IndexTransactionError.VersionLookupTableMismatch]: { + version: any; + addressTableLookups: MessageAddressTableLookup[]; + }; + [IndexTransactionError.InvalidLookupTable]: { accountKey: string }; +}; + +const indexers: InstructionIndexer[] = [ + AutocratV0Indexer, + AutocratV0_1Indexer, + OpenbookTwapIndexer, + OpenbookV2Indexer, +]; + +enum TransactionVersionType { + Legacy = "Legacy", + V0 = "V0", +} + +const programToIndexer: Record< + string, + { indexer: InstructionIndexer; coder: BorshCoder } +> = Object.fromEntries( + indexers.map((indexer) => [ + indexer.PROGRAM_ID, + { indexer, coder: new BorshCoder(indexer.PROGRAM_IDL) }, + ]) +); + +function error( + e: E, + details: ErrorDetails[E] +): IndexTransactionResult { + return { indexed: false, error: { type: e, details } }; +} + +const ok = { indexed: true } as const; + +export async function indexTransaction( + txIdx: number, + signature: string +): Promise> { + const tx = await connection.getTransaction(signature, { + maxSupportedTransactionVersion: 0, + }); + + if (tx == null || tx === undefined) { + return error(IndexTransactionError.NoTxReturned, undefined); + } + + if (tx.meta?.err) { + // TODO: mark tx as processed + return ok; + } + + const { transaction } = tx; + const { signatures } = transaction; + + let txVersion: TransactionVersionType; + let accountKeys: MessageAccountKeys; + switch (tx.version) { + case "legacy": + txVersion = TransactionVersionType.Legacy; + if (transaction.message.addressTableLookups.length > 0) { + return error(IndexTransactionError.VersionLookupTableMismatch, { + version: txVersion, + addressTableLookups: transaction.message.addressTableLookups, + }); + } + accountKeys = transaction.message.getAccountKeys(); + break; + case 0: + txVersion = TransactionVersionType.V0; + if (transaction.message.addressTableLookups.length === 0) { + return error(IndexTransactionError.VersionLookupTableMismatch, { + version: txVersion, + addressTableLookups: transaction.message.addressTableLookups, + }); + } + // https://solana.stackexchange.com/questions/8652/how-do-i-parse-the-accounts-in-a-versioned-transaction + const lookupTables: AddressLookupTableAccount[] = []; + for (const { accountKey } of transaction.message.addressTableLookups) { + const lookupTable = await connection.getAddressLookupTable(accountKey); + if (lookupTable === null) { + console.log("no response from getAddressLookupTable"); + return error(IndexTransactionError.InvalidLookupTable, { + accountKey: accountKey.toBase58(), + }); + } + if (lookupTable.value === null) { + console.log("null lookup table value"); + return error(IndexTransactionError.InvalidLookupTable, { + accountKey: accountKey.toBase58(), + }); + } + lookupTables.push(lookupTable.value); + } + accountKeys = transaction.message.getAccountKeys({ + addressLookupTableAccounts: lookupTables, + }); + break; + default: + return error(IndexTransactionError.InvalidVersion, { + version: tx.version, + }); + } + + // console.log('indexing', signature, tx.version, tx.transaction.message.addressTableLookups.length); + + // TODO: maybe do something with inner instructions + // tx.meta?.innerInstructions + // console.log(JSON.stringify(tx)); + + /* + first tx has 5 signatures. Need to investigate whether all show up in the getSignaturesForAccount response. + We don't want to process the same tx multiple times. + if (signatures.length > 1) { + return error(IndexTransactionError.MoreSignaturesThanExpected, {signatures: tx.transaction.signatures}) + } + */ + + const txSig = signatures[0]; + if (txSig !== signature) { + return error(IndexTransactionError.WrongSignature, { signature: txSig }); + } + + //const accountKeys = transaction.message.getAccountKeys({a}); + const instructions = transaction.message.compiledInstructions; + const programs: string[] = []; + let matchingProgramFound = false; + const timeStr = new Date(tx.blockTime! * 1000) + .toISOString() + .replace("T", " ") + .replace(".000Z", ""); + for (let i = 0; i < instructions.length; ++i) { + const ix = instructions[i]; + const program = accountKeys.staticAccountKeys[ix.programIdIndex].toBase58(); + programs.push(program); + if (program in programToIndexer) { + matchingProgramFound = true; + const { indexer, coder } = programToIndexer[program]; + const ixIdx = i; + const prefix = `[${timeStr}][slot ${tx.slot}][${indexer.PROGRAM_NAME}] ${txIdx}.${ixIdx}.`; + const secondLogMessage = (tx.meta?.logMessages ?? [])[1]; + switch (secondLogMessage) { + case "Program log: Instruction: IdlCreateAccount": + console.log( + yellow(`${prefix} skipping IdlCreateAccount ${signature}`) + ); + continue; + case "Program log: Instruction: IdlWrite": + console.log(yellow(`${prefix} skipping IdlWrite ${signature}`)); + continue; + } + const decoded = coder.instruction.decode(Buffer.from(ix.data)); + if (decoded == null) { + console.log( + `${prefix} Cannot decode instruction ${i} of transaction ${signature}` + ); + console.log(tx.meta?.logMessages); + continue; + } + let ixLine = `${prefix} ${decoded.name} ${signature}`; + console.log(ixLine); + const result = await indexer.indexInstruction( + {} as any, // TODO: initialize db transaction and pass here + txIdx, + tx, + ixIdx, + decoded + ); + if (!result.indexed) { + return error(IndexTransactionError.FailedToIndexInstruction, undefined); + } + } + } + if (!matchingProgramFound) { + return error(IndexTransactionError.NoKnownProgram, { programs }); + } + + return ok; +} diff --git a/packages/indexer/src/local-cache.ts b/packages/old_indexer/src/local-cache.ts similarity index 100% rename from packages/indexer/src/local-cache.ts rename to packages/old_indexer/src/local-cache.ts diff --git a/packages/indexer/src/logger.ts b/packages/old_indexer/src/logger.ts similarity index 100% rename from packages/indexer/src/logger.ts rename to packages/old_indexer/src/logger.ts diff --git a/packages/old_indexer/src/match.ts b/packages/old_indexer/src/match.ts new file mode 100644 index 00000000..f4bc4fb5 --- /dev/null +++ b/packages/old_indexer/src/match.ts @@ -0,0 +1,19 @@ +/** + * The constructs here allow us to mimic Rust's strongly typed error handling + */ +export type TaggedUnion = { + type: string; + value?: any; +}; + +export type Result = + | { success: true; ok: Ok } + | { success: false; error: Err }; + +export function Err(error: Err): Result { + return { success: false, error }; +} + +export function Ok(ok: Ok): Result { + return { success: true, ok }; +} diff --git a/packages/old_indexer/src/proposal-indexer.ts b/packages/old_indexer/src/proposal-indexer.ts new file mode 100644 index 00000000..ffb4a590 --- /dev/null +++ b/packages/old_indexer/src/proposal-indexer.ts @@ -0,0 +1,46 @@ +import { AUTOCRAT_VERSIONS, OPENBOOK_PROGRAM_ID } from '@metadaoproject/futarchy-sdk/lib/constants'; +import { AutocratProgram, DaoState, ProgramVersion, Proposal } from '@metadaoproject/futarchy-sdk/lib/types'; +import { AccountMeta, PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'; +import { OpenbookV2, IDL as OPENBOOK_IDL } from '@openbook-dex/openbook-v2'; +import { Program, utils } from '@coral-xyz/anchor'; +import { connection, provider } from './connection'; +import { ProposalOutcome, MarketType } from '@metadaoproject/indexer-db/lib/schema'; + +const SUPPORTED_AUTOCRAT_VERSIONS = ['V0.1', 'V0']; + +// TODO: send this to monitoring +function emitErrorMetric(msg: String) { + console.log(msg); +} + +async function getDAOProposals({label, programId, idl}: ProgramVersion) { + //console.log(`fetching ${label} proposals`); + + if (!SUPPORTED_AUTOCRAT_VERSIONS.includes(label)) { + // TODO: Emit error metric + emitErrorMetric(`Unable to parse proposals with label ${label}`); + return []; + } + + // const dao = PublicKey.findProgramAddressSync( + // [utils.bytes.utf8.encode('WWCACOTMICMIBMHAFTTWYGHMB')], + // programId, + // )[0]; + + // const daoTreasury = PublicKey.findProgramAddressSync([dao.toBuffer()], programId)[0]; + + const autocratProgram = new Program(idl as AutocratProgram, programId, provider); + + // const openbook = new Program(OPENBOOK_IDL, OPENBOOK_PROGRAM_ID, provider); + + // const daoState = await autocratProgram.account.dao.fetch(dao); + + const proposals = (await autocratProgram.account.proposal.all()) + .sort((a, b) => b.account.number - a.account.number) // descending order + + return proposals; +} + +export async function getProposals() { + return (await Promise.all(AUTOCRAT_VERSIONS.map(getDAOProposals))).flat(); +} diff --git a/packages/indexer/src/server.ts b/packages/old_indexer/src/server.ts similarity index 100% rename from packages/indexer/src/server.ts rename to packages/old_indexer/src/server.ts diff --git a/packages/old_indexer/src/transaction/account-resolver.ts b/packages/old_indexer/src/transaction/account-resolver.ts new file mode 100644 index 00000000..0c1871a2 --- /dev/null +++ b/packages/old_indexer/src/transaction/account-resolver.ts @@ -0,0 +1,55 @@ +import { Result, Ok, Err } from '../match'; +import { VersionedTransactionResponse, AddressLookupTableAccount, MessageAccountKeys, MessageAddressTableLookup, RpcResponseAndContext, PublicKey } from "@solana/web3.js"; +import { connection } from '../connection'; + +export enum ResolveAccountsErrorType { + AddressTableLookupsInLegacy = 'AddressTableLookupsInLegacy', + MissingLookupTableResponse = 'MissingLookupTableResponse', + UnsupportedTransactionVersion = 'UnsupportedTransactionVersion' +} + +export type ResolveAccountsError = + { + type: ResolveAccountsErrorType.AddressTableLookupsInLegacy; + lookups: MessageAddressTableLookup[]; + } | + { + type: ResolveAccountsErrorType.MissingLookupTableResponse; + response: RpcResponseAndContext; + accountKey: PublicKey; + } | + { + type: ResolveAccountsErrorType.UnsupportedTransactionVersion; + version: any; + }; + +export async function resolveAccounts({transaction, version}: VersionedTransactionResponse): Promise> { + let accountKeys: MessageAccountKeys; + switch (version) { + case 'legacy': + if (transaction.message.addressTableLookups.length > 0) { + return Err({type: ResolveAccountsErrorType.AddressTableLookupsInLegacy, lookups: transaction.message.addressTableLookups}); + } + accountKeys = transaction.message.getAccountKeys(); + break; + case 0: + // https://solana.stackexchange.com/questions/8652/how-do-i-parse-the-accounts-in-a-versioned-transaction + const lookupTables: AddressLookupTableAccount[] = []; + for (const {accountKey} of transaction.message.addressTableLookups) { + const lookupTable = await connection.getAddressLookupTable(accountKey); + if (!lookupTable?.value) { + return Err({ + type: ResolveAccountsErrorType.MissingLookupTableResponse, + response: lookupTable, + accountKey + }); + } + lookupTables.push(lookupTable.value); + } + accountKeys = transaction.message.getAccountKeys({addressLookupTableAccounts: lookupTables}); + break; + default: + return Err({type: ResolveAccountsErrorType.UnsupportedTransactionVersion, version}); + } + return Ok(accountKeys); +} diff --git a/packages/old_indexer/src/transaction/history.ts b/packages/old_indexer/src/transaction/history.ts new file mode 100644 index 00000000..9a54da42 --- /dev/null +++ b/packages/old_indexer/src/transaction/history.ts @@ -0,0 +1,108 @@ +import { connection } from "../connection"; +import { PublicKey } from "@solana/web3.js"; +import { logger } from "../logger"; + +export type TransactionMeta = Awaited< + ReturnType<(typeof connection)["getSignaturesForAddress"]> +>[number]; + +function throwInvariantViolation( + account: PublicKey, + after: string | undefined, + before: string | undefined, + violation: string +) { + const error = new Error( + `Invariant violated. account ${account.toBase58()}, after ${after}, before ${before}: ${violation}` + ); + logger.errorWithChatBotAlert(error.message); + throw error; +} + +export async function getTransactionHistory( + account: PublicKey, + largerThanSlot: string, + range?: { after?: string; before?: string } +): Promise { + const { after, before } = range ?? {}; + + const history: TransactionMeta[] = []; + + let earliestSig: string | undefined = before; + + let page = 1; + while (true) { + // The Solana RPC tx API has us do a backwards walk + const transactions = await connection.getSignaturesForAddress( + account, + { before: earliestSig }, + "confirmed" + ); + if (transactions.length === 0) { + break; + } + const sigToIndex = new Map(); + let reachedAfter = false; + for (let i = 0; i < transactions.length; ++i) { + const cur = transactions[i]; + const prev = transactions[i - 1]; + if (sigToIndex.has(cur.signature)) { + throwInvariantViolation( + account, + after, + before, + `duplicate signature ${cur.signature} at indices ${sigToIndex.get( + cur.signature + )} and ${i}` + ); + } + if (prev !== undefined && cur.slot > prev.slot) { + // Transactions are assumed to be in time descending order. + throwInvariantViolation( + account, + after, + before, + `index ${i - 1} signature ${prev.signature} has slot ${ + prev.slot + } while index ${i} signature ${cur.signature} has slot ${cur.slot}` + ); + } + if (cur.signature === after) { + reachedAfter = true; + break; + } + // this causes unnecessary loss of txs being indexed, + // and if we have an indexer who STRICTLY needs everything in order, then we should create a config field + // on the indexers table that specifies this as being needed or not needed + // if (cur.slot < largerThanSlot) { + // throwInvariantViolation( + // account, + // after, + // before, + // `index ${i} signature ${cur.signature} has slot ${cur.slot} which is less than min slot ${largerThanSlot}` + // ); + // } + history.push(cur); + earliestSig = cur.signature; + } + if (earliestSig && sigToIndex.has(earliestSig)) { + throwInvariantViolation( + account, + after, + before, + `account contained before value of ${earliestSig}` + ); + } + logger.log( + `page ${page} for ${account.toBase58()} (${history.length} total)` + ); + page++; + if (reachedAfter) { + break; + } + } + + history.reverse(); // Now earliest transaction comes first. + + return history; +} diff --git a/packages/old_indexer/src/transaction/serializer.test.ts b/packages/old_indexer/src/transaction/serializer.test.ts new file mode 100644 index 00000000..034eb859 --- /dev/null +++ b/packages/old_indexer/src/transaction/serializer.test.ts @@ -0,0 +1,40 @@ +import { serialize, deserialize, Transaction } from "./serializer"; +import { expect, describe, test } from "bun:test"; + +describe("serializer", async () => { + test("serialize-deserialize", async () => { + const testTx: Transaction = { + blockTime: 0, + slot: 0, + recentBlockhash: "", + computeUnitsConsumed: BigInt(4), + fee: BigInt(2), + signatures: [], + version: "legacy", + logMessages: [], + accounts: [ + { + pubkey: "BIGINT:a300n", // false flag + isSigner: true, + isWriteable: false, + preBalance: BigInt(800), + postBalance: BigInt(3000000), + }, + ], + instructions: [], + }; + + const str = serialize(testTx); + + expect(str).toBe( + `{"blockTime":0,"slot":0,"recentBlockhash":"",` + + `"computeUnitsConsumed":"BIGINT:4","fee":"BIGINT:2","signatures":[],"version":"legacy","logMessages":[],` + + `"accounts":[{"pubkey":"BIGINT:a300n","isSigner":true,"isWriteable":false,"preBalance":"BIGINT:800","postBalance":"BIGINT:3000000"}],` + + `"instructions":[]}` + ); + + const deserialized = deserialize(str) as any; + + expect(deserialized).toEqual({ success: true, ok: testTx }); + }); +}); diff --git a/packages/old_indexer/src/transaction/serializer.ts b/packages/old_indexer/src/transaction/serializer.ts new file mode 100644 index 00000000..06e68da9 --- /dev/null +++ b/packages/old_indexer/src/transaction/serializer.ts @@ -0,0 +1,907 @@ +import { + AccountMeta, + CompiledInstruction, + ConfirmedTransactionMeta, + Message, + MessageAccountKeys, + PublicKey, + VersionedTransactionResponse, +} from "@solana/web3.js"; +import { Ok, Err, Result } from "../match"; +import { z } from "zod"; +import { resolveAccounts, ResolveAccountsError } from "./account-resolver"; +import * as base58 from "bs58"; +import { connection, provider } from "../connection"; +import { BorshInstructionCoder, Idl, Program } from "@coral-xyz/anchor"; +import { PROGRAM_ID_TO_IDL_MAP } from "../constants"; +import { + InstructionDisplay, + Instruction as AnchorInstruction, +} from "@coral-xyz/anchor/dist/cjs/coder/borsh/instruction"; +import { logger } from "../logger"; + +/** + * This version should be bumped every time we update this file. + * It will reset all the transaction watchers to slot 0 + * TODO: it should also create new indexers + */ +export const SERIALIZED_TRANSACTION_LOGIC_VERSION = 0; + +// bigint isn't JSON serializable +// https://github.com/GoogleChromeLabs/jsbi/issues/30#issuecomment-1006088574 +export function serialize(transaction: Transaction, pretty = false): string { + return JSON.stringify( + transaction, + (_, value) => + typeof value === "bigint" ? `BIGINT:${value.toString()}` : value, + pretty ? 2 : 0 + ); +} + +const bigintEncodingPattern = /^BIGINT:[0-9]+$/; +export function deserialize( + json: string +): Result { + const deserialized = JSON.parse(json, (_, value) => + typeof value === "string" && bigintEncodingPattern.test(value) + ? BigInt(value.split(":")[1]) + : value + ); + const parsed = SerializableTransaction.safeParse(deserialized); + if (parsed.success) { + return Ok(parsed.data); + } else { + return Err({ type: "ZodError", error: parsed.error }); + } +} + +export const SerializableTokenMeta = z.strictObject({ + mint: z.string(), + owner: z.string(), + amount: z.bigint(), + decimals: z.number(), +}); + +/** + * on the transaction level this will not have a name, but it will have the pre and post balances. + * At the instruction level, we WILL see the name, but we will not have pre and post balances. + */ +export const SerializableAccountMeta = z.strictObject({ + name: z.string().optional(), + pubkey: z.string(), + isSigner: z.boolean().optional(), + isWriteable: z.boolean().optional(), + // lamport balances (rent) + preBalance: z.bigint().optional(), + postBalance: z.bigint().optional(), + // if the account was an ATA + preTokenBalance: SerializableTokenMeta.optional(), + postTokenBalance: SerializableTokenMeta.optional(), +}); + +export const SerializableInstructionArg = z.strictObject({ + name: z.string(), + type: z.string(), + data: z.string(), +}); + +export const SerializableInstruction = z.strictObject({ + name: z.string(), + stackHeight: z.number(), + programIdIndex: z.number(), + data: z.string(), + accounts: z.array(z.number()), + accountsWithData: z.array(SerializableAccountMeta), + args: z.array(SerializableInstructionArg), +}); + +export const SerializableTransactionError = z + .strictObject({ + InstructionError: z + .tuple([ + z.number(), + z.union([z.string(), z.strictObject({ Custom: z.number() })]), + ]) + .optional(), + InsufficientFundsForRent: z + .strictObject({ + account_index: z.number(), + }) + .optional(), + }) + .optional(); + +export const SerializableTransaction = z.strictObject({ + blockTime: z.number(), + slot: z.number(), + recentBlockhash: z.string(), + computeUnitsConsumed: z.bigint(), + err: SerializableTransactionError, + fee: z.bigint(), + signatures: z.array(z.string()), + version: z.union([z.literal("legacy"), z.literal(0)]), + logMessages: z.array(z.string()), + accounts: z.array(SerializableAccountMeta), + instructions: z.array(SerializableInstruction), +}); + +export type Transaction = z.infer; +export type Account = z.infer; +export type TokenBalance = z.infer; +export type Instruction = z.infer; + +export enum GetTransactionErrorType { + NullGetTransactionResponse = "NullGetTransactionResponse", + ZodError = "ZodError", + ResolveAccountError = "ResolveAccountError", // problem getting account list from transaction + DuplicateTokenAccounts = "DuplicateTokenAccounts", // if multiple items in pre or post token balances reference the same account + OuterIxStackHeightNonNull = "OuterIxStackHeightNonNull", // it's expected that all outer instructions have a null stackHeight (even though it's really 1) + RepeatOuterIndicesForInnerIx = "RepeatOuterIndicesForInnerIx", // if multiple items in innerInstructions reference same outer instruction + InvalidStackHeightTransition = "InvalidStackHeightTransition", // if next instruction item in an inner instruction list increases by more than 1, or if it goes to less than 2 (only outers can have stack height 1) +} + +export type GetTransactionError = + | { + type: GetTransactionErrorType.NullGetTransactionResponse; + } + | { + type: GetTransactionErrorType.ZodError; + error: z.ZodError; + } + | { + type: GetTransactionErrorType.ResolveAccountError; + error: ResolveAccountsError; + } + | { + type: GetTransactionErrorType.DuplicateTokenAccounts; + balanceType: "pre" | "post"; + duplicates: Record; + } + | { + type: GetTransactionErrorType.OuterIxStackHeightNonNull; + outerInstruction: Message["compiledInstructions"][number]; + } + | { + type: GetTransactionErrorType.RepeatOuterIndicesForInnerIx; + repeatedIndex: number; + } + | { + type: GetTransactionErrorType.InvalidStackHeightTransition; + outerInstructionIndex: number; + innerInstructionIndex: number; + priorStackHeight: number; + innerStackHeight: number; + }; + +type TokenBalanceResponse = NonNullable< + NonNullable["postTokenBalances"] +>[number]; + +function parseTokenBalances( + tokenBalanceResponses: TokenBalanceResponse[], + accountsRaw: MessageAccountKeys +): Result< + Record, + { type: "duplicates"; duplicates: Record } +> { + const duplicates: Record = {}; + const parsed: Record = {}; + for (let i = 0; i < tokenBalanceResponses.length; ++i) { + const cur = tokenBalanceResponses[i]; + const { + accountIndex, + mint, + owner, + uiTokenAmount: { amount, decimals }, + } = cur; + const accountPubkey = accountsRaw.get(accountIndex)!.toBase58(); + if (parsed[accountPubkey] !== undefined) { + if (duplicates[accountPubkey] === undefined) { + duplicates[accountPubkey] = [parsed[accountPubkey][0]]; + } + duplicates[accountPubkey].push(cur); + } + parsed[accountPubkey] = [ + cur, + { + mint, + owner: owner!, + amount: BigInt(amount), + decimals, + }, + ]; + } + if (Object.keys(duplicates).length > 0) { + return Err({ type: "duplicates", duplicates }); + } + return Ok( + Object.fromEntries( + Object.entries(parsed).map(([account, [_response, balance]]) => [ + account, + balance, + ]) + ) + ); +} + +async function parseInstructions( + outer: Message["compiledInstructions"], + inner: NonNullable, + accounts: AccountMeta[] +): Promise> { + const innerInstructionMap: Record = {}; + for (let i = 0; i < inner.length; ++i) { + const { index, instructions } = inner[i]; + if (index in innerInstructionMap) { + return Err({ + type: GetTransactionErrorType.RepeatOuterIndicesForInnerIx, + repeatedIndex: index, + }); + } + innerInstructionMap[index] = instructions; + } + const instructions: Instruction[] = []; + for (let outerI = 0; outerI < outer.length; ++outerI) { + const curOuter = outer[outerI]; + // TODO: figure out why the outer and inner instruction types don't have a stackHeight member even though the rpc always returns this. + // perhaps we need to patch web3 libs or there's some edge case we aren't aware of. + if ("stackHeight" in curOuter) { + return Err({ + type: GetTransactionErrorType.OuterIxStackHeightNonNull, + outerInstruction: curOuter, + }); + } + const programAccount = accounts[curOuter.programIdIndex].pubkey; + const idl = await getIdlForProgram(programAccount); + const outerIxWithDisplay = getIxWithDisplay( + { + ...curOuter, + data: Buffer.from(curOuter.data), + accounts: curOuter.accountKeyIndexes, + }, + idl, + accounts + ); + + const outerName = outerIxWithDisplay?.instruction.name ?? "unknown"; + const outerArgs = outerIxWithDisplay?.instructionDisplay?.args ?? []; + const outerAccountsWithData = + outerIxWithDisplay?.instructionDisplay?.accounts ?? []; + instructions.push({ + stackHeight: 1, + programIdIndex: curOuter.programIdIndex, + data: base58.encode(curOuter.data), + accounts: curOuter.accountKeyIndexes, + name: outerName, + args: outerArgs, + // we do not have balances here + accountsWithData: outerAccountsWithData.map(({ isWritable, ...a }) => ({ + ...a, + isWriteable: isWritable, + pubkey: a.pubkey.toBase58(), + })), + }); + let curStackHeight = 1; + const curInnerInstructions = innerInstructionMap[outerI] ?? []; + for (let innerI = 0; innerI < curInnerInstructions.length; ++innerI) { + const curInner = curInnerInstructions[innerI]; + const innerStackHeight: number = (curInner as any).stackHeight; + const isInvalidStackHeight = + typeof innerStackHeight !== "number" || + (innerStackHeight > curStackHeight && + curStackHeight + 1 !== innerStackHeight) || + innerStackHeight < 2; + if (isInvalidStackHeight) { + return Err({ + type: GetTransactionErrorType.InvalidStackHeightTransition, + outerInstructionIndex: outerI, + innerInstructionIndex: innerI, + priorStackHeight: curStackHeight, + innerStackHeight, + }); + } + const programAccount = accounts[curInner.programIdIndex].pubkey; + const idl = await getIdlForProgram(programAccount); + const innerIxWithDisplay = getIxWithDisplay( + { + ...curOuter, + data: Buffer.from(curOuter.data), + accounts: curOuter.accountKeyIndexes, + }, + idl, + accounts + ); + + const innerName = innerIxWithDisplay?.instruction.name ?? "unknown"; + const innerArgs = innerIxWithDisplay?.instructionDisplay?.args ?? []; + const innerAccountsWithData = + innerIxWithDisplay?.instructionDisplay?.accounts ?? []; + + instructions.push({ + stackHeight: innerStackHeight, + programIdIndex: curInner.programIdIndex, + data: curInner.data, + accounts: curInner.accounts, + name: innerName, + args: innerArgs, + // we do not have balances here + accountsWithData: innerAccountsWithData.map(({ isWritable, ...a }) => ({ + ...a, + isWriteable: isWritable, + pubkey: a.pubkey.toBase58(), + })), + }); + curStackHeight = innerStackHeight; + } + } + return Ok(instructions); +} + +async function getIdlForProgram( + programAccount: PublicKey +): Promise { + try { + let idl: Idl | null = PROGRAM_ID_TO_IDL_MAP[programAccount.toBase58()]; + if (!idl) { + idl = await Program.fetchIdl(programAccount, provider); + } + return idl; + } catch (e) { + return null; + } +} + +export type IdlAccount = { + name: string; + isMut: boolean; + isSigner: boolean; +}; + +export type IdlAccounts = { + name: string; + accounts: IdlAccount[]; +}; + +/** + * @private + */ +export type IdlAccountItem = IdlAccounts | IdlAccount; + +function getIxWithDisplay( + instruction: { accounts: number[]; data: Buffer }, + idl: Idl | null, + accountMetas: AccountMeta[] +): { + instruction: AnchorInstruction; + instructionDisplay: InstructionDisplay | null; +} | null { + if (!idl) { + return null; + } + let coder: BorshInstructionCoder | null = null; + let decodedIx: AnchorInstruction | null = null; + + // Added because of this error: + // User defined types not provided + // TypeError: field.type is not an Object. (evaluating '"vec" in field.type') + try { + coder = new BorshInstructionCoder(idl); + } catch (e) { + logger.error("error with initializing coder", e); + return null; + } + + if (!coder) { + logger.error("no coder can't continue"); + return null; + } + + try { + decodedIx = coder.decode(Buffer.from(instruction.data)); + } catch (e) { + logger.error("error with coder decoding of instruction:", e); + return null; + } + + if (!decodedIx) { + return null; + } + + const ix = idl.instructions.find((instr) => instr.name === decodedIx.name); + const flatIdlAccounts = flattenIdlAccounts(ix?.accounts); + const accounts = instruction.accounts.map((number, idx) => { + const meta = accountMetas[number]; + if (idx < flatIdlAccounts.length) { + return { + name: flatIdlAccounts[idx].name, + ...meta, + }; + } + // "Remaining accounts" are unnamed in Anchor. + else { + return { + name: `Remaining ${idx - flatIdlAccounts.length}`, + ...meta, + }; + } + }); + try { + const ixDisplay = coder.format(decodedIx, accounts); + + return { + instruction: decodedIx, + instructionDisplay: ixDisplay, + }; + } catch (e) { + logger.error("error with coder formatting of decodedIx:", e); + return null; + } +} + +function flattenIdlAccounts( + accounts: IdlAccountItem[], + prefix?: string +): IdlAccount[] { + return accounts + .map((account) => { + const accName = account.name; + if (Object.prototype.hasOwnProperty.call(account, "accounts")) { + const newPrefix = prefix ? `${prefix} > ${accName}` : accName; + + return flattenIdlAccounts((account).accounts, newPrefix); + } else { + return { + ...(account), + name: prefix ? `${prefix} > ${accName}` : accName, + }; + } + }) + .flat(); +} + +export async function getTransaction( + signature: string +): Promise> { + const txResponse = await connection.getTransaction(signature, { + maxSupportedTransactionVersion: 0, + }); + if (!txResponse) { + return Err({ + type: GetTransactionErrorType.NullGetTransactionResponse, + }); + } + const accountsResponse = await resolveAccounts(txResponse); + if (!accountsResponse.success) { + return Err({ + type: GetTransactionErrorType.ResolveAccountError, + error: accountsResponse.error, + }); + } + const { ok: accountsRaw } = accountsResponse; + const accounts: Account[] = []; + // Index to token balance + const preTokenBalances = parseTokenBalances( + txResponse.meta?.preTokenBalances ?? [], + accountsRaw + ); + if (!preTokenBalances.success) { + return Err({ + type: GetTransactionErrorType.DuplicateTokenAccounts, + duplicates: preTokenBalances.error.duplicates, + balanceType: "pre", + }); + } + const postTokenBalances = parseTokenBalances( + txResponse.meta?.postTokenBalances ?? [], + accountsRaw + ); + if (!postTokenBalances.success) { + return Err({ + type: GetTransactionErrorType.DuplicateTokenAccounts, + duplicates: postTokenBalances.error.duplicates, + balanceType: "post", + }); + } + + for (let i = 0; i < accountsRaw.length; ++i) { + const cur = accountsRaw.get(i); + const pubkey = cur!.toBase58(); + accounts.push({ + name: "", + pubkey, + isSigner: txResponse.transaction.message.isAccountSigner(i), + isWriteable: txResponse.transaction.message.isAccountWritable(i), + preBalance: BigInt(txResponse.meta?.preBalances[i]!), + postBalance: BigInt(txResponse.meta?.postBalances[i]!), + preTokenBalance: preTokenBalances.ok[pubkey], + postTokenBalance: postTokenBalances.ok[pubkey], + }); + } + + const accountMetas: AccountMeta[] = accounts.map((a) => ({ + pubkey: new PublicKey(a.pubkey), + isWritable: a.isWriteable ?? false, + isSigner: a.isSigner ?? false, + })); + + const instructionsResult = await parseInstructions( + txResponse.transaction.message.compiledInstructions, + txResponse.meta?.innerInstructions!, + accountMetas + ); + if (!instructionsResult.success) { + return instructionsResult; + } + const instructions = instructionsResult.ok; + + const parseResult = SerializableTransaction.safeParse({ + blockTime: txResponse.blockTime, + slot: txResponse.slot, + recentBlockhash: txResponse.transaction.message.recentBlockhash, + computeUnitsConsumed: BigInt(txResponse.meta?.computeUnitsConsumed!), + err: txResponse.meta?.err ?? undefined, + fee: BigInt(txResponse.meta?.fee!), + signatures: txResponse.transaction.signatures, + version: txResponse.version, + logMessages: txResponse.meta?.logMessages, + accounts, + instructions, + }); + if (parseResult.success) { + return Ok(parseResult.data); + } else { + return Err({ + type: GetTransactionErrorType.ZodError, + error: parseResult.error, + }); + } +} + +export function parseFormattedInstructionArgsData(data: string) { + let jsonString = data.replace(/'/g, '"'); + + jsonString = jsonString.replace(/(\w+):/g, '"$1":'); + + jsonString = jsonString.replace(/:\s*(\w+)(?=,|})/g, (match, p1) => { + return isNaN(p1) ? `: "${p1}"` : `: ${p1}`; + }); + + return JSON.parse(jsonString) as T; +} + +/* +// from txResponse.transaction.message.serialize() +// 22RoFnkikwwiZ1Tw47mqEQL2oSKD4xJBRDr1xxyayvyoghQ73TtM16tRW8a8d1Ue9tQ5FroTCAMoQALhjXbLh7E8 +const sampleTransaction = { + "blockTime":1708392365, + "meta":{ + "computeUnitsConsumed":115351, + "err":null, + "fee":25080, + "innerInstructions":[ + { + "index":3, + "instructions":[ + { + "accounts":[0,1], + "data":"111112PhCZ6LAeHDFtvbyHvk1VQAu373K5bsDc7zGtGftewwNJhnARLbzL3VyendLazkiH", + "programIdIndex":7, + "stackHeight":2 + }, + { + "accounts":[0,6,8,11,7,17], + "data":"1", + "programIdIndex":12, + "stackHeight":2 + }, + { + "accounts":[11], + "data":"84eT", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[0,6], + "data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL", + "programIdIndex":7, + "stackHeight":3 + }, + { + "accounts":[6], + "data":"P", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[6,11], + "data":"6Pq53B79epzehHA633bmpuCS2h6Y3kdWX4if2ingmWebA", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[0,5,8,15,7,17], + "data":"1", + "programIdIndex":12, + "stackHeight":2 + }, + { + "accounts":[15], + "data":"84eT", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[0,5], + "data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL", + "programIdIndex":7, + "stackHeight":3 + }, + { + "accounts":[5], + "data":"P", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[5,15], + "data":"6Pq53B79epzehHA633bmpuCS2h6Y3kdWX4if2ingmWebA", + "programIdIndex":17, + "stackHeight":3 + }, + { + "accounts":[9], + "data":"5H2mQahfhqnGk5qEg5kSeUZ6U33HdY2UUShDuG4tURrKyhVyQznphqNTE1Tksz6t982WMdCEKTYSyde8zX8FGJ3dHBb4iB1cQatoccDG7p9WgNtkujuu9qwZyFXnXHjzG4ycF9xUaqd2vy3J8qVLkJpLXGHWTHaXscazUWZhPyx7qVHbBtuWG512LZUWXNefRhTzwUum", + "programIdIndex":16, + "stackHeight":2 + } + ] + } + ], + "loadedAddresses":{ + "readonly":[], + "writable":[] + }, + "logMessages":[ + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [1]", + "Program log: Instruction: CreateMarket", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]", + "Program log: Create","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: GetAccountDataSize", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1622 of 752557 compute units", + "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program log: Initialize the associated token account", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: InitializeImmutableOwner", + "Program log: Please upgrade to SPL Token 2022 for immutable owner support", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 745917 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: InitializeAccount3", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4241 of 742033 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 29544 of 767032 compute units", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]", + "Program log: Create", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: GetAccountDataSize", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1622 of 723500 compute units", + "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program log: Initialize the associated token account", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: InitializeImmutableOwner", + "Program log: Please upgrade to SPL Token 2022 for immutable owner support", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 716860 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: InitializeAccount3", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4241 of 712976 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20544 of 728975 compute units", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [2]", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 2126 of 688925 compute units", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 114751 of 799550 compute units", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success" + ], + "postBalances":[ + 4068672160,6792960,633916800,636255360,633916800,2039280,2039280,1,0,0,10290359120,1461600,731913600,1,0,1461600,1141440,934087680 + ], + "postTokenBalances":[ + { + "accountIndex":5, + "mint":"GrV2aGFHGtwNUiDWHRY6oP4DGf23PY4iNJWcV5ZgEKf", + "owner":"3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", + "programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "uiTokenAmount":{ + "amount":"0","decimals":6,"uiAmount":null,"uiAmountString":"0" + } + }, + { + "accountIndex":6, + "mint":"ADwCAfmY6FdkFHqdv3Qw4pBoVYNhEZLW3wcwr41sGx8E", + "owner":"3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", + "programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "uiTokenAmount":{ + "amount":"0", + "decimals":9, + "uiAmount":null, + "uiAmountString":"0" + } + } + ], + "preBalances":[ + 5983657720,0,0,0,0,0,0,1,0,0,10290359120,1461600,731913600,1,0,1461600,1141440,934087680 + ], + "preTokenBalances":[], + "rewards":[], + "status":{"Ok":null} + }, + "slot":249251231, + "transaction":{ + "message":{ + "header":{ + "numReadonlySignedAccounts":0, + "numReadonlyUnsignedAccounts":11, + "numRequiredSignatures":5 + }, + "accountKeys":[ + "99dZcXhrYgEmHeMKAb9ezPaBqgMdg1RjCGSfHa7BeQEX", + "4yoswUWGJ2s7Wio2tVeD7dvEEuHWxyaYTXUW5yELwX4M", + "6GLWiqsUzXV1NJDcPkbrVq51aJmSmvZwpJTBkMmKaaaA", + "6HiwCD32ErrLbDogWtTB2zxE6GLzypTpK4QuPDRjFpjr", + "D9Ew92TMULsVDERnMLUjpNpCKRnDQWptS4rFYSVSjT1B", + "2ZLJaGWXZk1279w1zp3y3m2bTaKdwE4VaZQns8FfpooJ", + "69KYjQpYokoBXctmnedNgeed1qxeTJCaXjazojdH2Rs9", + "11111111111111111111111111111111", + "3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", + "8rDvL1qM41mYVNYS6oKLfGXyBGov3jLtbELToxjSwShj", + "ADCCEAbH8eixGj5t73vb4sKecSKo7ndgDSuWGvER4Loy", + "ADwCAfmY6FdkFHqdv3Qw4pBoVYNhEZLW3wcwr41sGx8E", + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "ComputeBudget111111111111111111111111111111", + "GpLACVBR3DMxNDfeFMKrhNnycs7ghdCwJeXSvccL5a3Z", + "GrV2aGFHGtwNUiDWHRY6oP4DGf23PY4iNJWcV5ZgEKf", + "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + ], + "recentBlockhash":"GkH5dBDtp4uqx7ScQuJVYMyCgXsnx9Z6JTi61mKM873V", + "instructions":[ + { + "accounts":[0,4], + "data":"11115j3Nzc8Ljr4BPxH9a4EThoPhhCp8WzdyQ2E9yALd9XKwvnkJgCxCLttsb6Ld85UTMw", + "programIdIndex":7, + "stackHeight":null + }, + { + "accounts":[0,2], + "data":"11115j3Nzc8Ljr4BPxH9a4EThoPhhCp8WzdyQ2E9yALd9XKwvnkJgCxCLttsb6Ld85UTMw", + "programIdIndex":7, + "stackHeight":null + }, + { + "accounts":[0,3], + "data":"11115iNQLx57j4ojPNAEtHcpGMqznSwVj6ZfVtARVE5WcRCiw5qLa6a3oiZ7sf8CSJgs8R", + "programIdIndex":7, + "stackHeight":null + }, + { + "accounts":[1,8,4,2,3,0,6,5,11,15,7,17,12,16,16,10,14,16,14,9,16], + "data":"7mYL3pfoBAM6CMTKWMvUkm2Kpvg7a6h6gU4wo2KewGc1B8WaokBjSkXJ5qpRv7LmEziCcpQhpjt6G5X15GBXtbPHzAxUg1NEGC3y", + "programIdIndex":16, + "stackHeight":null + }, + { + "accounts":[], + "data":"3WBgs5fm8oDy", + "programIdIndex":13, + "stackHeight":null + } + ], + "indexToProgramIds":{} + }, + "signatures":[ + "22RoFnkikwwiZ1Tw47mqEQL2oSKD4xJBRDr1xxyayvyoghQ73TtM16tRW8a8d1Ue9tQ5FroTCAMoQALhjXbLh7E8", + "2w26krC3MgYd2J8HrRtdTx6ifd8FTdYmrWKQwcF4qDUgrWGViareC1wCgP4XvvDixXggJ2CJZvtVRkehRCH3G1N7", + "rBq7JkrEsFqW4jP5mo4RYYg2DdfLNTQxFtmXiyA7b1Bww7Bmz3fHWua6zhMruUHKfw1apjSsgGaPUtpVTRDR6rt", + "2nf8UFdpwr4wm3KFD3HjCQuNcAhYFgvKt4KhjhZ4mbuu6WJEWuCGEqyypZB6XkkGdsRdmkKod4PBSmRVKZ12cMpC", + "3D7YMtEzisFjkxeAuXFtFesYi3FAfruX4h9TeVQAb2yxnLexif6NK3oMAko5ohX5p6fLNEVm5jRgqizjkBvaHhbC" + ] + }, + "version":"legacy" +} +*/ + +/* +// console.logged txResponse +// 3ggvCQ979T5gRV56bUU4YGtYYJruAZypgTxgnrw4eoVP9ARKK8VT8j7Dy7TnBQ6r4j511yqYZM7mdkk8fJ363s9P +{ + blockTime: 1708665394, + meta: { + computeUnitsConsumed: 24859, + err: null, + fee: 7000, + innerInstructions: [ + [Object ...] + ], + loadedAddresses: { + readonly: [], + writable: [], + }, + logMessages: [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", "Program ComputeBudget111111111111111111111111111111 success", + "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN invoke [1]", "Program log: Instruction: CancelOrderByClientId", + "Program log: Observation: 3564785", "Program log: Weighted observation: 92481217255", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [2]", "Program log: Instruction: CancelOrderByClientOrderId", + "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 8391 of 185296 compute units", + "Program return: opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb AQAAAAAAAAA=", "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", + "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN consumed 24709 of 199850 compute units", + "Program return: TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN AQAAAAAAAAA=", "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN success" + ], + postBalances: [ 250122967, 633916800, 9688320, 633916800, 1614720, 6792960, 1, + 1141440, 1141440 + ], + postTokenBalances: [], + preBalances: [ 250129967, 633916800, 9688320, 633916800, 1614720, 6792960, 1, + 1141440, 1141440 + ], + preTokenBalances: [], + returnData: { + data: [ "AQAAAAAAAAA=", "base64" ], + programId: "TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN", + }, + rewards: [], + status: { + Ok: null, + }, + }, + slot: 249891238, + transaction: { + message: Message { + header: [Object ...], + accountKeys: [ + [PublicKey(8Cwx4yR2sFAC5Pdx2NgGHxCk1gJrtSTxJoyqVonqndhq) ...], [PublicKey(6GLWiqsUzXV1NJDcPkbrVq51aJmSmvZwpJTBkMmKaaaA) ...], [PublicKey(7DFk8ZwyRzEW8ysngKhybSaVtx92g7KhTZ2iqmTs5s3W) ...], [PublicKey(D9Ew92TMULsVDERnMLUjpNpCKRnDQWptS4rFYSVSjT1B) ...], [PublicKey(GpLACVBR3DMxNDfeFMKrhNnycs7ghdCwJeXSvccL5a3Z) ...], [PublicKey(4yoswUWGJ2s7Wio2tVeD7dvEEuHWxyaYTXUW5yELwX4M) ...], [PublicKey(ComputeBudget111111111111111111111111111111) ...], [PublicKey(opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb) ...], [PublicKey(TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN) ...] + ], + recentBlockhash: "9jKYzGuvqjYwnuhJmoSb5b8MEsirdqDXR3Sjvarg5VKF", + instructions: [ + [Object ...], [Object ...] + ], + indexToProgramIds: Map(2) { + 6: [PublicKey(ComputeBudget111111111111111111111111111111) ...], + 8: [PublicKey(TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN) ...], + }, + version: [Getter], + staticAccountKeys: [Getter], + compiledInstructions: [Getter], + addressTableLookups: [Getter], + getAccountKeys: [Function: getAccountKeys], + isAccountSigner: [Function: isAccountSigner], + isAccountWritable: [Function: isAccountWritable], + isProgramId: [Function: isProgramId], + programIds: [Function: programIds], + nonProgramIds: [Function: nonProgramIds], + serialize: [Function: serialize], + }, + signatures: [ "3ggvCQ979T5gRV56bUU4YGtYYJruAZypgTxgnrw4eoVP9ARKK8VT8j7Dy7TnBQ6r4j511yqYZM7mdkk8fJ363s9P" + ], + }, + version: "legacy", +} +*/ diff --git a/packages/old_indexer/src/transaction/watcher.ts b/packages/old_indexer/src/transaction/watcher.ts new file mode 100644 index 00000000..39eed8a3 --- /dev/null +++ b/packages/old_indexer/src/transaction/watcher.ts @@ -0,0 +1,619 @@ +import { ConfirmedSignatureInfo, PublicKey } from "@solana/web3.js"; +import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; +import { + SERIALIZED_TRANSACTION_LOGIC_VERSION, + Transaction, + getTransaction, + serialize, +} from "./serializer"; +import { getTransactionHistory } from "./history"; +import { connection } from "../connection"; +import { logger } from "../logger"; +import { Err, Ok, Result, TaggedUnion } from "../match"; +import { + InstructionType, + TransactionWatchStatus, + TransactionWatcherTransactionRecord, +} from "@metadaoproject/indexer-db/lib/schema"; +import { newTxQueue } from "../indexers/start-transaction-history-indexers"; + +/* +$ pnpm sql "select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers'" +> @metadaoproject/indexer-db@ sql /workspaces/meta-repo/repos/futarchy-indexer/packages/database +> bun src/run-sql.ts "select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers'" + +select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers' +total: 6 +table_catalog table_schema table_name column_name ordinal_position +--------------------------------------------------------------------------------------------- +railway public transaction_watchers acct 1 +railway public transaction_watchers latest_tx_sig 2 +railway public transaction_watchers description 3 +railway public transaction_watchers checked_up_to_slot 4 +railway public transaction_watchers first_tx_sig 5 +railway public transaction_watchers serializer_logic_version 6 +$ pnpm sql "insert into transaction_watchers values ('TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN', NULL, 'openbookv2 twap watcher', 0, NULL, 0)" +*/ + +export enum WatcherBackfillError { + StoppedBackfill = "StoppedBackfill", + SlotCheckHistoryMismatch = "SlotCheckHistoryMismatch", + GetTransactionHistoryFailure = "GetTransactionHistoryFailure", + TransactionParseFailure = "TransactionParseFailure", + TransactionUpsertFailure = "TransactionUpsertFailure", + WatcherUpdateFailure = "WatcherUpdateFailure", + WatcherNotFound = "WatcherNotFound", + StartedWithPollingIntervalSet = "StartedWithPollingIntervalSet", +} + +type TransactionWatcherRecord = typeof schema.transactionWatchers._.inferSelect; +type TransactionRecord = typeof schema.transactions._.inferInsert; + +const watchers: Record = {}; +const MAX_RETRIES = 12; + +class TransactionWatcher { + private account: PublicKey; + private description: string; + private latestTxSig: string | undefined; + private checkedUpToSlot: string; + private logicVersion: number; + private pollerIntervalId: ReturnType | undefined; + private rpcWebsocket: number | undefined; + private stopped: boolean; + private backfilling: boolean; + private errorCount: number = 0; + public constructor({ + acct, + description, + latestTxSig, + checkedUpToSlot, + serializerLogicVersion, + }: TransactionWatcherRecord) { + this.account = new PublicKey(acct); + this.description = description; + this.latestTxSig = latestTxSig ?? undefined; + this.checkedUpToSlot = checkedUpToSlot; + this.logicVersion = serializerLogicVersion; + this.stopped = false; + this.backfilling = false; + this.start(); + } + + private async start() { + if (this.pollerIntervalId !== undefined) { + logger.error( + `Interval was ${ + this.pollerIntervalId + } when starting ${this.account.toBase58()}` + ); + return Err({ type: WatcherBackfillError.StartedWithPollingIntervalSet }); + } + await this.handleBackfillFromLatest(); + // TODO: add websocket for realtime updates (might be lossy, but would allow us to increase poll time meaning less rpc costs) + this.pollerIntervalId = setInterval(async () => { + await this.handleBackfillFromLatest(); + }, 10000); + return Ok(`successfully started watcher for ${this.account.toBase58()}`); + } + + private async handleBackfillFromLatest() { + const backfillRes = await this.backfillFromLatest(); + switch (backfillRes.success) { + case true: + { + if (this.account) { + logger.info( + `successfully ran backfill for acct: ${this.account.toBase58()}` + ); + } + logger.info(`success message: ${backfillRes.ok}`); + } + break; + case false: + { + logger.error( + `error running backfill from latest: ${ + backfillRes.error.type + }. For acct: ${this.account.toBase58()}` + ); + } + break; + } + } + + private async backfillFromLatest(): Promise< + | { + success: false; + error: TaggedUnion; + } + | { + success: true; + ok: string; + } + > { + if (this.stopped) + return Ok("tried to call backfillFromLatest a stopped watcher"); + if (this.backfilling) + return Ok( + "tried to call backfillFromLatest on an already backfilling watcher" + ); + this.backfilling = true; + const acct = this.account.toBase58(); + const latestFinalizedSlot = BigInt(await connection.getSlot("finalized")); + const historyRes = + await this.getTransactionHistoryFromFinalizedSlotWithRetry(); + if (!historyRes.success) { + this.errorCount += 1; + if (this.errorCount > MAX_RETRIES) { + logger.errorWithChatBotAlert("marking transaction watcher as failed"); + // update tx watcher status to failed and exit, but other tx watchers continue + const markFailedResult = await this.markTransactionWatcherAsFailed( + historyRes.error.type + ); + if (!markFailedResult?.success) { + return markFailedResult; + } + return historyRes; + } else { + return Ok("tx watcher hit an error, retrying backfill"); + } + } + // history fetch was successful + const history = historyRes.ok; + logger.info( + `history after ${this.latestTxSig} is length ${history.length}` + ); + let numIndexed = 0; + for (const signatureInfo of history) { + const res = await this.processTransactionInHistory( + acct, + signatureInfo, + numIndexed + ); + if (!res.success) { + logger.error( + "error processing transaction", + res.error, + signatureInfo.signature, + acct + ); + } + } + // Update checkedUpToSlot to latest confirmed slot. If we don't do this, then checkedUpToSlot would only be updated once there's a new + // transaction, and this would mean indexers would stall in cases where some of the dependent watchers don't have frequent transactions. + // It's possible that this might be the source of bugs if somehow new transactions come in that are before the latest confirmed slot but were + // not returned by the RPC's tx history. + // EDIT: encountered above bug so trying to resolve by switching to finalized slot rather than confirmed. + // EDIT: even switching to finalized didn't really work. This logic needs rethinking + const newCheckedUpToSlot = + BigInt(this.checkedUpToSlot) > latestFinalizedSlot + ? this.checkedUpToSlot + : latestFinalizedSlot.toString(); + if (newCheckedUpToSlot === latestFinalizedSlot.toString()) { + console.log( + `For acct ${acct}, using finalized slot of ${latestFinalizedSlot}` + ); + } + const updateResult = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + checkedUpToSlot: newCheckedUpToSlot.toString(), + updatedAt: new Date(), + }) + .where(eq(schema.transactionWatchers.acct, acct)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updateResult.length !== 1 || updateResult[0].acct !== acct) { + logger.error( + `Failed to update tx watcher for acct ${acct} at end of backfill` + ); + return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); + } + this.checkedUpToSlot = newCheckedUpToSlot; + this.backfilling = false; + return Ok(`${acct} watcher is up to date`); + } + + private async processTransactionInHistory( + acct: string, + signatureInfo: ConfirmedSignatureInfo, + numIndexed: number + ): Promise< + | { + success: true; + ok: { priorSlot: bigint; numIndexed: number }; + } + | { + success: false; + error: TaggedUnion; + } + > { + const priorSlot = this.checkedUpToSlot; + if (this.stopped) { + logger.error(`Stopped watcher for ${acct} mid backfill`); + return Err({ type: WatcherBackfillError.StoppedBackfill }); + } + const { slot: slotAsNum, signature } = signatureInfo; + const slot = BigInt(slotAsNum); + // TODO: lock should be done here. It's probably fine for now since we only have 1 instance. + // I can think of weird states though where you have this stopped watcher and another started one. + // Leaving as todo since optimistic locking might be preferred + const curWatcherRecord = ( + await usingDb((db) => + db + .select() + .from(schema.transactionWatchers) + .where(eq(schema.transactionWatchers.acct, acct)) + .execute() + ) + )?.[0]; + + if (!curWatcherRecord) + return Err({ type: WatcherBackfillError.WatcherNotFound }); + // TODO: we don't need to necessarily stop this watcher + // just because of one txn slot being less than the checked up to slo + // const { checkedUpToSlot } = curWatcherRecord; + // if (slot <= checkedUpToSlot) { + // const errorMessage = `watcher for account ${acct} supposedly checked up to slot ${checkedUpToSlot} but history returned sig ${signature} with slot ${slot}`; + // logger.error(errorMessage); + // this.stop(); + // return Err({ type: WatcherBackfillError.SlotCheckHistoryMismatch }); + // } + const maybeCurTxRecord = + (await usingDb((db) => + db + .select() + .from(schema.transactions) + .where(eq(schema.transactions.txSig, signature)) + .execute() + )) ?? []; + if ( + maybeCurTxRecord.length === 0 || + maybeCurTxRecord[0].serializerLogicVersion < + SERIALIZED_TRANSACTION_LOGIC_VERSION + ) { + const parseTxResult = await getTransaction(signature); + if (!parseTxResult.success) { + logger.error( + `Failed to parse tx ${signature}\n` + + JSON.stringify(parseTxResult.error) + ); + this.stop(); + return Err({ type: WatcherBackfillError.TransactionParseFailure }); + } + const { ok: serializableTx } = parseTxResult; + const res = await handleNewTransaction( + signature, + slot, + serializableTx, + acct + ); + if (res && !res?.success) { + return Err({ type: res.error.type }); + } + } + + // We could opt to only update slot at end, but updating it now means indexers can progress while a backfill is in progress. + // That's preferrable since the backfill could be a lot of transactions and it could stall if there are any bugs in the tx backup logic + // We can't set the checked up to slot as the current tx's slot, since there might be a tx after this one on the same slot. So we instead + // need to set it to the prior tx's slot if that slot is less than the current slot. + const newCheckedUpToSlot = + BigInt(slot) > BigInt(priorSlot) ? priorSlot : this.checkedUpToSlot; + const updateResult = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + acct, + latestTxSig: signature, + firstTxSig: curWatcherRecord.firstTxSig ?? signature, + serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, + checkedUpToSlot: newCheckedUpToSlot.toString(), + updatedAt: new Date(), + }) + .where(eq(schema.transactionWatchers.acct, acct)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updateResult.length !== 1 || updateResult[0].acct !== acct) { + logger.error( + `Failed to update tx watcher for acct ${acct} on tx ${signature}` + ); + return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); + } + this.checkedUpToSlot = newCheckedUpToSlot; + numIndexed++; + if (numIndexed % 50 === 0) { + logger.info(`(${numIndexed}) ${acct} watcher`); + } + + return Ok({ priorSlot: slot, numIndexed }); + } + + private async getTransactionHistoryFromFinalizedSlotWithRetry(): Promise< + Result + > { + const maxRetries = 3; + const retryDelay = 1000; + let maxSignatures = 0; + let responseWithMaxSignatures: ConfirmedSignatureInfo[] = []; + + for (let i = 0; i < maxRetries; i++) { + try { + const txSignatures = await getTransactionHistory( + this.account, + this.checkedUpToSlot.toString(), + { after: this.latestTxSig } + ); + + if (txSignatures.length > maxSignatures) { + maxSignatures = txSignatures.length; + responseWithMaxSignatures = txSignatures; + } + + if (i > 0 && txSignatures.length !== maxSignatures) { + console.log( + "Difference noticed in tx count during getTransactionHistory RPC call attempts. New length is", + txSignatures.length, + " vs previous length is", + maxSignatures + ); + } + } catch (error) { + if (i === maxRetries - 1) + return Err({ + type: WatcherBackfillError.GetTransactionHistoryFailure, + }); + } + + // Wait before retrying + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + } + + // Return the response with the max signatures after all retries + return Ok(responseWithMaxSignatures); + } + + private async markTransactionWatcherAsFailed(failureLog: string) { + this.backfilling = false; + this.stopped = true; + const acct = this.account.toBase58(); + const updateResult = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + acct, + status: TransactionWatchStatus.Failed, + failureLog, + updatedAt: new Date(), + }) + .where(eq(schema.transactionWatchers.acct, acct)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updateResult.length !== 1 || updateResult[0].acct !== acct) { + logger.errorWithChatBotAlert( + `Failed to mark tx watcher for acct ${acct} as failed` + ); + return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); + } + return Ok("successfully marked transaction watcher as failed"); + } + + public stop() { + this.stopped = true; + if (this.pollerIntervalId === undefined) { + logger.warn( + `Interval was ${ + this.pollerIntervalId + } when stopping ${this.account.toBase58()}` + ); + } + clearInterval(this.pollerIntervalId); + this.pollerIntervalId = undefined; + } +} + +let updatingWatchers = false; + +async function handleNewTransaction( + signature: string, + slot: bigint, + parsedTx: Transaction, + acct: string +) { + const transactionRecord: TransactionRecord = { + txSig: signature, + slot: slot.toString(), + blockTime: new Date(parsedTx.blockTime * 1000), // TODO need to verify if this is correct + failed: parsedTx.err !== undefined, + payload: serialize(parsedTx), + serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, + mainIxType: getMainIxTypeFromTransaction(parsedTx), + }; + const upsertResult = + (await usingDb((db) => + db + .insert(schema.transactions) + .values(transactionRecord) + .onConflictDoUpdate({ + target: schema.transactions.txSig, + set: transactionRecord, + }) + .returning({ txSig: schema.transactions.txSig }) + )) ?? []; + if (upsertResult.length !== 1 || upsertResult[0].txSig !== signature) { + logger.error( + `Failed to upsert ${signature}. ${JSON.stringify(transactionRecord)}` + ); + return Err({ type: WatcherBackfillError.TransactionUpsertFailure }); + } + + // TODO: maybe i need to validate below succeeded. I can't use returning because this isn't an upsert so it could + // be a no-op in the happy path + const watcherTxRecord: TransactionWatcherTransactionRecord = { + txSig: signature, + slot: slot.toString(), + watcherAcct: acct, + }; + const insertRes = + (await usingDb((db) => + db + .insert(schema.transactionWatcherTransactions) + .values(watcherTxRecord) + .onConflictDoNothing() + .returning({ acct: schema.transactionWatcherTransactions.watcherAcct }) + )) ?? []; + if (insertRes.length > 0) { + console.log("successfully inserted new t watch tx", insertRes[0].acct); + } + + // now insert into queue + await newTxQueue.push({ + transactions: transactionRecord, + transaction_watcher_transactions: watcherTxRecord, + }); +} + +export function getMainIxTypeFromTransaction( + tx: Transaction +): InstructionType | null { + const hasSwap = tx.instructions.some((ix) => ix.name === "swap"); + const hasMint = tx.instructions.some( + (ix) => ix.name === "mintConditionalTokens" + ); + if (hasSwap && hasMint) { + return InstructionType.VaultMintAndAmmSwap; + } + if (hasSwap) { + return InstructionType.AmmSwap; + } + if (tx.instructions.some((ix) => ix.name === "addLiquidity")) { + return InstructionType.AmmDeposit; + } + if (tx.instructions.some((ix) => ix.name === "removeLiquidity")) { + return InstructionType.AmmWithdraw; + } + if (tx.instructions.some((ix) => ix.name === "placeOrder")) { + return InstructionType.OpenbookPlaceOrder; + } + if (tx.instructions.some((ix) => ix.name === "cancelOrder")) { + return InstructionType.OpenbookCancelOrder; + } + if (hasMint) { + return InstructionType.VaultMintConditionalTokens; + } + if (tx.instructions.some((ix) => ix.name === "initializeProposal")) { + return InstructionType.AutocratInitializeProposal; + } + if (tx.instructions.some((ix) => ix.name === "finalizeProposal")) { + return InstructionType.AutocratFinalizeProposal; + } + if ( + tx.instructions.some( + (ix) => ix.name === "mergeConditionalTokensForUnderlyingTokens" + ) + ) { + return InstructionType.VaultMergeConditionalTokens; + } + if ( + tx.instructions.some( + (ix) => ix.name === "redeemConditionalTokensForUnderlyingTokens" + ) + ) { + return InstructionType.VaultRedeemConditionalTokensForUnderlyingTokens; + } + return null; +} + +export async function startTransactionWatchers() { + async function getWatchers() { + updatingWatchers = true; + const curWatchers = + (await usingDb((db) => + db + .select() + .from(schema.transactionWatchers) + .where( + eq(schema.transactionWatchers.status, TransactionWatchStatus.Active) + ) + .execute() + )) ?? []; + const curWatchersByAccount: Record = {}; + const watchersToStart: Set = new Set(); + const watchersToStop: Set = new Set(); + // TODO: we need a way to reset running watchers if they're slot or tx was rolled back + for (const watcherInDb of curWatchers) { + curWatchersByAccount[watcherInDb.acct] = watcherInDb; + const alreadyWatching = watcherInDb.acct in watchers; + if (!alreadyWatching) { + watchersToStart.add(watcherInDb.acct); + } else { + if ( + watcherInDb.serializerLogicVersion !== + SERIALIZED_TRANSACTION_LOGIC_VERSION + ) { + const { acct, serializerLogicVersion } = watcherInDb; + logger.info( + `reseting ${acct}. existing logic version of ${serializerLogicVersion} current is ${SERIALIZED_TRANSACTION_LOGIC_VERSION}` + ); + watchers[acct]?.stop(); + delete watchers[acct]; + const updated = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, + latestTxSig: null, + checkedUpToSlot: "0", + updatedAt: new Date(), + }) + .where(eq(schema.transactionWatchers.acct, acct)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updated.length !== 1 || updated[0].acct !== acct) { + const error = new Error( + `Failed to update ${acct} watcher. ${JSON.stringify(updated)}` + ); + logger.error(error.message); + throw error; + } + } + } + } + for (const runningWatcherAccount in watchers) { + if (!(runningWatcherAccount in curWatchersByAccount)) { + watchersToStop.add(runningWatcherAccount); + } + } + if (watchersToStop.size) { + logger.info(`Stopping ${watchersToStop.size} watchers:`); + let i = 0; + for (const watcherToStopAcct of watchersToStop) { + logger.info(` ${++i}. ${watcherToStopAcct}`); + watchers[watcherToStopAcct]?.stop(); + delete watchers[watcherToStopAcct]; + } + } + if (watchersToStart.size) { + logger.info(`Starting ${watchersToStart.size} watchers:`); + let i = 0; + for (const watcherToStartAcct of watchersToStart) { + const prefix = ` ${++i}. `; + logger.info(`${prefix}${watcherToStartAcct}`); + const cur = curWatchersByAccount[watcherToStartAcct]; + watchers[watcherToStartAcct] = new TransactionWatcher(cur); + } + } + updatingWatchers = false; + } + setInterval(() => { + if (!updatingWatchers) { + getWatchers(); + } + }, 5000); + getWatchers(); +} diff --git a/packages/old_indexer/src/types/errors.ts b/packages/old_indexer/src/types/errors.ts new file mode 100644 index 00000000..461ff265 --- /dev/null +++ b/packages/old_indexer/src/types/errors.ts @@ -0,0 +1,14 @@ +export enum AmmInstructionIndexerError { + GeneralError = "GeneralError", + MissingMarket = "MissingMarket", + FailedSwap = "FailedSwap", +} + +export enum SwapPersistableError { + GeneralError = "GeneralError", + AlreadyPersistedSwap = "AlreadyPersistedSwap", + NonSwapTransaction = "NonSwapTransaction", + TransactionParseError = "TransactionParseError", + ArbTransactionError = "ArbTransactionError", + PriceError = "PriceError", +} diff --git a/packages/old_indexer/src/types/index.ts b/packages/old_indexer/src/types/index.ts new file mode 100644 index 00000000..1e09b191 --- /dev/null +++ b/packages/old_indexer/src/types/index.ts @@ -0,0 +1,41 @@ + +import { + IndexerImplementation, + IndexerType, +} from "@metadaoproject/indexer-db/lib/schema"; + +export type IndexerWithAccountDeps = { + indexers: { + name: string; + implementation: IndexerImplementation; + latestSlotProcessed: string; + indexerType: IndexerType; + } | null; + indexer_account_dependencies: { + name: string; + acct: string; + latestTxSigProcessed: string | null; + } | null; +}; + +export type User = { + userAcct: string; +}; + +export type UserPerformanceTotals = { + tokensBought: number; + tokensSold: number; + volumeBought: number; + volumeSold: number; + tokensBoughtResolvingMarket: number; + tokensSoldResolvingMarket: number; + volumeBoughtResolvingMarket: number; + volumeSoldResolvingMarket: number; + buyOrderCount: number; + sellOrderCount: number; +}; + +export type UserPerformance = { + proposalAcct: string; +} & User & + UserPerformanceTotals; diff --git a/packages/old_indexer/src/types/swaps.ts b/packages/old_indexer/src/types/swaps.ts new file mode 100644 index 00000000..3ace4d68 --- /dev/null +++ b/packages/old_indexer/src/types/swaps.ts @@ -0,0 +1,9 @@ +import { + OrdersRecord, + TakesRecord, +} from "@metadaoproject/indexer-db/lib/schema"; + +export type SwapPersistable = { + ordersRecord: OrdersRecord; + takesRecord: TakesRecord; +}; diff --git a/packages/indexer/src/usecases/math.test.ts b/packages/old_indexer/src/usecases/math.test.ts similarity index 100% rename from packages/indexer/src/usecases/math.test.ts rename to packages/old_indexer/src/usecases/math.test.ts diff --git a/packages/indexer/src/usecases/math.ts b/packages/old_indexer/src/usecases/math.ts similarity index 100% rename from packages/indexer/src/usecases/math.ts rename to packages/old_indexer/src/usecases/math.ts diff --git a/packages/indexer/tsconfig.json b/packages/old_indexer/tsconfig.json similarity index 100% rename from packages/indexer/tsconfig.json rename to packages/old_indexer/tsconfig.json From 5d425e3f512481a7dfa42c0e99a8e8cee5bda3af Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 30 Oct 2024 19:37:39 -0400 Subject: [PATCH 05/29] clean up --- packages/{new_indexer => indexer}/Dockerfile | 0 .../{new_indexer => indexer}/package.json | 0 packages/{new_indexer => indexer}/readme.md | 0 .../src/adapters/telegram-bot.ts | 0 .../src/backfiller.ts | 0 .../src/connection.ts | 0 .../src/frontfiller.ts | 0 .../{new_indexer => indexer}/src/index.ts | 0 .../{new_indexer => indexer}/src/logger.ts | 0 .../src/subscriber.ts | 0 .../src/v3_indexer/builders/swaps.ts | 0 .../src/v3_indexer/connection.ts | 0 .../src/v3_indexer/constants.ts | 0 .../src/v3_indexer/indexer.ts | 0 .../indexers/account-info-indexer.ts | 0 .../indexers/account-logs-indexer.ts | 0 .../amm-market/amm-market-account-indexer.ts | 0 .../amm-market-account-interval-indexer.ts | 0 .../amm-market-instruction-indexer.ts | 0 .../amm-market-logs-subscribe-indexer.ts | 0 .../v3_indexer/indexers/amm-market/utils.ts | 0 .../indexers/autocrat/autocrat-dao-indexer.ts | 0 .../autocrat/autocrat-proposal-indexer.ts | 0 .../indexers/autocrat/autocrat-v0-indexer.ts | 0 .../autocrat/autocrat-v0_1-indexer.ts | 0 .../autocrat/autocrat-v0_2-indexer.ts | 0 .../birdeye/birdeye-prices-indexer.ts | 0 .../src/v3_indexer/indexers/common.ts | 0 .../src/v3_indexer/indexers/index.ts | 0 .../indexers/instruction-indexer.ts | 0 .../indexers/interval-fetch-indexer.ts | 0 .../jupiter/jupiter-quotes-indexer.ts | 0 .../openbook-twap-instruction-indexer.ts | 0 .../openbook-v2-account-indexer.ts | 0 .../openbook-v2/openbook-v2-indexer.ts | 0 .../indexers/start-account-info-indexers.ts | 0 .../indexers/start-interval-fetch-indexers.ts | 0 .../indexers/start-logs-subscribe-indexer.ts | 0 .../start-transaction-history-indexers.ts | 0 .../indexers/token/token-mint-indexer.ts | 0 .../src/v3_indexer/instruction-dispatch.ts | 0 .../src/v3_indexer/match.ts | 0 .../src/v3_indexer/processor.ts | 0 .../src/v3_indexer/proposal-indexer.ts | 0 .../transaction/account-resolver.ts | 0 .../src/v3_indexer/transaction/history.ts | 0 .../v3_indexer/transaction/serializer.test.ts | 0 .../src/v3_indexer/transaction/serializer.ts | 0 .../src/v3_indexer/transaction/watcher.ts | 0 .../src/v3_indexer/types/errors.ts | 0 .../src/v3_indexer/types/index.ts | 0 .../src/v3_indexer/types/swaps.ts | 0 .../src/v4_indexer/indexer.ts | 0 .../src/v4_indexer/processor.ts | 0 .../{new_indexer => indexer}/tsconfig.json | 0 packages/old_indexer/Dockerfile | 23 - packages/old_indexer/package.json | 47 - .../old_indexer/src/adapters/telegram-bot.ts | 91 -- packages/old_indexer/src/builders/swaps.ts | 428 -------- packages/old_indexer/src/cli/index.ts | 5 - .../src/cli/txw/common/select-account.ts | 21 - packages/old_indexer/src/cli/txw/create.ts | 4 - packages/old_indexer/src/cli/txw/index.ts | 16 - packages/old_indexer/src/cli/txw/populate.ts | 473 --------- packages/old_indexer/src/cli/txw/reset.ts | 79 -- packages/old_indexer/src/cli/txw/validate.ts | 40 - packages/old_indexer/src/connection.ts | 30 - packages/old_indexer/src/constants.ts | 21 - .../old_indexer/src/endpoints/get-metrics.ts | 21 - packages/old_indexer/src/index.ts | 10 - .../src/indexers/account-info-indexer.ts | 16 - .../src/indexers/account-logs-indexer.ts | 16 - .../amm-market/amm-market-account-indexer.ts | 37 - .../amm-market-account-interval-indexer.ts | 65 -- .../amm-market-instruction-indexer.ts | 66 -- .../amm-market-logs-subscribe-indexer.ts | 46 - .../src/indexers/amm-market/utils.ts | 158 --- .../indexers/autocrat/autocrat-dao-indexer.ts | 134 --- .../autocrat/autocrat-proposal-indexer.ts | 946 ------------------ .../indexers/autocrat/autocrat-v0-indexer.ts | 21 - .../autocrat/autocrat-v0_1-indexer.ts | 21 - .../autocrat/autocrat-v0_2-indexer.ts | 21 - .../birdeye/birdeye-prices-indexer.ts | 102 -- packages/old_indexer/src/indexers/common.ts | 12 - packages/old_indexer/src/indexers/index.ts | 119 --- .../src/indexers/instruction-indexer.ts | 44 - .../src/indexers/interval-fetch-indexer.ts | 13 - .../jupiter/jupiter-quotes-indexer.ts | 224 ----- .../openbook-twap-instruction-indexer.ts | 26 - .../openbook-v2-account-indexer.ts | 98 -- .../openbook-v2/openbook-v2-indexer.ts | 11 - .../indexers/start-account-info-indexers.ts | 63 -- .../indexers/start-interval-fetch-indexers.ts | 187 ---- .../indexers/start-logs-subscribe-indexer.ts | 46 - .../start-transaction-history-indexers.ts | 156 --- .../src/indexers/token/token-mint-indexer.ts | 70 -- .../old_indexer/src/instruction-dispatch.ts | 220 ---- packages/old_indexer/src/local-cache.ts | 40 - packages/old_indexer/src/logger.ts | 83 -- packages/old_indexer/src/match.ts | 19 - packages/old_indexer/src/proposal-indexer.ts | 46 - packages/old_indexer/src/server.ts | 18 - .../src/transaction/account-resolver.ts | 55 - .../old_indexer/src/transaction/history.ts | 108 -- .../src/transaction/serializer.test.ts | 40 - .../old_indexer/src/transaction/serializer.ts | 907 ----------------- .../old_indexer/src/transaction/watcher.ts | 619 ------------ packages/old_indexer/src/types/errors.ts | 14 - packages/old_indexer/src/types/index.ts | 41 - packages/old_indexer/src/types/swaps.ts | 9 - .../old_indexer/src/usecases/math.test.ts | 17 - packages/old_indexer/src/usecases/math.ts | 23 - packages/old_indexer/tsconfig.json | 9 - packages/v4_indexer/Dockerfile | 23 - packages/v4_indexer/package.json | 47 - .../v4_indexer/src/adapters/telegram-bot.ts | 88 -- packages/v4_indexer/src/connection.ts | 19 - packages/v4_indexer/src/index.ts | 60 -- packages/v4_indexer/src/indexEvents.ts | 505 ---------- packages/v4_indexer/src/logger.ts | 83 -- packages/v4_indexer/src/populateSignatures.ts | 155 --- packages/v4_indexer/tsconfig.json | 9 - 122 files changed, 7284 deletions(-) rename packages/{new_indexer => indexer}/Dockerfile (100%) rename packages/{new_indexer => indexer}/package.json (100%) rename packages/{new_indexer => indexer}/readme.md (100%) rename packages/{new_indexer => indexer}/src/adapters/telegram-bot.ts (100%) rename packages/{new_indexer => indexer}/src/backfiller.ts (100%) rename packages/{new_indexer => indexer}/src/connection.ts (100%) rename packages/{new_indexer => indexer}/src/frontfiller.ts (100%) rename packages/{new_indexer => indexer}/src/index.ts (100%) rename packages/{new_indexer => indexer}/src/logger.ts (100%) rename packages/{new_indexer => indexer}/src/subscriber.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/builders/swaps.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/connection.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/constants.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/account-info-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/account-logs-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/amm-market/utils.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/common.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/index.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/instruction-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/interval-fetch-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/start-account-info-indexers.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/start-interval-fetch-indexers.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/start-transaction-history-indexers.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/indexers/token/token-mint-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/instruction-dispatch.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/match.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/processor.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/proposal-indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/transaction/account-resolver.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/transaction/history.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/transaction/serializer.test.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/transaction/serializer.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/transaction/watcher.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/types/errors.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/types/index.ts (100%) rename packages/{new_indexer => indexer}/src/v3_indexer/types/swaps.ts (100%) rename packages/{new_indexer => indexer}/src/v4_indexer/indexer.ts (100%) rename packages/{new_indexer => indexer}/src/v4_indexer/processor.ts (100%) rename packages/{new_indexer => indexer}/tsconfig.json (100%) delete mode 100644 packages/old_indexer/Dockerfile delete mode 100644 packages/old_indexer/package.json delete mode 100644 packages/old_indexer/src/adapters/telegram-bot.ts delete mode 100644 packages/old_indexer/src/builders/swaps.ts delete mode 100644 packages/old_indexer/src/cli/index.ts delete mode 100644 packages/old_indexer/src/cli/txw/common/select-account.ts delete mode 100644 packages/old_indexer/src/cli/txw/create.ts delete mode 100644 packages/old_indexer/src/cli/txw/index.ts delete mode 100644 packages/old_indexer/src/cli/txw/populate.ts delete mode 100644 packages/old_indexer/src/cli/txw/reset.ts delete mode 100644 packages/old_indexer/src/cli/txw/validate.ts delete mode 100644 packages/old_indexer/src/connection.ts delete mode 100644 packages/old_indexer/src/constants.ts delete mode 100644 packages/old_indexer/src/endpoints/get-metrics.ts delete mode 100644 packages/old_indexer/src/index.ts delete mode 100644 packages/old_indexer/src/indexers/account-info-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/account-logs-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/amm-market/utils.ts delete mode 100644 packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/common.ts delete mode 100644 packages/old_indexer/src/indexers/index.ts delete mode 100644 packages/old_indexer/src/indexers/instruction-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/interval-fetch-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/start-account-info-indexers.ts delete mode 100644 packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts delete mode 100644 packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts delete mode 100644 packages/old_indexer/src/indexers/start-transaction-history-indexers.ts delete mode 100644 packages/old_indexer/src/indexers/token/token-mint-indexer.ts delete mode 100644 packages/old_indexer/src/instruction-dispatch.ts delete mode 100644 packages/old_indexer/src/local-cache.ts delete mode 100644 packages/old_indexer/src/logger.ts delete mode 100644 packages/old_indexer/src/match.ts delete mode 100644 packages/old_indexer/src/proposal-indexer.ts delete mode 100644 packages/old_indexer/src/server.ts delete mode 100644 packages/old_indexer/src/transaction/account-resolver.ts delete mode 100644 packages/old_indexer/src/transaction/history.ts delete mode 100644 packages/old_indexer/src/transaction/serializer.test.ts delete mode 100644 packages/old_indexer/src/transaction/serializer.ts delete mode 100644 packages/old_indexer/src/transaction/watcher.ts delete mode 100644 packages/old_indexer/src/types/errors.ts delete mode 100644 packages/old_indexer/src/types/index.ts delete mode 100644 packages/old_indexer/src/types/swaps.ts delete mode 100644 packages/old_indexer/src/usecases/math.test.ts delete mode 100644 packages/old_indexer/src/usecases/math.ts delete mode 100644 packages/old_indexer/tsconfig.json delete mode 100644 packages/v4_indexer/Dockerfile delete mode 100644 packages/v4_indexer/package.json delete mode 100644 packages/v4_indexer/src/adapters/telegram-bot.ts delete mode 100644 packages/v4_indexer/src/connection.ts delete mode 100644 packages/v4_indexer/src/index.ts delete mode 100644 packages/v4_indexer/src/indexEvents.ts delete mode 100644 packages/v4_indexer/src/logger.ts delete mode 100644 packages/v4_indexer/src/populateSignatures.ts delete mode 100644 packages/v4_indexer/tsconfig.json diff --git a/packages/new_indexer/Dockerfile b/packages/indexer/Dockerfile similarity index 100% rename from packages/new_indexer/Dockerfile rename to packages/indexer/Dockerfile diff --git a/packages/new_indexer/package.json b/packages/indexer/package.json similarity index 100% rename from packages/new_indexer/package.json rename to packages/indexer/package.json diff --git a/packages/new_indexer/readme.md b/packages/indexer/readme.md similarity index 100% rename from packages/new_indexer/readme.md rename to packages/indexer/readme.md diff --git a/packages/new_indexer/src/adapters/telegram-bot.ts b/packages/indexer/src/adapters/telegram-bot.ts similarity index 100% rename from packages/new_indexer/src/adapters/telegram-bot.ts rename to packages/indexer/src/adapters/telegram-bot.ts diff --git a/packages/new_indexer/src/backfiller.ts b/packages/indexer/src/backfiller.ts similarity index 100% rename from packages/new_indexer/src/backfiller.ts rename to packages/indexer/src/backfiller.ts diff --git a/packages/new_indexer/src/connection.ts b/packages/indexer/src/connection.ts similarity index 100% rename from packages/new_indexer/src/connection.ts rename to packages/indexer/src/connection.ts diff --git a/packages/new_indexer/src/frontfiller.ts b/packages/indexer/src/frontfiller.ts similarity index 100% rename from packages/new_indexer/src/frontfiller.ts rename to packages/indexer/src/frontfiller.ts diff --git a/packages/new_indexer/src/index.ts b/packages/indexer/src/index.ts similarity index 100% rename from packages/new_indexer/src/index.ts rename to packages/indexer/src/index.ts diff --git a/packages/new_indexer/src/logger.ts b/packages/indexer/src/logger.ts similarity index 100% rename from packages/new_indexer/src/logger.ts rename to packages/indexer/src/logger.ts diff --git a/packages/new_indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts similarity index 100% rename from packages/new_indexer/src/subscriber.ts rename to packages/indexer/src/subscriber.ts diff --git a/packages/new_indexer/src/v3_indexer/builders/swaps.ts b/packages/indexer/src/v3_indexer/builders/swaps.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/builders/swaps.ts rename to packages/indexer/src/v3_indexer/builders/swaps.ts diff --git a/packages/new_indexer/src/v3_indexer/connection.ts b/packages/indexer/src/v3_indexer/connection.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/connection.ts rename to packages/indexer/src/v3_indexer/connection.ts diff --git a/packages/new_indexer/src/v3_indexer/constants.ts b/packages/indexer/src/v3_indexer/constants.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/constants.ts rename to packages/indexer/src/v3_indexer/constants.ts diff --git a/packages/new_indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexer.ts rename to packages/indexer/src/v3_indexer/indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/account-info-indexer.ts b/packages/indexer/src/v3_indexer/indexers/account-info-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/account-info-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/account-info-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/account-logs-indexer.ts b/packages/indexer/src/v3_indexer/indexers/account-logs-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/account-logs-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/account-logs-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-instruction-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-logs-subscribe-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/amm-market/utils.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/amm-market/utils.ts rename to packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_1-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-v0_2-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts b/packages/indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/birdeye/birdeye-prices-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/common.ts b/packages/indexer/src/v3_indexer/indexers/common.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/common.ts rename to packages/indexer/src/v3_indexer/indexers/common.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/index.ts b/packages/indexer/src/v3_indexer/indexers/index.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/index.ts rename to packages/indexer/src/v3_indexer/indexers/index.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/instruction-indexer.ts b/packages/indexer/src/v3_indexer/indexers/instruction-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/instruction-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/instruction-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts b/packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts b/packages/indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/jupiter/jupiter-quotes-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts b/packages/indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/openbook-twap/openbook-twap-instruction-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts b/packages/indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-account-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts b/packages/indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/openbook-v2/openbook-v2-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts b/packages/indexer/src/v3_indexer/indexers/start-account-info-indexers.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/start-account-info-indexers.ts rename to packages/indexer/src/v3_indexer/indexers/start-account-info-indexers.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts b/packages/indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts rename to packages/indexer/src/v3_indexer/indexers/start-interval-fetch-indexers.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts b/packages/indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/start-logs-subscribe-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts b/packages/indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts rename to packages/indexer/src/v3_indexer/indexers/start-transaction-history-indexers.ts diff --git a/packages/new_indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts b/packages/indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts rename to packages/indexer/src/v3_indexer/indexers/token/token-mint-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/instruction-dispatch.ts b/packages/indexer/src/v3_indexer/instruction-dispatch.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/instruction-dispatch.ts rename to packages/indexer/src/v3_indexer/instruction-dispatch.ts diff --git a/packages/new_indexer/src/v3_indexer/match.ts b/packages/indexer/src/v3_indexer/match.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/match.ts rename to packages/indexer/src/v3_indexer/match.ts diff --git a/packages/new_indexer/src/v3_indexer/processor.ts b/packages/indexer/src/v3_indexer/processor.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/processor.ts rename to packages/indexer/src/v3_indexer/processor.ts diff --git a/packages/new_indexer/src/v3_indexer/proposal-indexer.ts b/packages/indexer/src/v3_indexer/proposal-indexer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/proposal-indexer.ts rename to packages/indexer/src/v3_indexer/proposal-indexer.ts diff --git a/packages/new_indexer/src/v3_indexer/transaction/account-resolver.ts b/packages/indexer/src/v3_indexer/transaction/account-resolver.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/transaction/account-resolver.ts rename to packages/indexer/src/v3_indexer/transaction/account-resolver.ts diff --git a/packages/new_indexer/src/v3_indexer/transaction/history.ts b/packages/indexer/src/v3_indexer/transaction/history.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/transaction/history.ts rename to packages/indexer/src/v3_indexer/transaction/history.ts diff --git a/packages/new_indexer/src/v3_indexer/transaction/serializer.test.ts b/packages/indexer/src/v3_indexer/transaction/serializer.test.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/transaction/serializer.test.ts rename to packages/indexer/src/v3_indexer/transaction/serializer.test.ts diff --git a/packages/new_indexer/src/v3_indexer/transaction/serializer.ts b/packages/indexer/src/v3_indexer/transaction/serializer.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/transaction/serializer.ts rename to packages/indexer/src/v3_indexer/transaction/serializer.ts diff --git a/packages/new_indexer/src/v3_indexer/transaction/watcher.ts b/packages/indexer/src/v3_indexer/transaction/watcher.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/transaction/watcher.ts rename to packages/indexer/src/v3_indexer/transaction/watcher.ts diff --git a/packages/new_indexer/src/v3_indexer/types/errors.ts b/packages/indexer/src/v3_indexer/types/errors.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/types/errors.ts rename to packages/indexer/src/v3_indexer/types/errors.ts diff --git a/packages/new_indexer/src/v3_indexer/types/index.ts b/packages/indexer/src/v3_indexer/types/index.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/types/index.ts rename to packages/indexer/src/v3_indexer/types/index.ts diff --git a/packages/new_indexer/src/v3_indexer/types/swaps.ts b/packages/indexer/src/v3_indexer/types/swaps.ts similarity index 100% rename from packages/new_indexer/src/v3_indexer/types/swaps.ts rename to packages/indexer/src/v3_indexer/types/swaps.ts diff --git a/packages/new_indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts similarity index 100% rename from packages/new_indexer/src/v4_indexer/indexer.ts rename to packages/indexer/src/v4_indexer/indexer.ts diff --git a/packages/new_indexer/src/v4_indexer/processor.ts b/packages/indexer/src/v4_indexer/processor.ts similarity index 100% rename from packages/new_indexer/src/v4_indexer/processor.ts rename to packages/indexer/src/v4_indexer/processor.ts diff --git a/packages/new_indexer/tsconfig.json b/packages/indexer/tsconfig.json similarity index 100% rename from packages/new_indexer/tsconfig.json rename to packages/indexer/tsconfig.json diff --git a/packages/old_indexer/Dockerfile b/packages/old_indexer/Dockerfile deleted file mode 100644 index f7f978a6..00000000 --- a/packages/old_indexer/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:alpine3.18 - -# Some of the dependencies require node-gyp -RUN apk add --no-cache python3 make g++ -RUN if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi - -# Bun requires glibc https://github.com/oven-sh/bun/issues/5545#issuecomment-1722306576 -RUN apk --no-cache add ca-certificates wget -RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk -RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk - -RUN apk add --no-cache git - -EXPOSE 8080 -RUN corepack prepare pnpm@9.12.1 --activate -RUN corepack enable -ENV REPO_DIR /home/indexer/futarchy-indexer -RUN mkdir -p $REPO_DIR -WORKDIR $REPO_DIR -COPY . . -RUN pnpm install -CMD ["pnpm", "start-service"] diff --git a/packages/old_indexer/package.json b/packages/old_indexer/package.json deleted file mode 100644 index 0cce1384..00000000 --- a/packages/old_indexer/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@metadaoproject/indexer-service", - "description": "indexer microservice", - "private": "true", - "scripts": { - "cli": "bun src/cli/index.ts", - "start": "bun src/index.ts", - "test": "bun test" - }, - "dependencies": { - "@coral-xyz/anchor": "^0.29.0", - "@debridge-finance/solana-transaction-parser": "^2.0.1", - "@lukasdeco/prom-client": "^15.1.4", - "@metadaoproject/futarchy": "^0.4.0-alpha.21", - "@metadaoproject/futarchy-sdk": "4.0.0-alpha.31", - "@metadaoproject/indexer-db": "workspace:*", - "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", - "@metaplex-foundation/umi-uploader-bundlr": "^0.9.1", - "@openbook-dex/openbook-v2": "^0.1.9", - "@orca-so/whirlpools-sdk": "^0.12.5", - "@solana/spl-token": "^0.3.8", - "@solana/web3.js": "^1.90.0", - "@types/cors": "^2.8.17", - "ansicolor": "^2.0.1", - "axios": "^1.7.2", - "bs58": "^4.0.1", - "commander": "^12.0.0", - "cors": "^2.8.5", - "croner": "^8.0.2", - "drizzle-orm": "^0.30.6", - "express": "^4.19.2", - "fastq": "^1.17.1", - "inquirer": "^9.2.14", - "jsonwebtoken": "^9.0.2", - "match-discriminated-union": "^1.0.0", - "tweetnacl": "^1.0.3", - "zod": "^3.22.4" - }, - "devDependencies": { - "@types/bs58": "^4.0.1", - "@types/express": "^4.17.21", - "@types/inquirer": "^9.0.7", - "@types/jsonwebtoken": "^9.0.6", - "@types/node": "^20.10.6", - "bun-types": "^1.0.30" - } -} diff --git a/packages/old_indexer/src/adapters/telegram-bot.ts b/packages/old_indexer/src/adapters/telegram-bot.ts deleted file mode 100644 index af64e82b..00000000 --- a/packages/old_indexer/src/adapters/telegram-bot.ts +++ /dev/null @@ -1,91 +0,0 @@ -import axios, { AxiosInstance, AxiosResponse } from "axios"; - -type TelegramBotConfig = { - token: string; -}; - -export class TelegramBotAPI implements AlertChatBotInterface { - private readonly apiUrl: string; - private readonly httpClient: AxiosInstance; - - constructor(config: TelegramBotConfig) { - this.apiUrl = `https://api.telegram.org/bot${config.token}/`; - this.httpClient = axios.create({ - baseURL: this.apiUrl, - headers: { - "Content-Type": "application/json", - }, - }); - } - - private async request( - method: "GET" | "POST", - endpoint: string, - params?: object - ): Promise | null> { - let response: AxiosResponse>; - try { - if (method === "GET") { - response = await this.httpClient.get(endpoint, { params }); - } else { - response = await this.httpClient.post(endpoint, params); - } - return response.data; - } catch (error) { - console.error( - `Failed to make request: ${error}. Method: ${method}. Endpoint: ${endpoint}` - ); - return null; - } - } - - public async getMe(): Promise | null> { - return this.request("GET", "getMe"); - } - - public async sendMessage( - chatId: number | string, - text: string - ): Promise | null> { - const params = { chat_id: chatId, text }; - try { - return this.request("POST", "sendMessage", params); - } catch (e) { - console.error(e); - return null; - } - } - - public async getUpdates( - offset?: number, - limit?: number, - timeout?: number, - allowed_updates?: string[] - ): Promise | null> { - const params = { offset, limit, timeout, allowed_updates }; - return this.request("GET", "getUpdates", params); - } - - // Add more methods as needed for other API endpoints -} - -type ChatbotApiResponse = { - ok: boolean; - result?: T; - description?: string; - error_code?: number; -}; - -export interface AlertChatBotInterface { - getMe(): Promise | null>; - sendMessage( - chatId: number | string, - text: string - ): Promise | null>; - getUpdates( - offset?: number, - limit?: number, - timeout?: number, - allowed_updates?: string[] - ): Promise | null>; -} diff --git a/packages/old_indexer/src/builders/swaps.ts b/packages/old_indexer/src/builders/swaps.ts deleted file mode 100644 index 8981a0bd..00000000 --- a/packages/old_indexer/src/builders/swaps.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { Context } from "@solana/web3.js"; -import { Err, Ok, Result, TaggedUnion } from "../match"; -import { - AmmInstructionIndexerError, - SwapPersistableError, -} from "../types/errors"; -import { schema, usingDb, eq } from "@metadaoproject/indexer-db"; -import { - OrderSide, - OrdersRecord, - // PricesRecord, - // PricesType, - TakesRecord, - TransactionRecord, -} from "@metadaoproject/indexer-db/lib/schema"; -import { BN } from "@coral-xyz/anchor"; -import { - Instruction, - SERIALIZED_TRANSACTION_LOGIC_VERSION, - Transaction, - getTransaction, - parseFormattedInstructionArgsData, - serialize, -} from "../transaction/serializer"; -import { logger } from "../logger"; -import { getMainIxTypeFromTransaction } from "../transaction/watcher"; -import { getHumanPrice } from "../usecases/math"; - -export class SwapPersistable { - private ordersRecord: OrdersRecord; - private takesRecord: TakesRecord; - private transactionRecord: TransactionRecord; - //private priceRecord: PricesRecord; - constructor( - ordersRecord: OrdersRecord, - takesRecord: TakesRecord, - transactionRecord: TransactionRecord, - //priceRecord: PricesRecord - ) { - this.ordersRecord = ordersRecord; - this.takesRecord = takesRecord; - this.transactionRecord = transactionRecord; - //this.priceRecord = priceRecord; - } - - async persist() { - try { - const upsertResult = - (await usingDb((db) => - db - .insert(schema.transactions) - .values(this.transactionRecord) - .onConflictDoUpdate({ - target: schema.transactions.txSig, - set: this.transactionRecord, - }) - .returning({ txSig: schema.transactions.txSig }) - )) ?? []; - if ( - upsertResult.length !== 1 || - upsertResult[0].txSig !== this.transactionRecord.txSig - ) { - logger.warn( - `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( - this.transactionRecord - )}` - ); - } - // Insert user if they aren't already in the database - const insertUsersResult = (await usingDb((db) => - db - .insert(schema.users) - .values({ userAcct: this.ordersRecord.actorAcct }) - .onConflictDoNothing() - .returning({ userAcct: schema.users.userAcct }) - )) ?? []; - if ( - insertUsersResult.length !== 1 || - insertUsersResult[0].userAcct !== this.ordersRecord.actorAcct - ) { - logger.warn( - `Failed to upsert user ${this.ordersRecord.actorAcct}. ${JSON.stringify( - this.ordersRecord - )}` - ); - if(insertUsersResult.length <= 0) { - logger.warn(`User already exists in db: ${this.ordersRecord.actorAcct}`); - } - } - - // const priceInsertRes = - // (await usingDb((db) => - // db - // .insert(schema.prices) - // .values(this.priceRecord) - // .onConflictDoNothing() - // .returning({ marketAcct: schema.prices.marketAcct, updatedSlot: schema.prices.updatedSlot }) - // )) ?? []; - // if ( - // priceInsertRes.length !== 1 || - // (priceInsertRes[0].marketAcct !== this.priceRecord.marketAcct && - // priceInsertRes[0].updatedSlot !== this.priceRecord.updatedSlot) - // ) { - // logger.warn( - // `Failed to insert price ${this.priceRecord.marketAcct}. ${JSON.stringify( - // this.priceRecord - // )}` - // ); - // } - const orderInsertRes = - (await usingDb((db) => - db - .insert(schema.orders) - .values(this.ordersRecord) - .onConflictDoNothing() - .returning({ txSig: schema.takes.orderTxSig }) - )) ?? []; - if (orderInsertRes.length > 0) { - console.log( - "successfully inserted swap order record", - orderInsertRes[0].txSig - ); - } else { - logger.warn( - `did not save swap order in persister. - ${this.ordersRecord.orderTxSig}` - ); - } - const takeInsertRes = - (await usingDb((db) => - db - .insert(schema.takes) - .values(this.takesRecord) - .onConflictDoNothing() - .returning({ txSig: schema.takes.orderTxSig }) - )) ?? []; - if (takeInsertRes.length > 0) { - logger.log( - `successfully inserted swap take record. - ${takeInsertRes[0].txSig}` - ); - } else { - logger.warn( - `did not save swap take record in persister. - ${this.takesRecord.orderTxSig}` - ); - } - } catch (e) { - logger.errorWithChatBotAlert(`error with persisting swap: ${e}`); - } - } -} - -export class SwapBuilder { - constructor() {} - async withSignatureAndCtx( - signature: string, - ctx: Context - ): Promise> { - try { - // first check to see if swap is already persisted - const swapOrder = - (await usingDb((db) => - db - .select() - .from(schema.orders) - .where(eq(schema.orders.orderTxSig, signature)) - .execute() - )) ?? []; - if (swapOrder.length > 0) { - return Err({ type: SwapPersistableError.AlreadyPersistedSwap }); - } - - const txRes = await getTransaction(signature); - if (!txRes.success) { - return Err({ - type: SwapPersistableError.TransactionParseError, - value: txRes.error, - }); - } - - const tx = txRes.ok; - const swapIx = tx.instructions.find((ix) => ix.name === "swap"); - if (!!swapIx) { - // sometimes we mint cond tokens for the user right before we do the swap ix - const mintIx = tx.instructions?.find( - (i) => i.name === "mintConditionalTokens" - ); - // What if there's more than one? - const mergeIx = tx.instructions?.find((i) => i.name === "mergeConditionalTokensForUnderlyingTokens"); - - if (mergeIx && mintIx) { - console.error("ARB TRANSACTION DETECTED") - return Err({ type: SwapPersistableError.ArbTransactionError }); - } - - const result = await this.buildOrderFromSwapIx(swapIx, tx, mintIx); - if (!result.success) { - return Err(result.error); - } - const { swapOrder, swapTake } = result.ok; - - // TODO: consider co-locating this logic so it can be shared - // TODO doing this twice... also doing this above - - const transactionRecord: TransactionRecord = { - txSig: signature, - slot: ctx.slot.toString(), - blockTime: new Date(tx.blockTime * 1000), // TODO need to verify if this is correct - failed: tx.err !== undefined, - payload: serialize(tx), - serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, - mainIxType: getMainIxTypeFromTransaction(tx), - }; - - // TODO: This needs smore work before it's ready - // const priceRecord: PricesRecord = { - // marketAcct: swapOrder.marketAcct, - // updatedSlot: ctx.slot.toString(), - // createdAt: transactionRecord.blockTime, - // // TODO: This doesn't have base and quote... So could be an issue.. - // price: swapTake.quotePrice, - // pricesType: PricesType.Conditional, - // } - - return Ok(new SwapPersistable(swapOrder, swapTake, transactionRecord)); // priceRecord - } - return Err({ type: SwapPersistableError.NonSwapTransaction }); - } catch (e: any) { - logger.errorWithChatBotAlert( - "swap peristable general error", - e.message - ? { - message: e.message, - stack: e.stack, - name: e.name, - cause: e.cause, - fileName: e.fileName, - lineNumber: e.lineNumber, - } - : e - ); - return Err({ type: SwapPersistableError.GeneralError }); - } - } - - async buildOrderFromSwapIx( - swapIx: Instruction, - tx: Transaction, - mintIx: Instruction | undefined - ): Promise< - Result<{ swapOrder: OrdersRecord; swapTake: TakesRecord }, TaggedUnion> - > { - if (!swapIx) return Err({ type: "missing data" }); - - const marketAcct = swapIx.accountsWithData.find((a) => a.name === "amm"); - if (!marketAcct) return Err({ type: "missing data" }); - const userAcct = swapIx.accountsWithData.find((a) => a.name === "user"); - if (!userAcct) return Err({ type: "missing data" }); - // TODO fix - const userBaseAcct = swapIx.accountsWithData.find( - (a) => a.name === "userBaseAccount" - ); - if (!userBaseAcct) return Err({ type: "missing data" }); - const userQuoteAcct = swapIx.accountsWithData.find( - (a) => a.name === "userQuoteAccount" - ); - if (!userQuoteAcct) return Err({ type: "missing data" }); - - if (!swapIx.args) return Err({ type: "missing data" }); - const swapArgs = swapIx.args.find((a) => a.type === "SwapArgs"); - if (!swapArgs) return Err({ type: "missing swap args" }); - const swapArgsParsed = parseFormattedInstructionArgsData<{ - swapType: string; - inputAmount: number; - outputAmount: number; - }>(swapArgs?.data ?? ""); - - const mintAmount = mintIx - ? mintIx.args.find((a) => a.name === "amount")?.data ?? "0" - : "0"; - // determine side - const side = - swapArgsParsed?.swapType === "Buy" ? OrderSide.BID : OrderSide.ASK; - - // get balances - const userBaseAcctWithBalances = tx.accounts.find( - (a) => a.pubkey === userBaseAcct.pubkey - ); - - const userBasePreBalance = - userBaseAcctWithBalances?.preTokenBalance?.amount ?? BigInt(0); - - const userBasePreBalanceWithPotentialMint = - side === OrderSide.ASK - ? userBasePreBalance +BigInt(Number(mintAmount)) - : userBaseAcctWithBalances?.preTokenBalance?.amount; - - const userBasePostBalance = - userBaseAcctWithBalances?.postTokenBalance?.amount; - - const userQuoteAcctWithBalances = tx.accounts.find( - (a) => a.pubkey === userQuoteAcct.pubkey - ); - - const userQuotePreBalance = - userQuoteAcctWithBalances?.preTokenBalance?.amount ?? BigInt(0); - - const userQuotePreBalanceWithPotentialMint = - side === OrderSide.BID - ? userQuotePreBalance + BigInt(Number(mintAmount)) - : userQuoteAcctWithBalances?.preTokenBalance?.amount; - - const userQuotePostBalance = - userQuoteAcctWithBalances?.postTokenBalance?.amount; - - const baseAmount = new BN( - (userBasePostBalance ?? BigInt(0)) - - (userBasePreBalanceWithPotentialMint ?? BigInt(0)) - ).abs(); - const quoteAmount = new BN( - (userQuotePostBalance ?? BigInt(0)) - - (userQuotePreBalanceWithPotentialMint ?? BigInt(0)) - ).abs(); - - if ( - !!tx.err && - quoteAmount.toString() === "0" && - baseAmount.toString() === "0" - ) { - return Err({ type: AmmInstructionIndexerError.FailedSwap }); - } - - // determine price - // NOTE: This is estimated given the output is a min expected value - // default is input / output (buying a token with USDC or whatever) - const marketAcctRecord = - (await usingDb((db) => - db - .select() - .from(schema.markets) - .where(eq(schema.markets.marketAcct, marketAcct.pubkey)) - .execute() - )) ?? []; - if (marketAcctRecord.length === 0) { - return Err({ type: AmmInstructionIndexerError.MissingMarket }); - } - const baseToken = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.mintAcct, marketAcctRecord[0].baseMintAcct)) - .execute() - )) ?? []; - if (baseToken.length === 0) { - return Err({ type: AmmInstructionIndexerError.MissingMarket }); - } - const quoteToken = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.mintAcct, marketAcctRecord[0].quoteMintAcct)) - .limit(1) - .execute() - )) ?? []; - if (baseToken.length === 0) { - return Err({ type: AmmInstructionIndexerError.MissingMarket }); - } - - let price: number | null = null; - - if (quoteAmount.toString() && baseAmount.toString()) { - console.log(quoteAmount.toString(), baseAmount.toString()); - try{ - const ammPrice = quoteAmount.mul(new BN(10).pow(new BN(12))).div(baseAmount) - - price = getHumanPrice( - ammPrice, - baseToken[0].decimals, - quoteToken[0].decimals - ); - } catch (e) { - logger.error("error getting price", e); - return Err({ type: SwapPersistableError.GeneralError }); - } - } - // TODO: Need to likely handle rounding..... - // index a swap here - - const signature = tx.signatures[0]; - const now = new Date(); - - const swapOrder: OrdersRecord = { - marketAcct: marketAcct.pubkey, - orderBlock: tx.slot.toString(), - orderTime: now, - orderTxSig: signature, - quotePrice: price?.toString() ?? "0", - actorAcct: userAcct.pubkey, - // TODO: If and only if the transaction is SUCCESSFUL does this value equal this.. - filledBaseAmount: baseAmount.toString(), - isActive: false, - side: side, - // TODO: If transaction is failed then this is the output amount... - unfilledBaseAmount: "0", - updatedAt: now, - }; - - const swapTake: TakesRecord = { - marketAcct: marketAcct.pubkey, - // This will always be the DAO / proposal base token, so while it may be NICE to have a key - // to use to reference on data aggregate, it's not directly necessary. - baseAmount: baseAmount.toString(), // NOTE: This is always the base token given we have a BASE / QUOTE relationship - orderBlock: tx.slot.toString(), - orderTime: now, - orderTxSig: signature, - quotePrice: price?.toString() ?? "0", - // TODO: this is coded into the market, in the case of our AMM, it's 1% - // this fee is based on the INPUT value (so if we're buying its USDC, selling its TOKEN) - takerBaseFee: BigInt(0), - takerQuoteFee: BigInt(0), - }; - - return Ok({ swapOrder, swapTake }); - } -} diff --git a/packages/old_indexer/src/cli/index.ts b/packages/old_indexer/src/cli/index.ts deleted file mode 100644 index 210f8a59..00000000 --- a/packages/old_indexer/src/cli/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { program } from 'commander'; -import { txw } from './txw'; - -txw(program.command('txw')) -program.parse(); diff --git a/packages/old_indexer/src/cli/txw/common/select-account.ts b/packages/old_indexer/src/cli/txw/common/select-account.ts deleted file mode 100644 index 91b29e6a..00000000 --- a/packages/old_indexer/src/cli/txw/common/select-account.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { usingDb, schema } from "@metadaoproject/indexer-db"; -import inquirer from "inquirer"; - -export async function selectAccount(): Promise { - const accounts = ( - (await usingDb((db) => db.select().from(schema.transactionWatchers))) ?? [] - ).map(({ acct }) => acct); - const prompt = inquirer.createPromptModule(); - const ACCOUNT_ANSWER = "account"; - const account: string = ( - await prompt([ - { - type: "list", - name: ACCOUNT_ANSWER, - message: "Select account to reset:", - choices: accounts, - }, - ]) - )[ACCOUNT_ANSWER]; - return account; -} diff --git a/packages/old_indexer/src/cli/txw/create.ts b/packages/old_indexer/src/cli/txw/create.ts deleted file mode 100644 index 69210eb7..00000000 --- a/packages/old_indexer/src/cli/txw/create.ts +++ /dev/null @@ -1,4 +0,0 @@ -export async function create() { - // TODO: implement creation of a tx watcher - console.log('creatooooor'); -} \ No newline at end of file diff --git a/packages/old_indexer/src/cli/txw/index.ts b/packages/old_indexer/src/cli/txw/index.ts deleted file mode 100644 index 7722099a..00000000 --- a/packages/old_indexer/src/cli/txw/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Command } from 'commander'; -import { create } from './create'; -import { reset } from './reset'; -import { validate } from './validate'; - -export function txw(cmd: Command) { - cmd - .command('reset') - .action(reset); - cmd - .command('create') - .action(create); - cmd - .command('validate') - .action(validate); -} diff --git a/packages/old_indexer/src/cli/txw/populate.ts b/packages/old_indexer/src/cli/txw/populate.ts deleted file mode 100644 index 1458c3df..00000000 --- a/packages/old_indexer/src/cli/txw/populate.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { - usingDb, - schema, - eq, - notInArray, - and, - notIlike, -} from "@metadaoproject/indexer-db"; -import { - MarketRecord, - MarketType, - TokenRecord, -} from "@metadaoproject/indexer-db/lib/schema"; -import { - ORCA_WHIRLPOOLS_CONFIG, - ORCA_WHIRLPOOL_PROGRAM_ID, - PDAUtil, - WhirlpoolContext, - buildWhirlpoolClient, -} from "@orca-so/whirlpools-sdk"; -import { PublicKey } from "@solana/web3.js"; -import { connection, readonlyWallet } from "../../connection"; -import { Err, Ok } from "../../match"; -import { - JupiterQuoteIndexingError, - fetchQuoteFromJupe, -} from "../../indexers/jupiter/jupiter-quotes-indexer"; - -import Cron from "croner"; -import { logger } from "../../logger"; - -type IndexerAccountDependency = - typeof schema.indexerAccountDependencies._.inferInsert; - -export function startIndexerAccountDependencyPopulation() { - const job = Cron("*/5 * * * *", () => { - populateIndexerAccountDependencies(); - }); - console.log("populating indexers at ", job.nextRun()); -} - -async function populateIndexerAccountDependencies() { - // populating market indexers - try { - await populateTokenMintIndexerAccountDependencies(); - await populateAmmMarketIndexerAccountDependencies(); - await populateOpenbookMarketIndexerAccountDependencies(); - await populateSpotPriceMarketIndexerAccountDependencies(); - } catch (e) { - logger.error("error populating indexers", e); - } -} -async function populateTokenMintIndexerAccountDependencies() { - const mints: TokenRecord[] = - (await usingDb((db) => db.select().from(schema.tokens).execute())) ?? []; - - for (const mint of mints) { - const newTokenMintIndexerDep: IndexerAccountDependency = { - acct: mint.mintAcct, - name: "token-mint-accounts", - latestTxSigProcessed: null, - }; - const insertRes = - (await usingDb((db) => - db - .insert(schema.indexerAccountDependencies) - .values([newTokenMintIndexerDep]) - .onConflictDoNothing() - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - if (insertRes.length > 0) { - console.log( - "successfully populated indexer dependency for token mint account:", - insertRes[0].acct - ); - } - } - - console.log("Successfully populated token mint indexers"); -} - -async function populateAmmMarketIndexerAccountDependencies() { - const ammMarkets = - (await usingDb((db) => - db - .select() - .from(schema.markets) - .where(and(eq(schema.markets.marketType, MarketType.FUTARCHY_AMM))) - .execute() - )) ?? []; - - for (const ammMarket of ammMarkets) { - const newAmmIndexerDep: IndexerAccountDependency = { - acct: ammMarket.marketAcct.toString(), - name: "amm-market-accounts", - latestTxSigProcessed: null, - }; - const newAmmIntervalIndexerDep: IndexerAccountDependency = { - acct: ammMarket.marketAcct.toString(), - name: "amm-market-accounts-fetch", - latestTxSigProcessed: null, - }; - const newAmmLogsSubscribeIndexerDep: IndexerAccountDependency = { - acct: ammMarket.marketAcct.toString(), - name: "amm-markets-logs-subscribe-indexer", - latestTxSigProcessed: null, - }; - - const ammInsertResult = - (await usingDb((db) => - db - .insert(schema.indexerAccountDependencies) - .values([ - newAmmIndexerDep, - newAmmIntervalIndexerDep, - newAmmLogsSubscribeIndexerDep, - ]) - .onConflictDoNothing() - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - if (ammInsertResult.length > 0) { - console.log( - "successfully populated indexer dependency for amm market account:", - ammInsertResult[0].acct - ); - } - } - - console.log(`Successfully populated AMM indexers`); -} - -async function populateOpenbookMarketIndexerAccountDependencies() { - const indexerAccountsQuery = - (await usingDb((db) => - db - .select({ acct: schema.indexerAccountDependencies.acct }) - .from(schema.indexerAccountDependencies) - )) ?? []; - const openbookMarkets = - (await usingDb((db) => - db - .select() - .from(schema.markets) - .where( - and( - eq(schema.markets.marketType, MarketType.OPEN_BOOK_V2), - notInArray( - schema.markets.marketAcct, - indexerAccountsQuery.map((ai) => ai.acct) - ) - ) - ) - .execute() - )) ?? []; - - for (const openbookMarket of openbookMarkets) { - const newopenbookIndexerDep: IndexerAccountDependency = { - acct: openbookMarket.marketAcct.toString(), - name: "openbook-market-accounts", - latestTxSigProcessed: null, - }; - - const openbookInsertResult = - (await usingDb((db) => - db - .insert(schema.indexerAccountDependencies) - .values(newopenbookIndexerDep) - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - if (openbookInsertResult.length > 0) { - logger.log( - "successfully populated indexer dependency for openbook market account:", - openbookInsertResult[0].acct - ); - } else { - logger.error( - "error with inserting indexer dependency for openbook market:", - openbookMarket.marketAcct - ); - } - } - - logger.log("Successfully populated openbook market indexers"); -} - -enum PopulateSpotPriceMarketErrors { - NotSupportedByJup = "NotSupportedByJup", - GeneralJupError = "GeneralJupError", -} - -async function populateSpotPriceMarketIndexerAccountDependencies() { - const baseDaoTokens = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where( - and( - notIlike(schema.tokens.name, "%proposal%"), - notInArray(schema.tokens.symbol, ["USDC", "mUSDC"]) - ) - ) - .execute() - )) ?? []; - - // Loop through each token to find its corresponding USDC market address - for (const token of baseDaoTokens) { - const result = await populateJupQuoteIndexerAndMarket(token); - // for ones that don't work on jup, do birdeye - if (!result.success) { - await populateBirdEyePricesIndexerAndMarket(token); - } - // Not enough coverage on orca for now so disabling - // await populateOrcaWhirlpoolMarket(token); - } -} - -async function populateJupQuoteIndexerAndMarket(token: { - symbol: string; - name: string; - imageUrl: string | null; - mintAcct: string; - supply: bigint; - decimals: number; - updatedAt: Date; -}) { - const { mintAcct } = token; - try { - //check to see if jupiter can support this token - const number = await fetchQuoteFromJupe(mintAcct); - if (!number) { - return Err({ type: JupiterQuoteIndexingError.JupiterFetchError }); - } - - // it is supported, so let's continue on - const [usdcToken] = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.symbol, "USDC")) - .execute() - )) ?? []; - if (!usdcToken) - return Err({ - type: JupiterQuoteIndexingError.GeneralJupiterQuoteIndexError, - }); - - const baseTokenDependency: IndexerAccountDependency = { - acct: mintAcct, - name: "jupiter-quotes", - }; - - const insertRes = - (await usingDb((db) => - db - .insert(schema.indexerAccountDependencies) - .values(baseTokenDependency) - .onConflictDoNothing() - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - - if (insertRes.length > 0) { - console.log( - "successfully inserted jupiter quote acct dep for tracking", - insertRes[0].acct - ); - } - - const jupMarket: MarketRecord = { - marketAcct: mintAcct, - baseLotSize: BigInt(0), - baseMakerFee: 0, - baseMintAcct: mintAcct, - baseTakerFee: 0, - marketType: MarketType.JUPITER_QUOTE, - quoteMintAcct: usdcToken.mintAcct, - quoteLotSize: BigInt(0), - quoteTickSize: BigInt(0), - quoteMakerFee: 0, - quoteTakerFee: 0, - createTxSig: "", - activeSlot: null, - inactiveSlot: null, - createdAt: new Date(), - }; - - const marketInserRes = - (await usingDb((db) => - db - .insert(schema.markets) - .values(jupMarket) - .onConflictDoNothing() - .returning({ acct: schema.markets.marketAcct }) - )) ?? []; - - if (marketInserRes.length > 0) { - console.log( - "successfully inserted jupiter market, markets record for tracking", - marketInserRes[0].acct - ); - } - return Ok(null); - } catch (error) { - logger.warn( - `Error populating jupiter quote indexer and market for USDC/${token.symbol}: ${error}` - ); - return Err({ type: PopulateSpotPriceMarketErrors.GeneralJupError }); - } -} - -async function populateBirdEyePricesIndexerAndMarket(token: { - symbol: string; - name: string; - imageUrl: string | null; - mintAcct: string; - supply: bigint; - decimals: number; - updatedAt: Date; -}) { - const { mintAcct } = token; - try { - const [usdcToken] = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.symbol, "USDC")) - .execute() - )) ?? []; - - if (!usdcToken) return; - - const baseTokenDependency: IndexerAccountDependency = { - acct: mintAcct, - name: "birdeye-prices", - }; - - const insertRes = - (await usingDb((db) => - db - .insert(schema.indexerAccountDependencies) - .values(baseTokenDependency) - .onConflictDoNothing() - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - - if (insertRes.length > 0) { - console.log( - "successfully inserted birdeye prices acct dep for tracking", - insertRes[0].acct - ); - } - - const birdeyeMarket: MarketRecord = { - marketAcct: mintAcct, - baseLotSize: BigInt(0), - baseMakerFee: 0, - baseMintAcct: mintAcct, - baseTakerFee: 0, - marketType: MarketType.BIRDEYE_PRICES, - quoteMintAcct: usdcToken.mintAcct, - quoteLotSize: BigInt(0), - quoteTickSize: BigInt(0), - quoteMakerFee: 0, - quoteTakerFee: 0, - createTxSig: "", - activeSlot: null, - inactiveSlot: null, - createdAt: new Date(), - }; - - const marketInserRes = - (await usingDb((db) => - db - .insert(schema.markets) - .values(birdeyeMarket) - .onConflictDoNothing() - .returning({ acct: schema.markets.marketAcct }) - )) ?? []; - - if (marketInserRes.length > 0) { - console.log( - "successfully inserted birdeye market, markets record for tracking", - marketInserRes[0].acct - ); - } - } catch (error) { - logger.error( - `Error populating birdeye quote indexer and market for USDC/${token.symbol}: ${error}` - ); - } - - console.log("successfully populate birdeye spot indexer for", token.symbol); -} - -/** - * NOT BEING USED FOR NOW. DOESN'T SUPPORT MANY PRICES WE NEED. - * @param token - */ -// async function populateOrcaWhirlpoolMarket(token: { -// symbol: string; -// name: string; -// imageUrl: string | null; -// mintAcct: string; -// supply: bigint; -// decimals: number; -// updatedAt: Date; -// }) { -// try { -// const [usdcToken] = await usingDb((db) => -// db -// .select() -// .from(schema.tokens) -// .where(eq(schema.tokens.symbol, "USDC")) -// .execute() -// ); - -// const pda = PDAUtil.getWhirlpool( -// ORCA_WHIRLPOOL_PROGRAM_ID, -// ORCA_WHIRLPOOLS_CONFIG, -// new PublicKey(token.mintAcct), -// // new PublicKey(usdcToken[0].mintAcct), -// new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), -// 128 -// ); - -// const ctx = WhirlpoolContext.from( -// connection, -// readonlyWallet, -// ORCA_WHIRLPOOL_PROGRAM_ID -// ); -// const client = buildWhirlpoolClient(ctx); -// const pool = await client.getPool(pda.publicKey); -// console.log("orca pool", pool); - -// const orcaWhirlpoolMarket: MarketRecord = { -// asksTokenAcct: token.mintAcct, -// baseLotSize: BigInt(10 ** token.decimals), -// baseMakerFee: 0, -// baseMintAcct: token.mintAcct, -// baseTakerFee: 0, -// bidsTokenAcct: usdcToken.mintAcct, -// createTxSig: "", -// marketAcct: pool.getAddress().toString(), -// marketType: MarketType.ORCA_WHIRLPOOL, -// quoteLotSize: BigInt(10 ** usdcToken.decimals), -// quoteMakerFee: 0, -// quoteMintAcct: usdcToken.mintAcct, -// quoteTakerFee: 0, -// quoteTickSize: BigInt(0), -// }; - -// const insertRes = await usingDb((db) => -// db -// .insert(schema.markets) -// .values(orcaWhirlpoolMarket) -// .onConflictDoNothing() -// .returning({ acct: schema.markets.marketAcct }) -// ); - -// if (insertRes.length > 0) { -// console.log( -// "successfully inserted whirlpool market for tracking", -// insertRes[0].acct -// ); -// } -// } catch (error) { -// logger.error( -// `Error fetching market address for USDC/${token.symbol}: ${error}` -// ); -// } -// } diff --git a/packages/old_indexer/src/cli/txw/reset.ts b/packages/old_indexer/src/cli/txw/reset.ts deleted file mode 100644 index e275eaa3..00000000 --- a/packages/old_indexer/src/cli/txw/reset.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; -import inquirer from "inquirer"; -import { selectAccount } from "./common/select-account"; -import { getTransaction } from "../../transaction/serializer"; - -export async function reset() { - const account = await selectAccount(); - const prompt = inquirer.createPromptModule(); - const TX_ANSWER = "tx"; - const transaction: string = ( - await prompt([ - { - type: "input", - name: TX_ANSWER, - message: `Reset ${account} back to transaction (empty for full reset):`, - }, - ]) - )[TX_ANSWER]; - const fullReset = !transaction; - let slotToResetTo = 0; - let txToResetTo = fullReset ? null : transaction; - if (fullReset) { - console.log(`Full reset for tx watcher on ${account}`); - const updateResult = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - latestTxSig: null, - firstTxSig: null, - checkedUpToSlot: BigInt(slotToResetTo), - }) - .where(eq(schema.transactionWatchers.acct, account)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updateResult.length !== 1) { - console.log("Failed to update record"); - console.log(JSON.stringify(updateResult)); - return; - } - } else { - const txResult = await getTransaction(transaction); - if (!txResult.success) { - console.log(`Transaction ${transaction} is invalid`); - console.log(JSON.stringify(txResult.error)); - return; - } - if (!txResult.ok.accounts.map(({ pubkey }) => pubkey).includes(account)) { - console.log( - `Transaction ${transaction} does not reference account ${account}` - ); - return; - } - // TODO: another edge case is the supplied transaction is after the progress of the watcher. That should also not be allowed. - // Until that's solved it'll probably just require another reset operation but with a valid transaction - slotToResetTo = txResult.ok.slot; - console.log( - `Resetting tx watcher on ${account} to tx ${transaction} (slot ${slotToResetTo})` - ); - txToResetTo = transaction; - const updateResult = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - latestTxSig: txToResetTo, - checkedUpToSlot: BigInt(slotToResetTo), - }) - .where(eq(schema.transactionWatchers.acct, account)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updateResult.length !== 1) { - console.log("Failed to update record"); - console.log(JSON.stringify(updateResult)); - return; - } - } - console.log(`Successfully reset`); -} diff --git a/packages/old_indexer/src/cli/txw/validate.ts b/packages/old_indexer/src/cli/txw/validate.ts deleted file mode 100644 index 977556fd..00000000 --- a/packages/old_indexer/src/cli/txw/validate.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { getTransactionHistory } from "../../transaction/history"; -import { selectAccount } from "./common/select-account"; -import { usingDb, schema, desc, count, lte } from "@metadaoproject/indexer-db"; -import { logger } from "../../logger"; - -export async function validate() { - const account = await selectAccount(); - const accountPk = new PublicKey(account); - // First we start by simply validating the counts - const latestTxResult = - (await usingDb((db) => - db - .select() - .from(schema.transactionWatcherTransactions) - .orderBy(desc(schema.transactionWatcherTransactions.slot)) - .limit(1) - )) ?? []; - const [latestTx] = latestTxResult; - if (!latestTx) { - logger.log(`No latest transaction for account ${account}`); - return; - } - const txCount = - (await usingDb((db) => - db - .select({ count: count() }) - .from(schema.transactionWatcherTransactions) - .where(lte(schema.transactionWatcherTransactions.slot, latestTx.slot)) - )) ?? []; - const totalCached = txCount[0].count; - logger.log(`Cached: ${totalCached} for ${account}`); - const history = await getTransactionHistory(accountPk, BigInt(0), { - before: latestTx.txSig, - }); - const totalFromHistory = history.length + 1; // +1 for the latest tx sig - logger.log(`History: ${totalFromHistory}`); - logger.log(totalFromHistory === totalCached ? "Match" : `No match`); - // TODO: go through history and cached and find missing ones -} diff --git a/packages/old_indexer/src/connection.ts b/packages/old_indexer/src/connection.ts deleted file mode 100644 index 47e2bd76..00000000 --- a/packages/old_indexer/src/connection.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Connection } from "@solana/web3.js"; -import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; -import { - FutarchyRPCClient, - FutarchyIndexerClient, -} from "@metadaoproject/futarchy-sdk"; -import { ConditionalVaultClient } from "@metadaoproject/futarchy/v0.3"; - -export const RPC_ENDPOINT = process.env.RPC_ENDPOINT ?? ""; -export const INDEXER_URL = process.env.INDEXER_URL ?? ""; -export const INDEXER_WSS_URL = process.env.INDEXER_WSS_URL ?? ""; -export const connection: Connection = new Connection(RPC_ENDPOINT, "confirmed"); -// the indexer will only be reading, not writing -export const readonlyWallet: Wallet = undefined as unknown as Wallet; -export const provider = new AnchorProvider(connection, readonlyWallet, { - commitment: "confirmed", -}); - -export const rpcReadClient = FutarchyRPCClient.make(provider, undefined); - -export const indexerReadClient = FutarchyIndexerClient.make( - rpcReadClient, - INDEXER_URL, - INDEXER_WSS_URL, - "" -); - -export const conditionalVaultClient = ConditionalVaultClient.createClient({ - provider, -}); diff --git a/packages/old_indexer/src/constants.ts b/packages/old_indexer/src/constants.ts deleted file mode 100644 index ad5bc692..00000000 --- a/packages/old_indexer/src/constants.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Idl } from "@coral-xyz/anchor"; -import { - AMM_PROGRAM_ID, - AUTOCRAT_PROGRAM_ID, - AmmIDL, - AutocratIDL, - CONDITIONAL_VAULT_PROGRAM_ID, - ConditionalVaultIDL, -} from "@metadaoproject/futarchy/v0.3"; - -export const SLOTS_TO_DAYS: Record = { - "648000": 3, - "2160000": 10, - "1080000": 5, -}; - -export const PROGRAM_ID_TO_IDL_MAP: Record = { - [AMM_PROGRAM_ID.toBase58()]: AmmIDL as Idl, - [AUTOCRAT_PROGRAM_ID.toBase58()]: AutocratIDL as Idl, - [CONDITIONAL_VAULT_PROGRAM_ID.toBase58()]: ConditionalVaultIDL as Idl, -}; diff --git a/packages/old_indexer/src/endpoints/get-metrics.ts b/packages/old_indexer/src/endpoints/get-metrics.ts deleted file mode 100644 index 112b3867..00000000 --- a/packages/old_indexer/src/endpoints/get-metrics.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Request, Response } from "express"; -import { Registry, collectDefaultMetrics } from "@lukasdeco/prom-client"; - -const register = new Registry(); -register.setDefaultLabels({ - app: "futarchy-indexer", -}); -collectDefaultMetrics({ - register, - excludedMetrics: [ - "nodejs_eventloop_lag_seconds", - "nodejs_heap_space_size_total_bytes", - ], -}); - -export async function getMetrics(_: Request, res: Response) { - res.setHeader("Content-Type", register.contentType); - - const data = await register.metrics(); - res.status(200).send(data); -} diff --git a/packages/old_indexer/src/index.ts b/packages/old_indexer/src/index.ts deleted file mode 100644 index ca80a5f0..00000000 --- a/packages/old_indexer/src/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { startIndexers } from "./indexers"; -import { startIndexerAccountDependencyPopulation } from "./cli/txw/populate"; -import { startTransactionWatchers } from "./transaction/watcher"; -import { startServer } from "./server"; - -startServer(); -startIndexerAccountDependencyPopulation(); - -await startTransactionWatchers(); -await startIndexers(); diff --git a/packages/old_indexer/src/indexers/account-info-indexer.ts b/packages/old_indexer/src/indexers/account-info-indexer.ts deleted file mode 100644 index 29f127e6..00000000 --- a/packages/old_indexer/src/indexers/account-info-indexer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; -import { Result, TaggedUnion } from "../match"; -export type AccountInfoIndexer = { - index( - accountInfo: AccountInfo, - account: PublicKey, - context: Context - ): Promise< - Result< - { - acct: string; - }, - TaggedUnion - > - >; -}; diff --git a/packages/old_indexer/src/indexers/account-logs-indexer.ts b/packages/old_indexer/src/indexers/account-logs-indexer.ts deleted file mode 100644 index fcc2950f..00000000 --- a/packages/old_indexer/src/indexers/account-logs-indexer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Context, Logs, PublicKey } from "@solana/web3.js"; -import { Result, TaggedUnion } from "../match"; -export type AccountLogsIndexer = { - index( - logs: Logs, - account: PublicKey, - context: Context - ): Promise< - Result< - { - acct: string; - }, - TaggedUnion - > - >; -}; diff --git a/packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts deleted file mode 100644 index d54a4c28..00000000 --- a/packages/old_indexer/src/indexers/amm-market/amm-market-account-indexer.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { AccountInfoIndexer } from "../account-info-indexer"; -import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; -import { Err, Ok } from "../../match"; -import { indexAmmMarketAccountWithContext } from "./utils"; -import { logger } from "../../logger"; - -export enum AmmAccountIndexerError { - GeneralError = "GeneralError", -} - -export const AmmMarketAccountUpdateIndexer: AccountInfoIndexer = { - index: async ( - accountInfo: AccountInfo, - account: PublicKey, - context: Context - ) => { - try { - const res = await indexAmmMarketAccountWithContext( - accountInfo, - account, - context - ); - - if (res.success) { - logger.log(res.ok); - return Ok({ acct: account.toBase58() }); - } - return res; - } catch (e) { - logger.errorWithChatBotAlert( - "general error with indexing amm market account info:", - e - ); - return Err({ type: AmmAccountIndexerError.GeneralError }); - } - }, -}; diff --git a/packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts deleted file mode 100644 index ad3b511b..00000000 --- a/packages/old_indexer/src/indexers/amm-market/amm-market-account-interval-indexer.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { Err, Ok, Result } from "../../match"; -import { indexAmmMarketAccountWithContext } from "./utils"; -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { connection } from "../../connection"; -import { logger } from "../../logger"; -import { AmmMarketAccountIndexingErrors } from "./utils"; - -export enum AmmAccountIntervalIndexerError { - General = "General", - InvalidRPCResponse = "InvalidRPCResponse", - BlankAccountAddr = "BlankAccountAddr", -} - -export const AmmMarketAccountIntervalFetchIndexer: IntervalFetchIndexer = { - cronExpression: "50 * * * * *", - retries: 3, - index: async (acct: string) => { - if (acct === "") { - return Err({ - type: AmmAccountIntervalIndexerError.BlankAccountAddr, - }); - } - try { - const account = new PublicKey(acct); - const resWithContext = await connection.getAccountInfoAndContext(account); - if (!resWithContext.value) { - return Err({ - type: AmmAccountIntervalIndexerError.InvalidRPCResponse, - }); - } - - const res = await indexAmmMarketAccountWithContext( - resWithContext.value, - account, - resWithContext.context - ); - - if (res.success) { - logger.log(res.ok); - return Ok({ acct: account.toBase58() }); - } - return res; - } catch (e) { - if ( - e instanceof Object && - 'success' in e && - !e.success && - 'error' in e && - typeof e.error === 'object' && - e.error !== null && - 'type' in e.error - ) { - if (e.error.type === AmmMarketAccountIndexingErrors.AmmV4TwapIndexError) { - logger.error("failed to index amm twap for v4 amm", acct); - } else { - logger.errorWithChatBotAlert("general error with indexing amm market account info interval fetcher:", e); - } - } else { - logger.errorWithChatBotAlert("general error with indexing amm market account info interval fetcher:", e); - } - return Err({ type: AmmAccountIntervalIndexerError.General }); - } - }, -}; diff --git a/packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts deleted file mode 100644 index 7f833a41..00000000 --- a/packages/old_indexer/src/indexers/amm-market/amm-market-instruction-indexer.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { VersionedTransactionResponse } from "@solana/web3.js"; -import { Err, Ok, Result, TaggedUnion } from "../../match"; -import { TransactionRecord } from "@metadaoproject/indexer-db/lib/schema"; -import { AMM_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; -import { InstructionIndexer } from "../instruction-indexer"; -import { - AmmInstructionIndexerError, - SwapPersistableError, -} from "../../types/errors"; -import { ammClient, IDL } from "../common"; -import { SwapBuilder } from "../../builders/swaps"; -import { logger } from "../../logger"; -import { GetTransactionErrorType } from "../../transaction/serializer"; - -export const AmmMarketInstructionsIndexer: InstructionIndexer = { - PROGRAM_ID: AMM_PROGRAM_ID.toString(), - PROGRAM_IDL: ammClient.program.idl, - PROGRAM_NAME: "amm", - indexInstruction: async ( - transactionIndex: number, - transactionResponse: VersionedTransactionResponse, - instructionIndex: number, - decodedInstruction: IDL["instructions"][number] - ) => { - return Ok({ txSig: "" }); - }, - async indexTransactionSig(transaction: TransactionRecord): Promise< - Result< - { - txSig: string; - }, - TaggedUnion - > - > { - const builder = new SwapBuilder(); - const buildRes = await builder.withSignatureAndCtx(transaction.txSig, { - slot: Number(transaction.slot), - }); - if (!buildRes.success) { - if ( - buildRes.error.type === SwapPersistableError.NonSwapTransaction || - buildRes.error.type === SwapPersistableError.AlreadyPersistedSwap || - buildRes.error.type === SwapPersistableError.ArbTransactionError || - buildRes.error.type === AmmInstructionIndexerError.FailedSwap || - (buildRes.error.type === SwapPersistableError.TransactionParseError && - buildRes.error.value?.type === - GetTransactionErrorType.NullGetTransactionResponse) || - buildRes.error.type === SwapPersistableError.PriceError - ) { - logger.error( - `error with indexing amm transaction ${transaction.txSig}`, - buildRes.error - ); - } else { - logger.errorWithChatBotAlert( - `error with indexing amm transaction ${transaction.txSig}`, - buildRes.error - ); - } - return Err({ type: AmmInstructionIndexerError.GeneralError }); - } - const persistable = buildRes.ok; - await persistable.persist(); - return Ok({ txSig: transaction.txSig }); - }, -}; diff --git a/packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts b/packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts deleted file mode 100644 index 1946b6bc..00000000 --- a/packages/old_indexer/src/indexers/amm-market/amm-market-logs-subscribe-indexer.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Context, Logs, PublicKey } from "@solana/web3.js"; -import { Err, Ok } from "../../match"; -import { AccountLogsIndexer } from "../account-logs-indexer"; -import { SwapBuilder } from "../../builders/swaps"; -import { logger } from "../../logger"; -import { SwapPersistableError } from "../../types/errors"; -import { GetTransactionErrorType } from "../../transaction/serializer"; - -export enum AmmAccountLogsIndexerError { - GeneralError = "GeneralError", -} - -export const AmmMarketLogsSubscribeIndexer: AccountLogsIndexer = { - index: async (logs: Logs, account: PublicKey, context: Context) => { - const builder = new SwapBuilder(); - const buildRes = await builder.withSignatureAndCtx(logs.signature, context); - if (!buildRes.success) { - if ( - buildRes.error.type === SwapPersistableError.NonSwapTransaction || - buildRes.error.type === SwapPersistableError.AlreadyPersistedSwap || - (buildRes.error.type === SwapPersistableError.TransactionParseError && - buildRes.error.value?.type === - GetTransactionErrorType.NullGetTransactionResponse) || - buildRes.error.type === SwapPersistableError.PriceError || - buildRes.error.type === SwapPersistableError.ArbTransactionError - ) { - logger.error( - `error with indexing amm logs, signature: ${logs.signature}`, - buildRes.error - ); - } else { - logger.errorWithChatBotAlert( - `error with indexing amm logs, signature: ${logs.signature}`, - buildRes.error - ); - } - return Err({ - type: AmmAccountLogsIndexerError.GeneralError, - value: buildRes.error.type + " " + buildRes.error.value, - }); - } - const persistable = buildRes.ok; - await persistable.persist(); - return Ok({ acct: account.toBase58() }); - }, -}; diff --git a/packages/old_indexer/src/indexers/amm-market/utils.ts b/packages/old_indexer/src/indexers/amm-market/utils.ts deleted file mode 100644 index eeb11945..00000000 --- a/packages/old_indexer/src/indexers/amm-market/utils.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { BN } from "@coral-xyz/anchor"; -import { BN_0, enrichTokenMetadata } from "@metadaoproject/futarchy-sdk"; -import { PriceMath } from "@metadaoproject/futarchy/v0.4"; -import { schema, usingDb, eq } from "@metadaoproject/indexer-db"; -import { PricesType } from "@metadaoproject/indexer-db/lib/schema"; -import { - TwapRecord, - PricesRecord, -} from "@metadaoproject/indexer-db/lib/schema"; -import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; -import { provider, rpcReadClient } from "../../connection"; -import { Err, Ok, Result, TaggedUnion } from "../../match"; -import { logger } from "../../logger"; -import { getHumanPrice } from "../../usecases/math"; - -export enum AmmMarketAccountIndexingErrors { - AmmTwapIndexError = "AmmTwapIndexError", - MarketMissingError = "MarketMissingError", - AmmV4TwapIndexError = "AmmV4TwapIndexError", - AmmTwapPriceError = "AmmTwapPriceError", - AmmTwapNoInsertError = "AmmTwapNoInsertError", -} - -export async function indexAmmMarketAccountWithContext( - accountInfo: AccountInfo, - account: PublicKey, - context: Context -): Promise> { - const ammMarketAccount = await rpcReadClient.markets.amm.decodeMarket( - accountInfo - ); - const baseToken = await enrichTokenMetadata( - ammMarketAccount.baseMint, - provider - ); - const quoteToken = await enrichTokenMetadata( - ammMarketAccount.quoteMint, - provider - ); - - // if we don't have an oracle.aggregator of 0 let's run this mf - if (ammMarketAccount.oracle.aggregator.toString() !== BN_0.toString()) { - // indexing the twap - const market = await usingDb((db) => - db - .select() - .from(schema.markets) - .where(eq(schema.markets.marketAcct, account.toBase58())) - .execute() - ); - if (market === undefined || market.length === 0) { - return Err({ type: AmmMarketAccountIndexingErrors.MarketMissingError }); - } - - const twapCalculation: BN = ammMarketAccount.oracle.aggregator.div( - ammMarketAccount.oracle.lastUpdatedSlot.sub( - ammMarketAccount.createdAtSlot - ) - ); - - const proposalAcct = market[0].proposalAcct; - - // if (proposalAcct === null) { - // logger.error("failed to index amm twap for v4 amm", account.toBase58()); - // return Err({ type: AmmMarketAccountIndexingErrors.AmmV4TwapIndexError }); - // } - const twapNumber: string = twapCalculation.toString(); - const newTwap: TwapRecord = { - curTwap: twapNumber, - marketAcct: account.toBase58(), - observationAgg: ammMarketAccount.oracle.aggregator.toString(), - proposalAcct: proposalAcct, - // alternatively, we could pass in the context of the update here - updatedSlot: context - ? context.slot.toString() - : ammMarketAccount.oracle.lastUpdatedSlot.toString(), - lastObservation: ammMarketAccount.oracle.lastObservation.toString(), - lastPrice: ammMarketAccount.oracle.lastPrice.toString(), - }; - - try{ - // TODO batch commits across inserts - maybe with event queue - const twapUpsertResult = await usingDb((db) => - db - .insert(schema.twaps) - .values(newTwap) - .onConflictDoNothing() - .returning({ marketAcct: schema.twaps.marketAcct }) - ); - - if (twapUpsertResult === undefined || twapUpsertResult.length === 0) { - logger.error("failed to upsert twap", newTwap); - // return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapNoInsertError }); - } - } catch (e) { - logger.error("failed to upsert twap", e); - return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapNoInsertError }); - } - } - - let priceFromReserves: BN; - - if (ammMarketAccount.baseAmount.toNumber() === 0 || ammMarketAccount.baseAmount.toNumber() === 0) { - logger.error("NO RESERVES", ammMarketAccount); - return Ok("no price from reserves"); - } - - try { - priceFromReserves = PriceMath.getAmmPriceFromReserves( - ammMarketAccount.baseAmount, - ammMarketAccount.quoteAmount - ); - } catch (e) { - logger.error("failed to get price from reserves", e); - return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); - } - - let conditionalMarketSpotPrice: number; - try { - conditionalMarketSpotPrice = getHumanPrice( - priceFromReserves, - baseToken.decimals!!, - quoteToken.decimals!! - ); - } catch (e) { - logger.error("failed to get human price", e); - return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); - } - - const newAmmConditionaPrice: PricesRecord = { - marketAcct: account.toBase58(), - updatedSlot: context - ? context.slot.toString() - : ammMarketAccount.oracle.lastUpdatedSlot.toString(), - price: conditionalMarketSpotPrice.toString(), - pricesType: PricesType.Conditional, - createdBy: "amm-market-indexer", - baseAmount: ammMarketAccount.baseAmount.toString(), - quoteAmount: ammMarketAccount.quoteAmount.toString(), - }; - - const pricesInsertResult = await usingDb((db) => - db - .insert(schema.prices) - .values(newAmmConditionaPrice) - .onConflictDoUpdate({ - target: [schema.prices.createdAt, schema.prices.marketAcct], - set: newAmmConditionaPrice, - }) - .returning({ marketAcct: schema.prices.marketAcct }) - ); - if (pricesInsertResult === undefined || pricesInsertResult.length === 0) { - logger.error("failed to index amm price", newAmmConditionaPrice.marketAcct); - return Err({ type: AmmMarketAccountIndexingErrors.AmmTwapPriceError }); - } - - return Ok(`successfully indexed amm: ${account.toBase58()}`); -} diff --git a/packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts deleted file mode 100644 index 3deb8588..00000000 --- a/packages/old_indexer/src/indexers/autocrat/autocrat-dao-indexer.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { rpcReadClient, connection } from "../../connection"; -import { usingDb, schema } from "@metadaoproject/indexer-db"; -import { Dao } from "@metadaoproject/futarchy-sdk"; -import { Err, Ok } from "../../match"; -import { PublicKey } from "@solana/web3.js"; -import { DaoRecord, TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; -import { getMint } from "@solana/spl-token"; -import { logger } from "../../logger"; - -export enum AutocratDaoIndexerError { - GeneralError = "GeneralError", - DuplicateError = "DuplicateError", - MissingParamError = "MissingParamError", - NotFoundError = "NotFoundError", - MissingChainResponseError = "MissingChainResponseError", - NothingToInsertError = "NothingToInsertError", -} - -export const AutocratDaoIndexer: IntervalFetchIndexer = { - cronExpression: "*/20 * * * * *", - index: async () => { - try { - // Fetches all daos from the database - const dbDaos: DaoRecord[] = - (await usingDb((db) => db.select().from(schema.daos).execute())) ?? []; - const onChainDaos = await rpcReadClient.daos.fetchAllDaos(); - - const daosToInsert: Dao[] = []; - for (const daoAggregate of onChainDaos) { - for (const dao of daoAggregate.daos) { - // if ( - // !dbDaos.find((dbDao) => - // new PublicKey(dbDao.daoAcct).equals(dao.publicKey) - // ) - // ) { - // daosToInsert.push(dao); - // } - daosToInsert.push(dao); - } - } - - console.log("DAOS to insert"); - console.log(daosToInsert.map((dao) => dao.publicKey.toString())); - - daosToInsert.map(async (dao) => { - if ( - dao.baseToken.publicKey == null || - dao.quoteToken.publicKey == null - ) { - logger.error("Unable to determine public key for dao tokens"); - return Err({ type: AutocratDaoIndexerError.MissingParamError }); - } - // const baseTokenData = await enrichTokenMetadata( - // new PublicKey(dao.baseToken.publicKey), - // provider - // ); - const baseTokenMint = await getMint( - connection, - new PublicKey(dao.baseToken.publicKey) - ); - - // Puts the base tokens into the DB before we try to insert the dao - let token: TokenRecord = { - symbol: dao.baseToken.symbol, - name: dao.baseToken.name ? dao.baseToken.name : dao.baseToken.symbol, - decimals: dao.baseToken.decimals, - mintAcct: dao.baseToken.publicKey, - supply: baseTokenMint.supply.toString(), - updatedAt: new Date(), - }; - - await usingDb((db) => - db.insert(schema.tokens).values(token).onConflictDoNothing().execute() - ); - - let daoToInsert: DaoRecord = { - daoAcct: dao.publicKey.toBase58(), - programAcct: dao.protocol.autocrat.programId.toString(), - baseAcct: dao.baseToken.publicKey, - quoteAcct: dao.quoteToken.publicKey, - slotsPerProposal: dao.daoAccount.slotsPerProposal.toString(), - treasuryAcct: dao.daoAccount.treasury.toBase58(), - minBaseFutarchicLiquidity: - dao.daoAccount.minBaseFutarchicLiquidity - ? dao.daoAccount.minBaseFutarchicLiquidity.toString() - : 0 - , - minQuoteFutarchicLiquidity: - dao.daoAccount.minQuoteFutarchicLiquidity - ? dao.daoAccount.minQuoteFutarchicLiquidity.toString() - : 0 - , - passThresholdBps: BigInt(dao.daoAccount.passThresholdBps), - twapInitialObservation: - dao.daoAccount.twapInitialObservation - ? dao.daoAccount.twapInitialObservation.toString() - : 0 - , - twapMaxObservationChangePerUpdate: - dao.daoAccount.twapMaxObservationChangePerUpdate - ? dao.daoAccount.twapMaxObservationChangePerUpdate.toString() - : 0 - , - }; - // After we have the token in the DB, we can now insert the dao - await usingDb((db) => - db - .insert(schema.daos) - .values(daoToInsert) - .onConflictDoUpdate({ - set: { - minBaseFutarchicLiquidity: - daoToInsert.minBaseFutarchicLiquidity, - minQuoteFutarchicLiquidity: - daoToInsert.minQuoteFutarchicLiquidity, - twapInitialObservation: daoToInsert.twapInitialObservation, - twapMaxObservationChangePerUpdate: - daoToInsert.twapMaxObservationChangePerUpdate, - passThresholdBps: daoToInsert.passThresholdBps, - }, - target: schema.daos.daoAcct, - }) - .execute() - ); - }); - - return Ok({ acct: "Updated daos" }); - } catch (err) { - logger.errorWithChatBotAlert(err); - return Err({ type: AutocratDaoIndexerError.GeneralError }); - } - }, -}; diff --git a/packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts deleted file mode 100644 index 84047d27..00000000 --- a/packages/old_indexer/src/indexers/autocrat/autocrat-proposal-indexer.ts +++ /dev/null @@ -1,946 +0,0 @@ -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { - rpcReadClient, - conditionalVaultClient, - provider, -} from "../../connection"; -import { - usingDb, - schema, - eq, - or, - gt, - lte, - and, - isNull, - sql, - inArray, -} from "@metadaoproject/indexer-db"; -import { Err, Ok } from "../../match"; -import { PublicKey } from "@solana/web3.js"; -import { - ConditionalVaultRecord, - DaoRecord, - MarketRecord, - MarketType, - ProposalRecord, - ProposalStatus, - TokenAcctRecord, - TokenRecord, - UserPerformanceRecord, -} from "@metadaoproject/indexer-db/lib/schema"; -import { - getAccount, - getAssociatedTokenAddressSync, - getMint, -} from "@solana/spl-token"; -import { - ProposalAccountWithKey, - enrichTokenMetadata, -} from "@metadaoproject/futarchy-sdk"; -import { BN } from "@coral-xyz/anchor"; -import { gte } from "drizzle-orm"; -import { desc } from "drizzle-orm"; -import { logger } from "../../logger"; -import { PriceMath, ProposalAccount } from "@metadaoproject/futarchy/v0.3"; -import { UserPerformance, UserPerformanceTotals } from "../../types"; -import { alias } from "drizzle-orm/pg-core"; -import { bigint } from "drizzle-orm/mysql-core"; - -export enum AutocratDaoIndexerError { - GeneralError = "GeneralError", - DuplicateError = "DuplicateError", - MissingParamError = "MissingParamError", - MissingProtocolError = "MissingProtocolError", - NotFoundError = "NotFoundError", - MissingChainResponseError = "MissingChainResponseError", - NothingToInsertError = "NothingToInsertError", -} - -export const AutocratProposalIndexer: IntervalFetchIndexer = { - cronExpression: "5 * * * * *", - index: async () => { - try { - const { currentSlot, currentTime } = - ( - await usingDb((db) => - db - .select({ - currentSlot: schema.prices.updatedSlot, - currentTime: schema.prices.createdAt, - }) - .from(schema.prices) - .orderBy(sql`${schema.prices.updatedSlot} DESC`) - .limit(1) - .execute() - ) - )?.[0] ?? {}; - - console.log("currentSlot", currentSlot); - if (!currentSlot || !currentTime) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - logger.log("Autocrat proposal indexer"); - const dbProposals: ProposalRecord[] = - (await usingDb((db) => db.select().from(schema.proposals).execute())) ?? - []; - - const protocolV0_3 = rpcReadClient.futarchyProtocols.find( - (protocol) => protocol.deploymentVersion == "V0.3" - ); - - const onChainProposals = - (await protocolV0_3?.autocrat.account.proposal.all()!!) as ProposalAccountWithKey[]; - - const proposalsToInsert = []; - for (const proposal of onChainProposals) { - if ( - !dbProposals.find((dbProposal) => - new PublicKey(dbProposal.proposalAcct).equals(proposal.publicKey) && - dbProposal.endedAt === null - ) - ) { - proposalsToInsert.push(proposal); - } - } - - logger.log("Proposals to insert"); - logger.log( - proposalsToInsert.map((proposal) => proposal.publicKey.toString()) - ); - - if(!onChainProposals.length) return Err({ type: AutocratDaoIndexerError.NothingToInsertError }); - - if(!proposalsToInsert.length) return Ok({ acct: "Nothing to insert, we're okay" }); - - proposalsToInsert.map(async (proposal) => { - const storedBaseVault = await conditionalVaultClient.getVault( - proposal.account.baseVault - ); - const storedQuoteVault = await conditionalVaultClient.getVault( - proposal.account.quoteVault - ); - - - const basePass: PublicKey = - storedBaseVault.conditionalOnFinalizeTokenMint; - const baseFail: PublicKey = - storedBaseVault.conditionalOnRevertTokenMint; - const quotePass: PublicKey = - storedQuoteVault.conditionalOnFinalizeTokenMint; - const quoteFail: PublicKey = - storedQuoteVault.conditionalOnRevertTokenMint; - - let baseVault: ConditionalVaultRecord = { - condVaultAcct: proposal.account.baseVault.toString(), - settlementAuthority: storedBaseVault.settlementAuthority.toString(), - underlyingMintAcct: storedBaseVault.underlyingTokenMint.toString(), - underlyingTokenAcct: - storedBaseVault.underlyingTokenAccount.toString(), - condFinalizeTokenMintAcct: basePass.toString(), - condRevertTokenMintAcct: baseFail.toString(), - status: "active", - }; - - let quoteVault: ConditionalVaultRecord = { - condVaultAcct: proposal.account.quoteVault.toString(), - settlementAuthority: storedQuoteVault.settlementAuthority.toString(), - underlyingMintAcct: storedQuoteVault.underlyingTokenMint.toString(), - underlyingTokenAcct: - storedQuoteVault.underlyingTokenAccount.toString(), - condFinalizeTokenMintAcct: quotePass.toString(), - condRevertTokenMintAcct: quoteFail.toString(), - status: "active", - }; - - await usingDb((db) => - db - .insert(schema.conditionalVaults) - .values([baseVault, quoteVault]) - .onConflictDoNothing() - .execute() - ); - - const proposalAcct = proposal.account; - const daoAcct = proposalAcct.dao; - if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - const passAmm = proposalAcct.passAmm; - const failAmm = proposalAcct.failAmm; - if(!passAmm || !failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - - const dbDao: DaoRecord | undefined = ( - await usingDb((db) => - db - .select() - .from(schema.daos) - .where(eq(schema.daos.daoAcct, daoAcct.toBase58())) - .execute() - ) - )?.[0]; - - if (!dbDao) return; - - const dbProposal: ProposalRecord = { - proposalAcct: proposal.publicKey.toString(), - proposalNum: BigInt(proposal.account.number.toString()), - autocratVersion: 0.3, - daoAcct: daoAcct.toString(), - proposerAcct: proposal.account.proposer.toString(), - status: ProposalStatus.Pending, - descriptionURL: proposal.account.descriptionUrl, - initialSlot: proposal.account.slotEnqueued.toString(), - passMarketAcct: passAmm.toString(), - failMarketAcct: failAmm.toString(), - baseVault: proposal.account.baseVault.toString(), - quoteVault: proposal.account.quoteVault.toString(), - endSlot: - proposal.account.slotEnqueued - .add(new BN(dbDao.slotsPerProposal?.toString())) - .toString() - , - durationInSlots: dbDao.slotsPerProposal, - minBaseFutarchicLiquidity: dbDao.minBaseFutarchicLiquidity ?? null, - minQuoteFutarchicLiquidity: dbDao.minQuoteFutarchicLiquidity ?? null, - passThresholdBps: dbDao.passThresholdBps, - twapInitialObservation: dbDao.twapInitialObservation ?? null, - twapMaxObservationChangePerUpdate: - dbDao.twapMaxObservationChangePerUpdate ?? null, - }; - - await usingDb((db) => - db - .insert(schema.proposals) - .values([dbProposal]) - .onConflictDoNothing() - .execute() - ); - await insertAssociatedAccountsDataForProposal(proposal, currentTime); - }); - - logger.log("inserted proposals"); - - for (const onChainProposal of onChainProposals) { - if (onChainProposal.account.state.pending) { - - const daoAcct = onChainProposal.account.dao; - if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - const dbDao: DaoRecord | undefined = ( - await usingDb((db) => - db - .select() - .from(schema.daos) - .where( - eq( - schema.daos.daoAcct, - daoAcct.toBase58() - ) - ) - .execute() - ) - )?.[0]; - - if (!dbDao) continue; - - // Setup for calculating time left - const initialSlot = new BN(onChainProposal.account.slotEnqueued.toString()); - - const slotsPerProposal = new BN(dbDao.slotsPerProposal?.toString()); - - //const endSlot: BN = initialSlot.add(slotsPerProposal); - - const currentSlotBN = new BN(currentSlot.toString()); - - const slotDifference = initialSlot - .add(slotsPerProposal) - .sub(currentSlotBN); - - // Setup time to add to the date.. - const timeLeftSecondsEstimate = (slotDifference.toNumber() * 400) / 1000 // MS to seconds - // const timeLeftMinutesEstimate = timeLeftSecondsEstimate / 60 // MS to seconds to minutes - // const timeLeftHoursEstimate = timeLeftMinutesEstimate / 60 - - const endedAt = new Date(currentTime.toUTCString()); - // endedAt.setHours(endedAt.getHours() + timeLeftHoursEstimate); - // endedAt.setMinutes(endedAt.getMinutes() + timeLeftMinutesEstimate); - endedAt.setSeconds(endedAt.getSeconds() + timeLeftSecondsEstimate); // setSeconds accepts float and will increase to hours etc. - - await usingDb((db) => - db - .update(schema.proposals) - .set({ - endedAt, - proposalAcct: onChainProposal.publicKey.toString(), - proposalNum: BigInt(onChainProposal.account.number.toString()), - autocratVersion: 0.3, - status: ProposalStatus.Pending, - descriptionURL: onChainProposal.account.descriptionUrl, - initialSlot: - onChainProposal.account.slotEnqueued.toString() - , - endSlot: - onChainProposal.account.slotEnqueued - .add(new BN(dbDao.slotsPerProposal?.toString())) - .toString() - , - updatedAt: sql`NOW()`, - }) - .where( - and( - eq( - schema.proposals.proposalAcct, - onChainProposal.publicKey.toString() - ), - sql`CAST(${schema.proposals.endSlot} AS NUMERIC) >= CAST(${currentSlot.toString()} AS NUMERIC)`, - isNull(schema.proposals.completedAt) - ) - ) - .execute() - ); - } - if (onChainProposal.account.state.passed) { - await usingDb((db) => - db - .update(schema.proposals) - .set({ status: ProposalStatus.Passed, completedAt: currentTime }) - .where( - and( - eq( - schema.proposals.proposalAcct, - onChainProposal.publicKey.toString() - ), - isNull(schema.proposals.completedAt) - ) - ) - .execute() - ); - - await usingDb((db) => - db - .update(schema.conditionalVaults) - .set({ status: "finalized" }) - .where( - eq( - schema.conditionalVaults.condVaultAcct, - onChainProposal.account.baseVault.toString() - ) - ) - .execute() - ); - - await usingDb((db) => - db - .update(schema.conditionalVaults) - .set({ status: "finalized" }) - .where( - eq( - schema.conditionalVaults.condVaultAcct, - onChainProposal.account.quoteVault.toString() - ) - ) - .execute() - ); - - await calculateUserPerformance(onChainProposal); - } - if (onChainProposal.account.state.failed) { - await usingDb((db) => - db - .update(schema.proposals) - .set({ status: ProposalStatus.Failed, completedAt: currentTime }) - .where( - and( - eq( - schema.proposals.proposalAcct, - onChainProposal.publicKey.toString() - ), - isNull(schema.proposals.completedAt) - ) - ) - .execute() - ); - - await usingDb((db) => - db - .update(schema.conditionalVaults) - .set({ status: "reverted" }) - .where( - eq( - schema.conditionalVaults.condVaultAcct, - onChainProposal.account.baseVault.toString() - ) - ) - .execute() - ); - - await usingDb((db) => - db - .update(schema.conditionalVaults) - .set({ status: "reverted" }) - .where( - eq( - schema.conditionalVaults.condVaultAcct, - onChainProposal.account.quoteVault.toString() - ) - ) - .execute() - ); - await calculateUserPerformance(onChainProposal); - } - - // check if markets are there, if they aren't insert them - // Check if markets are there, if they aren't, insert them - const passAmm = onChainProposal.account.passAmm; - const failAmm = onChainProposal.account.failAmm; - if(!passAmm || !failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - const existingMarkets = - (await usingDb((db) => - db - .select() - .from(schema.markets) - .where( - or( - eq( - schema.markets.marketAcct, - passAmm.toString() - ), - eq( - schema.markets.marketAcct, - failAmm.toString() - ) - ) - ) - .execute() - )) ?? []; - - if ( - !existingMarkets.some( - (market) => - market.marketAcct === passAmm.toString() - ) || - !existingMarkets.some( - (market) => - market.marketAcct === failAmm.toString() - ) - ) { - await insertAssociatedAccountsDataForProposal( - onChainProposal, - currentTime - ); - } - } - - logger.log("updated proposal and vault states"); - - return Ok({ acct: "Update proposal and vault states" }); - } catch (err) { - logger.error("error with proposal indexer:", err); - return Err({ type: AutocratDaoIndexerError.GeneralError }); - } - }, -}; - -async function insertAssociatedAccountsDataForProposal( - proposal: ProposalAccountWithKey, - currentTime: Date -) { - - const daoAcct = proposal.account.dao; - if(!daoAcct) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - const dao = - (await usingDb((db) => - db - .select() - .from(schema.daos) - .where(eq(schema.daos.daoAcct, daoAcct.toBase58())) - .execute() - )) ?? []; - - let daoDetails; - if (dao.length > 0) { - const daoId = dao[0].daoId; - if (daoId) { - daoDetails = await usingDb((db) => - db - .select() - .from(schema.daoDetails) - .where(eq(schema.daoDetails.daoId, daoId)) - .execute() - ); - } - } - - const baseTokenMetadata = await enrichTokenMetadata( - new PublicKey(dao[0].baseAcct), - provider - ); - - const storedBaseVault = await conditionalVaultClient.getVault( - proposal.account.baseVault - ); - const storedQuoteVault = await conditionalVaultClient.getVault( - proposal.account.quoteVault - ); - - const basePass: PublicKey = storedBaseVault.conditionalOnFinalizeTokenMint; - const baseFail: PublicKey = storedBaseVault.conditionalOnRevertTokenMint; - const quotePass: PublicKey = storedQuoteVault.conditionalOnFinalizeTokenMint; - const quoteFail: PublicKey = storedQuoteVault.conditionalOnRevertTokenMint; - - let baseVault: ConditionalVaultRecord = { - condVaultAcct: proposal.account.baseVault.toString(), - settlementAuthority: storedBaseVault.settlementAuthority.toString(), - underlyingMintAcct: storedBaseVault.underlyingTokenMint.toString(), - underlyingTokenAcct: storedBaseVault.underlyingTokenAccount.toString(), - condFinalizeTokenMintAcct: basePass.toString(), - condRevertTokenMintAcct: baseFail.toString(), - status: "active", - }; - - let quoteVault: ConditionalVaultRecord = { - condVaultAcct: proposal.account.quoteVault.toString(), - settlementAuthority: storedQuoteVault.settlementAuthority.toString(), - underlyingMintAcct: storedQuoteVault.underlyingTokenMint.toString(), - underlyingTokenAcct: storedQuoteVault.underlyingTokenAccount.toString(), - condFinalizeTokenMintAcct: quotePass.toString(), - condRevertTokenMintAcct: quoteFail.toString(), - status: "active", - }; - - await usingDb((db) => - db - .insert(schema.conditionalVaults) - .values([baseVault, quoteVault]) - .onConflictDoNothing() - .execute() - ); - - let tokensToInsert: TokenRecord[] = []; - for (const token of [basePass, baseFail, quotePass, quoteFail]) { - const metadata = await enrichTokenMetadata(token, provider); - const storedMint = await getMint(provider.connection, token); - - // NOTE: THIS IS ONLY FOR PROPOSALS AND ONLY FOR BASE / QUOTE CONDITIONAL - const isQuote = [quoteFail, quotePass].includes(token); - const isFail = [quoteFail, baseFail].includes(token); - let imageUrl, defaultSymbol, defaultName; - - let passOrFailPrefix = isFail ? "f" : "p"; - // TODO: This MAY have issue with devnet... - let baseSymbol = isQuote ? "USDC" : baseTokenMetadata.symbol; - defaultSymbol = passOrFailPrefix + baseSymbol; - defaultName = `Proposal ${proposal.account.number}: ${defaultSymbol}`; - - if (dao && daoDetails) { - if (isQuote) { - // Fail / Pass USDC - imageUrl = !isFail - ? "https://imagedelivery.net/HYEnlujCFMCgj6yA728xIw/f38677ab-8ec6-4706-6606-7d4e0a3cfc00/public" - : "https://imagedelivery.net/HYEnlujCFMCgj6yA728xIw/d9bfd8de-2937-419a-96f6-8d6a3a76d200/public"; - } else { - // Base Token - imageUrl = isFail - ? daoDetails[0].fail_token_image_url - : daoDetails[0].pass_token_image_url; - } - } - let tokenToInsert: TokenRecord = { - symbol: - metadata.name && !metadata.isFallback ? metadata.symbol : defaultSymbol, - name: metadata.name && !metadata.isFallback ? metadata.name : defaultName, - decimals: metadata.decimals, - mintAcct: token.toString(), - supply: storedMint.supply.toString(), - imageUrl: imageUrl ? imageUrl : "", - updatedAt: currentTime, - }; - tokensToInsert.push(tokenToInsert); - } - - await usingDb((db) => - db - .insert(schema.tokens) - .values(tokensToInsert) - .onConflictDoNothing() - .execute() - ); - - let tokenAcctsToInsert: TokenAcctRecord[] = []; - for (const [mint, owner] of [ - [basePass, proposal.account.passAmm], - [baseFail, proposal.account.failAmm], - [quotePass, proposal.account.passAmm], - [quoteFail, proposal.account.failAmm], - ]) { - if(!mint || !owner) continue; - let tokenAcct: TokenAcctRecord = { - mintAcct: mint.toString(), - updatedAt: currentTime, - tokenAcct: getAssociatedTokenAddressSync(mint, owner, true).toString(), - ownerAcct: owner.toString(), - amount: await getAccount( - provider.connection, - getAssociatedTokenAddressSync(mint, owner, true) - ).then((account) => account.amount.toString()), - }; - tokenAcctsToInsert.push(tokenAcct); - } - - await usingDb((db) => - db - .insert(schema.tokenAccts) - .values(tokenAcctsToInsert) - .onConflictDoNothing() - .execute() - ); - - for (const [mint, owner] of [ - [basePass, proposal.account.passAmm], - [baseFail, proposal.account.failAmm], - [quotePass, proposal.account.passAmm], - [quoteFail, proposal.account.failAmm], - ]) { - if(!mint || !owner) continue; - let tokenAcct: TokenAcctRecord = { - mintAcct: mint.toString(), - updatedAt: currentTime, - tokenAcct: getAssociatedTokenAddressSync(mint, owner, true).toString(), - ownerAcct: owner.toString(), - amount: await getAccount( - provider.connection, - getAssociatedTokenAddressSync(mint, owner, true) - ).then((account) => account.amount.toString()), - }; - tokenAcctsToInsert.push(tokenAcct); - } - - await usingDb((db) => - db - .insert(schema.tokenAccts) - .values(tokenAcctsToInsert) - .onConflictDoNothing() - .execute() - ); - - if(!proposal.account.passAmm || !proposal.account.failAmm) return Err({ type: AutocratDaoIndexerError.MissingParamError }); - - let passMarket: MarketRecord = { - marketAcct: proposal.account.passAmm.toString(), - proposalAcct: proposal.publicKey.toString(), - marketType: MarketType.FUTARCHY_AMM, - createTxSig: "", - baseMintAcct: storedBaseVault.conditionalOnFinalizeTokenMint.toString(), - quoteMintAcct: storedQuoteVault.conditionalOnFinalizeTokenMint.toString(), - baseLotSize: "1", - quoteLotSize: "1", - quoteTickSize: "1", - bidsTokenAcct: getAssociatedTokenAddressSync( - quotePass, - proposal.account.passAmm, - true - ).toString(), - asksTokenAcct: getAssociatedTokenAddressSync( - basePass, - proposal.account.passAmm, - true - ).toString(), - baseMakerFee: 0, - baseTakerFee: 100, - quoteMakerFee: 0, - quoteTakerFee: 100, - }; - - let failMarket: MarketRecord = { - marketAcct: proposal.account.failAmm.toString(), - proposalAcct: proposal.publicKey.toString(), - marketType: MarketType.FUTARCHY_AMM, - createTxSig: "", - baseMintAcct: storedBaseVault.conditionalOnRevertTokenMint.toString(), - quoteMintAcct: storedQuoteVault.conditionalOnRevertTokenMint.toString(), - baseLotSize: "1", - quoteLotSize: "1", - quoteTickSize: "1", - bidsTokenAcct: getAssociatedTokenAddressSync( - quoteFail, - proposal.account.failAmm, - true - ).toString(), - asksTokenAcct: getAssociatedTokenAddressSync( - baseFail, - proposal.account.failAmm, - true - ).toString(), - baseMakerFee: 0, - baseTakerFee: 100, - quoteMakerFee: 0, - quoteTakerFee: 100, - }; - - await usingDb((db) => - db - .insert(schema.markets) - .values([passMarket, failMarket]) - .onConflictDoNothing() - .execute() - ); -} - -async function calculateUserPerformance( - onChainProposal: ProposalAccountWithKey -) { - const quoteTokens = alias(schema.tokens, "quote_tokens"); // NOTE: This should be USDC for now - const baseTokens = alias(schema.tokens, "base_tokens"); - // calculate performance - const [proposal] = - (await usingDb((db) => { - return db - .select() - .from(schema.proposals) - .where( - eq( - schema.proposals.proposalAcct, - onChainProposal.publicKey.toString() - ) - ) - .leftJoin( - schema.daos, - eq(schema.proposals.daoAcct, schema.daos.daoAcct) - ) - .leftJoin(quoteTokens, eq(schema.daos.quoteAcct, quoteTokens.mintAcct)) - .leftJoin(baseTokens, eq(schema.daos.baseAcct, baseTokens.mintAcct)) - .limit(1) - .execute(); - })) ?? []; - - if (!proposal) return; - - const { proposals, daos, quote_tokens, base_tokens } = proposal; - - let proposalDaoAcct = daos?.daoAcct; - - if (!proposals) return; - - if (!proposalDaoAcct) { - proposalDaoAcct = proposals.daoAcct; - } - - if (!proposalDaoAcct) { - console.error("No daoAcct found"); - } - - const allOrders = - (await usingDb((db) => { - return db - .select() - .from(schema.orders) - .where( - inArray(schema.orders.marketAcct, [ - proposals.passMarketAcct, - proposals.failMarketAcct, - ]) - ) - .execute(); - })) ?? []; - - // Get the time for us to search across the price space for spot - const proposalFinalizedAt = proposals.completedAt ?? new Date(); - const proposalFinalizedAtMinus2Minutes = new Date(proposalFinalizedAt); - proposalFinalizedAtMinus2Minutes.setMinutes( - proposalFinalizedAt.getMinutes() - 2 - ); - - const resolvingMarket = - proposals.status === ProposalStatus.Passed - ? proposals.passMarketAcct - : proposals.failMarketAcct; - // TODO: Get spot price at proposal finalization or even current spot price - // if the proposal is still active (this would be UNREALISED P&L) - // TODO: If this is 0 we really need to throw and error and alert someone, we shouldn't have missing spot data - const spotPrice = - (await usingDb((db) => { - return db - .select() - .from(schema.prices) - .where( - and( - eq(schema.prices.marketAcct, base_tokens.mintAcct), - lte(schema.prices.createdAt, proposalFinalizedAt), - gt(schema.prices.createdAt, proposalFinalizedAtMinus2Minutes) - ) - ) - .limit(1) - .orderBy(desc(schema.prices.createdAt)) - .execute(); - })) ?? []; - - let actors = allOrders.reduce((current, next) => { - const actor = next.actorAcct; - let totals = current.get(actor); - - if (!totals) { - totals = { - tokensBought: 0, // Aggregate value for reporting - tokensSold: 0, - volumeBought: 0, - volumeSold: 0, - tokensBoughtResolvingMarket: 0, // P/F market buy quantity - tokensSoldResolvingMarket: 0, // P/F market sell quantity - volumeBoughtResolvingMarket: 0, // P/F market buy volume - volumeSoldResolvingMarket: 0, // P/F market sell volume - buyOrderCount: 0, - sellOrderCount: 0, - }; - } - - // Token Decimals used for nomalizing results - const baseTokenDecimals = base_tokens?.decimals; - const quoteTokenDecimals = quote_tokens?.decimals ?? 6; // NOTE: Safe for now - - if (!baseTokenDecimals || !quoteTokenDecimals) { - return current; - } - - // Debatable size or quantity, often used interchangably - const size = PriceMath.getHumanAmount( - new BN(next.filledBaseAmount), - baseTokenDecimals - ); - - // Amount or notional - const amount = Number(next.quotePrice).valueOf() * size; - - // Buy Side - if (next.side === "BID") { - totals.tokensBought = totals.tokensBought + size; - totals.volumeBought = totals.volumeBought + amount; - totals.buyOrderCount = totals.buyOrderCount + 1; - // If this is the resolving market then we want to keep a running tally for that for P&L - if (next.marketAcct === resolvingMarket) { - totals.tokensBoughtResolvingMarket = - totals.tokensBoughtResolvingMarket + size; - totals.volumeBoughtResolvingMarket = - totals.volumeBoughtResolvingMarket + amount; - } - // Sell Side - } else if (next.side === "ASK") { - totals.tokensSold = totals.tokensSold + size; - totals.volumeSold = totals.volumeSold + amount; - totals.sellOrderCount = totals.sellOrderCount + 1; - // If this is the resolving market then we want to keep a running tally for that for P&L - if (next.marketAcct === resolvingMarket) { - totals.tokensSoldResolvingMarket = - totals.tokensSoldResolvingMarket + size; - totals.volumeSoldResolvingMarket = - totals.volumeSoldResolvingMarket + amount; - } - } - - current.set(actor, totals); - - return current; - }, new Map()); - - const toInsert: Array = Array.from( - actors.entries() - ).map((k) => { - const [actor, values] = k; - - // NOTE: this gets us the delta, whereas we need to know the direction at the very end - const tradeSizeDelta = Math.abs( - values.tokensBoughtResolvingMarket - values.tokensSoldResolvingMarket - ); - - // NOTE: Directionally orients our last leg - const needsSellToExit = - values.tokensBoughtResolvingMarket > values.tokensSoldResolvingMarket; // boolean - - // We need to complete the round trip / final leg - if (tradeSizeDelta !== 0) { - // TODO: This needs to be revised given the spot price can't be null or 0 if we want to really do this - const lastLegNotional = - tradeSizeDelta * Number(spotPrice[0]?.price ?? "0"); - - if (needsSellToExit) { - // We've bought more than we've sold, therefore when we exit the position calulcation - // we need to count the remaining volume as a sell at spot price when conditional - // market is finalized. - values.volumeSoldResolvingMarket = - values.volumeSoldResolvingMarket + lastLegNotional; - } else { - values.volumeBoughtResolvingMarket = - values.volumeBoughtResolvingMarket + lastLegNotional; - } - } - - return { - proposalAcct: onChainProposal.publicKey.toString(), - daoAcct: proposalDaoAcct, - userAcct: actor, - tokensBought: values.tokensBought.toString(), - tokensSold: values.tokensSold.toString(), - volumeBought: values.volumeBought.toString(), - volumeSold: values.volumeSold.toString(), - tokensBoughtResolvingMarket: - values.tokensBoughtResolvingMarket.toString(), - tokensSoldResolvingMarket: values.tokensSoldResolvingMarket.toString(), - volumeBoughtResolvingMarket: - values.volumeBoughtResolvingMarket.toString(), - volumeSoldResolvingMarket: values.volumeSoldResolvingMarket.toString(), - buyOrdersCount: values.buyOrderCount as unknown as bigint, - sellOrdersCount: values.sellOrderCount as unknown as bigint, - }; - }); - - if (toInsert.length > 0) { - await usingDb((db) => { - return db.transaction(async (tx) => { - await tx - .insert(schema.users) - .values( - toInsert.map((i) => { - return { - userAcct: i.userAcct, - }; - }) - ) - .onConflictDoNothing(); - - await Promise.all( - toInsert.map(async (insert) => { - try { - await tx - .insert(schema.userPerformance) - .values(insert) - .onConflictDoUpdate({ - target: [ - schema.userPerformance.proposalAcct, - schema.userPerformance.userAcct, - ], - set: { - tokensBought: insert.tokensBought, - tokensSold: insert.tokensSold, - volumeBought: insert.volumeBought, - volumeSold: insert.volumeSold, - tokensBoughtResolvingMarket: - insert.tokensBoughtResolvingMarket, - tokensSoldResolvingMarket: insert.tokensSoldResolvingMarket, - volumeBoughtResolvingMarket: - insert.volumeBoughtResolvingMarket, - volumeSoldResolvingMarket: insert.volumeSoldResolvingMarket, - buyOrdersCount: insert.buyOrdersCount, - sellOrdersCount: insert.sellOrdersCount, - }, - }); - } catch (e) { - logger.error("error inserting user_performance record", e); - } - }) - ); - }); - }); - } -} - diff --git a/packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts deleted file mode 100644 index 9a31a557..00000000 --- a/packages/old_indexer/src/indexers/autocrat/autocrat-v0-indexer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; -import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0"; -import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; - -const AUTOCRAT_V0 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; - -if (AUTOCRAT_V0.label !== "V0") { - const error = new Error(`Mistook autocrat ${AUTOCRAT_V0.label} for V0`); - logger.error(error.message); - throw error; -} - -export const AutocratV0Indexer: InstructionIndexer = { - PROGRAM_NAME: "AutocrateV0", - PROGRAM_ID: AUTOCRAT_V0.programId.toBase58(), - PROGRAM_IDL: AUTOCRAT_V0.idl as any, - indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { - return Ok; - }, -}; diff --git a/packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts deleted file mode 100644 index 95d51d60..00000000 --- a/packages/old_indexer/src/indexers/autocrat/autocrat-v0_1-indexer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; -import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.1"; -import { InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; - -const AUTOCRAT_V0_1 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 2]; - -if (AUTOCRAT_V0_1.label !== "V0.1") { - const error = new Error(`Mistook autocrat ${AUTOCRAT_V0_1.label} for V0.1`); - logger.error(error.message); - throw error; -} - -export const AutocratV0_1Indexer: InstructionIndexer = { - PROGRAM_NAME: "AutocratV0.1", - PROGRAM_ID: AUTOCRAT_V0_1.programId.toBase58(), - PROGRAM_IDL: IDL, - indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { - return Ok; - }, -}; diff --git a/packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts b/packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts deleted file mode 100644 index ce56b9bf..00000000 --- a/packages/old_indexer/src/indexers/autocrat/autocrat-v0_2-indexer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AUTOCRAT_VERSIONS } from "@metadaoproject/futarchy-sdk/lib/constants"; -import { IDL, AutocratV0 } from "@metadaoproject/futarchy-sdk/lib/idl/autocrat_v0.2"; -import { InstructionIndexer, Ok } from "../instruction-indexer"; -import { logger } from "../../logger"; - -const AUTOCRAT_V0_2 = AUTOCRAT_VERSIONS[AUTOCRAT_VERSIONS.length - 1]; - -if (AUTOCRAT_V0_2.label !== "V0.2") { - const error = new Error(`Mistook autocrat ${AUTOCRAT_V0_2.label} for V0.2`); - logger.error(error.message); - throw error; -} - -export const AutocratV0_1Indexer: InstructionIndexer = { - PROGRAM_NAME: "AutocratV0.2", - PROGRAM_ID: AUTOCRAT_V0_2.programId.toBase58(), - PROGRAM_IDL: IDL, - indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { - return Ok; - }, -}; diff --git a/packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts b/packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts deleted file mode 100644 index cf0515e3..00000000 --- a/packages/old_indexer/src/indexers/birdeye/birdeye-prices-indexer.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { and, eq, schema, usingDb } from "@metadaoproject/indexer-db"; -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { Err, Ok } from "../../match"; -import { - IndexerAccountDependencyStatus, - PricesRecord, - PricesType, -} from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; - -const apiKey = process.env.BIRDEYE_API_KEY ?? ""; - -enum BirdeyePricesIndexingError { - BirdeyeFetchError = "BirdeyeFetchError", - BirdeyeFetchMissingResponse = "BirdeyeFetchMissingResponse", - GeneralBirdeyePricesIndexError = "GeneralBirdeyePricesIndexError", -} - -export const BirdeyePricesIndexer: IntervalFetchIndexer = { - cronExpression: "* * * * *", - retries: 12, - index: async (acct: string) => { - try { - const url = `https://public-api.birdeye.so/defi/price?address=${acct}`; - const tokenPriceRes = await fetch(url, { - headers: { - "X-API-KEY": apiKey, - }, - }); - - if (tokenPriceRes.status !== 200) { - logger.error( - "non-200 response from birdeye:", - tokenPriceRes.status, - tokenPriceRes.statusText - ); - } - - const tokenPriceJson = (await tokenPriceRes.json()) as BirdeyePricesRes; - - if (!tokenPriceJson.success) { - logger.error( - "error fetching from birdeye tokenPriceJson:", - tokenPriceJson - ); - if (tokenPriceJson.message === "Unauthorized") { - logger.error("birdeye api key is incorrect"); - const stopBirdeyeRes = await usingDb((db) => - db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "birdeye-prices"))).execute() - ); - if((stopBirdeyeRes?.rowCount ?? 0) > 0) { - logger.error("birdeye dependency disabled"); - } - } - return Err({ type: BirdeyePricesIndexingError.BirdeyeFetchError }); - } - - if (!tokenPriceJson.data) { - logger.error("bird eye prices fetch missing data"); - return Err({ - type: BirdeyePricesIndexingError.BirdeyeFetchMissingResponse, - }); - } - - const newPrice: PricesRecord = { - marketAcct: acct, - price: tokenPriceJson.data?.value.toString() ?? "", - pricesType: PricesType.Spot, - createdBy: "birdeye-prices-indexer", - // TODO: Fudge, birdeye doesn't have this so we might need to figure out something.. maybe just call the RPC - updatedSlot: "0", - }; - - const insertPriceRes = await usingDb((db) => - db - .insert(schema.prices) - .values(newPrice) - .onConflictDoNothing() - .execute() - ); - if ((insertPriceRes?.rowCount ?? 0) > 0) { - console.log("inserted new birdeye price", acct); - } - return Ok({ acct }); - } catch (e) { - logger.error("general error with birdeye prices indexer:", e); - return Err({ - type: BirdeyePricesIndexingError.GeneralBirdeyePricesIndexError, - }); - } - }, -}; - -type BirdeyePricesRes = { - data?: { - value: number; - updateUnixTime: number; - updateHumanTime: string; - }; - success: boolean; - message?: string; -}; diff --git a/packages/old_indexer/src/indexers/common.ts b/packages/old_indexer/src/indexers/common.ts deleted file mode 100644 index 4462a0dc..00000000 --- a/packages/old_indexer/src/indexers/common.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SolanaParser } from "@debridge-finance/solana-transaction-parser"; -import { AmmClient, AMM_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; -import { provider } from "../connection"; - -export const ammClient = new AmmClient(provider, AMM_PROGRAM_ID, []); -export type IDL = typeof ammClient.program.idl; -export const ammParser = new SolanaParser([ - { - idl: ammClient.program.idl, - programId: AMM_PROGRAM_ID, - }, -]); diff --git a/packages/old_indexer/src/indexers/index.ts b/packages/old_indexer/src/indexers/index.ts deleted file mode 100644 index a6d7f911..00000000 --- a/packages/old_indexer/src/indexers/index.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { eq, getClient, schema, usingDb } from "@metadaoproject/indexer-db"; -import { - IndexerAccountDependencyReadRecord, - IndexerAccountDependencyStatus, - IndexerType, -} from "@metadaoproject/indexer-db/lib/schema"; -import { startIntervalFetchIndexer } from "./start-interval-fetch-indexers"; -import { startAccountInfoIndexer } from "./start-account-info-indexers"; -import { startTransactionHistoryIndexer } from "./start-transaction-history-indexers"; -import { startLogsSubscribeIndexer } from "./start-logs-subscribe-indexer"; -import { IndexerWithAccountDeps } from "../types"; -import { logger } from "../logger"; - -export async function startIndexers() { - await startAllIndexers(); - await listenForNewAccountsToIndex(); - console.log("indexers successfully started"); -} - -export async function startAllIndexers() { - const allIndexers = - (await usingDb((db) => - db - .select() - .from(schema.indexers) - .fullJoin( - schema.indexerAccountDependencies, - eq(schema.indexerAccountDependencies.name, schema.indexers.name) - ) - .where( - eq( - schema.indexerAccountDependencies.status, - IndexerAccountDependencyStatus.Active - ) - ) - .execute() - )) ?? []; - - for (const indexerQueryRes of allIndexers) { - await startIndexer(indexerQueryRes); - } -} - -async function startIndexer(indexerQueryRes: any) { - switch (indexerQueryRes.indexers?.indexerType) { - case IndexerType.AccountInfo: - await startAccountInfoIndexer(indexerQueryRes); - break; - case IndexerType.IntervalFetch: - const job = await startIntervalFetchIndexer(indexerQueryRes); - if (job) { - console.log( - `scheduled to run account ${ - indexerQueryRes?.indexer_account_dependencies?.acct - } on the ${indexerQueryRes.indexers?.implementation} indexer at ${job - .nextRun() - ?.toISOString()} and on a pattern of ${job.getPattern()}` - ); - } - break; - case IndexerType.TXHistory: - startTransactionHistoryIndexer(indexerQueryRes); - break; - case IndexerType.LogSubscribe: - startLogsSubscribeIndexer(indexerQueryRes); - break; - default: - console.warn( - `Unknown indexer type: ${indexerQueryRes.indexers?.indexerType}` - ); - } -} - -async function listenForNewAccountsToIndex() { - const client = await getClient(); - client.query("LISTEN indexer_account_dependencies_insert_channel"); - - client.on("notification", async (msg) => { - const payload = JSON.parse(msg.payload ?? "{}"); - await handleNewAccountToIndex(payload); - }); -} - -async function handleNewAccountToIndex( - newRow: IndexerAccountDependencyReadRecord -) { - // Example function to handle the new row - try { - // skip disabled acct - if (newRow.status === IndexerAccountDependencyStatus.Disabled) return; - - const indexer = - (await usingDb((db) => - db - .select() - .from(schema.indexers) - .where(eq(schema.indexers.name, newRow.name)) - .execute() - )) ?? []; - if (!indexer[0]) { - console.warn( - "new indexer dependency inserted that does not tie to an indexer" - ); - return; - } - const indexerWithAccountDep: IndexerWithAccountDeps = { - indexer_account_dependencies: newRow, - indexers: indexer[0], - }; - await startIndexer(indexerWithAccountDep); - // Perform operations using Drizzle ORM - // For example, you could log the new row or trigger other indexers - } catch (e) { - logger.errorWithChatBotAlert( - "error with starting of indexing new account dependency", - e - ); - } -} diff --git a/packages/old_indexer/src/indexers/instruction-indexer.ts b/packages/old_indexer/src/indexers/instruction-indexer.ts deleted file mode 100644 index 39d5ea8a..00000000 --- a/packages/old_indexer/src/indexers/instruction-indexer.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { VersionedTransactionResponse } from "@solana/web3.js"; -import { Idl } from "@coral-xyz/anchor"; -import { Result, TaggedUnion } from "../match"; -import { IDL } from "./common"; - -export const Ok = { indexed: true }; -export const Err = { indexed: false }; - -type InstructionIDL = Idl | IDL; - -export type InstructionIndexer = { - readonly PROGRAM_NAME: string; - readonly PROGRAM_ID: string; - readonly PROGRAM_IDL: IDL; - - indexInstruction( - transactionIndex: number, - transactionResponse: VersionedTransactionResponse, - instructionIndex: number, - decodedInstruction?: IDL["instructions"][number] - ): Promise< - Result< - { - txSig: string; - }, - TaggedUnion - > - >; - indexTransactionSig(transaction: { - txSig: string; - slot: string; - blockTime: Date; - failed: boolean; - payload: string; - serializerLogicVersion: number; - }): Promise< - Result< - { - txSig: string; - }, - TaggedUnion - > - >; -}; diff --git a/packages/old_indexer/src/indexers/interval-fetch-indexer.ts b/packages/old_indexer/src/indexers/interval-fetch-indexer.ts deleted file mode 100644 index ce983ffc..00000000 --- a/packages/old_indexer/src/indexers/interval-fetch-indexer.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Result, TaggedUnion } from "../match"; -export type IntervalFetchIndexer = { - cronExpression: string; - retries?: number; - index(acct: string): Promise< - Result< - { - acct: string; - }, - TaggedUnion - > - >; -}; diff --git a/packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts b/packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts deleted file mode 100644 index 743529d7..00000000 --- a/packages/old_indexer/src/indexers/jupiter/jupiter-quotes-indexer.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { schema, usingDb, eq, and } from "@metadaoproject/indexer-db"; -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { Err, Ok } from "../../match"; -import { - IndexerAccountDependencyStatus, - PricesRecord, - PricesType, -} from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; - -export enum JupiterQuoteIndexingError { - JupiterFetchError = "JupiterFetchError", - GeneralJupiterQuoteIndexError = "GeneralJupiterQuoteIndexError", -} - -export const JupiterQuotesIndexer: IntervalFetchIndexer = { - cronExpression: "* * * * *", - retries: 12, - index: async (acct: string) => { - // get decimals from our DB - try { - const fetchQuoteRes = await fetchQuoteFromJupe(acct); - if (!fetchQuoteRes) { - return Err({ - type: JupiterQuoteIndexingError.JupiterFetchError, - }); - } - const [price, slot] = fetchQuoteRes; - const newPrice: PricesRecord = { - marketAcct: acct, - price: price.toString(), - pricesType: PricesType.Spot, - createdBy: "jupiter-quotes-indexer", - updatedSlot: slot?.toString() ?? "0", - }; - - const insertPriceRes = await usingDb((db) => - db - .insert(schema.prices) - .values(newPrice) - .onConflictDoNothing() - .execute() - ); - if ((insertPriceRes?.rowCount ?? 0) > 0) { - console.log("inserted new jup quote price", acct); - } - return Ok({ acct }); - } catch (e) { - logger.error("general error indexing jupiter quote: ", e); - return Err({ - type: JupiterQuoteIndexingError.GeneralJupiterQuoteIndexError, - }); - } - }, -}; - -type JupTokenQuoteRes = { - outAmount?: string; - inAmount?: string; - contextSlot?: number; - error?: string; -}; - -const convertJupTokenPrice = ( - data: JupTokenQuoteRes, - inputTokenDecimals: number, - outputTokenDecimals: number -): number => { - const price = - Number(data.outAmount ?? "0") / - 10 ** outputTokenDecimals / - (Number(data.inAmount ?? "0") / 10 ** inputTokenDecimals); - return price; -}; - -const convertJupBaseOutTokenPrice = ( - data: JupTokenQuoteRes, - quoteTokenDecimals: number, - baseTokenDecimals: number -): number => { - const inPrice = Number(data.inAmount ?? "0") / 10 ** quoteTokenDecimals; - const outPrice = Number(data.outAmount ?? "0") / 10 ** baseTokenDecimals; - return inPrice / outPrice; -}; - -export const fetchQuoteFromJupe = async ( - acct: string -): Promise<[number, number | undefined] | null> => { - try { - const baseToken = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.mintAcct, acct)) - .execute() - )) ?? []; - - // Define the output mint based on the input token - const quoteMint = - acct === "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ? "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; - - const quoteToken = - (await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.mintAcct, quoteMint)) - .execute() - )) ?? []; - - if (baseToken.length === 0 || quoteToken.length === 0) { - console.log("quote or base token not found in db for jupiter quotes indexer", acct); - return null; - } - - const amountVal = 1 * 10 ** baseToken[0].decimals; - - // Fetch ASK price (original fetch) - const askUrl = - `https://public.jupiterapi.com/quote?inputMint=${acct}&` + - `outputMint=${quoteMint}&` + - `amount=${amountVal.toString()}&` + - "slippageBps=30&" + - "swapMode=ExactIn&" + - "onlyDirectRoutes=false&" + - "maxAccounts=64&" + - "experimentalDexes=Jupiter%20LO"; - const askRes = await fetch(askUrl); - - if (askRes.status !== 200) { - logger.error( - "non-200 response from Jupiter ASK quote:", - askRes.status, - askRes.statusText - ); - if (askRes.status === 400) { - logger.error("jupiter request is malformed"); - const stopJupiterRes = await usingDb((db) => - db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "jupiter-quotes"))).execute() - ); - if((stopJupiterRes?.rowCount ?? 0) > 0) { - logger.error("jupiter dependency disabled"); - } - } - return null; - } - - const askJson = (await askRes.json()) as JupTokenQuoteRes; - - if (askJson.error || !askJson.outAmount || !askJson.inAmount) { - logger.error("Error with ASK quote response:", askJson); - return null; - } - - const askPrice = convertJupTokenPrice( - askJson, - baseToken[0].decimals, - quoteToken[0].decimals - ); - - // Fetch BID price (swapped input/output) - const bidUrl = - `https://public.jupiterapi.com/quote?inputMint=${quoteMint}&` + - `outputMint=${acct}&` + - `amount=${(1 * 10 ** quoteToken[0].decimals).toString()}&` + - "slippageBps=30&" + - "swapMode=ExactIn&" + - "onlyDirectRoutes=false&" + - "maxAccounts=64&" + - "experimentalDexes=Jupiter%20LO"; - const bidRes = await fetch(bidUrl); - - if (bidRes.status !== 200) { - logger.error( - "non-200 response from Jupiter BID quote:", - bidRes.status, - bidRes.statusText - ); - if (bidRes.status === 400) { - logger.error("jupiter request is malformed"); - const stopJupiterRes = await usingDb((db) => - db.update(schema.indexerAccountDependencies).set({ status: IndexerAccountDependencyStatus.Disabled }).where(and(eq(schema.indexerAccountDependencies.acct, acct), eq(schema.indexerAccountDependencies.name, "jupiter-quotes"))).execute() - ); - if((stopJupiterRes?.rowCount ?? 0) > 0) { - logger.error("jupiter dependency disabled"); - } - } - // TODO: We should really back the f-off here after like 10 times... - return null; - } - - const bidJson = (await bidRes.json()) as JupTokenQuoteRes; - - if (bidJson.error || !bidJson.outAmount || !bidJson.inAmount) { - logger.error("Error with BID quote response:", bidJson); - return null; - } - - const bidPrice = convertJupBaseOutTokenPrice( - bidJson, - quoteToken[0].decimals, - baseToken[0].decimals - ); - - if (!askPrice) { - return [bidPrice, askJson.contextSlot]; - } - if (!bidPrice) { - return [askPrice, askJson.contextSlot]; - } - - // Calculate the mid-price - const midPrice = (askPrice + bidPrice) / 2; - - // Return the mid-price and the context slot from the ASK response - return [midPrice, askJson.contextSlot]; - } catch (e) { - logger.error("error getting price from Jupiter: ", e); - return null; - } -}; diff --git a/packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts b/packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts deleted file mode 100644 index 894a9013..00000000 --- a/packages/old_indexer/src/indexers/openbook-twap/openbook-twap-instruction-indexer.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IDL, OpenbookTwap } from "@metadaoproject/futarchy-sdk/lib/idl/openbook_twap"; -import { OPENBOOK_TWAP_PROGRAM_ID } from "@metadaoproject/futarchy-sdk/lib/constants"; -import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; - -// Doing this rather than class implements pattern due to -// https://github.com/microsoft/TypeScript/issues/41399 -export const OpenbookTwapIndexer: InstructionIndexer = { - PROGRAM_NAME: "OpenbookTwap", - PROGRAM_ID: OPENBOOK_TWAP_PROGRAM_ID.toBase58(), - PROGRAM_IDL: IDL, - indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { - // TODO: in the future we want to switch on the instruction name and index the openbook program instruction - // build the order book, then from that deduce the twap change. - - // For now though, we're going to take a shortcut by just reading the logs. - // We get initial weighted observation aggregator via the createTwapMarket expected value - // see https://github.com/metaDAOproject/openbook-twap/blob/82690c33a091b82e908843a14ad1a571dfba12b1/programs/openbook-twap/src/lib.rs#L68 - // Afterwards we can extract the log line here - // and use it to increment the observation aggregator - // https://github.com/metaDAOproject/openbook-twap/blob/82690c33a091b82e908843a14ad1a571dfba12b1/programs/openbook-twap/src/lib.rs#L120 - // we simply take difference between transaction slot and proposal enqueued slot then divide the obs agg by this - // https://github.com/metaDAOproject/futarchy/blob/d5b91dc103e23d72900817e93b450e42274469c9/programs/autocrat_v0/src/lib.rs#L335 - - return Ok; - } -}; diff --git a/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts b/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts deleted file mode 100644 index 6edec736..00000000 --- a/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-account-indexer.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { AccountInfoIndexer } from "../account-info-indexer"; -import { rpcReadClient } from "../../connection"; -import { AccountInfo, Context, PublicKey } from "@solana/web3.js"; -import { schema, usingDb } from "@metadaoproject/indexer-db"; -import { Err, Ok } from "../../match"; -import { - OpenbookMarketFetchRequest, - getMidPrice, -} from "@metadaoproject/futarchy-sdk"; -import { - PricesRecord, - PricesType, -} from "@metadaoproject/indexer-db/lib/schema"; -import { logger } from "../../logger"; - -export enum OpenbookV2MarketAccountIndexerError { - MarketNotFound = "MarketNotFound", - GeneralError = "GeneralError", - OrderbookNotFound = "OrderbookNotFound", - MidPriceNotFound = "MidPriceNotFound", -} - -export const OpenbookV2MarketAccountUpdateIndexer: AccountInfoIndexer = { - index: async ( - _: AccountInfo, - account: PublicKey, - context: Context - ) => { - try { - const market = await rpcReadClient.markets.openbook.fetchMarket( - new OpenbookMarketFetchRequest(account, null as any) - ); - - if (!market) { - logger.error("Failed to fetch market"); - return Err({ - type: OpenbookV2MarketAccountIndexerError.MarketNotFound, - }); - } - - const orderbook = await rpcReadClient.markets.openbook.fetchOrderBook( - market - ); - if (!orderbook) { - logger.error("Failed to fetch order book"); - return Err({ - type: OpenbookV2MarketAccountIndexerError.OrderbookNotFound, - }); - } - - const midPrice = getMidPrice(orderbook); - if (!midPrice) { - logger.error("Failed to calculate mid price"); - return Err({ - type: OpenbookV2MarketAccountIndexerError.MidPriceNotFound, - }); - } - - // update the latest slot here - const newOpenbookConditionaPrice: PricesRecord = { - marketAcct: account.toString(), - updatedSlot: context.slot.toString(), - price: midPrice.toString(), - pricesType: PricesType.Conditional, - baseAmount: - market.marketInstance.account.baseDepositTotal.toString() - , - quoteAmount: - market.marketInstance.account.quoteDepositTotal.toString() - , - createdBy: "openbook-v2-account-indexer", - }; - - const pricesInsertResult = - (await usingDb((db) => - db - .insert(schema.prices) - .values(newOpenbookConditionaPrice) - .onConflictDoUpdate({ - target: [schema.prices.createdAt, schema.prices.marketAcct], - set: newOpenbookConditionaPrice, - }) - .returning({ marketAcct: schema.prices.marketAcct }) - )) ?? []; - - return Ok({ acct: pricesInsertResult[0].marketAcct }); - } catch (error) { - logger.error( - "Unexpected error in openbook v2 market info index function:", - error - ); - return Err({ - type: OpenbookV2MarketAccountIndexerError.GeneralError, - error, - }); - } - }, -}; diff --git a/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts b/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts deleted file mode 100644 index 7cb48703..00000000 --- a/packages/old_indexer/src/indexers/openbook-v2/openbook-v2-indexer.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { OPENBOOK_PROGRAM_ID } from "@metadaoproject/futarchy-sdk"; -import { Err, InstructionIndexer, Ok } from "../instruction-indexer"; - -export const OpenbookV2Indexer: InstructionIndexer = { - PROGRAM_NAME: "OpenBookV2", - PROGRAM_ID: OPENBOOK_PROGRAM_ID.toBase58(), - PROGRAM_IDL: null, - indexInstruction: async (dbTx, txIdx, txRes, ixIdx, ix) => { - return Ok; - }, -}; diff --git a/packages/old_indexer/src/indexers/start-account-info-indexers.ts b/packages/old_indexer/src/indexers/start-account-info-indexers.ts deleted file mode 100644 index 56f8f950..00000000 --- a/packages/old_indexer/src/indexers/start-account-info-indexers.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; -import { PublicKey } from "@solana/web3.js"; -import { connection } from "../connection"; -import { IndexerWithAccountDeps } from "../types"; -import { AccountInfoIndexer } from "./account-info-indexer"; -import { AmmMarketAccountUpdateIndexer } from "./amm-market/amm-market-account-indexer"; -import { OpenbookV2MarketAccountUpdateIndexer } from "./openbook-v2/openbook-v2-account-indexer"; -import { logger } from "../logger"; - -export async function startAccountInfoIndexer( - indexerQueryRes: IndexerWithAccountDeps -) { - const { indexers: indexer, indexer_account_dependencies: dependentAccount } = - indexerQueryRes; - if (!indexer) return; - const implementation = getAccountInfoIndexerImplementation( - indexer.implementation - ); - if (implementation && dependentAccount && dependentAccount.acct) { - const accountPubKey = new PublicKey(dependentAccount.acct); - - const accountInfo = await connection.getAccountInfoAndContext( - accountPubKey - ); - - //index refresh on startup - if (accountInfo.value) { - const res = await implementation.index( - accountInfo.value, - accountPubKey, - accountInfo.context - ); - if (!res.success) { - logger.error( - "error indexing account initial fetch", - accountPubKey.toString() - ); - } - } - - connection.onAccountChange(accountPubKey, async (accountInfo, context) => { - const res = await implementation.index( - accountInfo, - accountPubKey, - context - ); - if (!res.success) { - logger.error("error indexing account update", accountPubKey.toString()); - } - }); - } -} -function getAccountInfoIndexerImplementation( - implementation: IndexerImplementation -): AccountInfoIndexer | null { - switch (implementation) { - case IndexerImplementation.AmmMarketIndexer: - return AmmMarketAccountUpdateIndexer; - case IndexerImplementation.OpenbookV2MarketIndexer: - return OpenbookV2MarketAccountUpdateIndexer; - } - return null; -} diff --git a/packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts b/packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts deleted file mode 100644 index cebde233..00000000 --- a/packages/old_indexer/src/indexers/start-interval-fetch-indexers.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { - IndexerAccountDependencyStatus, - IndexerImplementation, -} from "@metadaoproject/indexer-db/lib/schema"; - -import { IndexerWithAccountDeps } from "../types"; -import { BirdeyePricesIndexer } from "./birdeye/birdeye-prices-indexer"; -import { IntervalFetchIndexer } from "./interval-fetch-indexer"; -import { JupiterQuotesIndexer } from "./jupiter/jupiter-quotes-indexer"; -import { AmmMarketAccountIntervalFetchIndexer } from "./amm-market/amm-market-account-interval-indexer"; -import { AutocratDaoIndexer } from "./autocrat/autocrat-dao-indexer"; -import { AutocratProposalIndexer } from "./autocrat/autocrat-proposal-indexer"; -import { TokenMintIndexer } from "./token/token-mint-indexer"; -import { Cron } from "croner"; -import { and, eq, schema, usingDb } from "@metadaoproject/indexer-db"; -import { logger } from "../logger"; - -// add croner for this -// instantiates new croner and returns in function, which could be potentially useful -// now we can stop the job if we have an error - -const maxResets = 5; - -export function startIntervalFetchIndexer( - indexerQueryRes: IndexerWithAccountDeps -): Cron | null { - let errorCount = 0; - let resets = 0; - const { indexers: indexer, indexer_account_dependencies: dependentAccount } = - indexerQueryRes; - if (!indexer) return null; - const implementation = getIntervalFetchIndexerImplementation( - indexer.implementation - ); - if (implementation && dependentAccount && dependentAccount.acct) { - const retries = implementation.retries ?? 3; // default 3 interval fetch retries - logger.log("setting interval fetch for:", dependentAccount.acct); - const job = new Cron( - implementation.cronExpression, - {}, - async (self: Cron) => { - const res = await implementation.index(dependentAccount.acct); - if (!res.success) { - logger.log( - `error with interval fetch indexer ${dependentAccount.acct}:`, - res.error - ); - errorCount += 1; - if (resets === maxResets) { - // we have already paused/reset this indexer the max times, we are stopping the whole thing for good - handleIntervalFetchFinalFailure(dependentAccount, self); - return; - } - if (errorCount > retries) { - handleIntervalFetchFailure(dependentAccount, self); - // now that the job has been paused for 100 minutes, we reset the error count to 0 - errorCount = 0; - resets += 1; - } - } else { - errorCount = 0; - logger.log( - `next run for ${dependentAccount.acct} with ${ - indexer.implementation - } at ${self.nextRun()}` - ); - } - } - ); - return job; - } - return null; -} -export function getIntervalFetchIndexerImplementation( - implementation: IndexerImplementation -): IntervalFetchIndexer | null { - switch (implementation) { - case IndexerImplementation.JupiterQuotesIndexer: - return JupiterQuotesIndexer; - case IndexerImplementation.BirdeyePricesIndexer: - return BirdeyePricesIndexer; - case IndexerImplementation.AmmMarketsAccountFetch: - return AmmMarketAccountIntervalFetchIndexer; - case IndexerImplementation.AutocratDaoIndexer: - return AutocratDaoIndexer; - case IndexerImplementation.AutocratProposalIndexer: - return AutocratProposalIndexer; - case IndexerImplementation.TokenMintIndexer: - return TokenMintIndexer; - } - return null; -} - -async function handleIntervalFetchFailure( - indexerWithAcct: IndexerWithAccountDeps["indexer_account_dependencies"], - job: Cron -) { - job.pause(); - const updateResult = - (await usingDb((db) => - db - .update(schema.indexerAccountDependencies) - .set({ - status: IndexerAccountDependencyStatus.Paused, - updatedAt: new Date(), - }) - .where( - and( - eq( - schema.indexerAccountDependencies.acct, - indexerWithAcct?.acct ?? "" - ), - eq( - schema.indexerAccountDependencies.name, - indexerWithAcct?.name ?? "" - ) - ) - ) - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - if (updateResult.length !== 1) { - logger.errorWithChatBotAlert( - `error with pausing interval fetch indexer ${indexerWithAcct?.acct}.` - ); - } - // we resume job after 100 minutes to try again - setTimeout(async () => { - job.resume(); - const updateResult = - (await usingDb((db) => - db - .update(schema.indexerAccountDependencies) - .set({ - status: IndexerAccountDependencyStatus.Active, - updatedAt: new Date(), - }) - .where( - and( - eq( - schema.indexerAccountDependencies.acct, - indexerWithAcct?.acct ?? "" - ), - eq( - schema.indexerAccountDependencies.name, - indexerWithAcct?.name ?? "" - ) - ) - ) - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - - if (updateResult.length !== 1) { - logger.errorWithChatBotAlert( - `failed to update indexer_account_dependency on acct ${indexerWithAcct?.acct} to Active even though the job has been resumed` - ); - } - }, 3600_000); -} - -async function handleIntervalFetchFinalFailure( - indexerWithAcct: IndexerWithAccountDeps["indexer_account_dependencies"], - job: Cron -) { - job.stop(); - const updateResult = - (await usingDb((db) => - db - .update(schema.indexerAccountDependencies) - .set({ - status: IndexerAccountDependencyStatus.Disabled, - updatedAt: new Date(), - }) - .where( - eq( - schema.indexerAccountDependencies.acct, - indexerWithAcct?.acct ?? "" - ) - ) - .returning({ acct: schema.indexerAccountDependencies.acct }) - )) ?? []; - - if (updateResult.length !== 1) { - logger.errorWithChatBotAlert( - `final error with interval fetch indexer ${indexerWithAcct?.acct}. status set to disabled.` - ); - } -} diff --git a/packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts b/packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts deleted file mode 100644 index 8e5584f7..00000000 --- a/packages/old_indexer/src/indexers/start-logs-subscribe-indexer.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; -import { PublicKey } from "@solana/web3.js"; -import { connection } from "../connection"; -import { IndexerWithAccountDeps } from "../types"; -import { AccountLogsIndexer } from "./account-logs-indexer"; -import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; -import { logger } from "../logger"; - -export async function startLogsSubscribeIndexer( - indexerQueryRes: IndexerWithAccountDeps -) { - const { indexers: indexer, indexer_account_dependencies: dependentAccount } = - indexerQueryRes; - if (!indexer) return; - const implementation = getLogsSubscribeIndexerImplementation( - indexer.implementation - ); - if (implementation && dependentAccount && dependentAccount.acct) { - const accountPubKey = new PublicKey(dependentAccount.acct); - - connection.onLogs(accountPubKey, async (logs, context) => { - // wait here because we need to fetch the txn from RPC - // and often we get no response if we try right after recieving the logs notification - await new Promise((resolve) => setTimeout(resolve, 1500)); - const res = await implementation.index(logs, accountPubKey, context); - if (!res.success) { - logger.error( - "error indexing account logs", - accountPubKey.toString(), - res.error.type, - JSON.stringify(res.error.value), - "logs: " + logs.signature - ); - } - }); - } -} -function getLogsSubscribeIndexerImplementation( - implementation: IndexerImplementation -): AccountLogsIndexer | null { - switch (implementation) { - case IndexerImplementation.AmmMarketsLogsSubscribe: - return AmmMarketLogsSubscribeIndexer; - } - return null; -} diff --git a/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts b/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts deleted file mode 100644 index 55a45df4..00000000 --- a/packages/old_indexer/src/indexers/start-transaction-history-indexers.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { - IndexerImplementation, - IndexerRecord, - TransactionRecord, - TransactionWatcherTransactionRecord, -} from "@metadaoproject/indexer-db/lib/schema"; - -import { IndexerWithAccountDeps } from "../types"; -import { AmmMarketInstructionsIndexer } from "./amm-market/amm-market-instruction-indexer"; -import { InstructionIndexer } from "./instruction-indexer"; -import { Idl } from "@coral-xyz/anchor"; -import { schema, usingDb, eq, and, gte } from "@metadaoproject/indexer-db"; -import * as fastq from "fastq"; -import type { queueAsPromised } from "fastq"; - -// it is stored as base58 but the - -export async function startTransactionHistoryIndexer( - indexerQueryRes: IndexerWithAccountDeps -) { - const { indexers: indexer, indexer_account_dependencies: dependentAccount } = - indexerQueryRes; - if (!indexer) return; - const implementation = getTransactionHistoryImplementation( - indexer.implementation - ); - if (implementation && dependentAccount && dependentAccount.acct) { - // query for all transactions for this acct with slots higher than this indexer - const transactions = - (await usingDb((db) => { - return db - .select() - .from(schema.transactions) - .fullJoin( - schema.transactionWatcherTransactions, - eq( - schema.transactionWatcherTransactions.txSig, - schema.transactions.txSig - ) - ) - .where( - and( - eq( - schema.transactionWatcherTransactions.watcherAcct, - dependentAccount.acct - ), - gte(schema.transactions.slot, indexer.latestSlotProcessed) - ) - ) - .execute(); - })) ?? []; - - await indexExistingTxs(transactions, implementation, indexer); - } -} - -async function indexExistingTxs( - transactions: { - transactions: TransactionRecord | null; - transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; - }[], - implementation: InstructionIndexer, - indexer: IndexerRecord -) { - for (const tx of transactions) { - if (tx.transactions?.txSig) { - const res = await implementation.indexTransactionSig(tx.transactions); - if (res.success) { - // update latest slot for indexer - const updateResult = - (await usingDb((db) => - db - .update(schema.indexers) - .set({ - latestSlotProcessed: tx.transactions?.slot, - }) - .where(eq(schema.indexers.name, indexer.name)) - .returning({ - latestSlotProcessed: schema.indexers.latestSlotProcessed, - }) - )) ?? []; - if (updateResult.length > 0) { - console.log( - `successfully updated indexer "${indexer.name}" to slot ${updateResult[0].latestSlotProcessed}` - ); - } - } - } - } -} - -export const newTxQueue: queueAsPromised<{ - transactions: TransactionRecord | null; - transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; -}> = fastq.promise(handleNewTxs, 1); - -async function handleNewTxs(msg: { - transactions: TransactionRecord | null; - transaction_watcher_transactions: TransactionWatcherTransactionRecord | null; -}) { - const { transactions: tx, transaction_watcher_transactions: watcherTx } = msg; - // query for the any indexer account dependencies based on the watcher acct, and then query for the indexer implementation based on that, then you are up and running - const indexerQueryRes = - (await usingDb((db) => { - return db - .select() - .from(schema.indexerAccountDependencies) - .fullJoin( - schema.indexers, - eq(schema.indexers.name, schema.indexerAccountDependencies.name) - ) - .where( - eq( - schema.indexerAccountDependencies.acct, - watcherTx?.watcherAcct ?? "" - ) - ) - .execute(); - })) ?? []; - if (indexerQueryRes.length === 0) { - console.log( - "skipping processing new tx, no indexer query result. Tx Sig:", - tx?.txSig - ); - return; - } - const { indexers: indexer } = indexerQueryRes[0]; - if (!indexer) { - console.log( - "skipping processing new tx, no indexer tied to query result. Tx Sig:", - tx?.txSig - ); - return; - } - const implementation = getTransactionHistoryImplementation( - indexer.implementation - ); - if (!implementation) { - console.log( - "skipping processing new tx, no implementation found. Tx Sig:", - tx?.txSig - ); - return; - } - indexExistingTxs([msg], implementation, indexer); -} - -export function getTransactionHistoryImplementation( - implementation: IndexerImplementation -): InstructionIndexer | null { - switch (implementation) { - case IndexerImplementation.AmmMarketInstructionsIndexer: - return AmmMarketInstructionsIndexer; - } - return null; -} diff --git a/packages/old_indexer/src/indexers/token/token-mint-indexer.ts b/packages/old_indexer/src/indexers/token/token-mint-indexer.ts deleted file mode 100644 index cde88d49..00000000 --- a/packages/old_indexer/src/indexers/token/token-mint-indexer.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { provider } from "../../connection"; -import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; -import { Err, Ok } from "../../match"; -import { PublicKey } from "@solana/web3.js"; -import { TokenRecord } from "@metadaoproject/indexer-db/lib/schema"; -import { TokenAccountNotFoundError, getMint } from "@solana/spl-token"; -import { logger } from "../../logger"; - -export enum TokenMintIndexerError { - GeneralError = "GeneralError", - MissingParamError = "MissingParamError", - NotFoundError = "NotFoundError", - MissingChainResponseError = "MissingChainResponseError", - NothingToInsertError = "NothingToInsertError", -} - -export const TokenMintIndexer: IntervalFetchIndexer = { - cronExpression: "5 * * * * *", - retries: 10, - index: async (mintStr: string) => { - try { - let mint = new PublicKey(mintStr); - - let storedMint; - try { - storedMint = await getMint(provider.connection, mint); - } catch (err) { - if (err instanceof TokenAccountNotFoundError) { - logger.error(`Mint ${mint.toString()} not found`); - return Err({ type: TokenMintIndexerError.NotFoundError }); - } else { - throw err; - } - } - - const dbMint: TokenRecord | undefined = ( - await usingDb((db) => - db - .select() - .from(schema.tokens) - .where(eq(schema.tokens.mintAcct, mint.toString())) - .execute() - ) - )?.[0]; - - if (!dbMint) return Err({ type: TokenMintIndexerError.NotFoundError }); - - if (dbMint.supply !== storedMint.supply.toString()) { - await usingDb((db) => - db - .update(schema.tokens) - .set({ supply: storedMint.supply.toString(), updatedAt: new Date() }) - .where(eq(schema.tokens.mintAcct, mint.toString())) - .execute() - ); - console.log( - `Updated supply for mint ${mint.toString()} from ${ - dbMint.supply - } to ${storedMint.supply}` - ); - } - - return Ok({ acct: "Update the token record" }); - } catch (err) { - logger.errorWithChatBotAlert(err); - return Err({ type: TokenMintIndexerError.GeneralError }); - } - }, -}; diff --git a/packages/old_indexer/src/instruction-dispatch.ts b/packages/old_indexer/src/instruction-dispatch.ts deleted file mode 100644 index 1821f3c9..00000000 --- a/packages/old_indexer/src/instruction-dispatch.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { connection } from "./connection"; -import { InstructionIndexer } from "./indexers/instruction-indexer"; -import { BorshCoder } from "@coral-xyz/anchor"; -import { OpenbookTwapIndexer } from "./indexers/openbook-twap/openbook-twap-instruction-indexer"; -import { OpenbookV2Indexer } from "./indexers/openbook-v2/openbook-v2-indexer"; -import { AutocratV0Indexer } from "./indexers/autocrat/autocrat-v0-indexer"; -import { AutocratV0_1Indexer } from "./indexers/autocrat/autocrat-v0_1-indexer"; -import { red, yellow } from "ansicolor"; -import { - AddressLookupTableAccount, - Message, - MessageAccountKeys, -} from "@solana/web3.js"; - -export type IndexTransactionResult = - | { indexed: true } - | { indexed: false; error: { type: E; details: ErrorDetails[E] } }; - -export enum IndexTransactionError { - NoTxReturned = "NoTxReturned", - NoKnownProgram = "NoKnownProgram", - MoreSignaturesThanExpected = "MoreSignaturesThanExpected", - WrongSignature = "WrongSignature", - FailedToIndexInstruction = "FailedToIndexInstruction", - InvalidVersion = "InvalidVersion", - VersionLookupTableMismatch = "VersionLookupTableMismatch", - InvalidLookupTable = "InvalidLookupTable", -} - -export type MessageAddressTableLookup = Message["addressTableLookups"][0]; - -export type ErrorDetails = { - [IndexTransactionError.NoTxReturned]: undefined; - [IndexTransactionError.NoKnownProgram]: { programs: string[] }; - [IndexTransactionError.MoreSignaturesThanExpected]: { signatures: string[] }; - [IndexTransactionError.WrongSignature]: { signature: string }; - [IndexTransactionError.FailedToIndexInstruction]: undefined; - [IndexTransactionError.InvalidVersion]: { version: any }; - [IndexTransactionError.VersionLookupTableMismatch]: { - version: any; - addressTableLookups: MessageAddressTableLookup[]; - }; - [IndexTransactionError.InvalidLookupTable]: { accountKey: string }; -}; - -const indexers: InstructionIndexer[] = [ - AutocratV0Indexer, - AutocratV0_1Indexer, - OpenbookTwapIndexer, - OpenbookV2Indexer, -]; - -enum TransactionVersionType { - Legacy = "Legacy", - V0 = "V0", -} - -const programToIndexer: Record< - string, - { indexer: InstructionIndexer; coder: BorshCoder } -> = Object.fromEntries( - indexers.map((indexer) => [ - indexer.PROGRAM_ID, - { indexer, coder: new BorshCoder(indexer.PROGRAM_IDL) }, - ]) -); - -function error( - e: E, - details: ErrorDetails[E] -): IndexTransactionResult { - return { indexed: false, error: { type: e, details } }; -} - -const ok = { indexed: true } as const; - -export async function indexTransaction( - txIdx: number, - signature: string -): Promise> { - const tx = await connection.getTransaction(signature, { - maxSupportedTransactionVersion: 0, - }); - - if (tx == null || tx === undefined) { - return error(IndexTransactionError.NoTxReturned, undefined); - } - - if (tx.meta?.err) { - // TODO: mark tx as processed - return ok; - } - - const { transaction } = tx; - const { signatures } = transaction; - - let txVersion: TransactionVersionType; - let accountKeys: MessageAccountKeys; - switch (tx.version) { - case "legacy": - txVersion = TransactionVersionType.Legacy; - if (transaction.message.addressTableLookups.length > 0) { - return error(IndexTransactionError.VersionLookupTableMismatch, { - version: txVersion, - addressTableLookups: transaction.message.addressTableLookups, - }); - } - accountKeys = transaction.message.getAccountKeys(); - break; - case 0: - txVersion = TransactionVersionType.V0; - if (transaction.message.addressTableLookups.length === 0) { - return error(IndexTransactionError.VersionLookupTableMismatch, { - version: txVersion, - addressTableLookups: transaction.message.addressTableLookups, - }); - } - // https://solana.stackexchange.com/questions/8652/how-do-i-parse-the-accounts-in-a-versioned-transaction - const lookupTables: AddressLookupTableAccount[] = []; - for (const { accountKey } of transaction.message.addressTableLookups) { - const lookupTable = await connection.getAddressLookupTable(accountKey); - if (lookupTable === null) { - console.log("no response from getAddressLookupTable"); - return error(IndexTransactionError.InvalidLookupTable, { - accountKey: accountKey.toBase58(), - }); - } - if (lookupTable.value === null) { - console.log("null lookup table value"); - return error(IndexTransactionError.InvalidLookupTable, { - accountKey: accountKey.toBase58(), - }); - } - lookupTables.push(lookupTable.value); - } - accountKeys = transaction.message.getAccountKeys({ - addressLookupTableAccounts: lookupTables, - }); - break; - default: - return error(IndexTransactionError.InvalidVersion, { - version: tx.version, - }); - } - - // console.log('indexing', signature, tx.version, tx.transaction.message.addressTableLookups.length); - - // TODO: maybe do something with inner instructions - // tx.meta?.innerInstructions - // console.log(JSON.stringify(tx)); - - /* - first tx has 5 signatures. Need to investigate whether all show up in the getSignaturesForAccount response. - We don't want to process the same tx multiple times. - if (signatures.length > 1) { - return error(IndexTransactionError.MoreSignaturesThanExpected, {signatures: tx.transaction.signatures}) - } - */ - - const txSig = signatures[0]; - if (txSig !== signature) { - return error(IndexTransactionError.WrongSignature, { signature: txSig }); - } - - //const accountKeys = transaction.message.getAccountKeys({a}); - const instructions = transaction.message.compiledInstructions; - const programs: string[] = []; - let matchingProgramFound = false; - const timeStr = new Date(tx.blockTime! * 1000) - .toISOString() - .replace("T", " ") - .replace(".000Z", ""); - for (let i = 0; i < instructions.length; ++i) { - const ix = instructions[i]; - const program = accountKeys.staticAccountKeys[ix.programIdIndex].toBase58(); - programs.push(program); - if (program in programToIndexer) { - matchingProgramFound = true; - const { indexer, coder } = programToIndexer[program]; - const ixIdx = i; - const prefix = `[${timeStr}][slot ${tx.slot}][${indexer.PROGRAM_NAME}] ${txIdx}.${ixIdx}.`; - const secondLogMessage = (tx.meta?.logMessages ?? [])[1]; - switch (secondLogMessage) { - case "Program log: Instruction: IdlCreateAccount": - console.log( - yellow(`${prefix} skipping IdlCreateAccount ${signature}`) - ); - continue; - case "Program log: Instruction: IdlWrite": - console.log(yellow(`${prefix} skipping IdlWrite ${signature}`)); - continue; - } - const decoded = coder.instruction.decode(Buffer.from(ix.data)); - if (decoded == null) { - console.log( - `${prefix} Cannot decode instruction ${i} of transaction ${signature}` - ); - console.log(tx.meta?.logMessages); - continue; - } - let ixLine = `${prefix} ${decoded.name} ${signature}`; - console.log(ixLine); - const result = await indexer.indexInstruction( - {} as any, // TODO: initialize db transaction and pass here - txIdx, - tx, - ixIdx, - decoded - ); - if (!result.indexed) { - return error(IndexTransactionError.FailedToIndexInstruction, undefined); - } - } - } - if (!matchingProgramFound) { - return error(IndexTransactionError.NoKnownProgram, { programs }); - } - - return ok; -} diff --git a/packages/old_indexer/src/local-cache.ts b/packages/old_indexer/src/local-cache.ts deleted file mode 100644 index c845545e..00000000 --- a/packages/old_indexer/src/local-cache.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import { logger } from "./logger"; - -const CACHE_DIR = path.resolve(__dirname, "cache"); -const CACHE_LOCALLY = false; // TODO: turn off when ready to actually start indexing - -if (!fs.existsSync(CACHE_DIR)) { - await fs.promises.mkdir(CACHE_DIR); -} - -function getFileAndDirPath(key: string[]): { file: string; dir: string } { - if (key.length === 0) { - const error = new Error("Invalid empty key"); - logger.error(error.message); - throw error; - } - const keyCopy = [...key]; - const filename = keyCopy.pop()!; - const dir = path.resolve(CACHE_DIR, keyCopy.join("/")); - const file = path.resolve(dir, filename); - return { file, dir }; -} - -export async function get(key: string[]): Promise { - if (!CACHE_LOCALLY) return undefined; - const { file } = getFileAndDirPath(key); - if (fs.existsSync(file)) { - logger.log(`Cache hit on ${key.join("/")}`); - return (await fs.promises.readFile(file)).toString().split("\n"); - } - return undefined; -} - -export async function set(key: string[], value: string[]): Promise { - if (!CACHE_LOCALLY) return; - const { file, dir } = getFileAndDirPath(key); - await fs.promises.mkdir(dir, { recursive: true }); - await fs.promises.writeFile(file, value.join("\n")); -} diff --git a/packages/old_indexer/src/logger.ts b/packages/old_indexer/src/logger.ts deleted file mode 100644 index 7760a066..00000000 --- a/packages/old_indexer/src/logger.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Counter } from "@lukasdeco/prom-client"; -import { AlertChatBotInterface, TelegramBotAPI } from "./adapters/telegram-bot"; - -const TELEGRAM_ALERT_CHAT_ID = process.env.TELEGRAM_ALERT_CHAT_ID ?? ""; - -export class Logger { - private errorCounter; - private warnCounter; - private chatBotApi: AlertChatBotInterface; - - constructor(chatBotApi: AlertChatBotInterface) { - this.errorCounter = new Counter({ - name: "errors", - help: "number of errors", - }); - - this.warnCounter = new Counter({ - name: "warnings", - help: "number of warnings", - }); - this.chatBotApi = chatBotApi; - } - - private formatData(data: any[]): string { - return data - .map((item) => { - if (typeof item === "object") { - try { - const jsonItem = JSON.stringify(item); - if (item.message && !jsonItem.includes(item.message)) { - return jsonItem + " " + item.message; - } - return jsonItem; - } catch (error) { - return "[Circular]"; - } - } - if (typeof item === "undefined") { - return "undefined"; - } - try { - return item.toString(); - } catch (e) { - return ""; - } - }) - .join(" "); - } - - log(...data: any[]): void { - console.log(this.formatData(data)); - } - - info(...data: any[]): void { - console.info(this.formatData(data)); - } - - error(...data: any[]): void { - console.error(this.formatData(data)); - this.errorCounter.inc(); - } - - errorWithChatBotAlert(...data: any[]): void { - const formattedData = this.formatData(data); - console.error(formattedData); - this.errorCounter.inc(); - if (TELEGRAM_ALERT_CHAT_ID) { - this.chatBotApi.sendMessage(TELEGRAM_ALERT_CHAT_ID, formattedData); - } - } - - warn(message: string): void { - console.warn(message); - this.warnCounter.inc(); - } -} - -// TODO: add lint rule preventing default exports (default exports are antithetical to IDE auto refactors) -const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; -const telegramBotAPI = new TelegramBotAPI({ - token: TELEGRAM_BOT_TOKEN ?? "", -}); -export const logger = new Logger(telegramBotAPI); diff --git a/packages/old_indexer/src/match.ts b/packages/old_indexer/src/match.ts deleted file mode 100644 index f4bc4fb5..00000000 --- a/packages/old_indexer/src/match.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * The constructs here allow us to mimic Rust's strongly typed error handling - */ -export type TaggedUnion = { - type: string; - value?: any; -}; - -export type Result = - | { success: true; ok: Ok } - | { success: false; error: Err }; - -export function Err(error: Err): Result { - return { success: false, error }; -} - -export function Ok(ok: Ok): Result { - return { success: true, ok }; -} diff --git a/packages/old_indexer/src/proposal-indexer.ts b/packages/old_indexer/src/proposal-indexer.ts deleted file mode 100644 index ffb4a590..00000000 --- a/packages/old_indexer/src/proposal-indexer.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { AUTOCRAT_VERSIONS, OPENBOOK_PROGRAM_ID } from '@metadaoproject/futarchy-sdk/lib/constants'; -import { AutocratProgram, DaoState, ProgramVersion, Proposal } from '@metadaoproject/futarchy-sdk/lib/types'; -import { AccountMeta, PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'; -import { OpenbookV2, IDL as OPENBOOK_IDL } from '@openbook-dex/openbook-v2'; -import { Program, utils } from '@coral-xyz/anchor'; -import { connection, provider } from './connection'; -import { ProposalOutcome, MarketType } from '@metadaoproject/indexer-db/lib/schema'; - -const SUPPORTED_AUTOCRAT_VERSIONS = ['V0.1', 'V0']; - -// TODO: send this to monitoring -function emitErrorMetric(msg: String) { - console.log(msg); -} - -async function getDAOProposals({label, programId, idl}: ProgramVersion) { - //console.log(`fetching ${label} proposals`); - - if (!SUPPORTED_AUTOCRAT_VERSIONS.includes(label)) { - // TODO: Emit error metric - emitErrorMetric(`Unable to parse proposals with label ${label}`); - return []; - } - - // const dao = PublicKey.findProgramAddressSync( - // [utils.bytes.utf8.encode('WWCACOTMICMIBMHAFTTWYGHMB')], - // programId, - // )[0]; - - // const daoTreasury = PublicKey.findProgramAddressSync([dao.toBuffer()], programId)[0]; - - const autocratProgram = new Program(idl as AutocratProgram, programId, provider); - - // const openbook = new Program(OPENBOOK_IDL, OPENBOOK_PROGRAM_ID, provider); - - // const daoState = await autocratProgram.account.dao.fetch(dao); - - const proposals = (await autocratProgram.account.proposal.all()) - .sort((a, b) => b.account.number - a.account.number) // descending order - - return proposals; -} - -export async function getProposals() { - return (await Promise.all(AUTOCRAT_VERSIONS.map(getDAOProposals))).flat(); -} diff --git a/packages/old_indexer/src/server.ts b/packages/old_indexer/src/server.ts deleted file mode 100644 index e4f8cd32..00000000 --- a/packages/old_indexer/src/server.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getMetrics } from "./endpoints/get-metrics"; -import { logger } from "./logger"; -import cors from "cors"; -import express from "express"; - -const PORT = process.env.PORT ?? 8080; - -export function startServer() { - logger.log("starting server"); - const app = express(); - app.use(express.json()); - app.use(cors({ origin: "*", allowedHeaders: ["Content-Type"] })); - app.get("/metrics", getMetrics); - - app.listen(PORT, () => { - logger.log(`Server listening on Port ${PORT}`); - }); -} diff --git a/packages/old_indexer/src/transaction/account-resolver.ts b/packages/old_indexer/src/transaction/account-resolver.ts deleted file mode 100644 index 0c1871a2..00000000 --- a/packages/old_indexer/src/transaction/account-resolver.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Result, Ok, Err } from '../match'; -import { VersionedTransactionResponse, AddressLookupTableAccount, MessageAccountKeys, MessageAddressTableLookup, RpcResponseAndContext, PublicKey } from "@solana/web3.js"; -import { connection } from '../connection'; - -export enum ResolveAccountsErrorType { - AddressTableLookupsInLegacy = 'AddressTableLookupsInLegacy', - MissingLookupTableResponse = 'MissingLookupTableResponse', - UnsupportedTransactionVersion = 'UnsupportedTransactionVersion' -} - -export type ResolveAccountsError = - { - type: ResolveAccountsErrorType.AddressTableLookupsInLegacy; - lookups: MessageAddressTableLookup[]; - } | - { - type: ResolveAccountsErrorType.MissingLookupTableResponse; - response: RpcResponseAndContext; - accountKey: PublicKey; - } | - { - type: ResolveAccountsErrorType.UnsupportedTransactionVersion; - version: any; - }; - -export async function resolveAccounts({transaction, version}: VersionedTransactionResponse): Promise> { - let accountKeys: MessageAccountKeys; - switch (version) { - case 'legacy': - if (transaction.message.addressTableLookups.length > 0) { - return Err({type: ResolveAccountsErrorType.AddressTableLookupsInLegacy, lookups: transaction.message.addressTableLookups}); - } - accountKeys = transaction.message.getAccountKeys(); - break; - case 0: - // https://solana.stackexchange.com/questions/8652/how-do-i-parse-the-accounts-in-a-versioned-transaction - const lookupTables: AddressLookupTableAccount[] = []; - for (const {accountKey} of transaction.message.addressTableLookups) { - const lookupTable = await connection.getAddressLookupTable(accountKey); - if (!lookupTable?.value) { - return Err({ - type: ResolveAccountsErrorType.MissingLookupTableResponse, - response: lookupTable, - accountKey - }); - } - lookupTables.push(lookupTable.value); - } - accountKeys = transaction.message.getAccountKeys({addressLookupTableAccounts: lookupTables}); - break; - default: - return Err({type: ResolveAccountsErrorType.UnsupportedTransactionVersion, version}); - } - return Ok(accountKeys); -} diff --git a/packages/old_indexer/src/transaction/history.ts b/packages/old_indexer/src/transaction/history.ts deleted file mode 100644 index 9a54da42..00000000 --- a/packages/old_indexer/src/transaction/history.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { connection } from "../connection"; -import { PublicKey } from "@solana/web3.js"; -import { logger } from "../logger"; - -export type TransactionMeta = Awaited< - ReturnType<(typeof connection)["getSignaturesForAddress"]> ->[number]; - -function throwInvariantViolation( - account: PublicKey, - after: string | undefined, - before: string | undefined, - violation: string -) { - const error = new Error( - `Invariant violated. account ${account.toBase58()}, after ${after}, before ${before}: ${violation}` - ); - logger.errorWithChatBotAlert(error.message); - throw error; -} - -export async function getTransactionHistory( - account: PublicKey, - largerThanSlot: string, - range?: { after?: string; before?: string } -): Promise { - const { after, before } = range ?? {}; - - const history: TransactionMeta[] = []; - - let earliestSig: string | undefined = before; - - let page = 1; - while (true) { - // The Solana RPC tx API has us do a backwards walk - const transactions = await connection.getSignaturesForAddress( - account, - { before: earliestSig }, - "confirmed" - ); - if (transactions.length === 0) { - break; - } - const sigToIndex = new Map(); - let reachedAfter = false; - for (let i = 0; i < transactions.length; ++i) { - const cur = transactions[i]; - const prev = transactions[i - 1]; - if (sigToIndex.has(cur.signature)) { - throwInvariantViolation( - account, - after, - before, - `duplicate signature ${cur.signature} at indices ${sigToIndex.get( - cur.signature - )} and ${i}` - ); - } - if (prev !== undefined && cur.slot > prev.slot) { - // Transactions are assumed to be in time descending order. - throwInvariantViolation( - account, - after, - before, - `index ${i - 1} signature ${prev.signature} has slot ${ - prev.slot - } while index ${i} signature ${cur.signature} has slot ${cur.slot}` - ); - } - if (cur.signature === after) { - reachedAfter = true; - break; - } - // this causes unnecessary loss of txs being indexed, - // and if we have an indexer who STRICTLY needs everything in order, then we should create a config field - // on the indexers table that specifies this as being needed or not needed - // if (cur.slot < largerThanSlot) { - // throwInvariantViolation( - // account, - // after, - // before, - // `index ${i} signature ${cur.signature} has slot ${cur.slot} which is less than min slot ${largerThanSlot}` - // ); - // } - history.push(cur); - earliestSig = cur.signature; - } - if (earliestSig && sigToIndex.has(earliestSig)) { - throwInvariantViolation( - account, - after, - before, - `account contained before value of ${earliestSig}` - ); - } - logger.log( - `page ${page} for ${account.toBase58()} (${history.length} total)` - ); - page++; - if (reachedAfter) { - break; - } - } - - history.reverse(); // Now earliest transaction comes first. - - return history; -} diff --git a/packages/old_indexer/src/transaction/serializer.test.ts b/packages/old_indexer/src/transaction/serializer.test.ts deleted file mode 100644 index 034eb859..00000000 --- a/packages/old_indexer/src/transaction/serializer.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { serialize, deserialize, Transaction } from "./serializer"; -import { expect, describe, test } from "bun:test"; - -describe("serializer", async () => { - test("serialize-deserialize", async () => { - const testTx: Transaction = { - blockTime: 0, - slot: 0, - recentBlockhash: "", - computeUnitsConsumed: BigInt(4), - fee: BigInt(2), - signatures: [], - version: "legacy", - logMessages: [], - accounts: [ - { - pubkey: "BIGINT:a300n", // false flag - isSigner: true, - isWriteable: false, - preBalance: BigInt(800), - postBalance: BigInt(3000000), - }, - ], - instructions: [], - }; - - const str = serialize(testTx); - - expect(str).toBe( - `{"blockTime":0,"slot":0,"recentBlockhash":"",` + - `"computeUnitsConsumed":"BIGINT:4","fee":"BIGINT:2","signatures":[],"version":"legacy","logMessages":[],` + - `"accounts":[{"pubkey":"BIGINT:a300n","isSigner":true,"isWriteable":false,"preBalance":"BIGINT:800","postBalance":"BIGINT:3000000"}],` + - `"instructions":[]}` - ); - - const deserialized = deserialize(str) as any; - - expect(deserialized).toEqual({ success: true, ok: testTx }); - }); -}); diff --git a/packages/old_indexer/src/transaction/serializer.ts b/packages/old_indexer/src/transaction/serializer.ts deleted file mode 100644 index 06e68da9..00000000 --- a/packages/old_indexer/src/transaction/serializer.ts +++ /dev/null @@ -1,907 +0,0 @@ -import { - AccountMeta, - CompiledInstruction, - ConfirmedTransactionMeta, - Message, - MessageAccountKeys, - PublicKey, - VersionedTransactionResponse, -} from "@solana/web3.js"; -import { Ok, Err, Result } from "../match"; -import { z } from "zod"; -import { resolveAccounts, ResolveAccountsError } from "./account-resolver"; -import * as base58 from "bs58"; -import { connection, provider } from "../connection"; -import { BorshInstructionCoder, Idl, Program } from "@coral-xyz/anchor"; -import { PROGRAM_ID_TO_IDL_MAP } from "../constants"; -import { - InstructionDisplay, - Instruction as AnchorInstruction, -} from "@coral-xyz/anchor/dist/cjs/coder/borsh/instruction"; -import { logger } from "../logger"; - -/** - * This version should be bumped every time we update this file. - * It will reset all the transaction watchers to slot 0 - * TODO: it should also create new indexers - */ -export const SERIALIZED_TRANSACTION_LOGIC_VERSION = 0; - -// bigint isn't JSON serializable -// https://github.com/GoogleChromeLabs/jsbi/issues/30#issuecomment-1006088574 -export function serialize(transaction: Transaction, pretty = false): string { - return JSON.stringify( - transaction, - (_, value) => - typeof value === "bigint" ? `BIGINT:${value.toString()}` : value, - pretty ? 2 : 0 - ); -} - -const bigintEncodingPattern = /^BIGINT:[0-9]+$/; -export function deserialize( - json: string -): Result { - const deserialized = JSON.parse(json, (_, value) => - typeof value === "string" && bigintEncodingPattern.test(value) - ? BigInt(value.split(":")[1]) - : value - ); - const parsed = SerializableTransaction.safeParse(deserialized); - if (parsed.success) { - return Ok(parsed.data); - } else { - return Err({ type: "ZodError", error: parsed.error }); - } -} - -export const SerializableTokenMeta = z.strictObject({ - mint: z.string(), - owner: z.string(), - amount: z.bigint(), - decimals: z.number(), -}); - -/** - * on the transaction level this will not have a name, but it will have the pre and post balances. - * At the instruction level, we WILL see the name, but we will not have pre and post balances. - */ -export const SerializableAccountMeta = z.strictObject({ - name: z.string().optional(), - pubkey: z.string(), - isSigner: z.boolean().optional(), - isWriteable: z.boolean().optional(), - // lamport balances (rent) - preBalance: z.bigint().optional(), - postBalance: z.bigint().optional(), - // if the account was an ATA - preTokenBalance: SerializableTokenMeta.optional(), - postTokenBalance: SerializableTokenMeta.optional(), -}); - -export const SerializableInstructionArg = z.strictObject({ - name: z.string(), - type: z.string(), - data: z.string(), -}); - -export const SerializableInstruction = z.strictObject({ - name: z.string(), - stackHeight: z.number(), - programIdIndex: z.number(), - data: z.string(), - accounts: z.array(z.number()), - accountsWithData: z.array(SerializableAccountMeta), - args: z.array(SerializableInstructionArg), -}); - -export const SerializableTransactionError = z - .strictObject({ - InstructionError: z - .tuple([ - z.number(), - z.union([z.string(), z.strictObject({ Custom: z.number() })]), - ]) - .optional(), - InsufficientFundsForRent: z - .strictObject({ - account_index: z.number(), - }) - .optional(), - }) - .optional(); - -export const SerializableTransaction = z.strictObject({ - blockTime: z.number(), - slot: z.number(), - recentBlockhash: z.string(), - computeUnitsConsumed: z.bigint(), - err: SerializableTransactionError, - fee: z.bigint(), - signatures: z.array(z.string()), - version: z.union([z.literal("legacy"), z.literal(0)]), - logMessages: z.array(z.string()), - accounts: z.array(SerializableAccountMeta), - instructions: z.array(SerializableInstruction), -}); - -export type Transaction = z.infer; -export type Account = z.infer; -export type TokenBalance = z.infer; -export type Instruction = z.infer; - -export enum GetTransactionErrorType { - NullGetTransactionResponse = "NullGetTransactionResponse", - ZodError = "ZodError", - ResolveAccountError = "ResolveAccountError", // problem getting account list from transaction - DuplicateTokenAccounts = "DuplicateTokenAccounts", // if multiple items in pre or post token balances reference the same account - OuterIxStackHeightNonNull = "OuterIxStackHeightNonNull", // it's expected that all outer instructions have a null stackHeight (even though it's really 1) - RepeatOuterIndicesForInnerIx = "RepeatOuterIndicesForInnerIx", // if multiple items in innerInstructions reference same outer instruction - InvalidStackHeightTransition = "InvalidStackHeightTransition", // if next instruction item in an inner instruction list increases by more than 1, or if it goes to less than 2 (only outers can have stack height 1) -} - -export type GetTransactionError = - | { - type: GetTransactionErrorType.NullGetTransactionResponse; - } - | { - type: GetTransactionErrorType.ZodError; - error: z.ZodError; - } - | { - type: GetTransactionErrorType.ResolveAccountError; - error: ResolveAccountsError; - } - | { - type: GetTransactionErrorType.DuplicateTokenAccounts; - balanceType: "pre" | "post"; - duplicates: Record; - } - | { - type: GetTransactionErrorType.OuterIxStackHeightNonNull; - outerInstruction: Message["compiledInstructions"][number]; - } - | { - type: GetTransactionErrorType.RepeatOuterIndicesForInnerIx; - repeatedIndex: number; - } - | { - type: GetTransactionErrorType.InvalidStackHeightTransition; - outerInstructionIndex: number; - innerInstructionIndex: number; - priorStackHeight: number; - innerStackHeight: number; - }; - -type TokenBalanceResponse = NonNullable< - NonNullable["postTokenBalances"] ->[number]; - -function parseTokenBalances( - tokenBalanceResponses: TokenBalanceResponse[], - accountsRaw: MessageAccountKeys -): Result< - Record, - { type: "duplicates"; duplicates: Record } -> { - const duplicates: Record = {}; - const parsed: Record = {}; - for (let i = 0; i < tokenBalanceResponses.length; ++i) { - const cur = tokenBalanceResponses[i]; - const { - accountIndex, - mint, - owner, - uiTokenAmount: { amount, decimals }, - } = cur; - const accountPubkey = accountsRaw.get(accountIndex)!.toBase58(); - if (parsed[accountPubkey] !== undefined) { - if (duplicates[accountPubkey] === undefined) { - duplicates[accountPubkey] = [parsed[accountPubkey][0]]; - } - duplicates[accountPubkey].push(cur); - } - parsed[accountPubkey] = [ - cur, - { - mint, - owner: owner!, - amount: BigInt(amount), - decimals, - }, - ]; - } - if (Object.keys(duplicates).length > 0) { - return Err({ type: "duplicates", duplicates }); - } - return Ok( - Object.fromEntries( - Object.entries(parsed).map(([account, [_response, balance]]) => [ - account, - balance, - ]) - ) - ); -} - -async function parseInstructions( - outer: Message["compiledInstructions"], - inner: NonNullable, - accounts: AccountMeta[] -): Promise> { - const innerInstructionMap: Record = {}; - for (let i = 0; i < inner.length; ++i) { - const { index, instructions } = inner[i]; - if (index in innerInstructionMap) { - return Err({ - type: GetTransactionErrorType.RepeatOuterIndicesForInnerIx, - repeatedIndex: index, - }); - } - innerInstructionMap[index] = instructions; - } - const instructions: Instruction[] = []; - for (let outerI = 0; outerI < outer.length; ++outerI) { - const curOuter = outer[outerI]; - // TODO: figure out why the outer and inner instruction types don't have a stackHeight member even though the rpc always returns this. - // perhaps we need to patch web3 libs or there's some edge case we aren't aware of. - if ("stackHeight" in curOuter) { - return Err({ - type: GetTransactionErrorType.OuterIxStackHeightNonNull, - outerInstruction: curOuter, - }); - } - const programAccount = accounts[curOuter.programIdIndex].pubkey; - const idl = await getIdlForProgram(programAccount); - const outerIxWithDisplay = getIxWithDisplay( - { - ...curOuter, - data: Buffer.from(curOuter.data), - accounts: curOuter.accountKeyIndexes, - }, - idl, - accounts - ); - - const outerName = outerIxWithDisplay?.instruction.name ?? "unknown"; - const outerArgs = outerIxWithDisplay?.instructionDisplay?.args ?? []; - const outerAccountsWithData = - outerIxWithDisplay?.instructionDisplay?.accounts ?? []; - instructions.push({ - stackHeight: 1, - programIdIndex: curOuter.programIdIndex, - data: base58.encode(curOuter.data), - accounts: curOuter.accountKeyIndexes, - name: outerName, - args: outerArgs, - // we do not have balances here - accountsWithData: outerAccountsWithData.map(({ isWritable, ...a }) => ({ - ...a, - isWriteable: isWritable, - pubkey: a.pubkey.toBase58(), - })), - }); - let curStackHeight = 1; - const curInnerInstructions = innerInstructionMap[outerI] ?? []; - for (let innerI = 0; innerI < curInnerInstructions.length; ++innerI) { - const curInner = curInnerInstructions[innerI]; - const innerStackHeight: number = (curInner as any).stackHeight; - const isInvalidStackHeight = - typeof innerStackHeight !== "number" || - (innerStackHeight > curStackHeight && - curStackHeight + 1 !== innerStackHeight) || - innerStackHeight < 2; - if (isInvalidStackHeight) { - return Err({ - type: GetTransactionErrorType.InvalidStackHeightTransition, - outerInstructionIndex: outerI, - innerInstructionIndex: innerI, - priorStackHeight: curStackHeight, - innerStackHeight, - }); - } - const programAccount = accounts[curInner.programIdIndex].pubkey; - const idl = await getIdlForProgram(programAccount); - const innerIxWithDisplay = getIxWithDisplay( - { - ...curOuter, - data: Buffer.from(curOuter.data), - accounts: curOuter.accountKeyIndexes, - }, - idl, - accounts - ); - - const innerName = innerIxWithDisplay?.instruction.name ?? "unknown"; - const innerArgs = innerIxWithDisplay?.instructionDisplay?.args ?? []; - const innerAccountsWithData = - innerIxWithDisplay?.instructionDisplay?.accounts ?? []; - - instructions.push({ - stackHeight: innerStackHeight, - programIdIndex: curInner.programIdIndex, - data: curInner.data, - accounts: curInner.accounts, - name: innerName, - args: innerArgs, - // we do not have balances here - accountsWithData: innerAccountsWithData.map(({ isWritable, ...a }) => ({ - ...a, - isWriteable: isWritable, - pubkey: a.pubkey.toBase58(), - })), - }); - curStackHeight = innerStackHeight; - } - } - return Ok(instructions); -} - -async function getIdlForProgram( - programAccount: PublicKey -): Promise { - try { - let idl: Idl | null = PROGRAM_ID_TO_IDL_MAP[programAccount.toBase58()]; - if (!idl) { - idl = await Program.fetchIdl(programAccount, provider); - } - return idl; - } catch (e) { - return null; - } -} - -export type IdlAccount = { - name: string; - isMut: boolean; - isSigner: boolean; -}; - -export type IdlAccounts = { - name: string; - accounts: IdlAccount[]; -}; - -/** - * @private - */ -export type IdlAccountItem = IdlAccounts | IdlAccount; - -function getIxWithDisplay( - instruction: { accounts: number[]; data: Buffer }, - idl: Idl | null, - accountMetas: AccountMeta[] -): { - instruction: AnchorInstruction; - instructionDisplay: InstructionDisplay | null; -} | null { - if (!idl) { - return null; - } - let coder: BorshInstructionCoder | null = null; - let decodedIx: AnchorInstruction | null = null; - - // Added because of this error: - // User defined types not provided - // TypeError: field.type is not an Object. (evaluating '"vec" in field.type') - try { - coder = new BorshInstructionCoder(idl); - } catch (e) { - logger.error("error with initializing coder", e); - return null; - } - - if (!coder) { - logger.error("no coder can't continue"); - return null; - } - - try { - decodedIx = coder.decode(Buffer.from(instruction.data)); - } catch (e) { - logger.error("error with coder decoding of instruction:", e); - return null; - } - - if (!decodedIx) { - return null; - } - - const ix = idl.instructions.find((instr) => instr.name === decodedIx.name); - const flatIdlAccounts = flattenIdlAccounts(ix?.accounts); - const accounts = instruction.accounts.map((number, idx) => { - const meta = accountMetas[number]; - if (idx < flatIdlAccounts.length) { - return { - name: flatIdlAccounts[idx].name, - ...meta, - }; - } - // "Remaining accounts" are unnamed in Anchor. - else { - return { - name: `Remaining ${idx - flatIdlAccounts.length}`, - ...meta, - }; - } - }); - try { - const ixDisplay = coder.format(decodedIx, accounts); - - return { - instruction: decodedIx, - instructionDisplay: ixDisplay, - }; - } catch (e) { - logger.error("error with coder formatting of decodedIx:", e); - return null; - } -} - -function flattenIdlAccounts( - accounts: IdlAccountItem[], - prefix?: string -): IdlAccount[] { - return accounts - .map((account) => { - const accName = account.name; - if (Object.prototype.hasOwnProperty.call(account, "accounts")) { - const newPrefix = prefix ? `${prefix} > ${accName}` : accName; - - return flattenIdlAccounts((account).accounts, newPrefix); - } else { - return { - ...(account), - name: prefix ? `${prefix} > ${accName}` : accName, - }; - } - }) - .flat(); -} - -export async function getTransaction( - signature: string -): Promise> { - const txResponse = await connection.getTransaction(signature, { - maxSupportedTransactionVersion: 0, - }); - if (!txResponse) { - return Err({ - type: GetTransactionErrorType.NullGetTransactionResponse, - }); - } - const accountsResponse = await resolveAccounts(txResponse); - if (!accountsResponse.success) { - return Err({ - type: GetTransactionErrorType.ResolveAccountError, - error: accountsResponse.error, - }); - } - const { ok: accountsRaw } = accountsResponse; - const accounts: Account[] = []; - // Index to token balance - const preTokenBalances = parseTokenBalances( - txResponse.meta?.preTokenBalances ?? [], - accountsRaw - ); - if (!preTokenBalances.success) { - return Err({ - type: GetTransactionErrorType.DuplicateTokenAccounts, - duplicates: preTokenBalances.error.duplicates, - balanceType: "pre", - }); - } - const postTokenBalances = parseTokenBalances( - txResponse.meta?.postTokenBalances ?? [], - accountsRaw - ); - if (!postTokenBalances.success) { - return Err({ - type: GetTransactionErrorType.DuplicateTokenAccounts, - duplicates: postTokenBalances.error.duplicates, - balanceType: "post", - }); - } - - for (let i = 0; i < accountsRaw.length; ++i) { - const cur = accountsRaw.get(i); - const pubkey = cur!.toBase58(); - accounts.push({ - name: "", - pubkey, - isSigner: txResponse.transaction.message.isAccountSigner(i), - isWriteable: txResponse.transaction.message.isAccountWritable(i), - preBalance: BigInt(txResponse.meta?.preBalances[i]!), - postBalance: BigInt(txResponse.meta?.postBalances[i]!), - preTokenBalance: preTokenBalances.ok[pubkey], - postTokenBalance: postTokenBalances.ok[pubkey], - }); - } - - const accountMetas: AccountMeta[] = accounts.map((a) => ({ - pubkey: new PublicKey(a.pubkey), - isWritable: a.isWriteable ?? false, - isSigner: a.isSigner ?? false, - })); - - const instructionsResult = await parseInstructions( - txResponse.transaction.message.compiledInstructions, - txResponse.meta?.innerInstructions!, - accountMetas - ); - if (!instructionsResult.success) { - return instructionsResult; - } - const instructions = instructionsResult.ok; - - const parseResult = SerializableTransaction.safeParse({ - blockTime: txResponse.blockTime, - slot: txResponse.slot, - recentBlockhash: txResponse.transaction.message.recentBlockhash, - computeUnitsConsumed: BigInt(txResponse.meta?.computeUnitsConsumed!), - err: txResponse.meta?.err ?? undefined, - fee: BigInt(txResponse.meta?.fee!), - signatures: txResponse.transaction.signatures, - version: txResponse.version, - logMessages: txResponse.meta?.logMessages, - accounts, - instructions, - }); - if (parseResult.success) { - return Ok(parseResult.data); - } else { - return Err({ - type: GetTransactionErrorType.ZodError, - error: parseResult.error, - }); - } -} - -export function parseFormattedInstructionArgsData(data: string) { - let jsonString = data.replace(/'/g, '"'); - - jsonString = jsonString.replace(/(\w+):/g, '"$1":'); - - jsonString = jsonString.replace(/:\s*(\w+)(?=,|})/g, (match, p1) => { - return isNaN(p1) ? `: "${p1}"` : `: ${p1}`; - }); - - return JSON.parse(jsonString) as T; -} - -/* -// from txResponse.transaction.message.serialize() -// 22RoFnkikwwiZ1Tw47mqEQL2oSKD4xJBRDr1xxyayvyoghQ73TtM16tRW8a8d1Ue9tQ5FroTCAMoQALhjXbLh7E8 -const sampleTransaction = { - "blockTime":1708392365, - "meta":{ - "computeUnitsConsumed":115351, - "err":null, - "fee":25080, - "innerInstructions":[ - { - "index":3, - "instructions":[ - { - "accounts":[0,1], - "data":"111112PhCZ6LAeHDFtvbyHvk1VQAu373K5bsDc7zGtGftewwNJhnARLbzL3VyendLazkiH", - "programIdIndex":7, - "stackHeight":2 - }, - { - "accounts":[0,6,8,11,7,17], - "data":"1", - "programIdIndex":12, - "stackHeight":2 - }, - { - "accounts":[11], - "data":"84eT", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[0,6], - "data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL", - "programIdIndex":7, - "stackHeight":3 - }, - { - "accounts":[6], - "data":"P", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[6,11], - "data":"6Pq53B79epzehHA633bmpuCS2h6Y3kdWX4if2ingmWebA", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[0,5,8,15,7,17], - "data":"1", - "programIdIndex":12, - "stackHeight":2 - }, - { - "accounts":[15], - "data":"84eT", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[0,5], - "data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL", - "programIdIndex":7, - "stackHeight":3 - }, - { - "accounts":[5], - "data":"P", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[5,15], - "data":"6Pq53B79epzehHA633bmpuCS2h6Y3kdWX4if2ingmWebA", - "programIdIndex":17, - "stackHeight":3 - }, - { - "accounts":[9], - "data":"5H2mQahfhqnGk5qEg5kSeUZ6U33HdY2UUShDuG4tURrKyhVyQznphqNTE1Tksz6t982WMdCEKTYSyde8zX8FGJ3dHBb4iB1cQatoccDG7p9WgNtkujuu9qwZyFXnXHjzG4ycF9xUaqd2vy3J8qVLkJpLXGHWTHaXscazUWZhPyx7qVHbBtuWG512LZUWXNefRhTzwUum", - "programIdIndex":16, - "stackHeight":2 - } - ] - } - ], - "loadedAddresses":{ - "readonly":[], - "writable":[] - }, - "logMessages":[ - "Program 11111111111111111111111111111111 invoke [1]", - "Program 11111111111111111111111111111111 success", - "Program 11111111111111111111111111111111 invoke [1]", - "Program 11111111111111111111111111111111 success", - "Program 11111111111111111111111111111111 invoke [1]", - "Program 11111111111111111111111111111111 success", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [1]", - "Program log: Instruction: CreateMarket", - "Program 11111111111111111111111111111111 invoke [2]", - "Program 11111111111111111111111111111111 success", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]", - "Program log: Create","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: GetAccountDataSize", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1622 of 752557 compute units", - "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program 11111111111111111111111111111111 invoke [3]", - "Program 11111111111111111111111111111111 success", - "Program log: Initialize the associated token account", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: InitializeImmutableOwner", - "Program log: Please upgrade to SPL Token 2022 for immutable owner support", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 745917 compute units", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: InitializeAccount3", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4241 of 742033 compute units", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 29544 of 767032 compute units", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]", - "Program log: Create", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: GetAccountDataSize", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1622 of 723500 compute units", - "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program 11111111111111111111111111111111 invoke [3]", - "Program 11111111111111111111111111111111 success", - "Program log: Initialize the associated token account", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: InitializeImmutableOwner", - "Program log: Please upgrade to SPL Token 2022 for immutable owner support", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 716860 compute units", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", - "Program log: Instruction: InitializeAccount3", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4241 of 712976 compute units", - "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20544 of 728975 compute units", - "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [2]", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 2126 of 688925 compute units", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 114751 of 799550 compute units", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", - "Program ComputeBudget111111111111111111111111111111 invoke [1]", - "Program ComputeBudget111111111111111111111111111111 success" - ], - "postBalances":[ - 4068672160,6792960,633916800,636255360,633916800,2039280,2039280,1,0,0,10290359120,1461600,731913600,1,0,1461600,1141440,934087680 - ], - "postTokenBalances":[ - { - "accountIndex":5, - "mint":"GrV2aGFHGtwNUiDWHRY6oP4DGf23PY4iNJWcV5ZgEKf", - "owner":"3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", - "programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "uiTokenAmount":{ - "amount":"0","decimals":6,"uiAmount":null,"uiAmountString":"0" - } - }, - { - "accountIndex":6, - "mint":"ADwCAfmY6FdkFHqdv3Qw4pBoVYNhEZLW3wcwr41sGx8E", - "owner":"3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", - "programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "uiTokenAmount":{ - "amount":"0", - "decimals":9, - "uiAmount":null, - "uiAmountString":"0" - } - } - ], - "preBalances":[ - 5983657720,0,0,0,0,0,0,1,0,0,10290359120,1461600,731913600,1,0,1461600,1141440,934087680 - ], - "preTokenBalances":[], - "rewards":[], - "status":{"Ok":null} - }, - "slot":249251231, - "transaction":{ - "message":{ - "header":{ - "numReadonlySignedAccounts":0, - "numReadonlyUnsignedAccounts":11, - "numRequiredSignatures":5 - }, - "accountKeys":[ - "99dZcXhrYgEmHeMKAb9ezPaBqgMdg1RjCGSfHa7BeQEX", - "4yoswUWGJ2s7Wio2tVeD7dvEEuHWxyaYTXUW5yELwX4M", - "6GLWiqsUzXV1NJDcPkbrVq51aJmSmvZwpJTBkMmKaaaA", - "6HiwCD32ErrLbDogWtTB2zxE6GLzypTpK4QuPDRjFpjr", - "D9Ew92TMULsVDERnMLUjpNpCKRnDQWptS4rFYSVSjT1B", - "2ZLJaGWXZk1279w1zp3y3m2bTaKdwE4VaZQns8FfpooJ", - "69KYjQpYokoBXctmnedNgeed1qxeTJCaXjazojdH2Rs9", - "11111111111111111111111111111111", - "3hNNEucrY9Ns1fzWxSaVRDzeCCxELtEpMoVBECzxDWAC", - "8rDvL1qM41mYVNYS6oKLfGXyBGov3jLtbELToxjSwShj", - "ADCCEAbH8eixGj5t73vb4sKecSKo7ndgDSuWGvER4Loy", - "ADwCAfmY6FdkFHqdv3Qw4pBoVYNhEZLW3wcwr41sGx8E", - "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", - "ComputeBudget111111111111111111111111111111", - "GpLACVBR3DMxNDfeFMKrhNnycs7ghdCwJeXSvccL5a3Z", - "GrV2aGFHGtwNUiDWHRY6oP4DGf23PY4iNJWcV5ZgEKf", - "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb", - "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - ], - "recentBlockhash":"GkH5dBDtp4uqx7ScQuJVYMyCgXsnx9Z6JTi61mKM873V", - "instructions":[ - { - "accounts":[0,4], - "data":"11115j3Nzc8Ljr4BPxH9a4EThoPhhCp8WzdyQ2E9yALd9XKwvnkJgCxCLttsb6Ld85UTMw", - "programIdIndex":7, - "stackHeight":null - }, - { - "accounts":[0,2], - "data":"11115j3Nzc8Ljr4BPxH9a4EThoPhhCp8WzdyQ2E9yALd9XKwvnkJgCxCLttsb6Ld85UTMw", - "programIdIndex":7, - "stackHeight":null - }, - { - "accounts":[0,3], - "data":"11115iNQLx57j4ojPNAEtHcpGMqznSwVj6ZfVtARVE5WcRCiw5qLa6a3oiZ7sf8CSJgs8R", - "programIdIndex":7, - "stackHeight":null - }, - { - "accounts":[1,8,4,2,3,0,6,5,11,15,7,17,12,16,16,10,14,16,14,9,16], - "data":"7mYL3pfoBAM6CMTKWMvUkm2Kpvg7a6h6gU4wo2KewGc1B8WaokBjSkXJ5qpRv7LmEziCcpQhpjt6G5X15GBXtbPHzAxUg1NEGC3y", - "programIdIndex":16, - "stackHeight":null - }, - { - "accounts":[], - "data":"3WBgs5fm8oDy", - "programIdIndex":13, - "stackHeight":null - } - ], - "indexToProgramIds":{} - }, - "signatures":[ - "22RoFnkikwwiZ1Tw47mqEQL2oSKD4xJBRDr1xxyayvyoghQ73TtM16tRW8a8d1Ue9tQ5FroTCAMoQALhjXbLh7E8", - "2w26krC3MgYd2J8HrRtdTx6ifd8FTdYmrWKQwcF4qDUgrWGViareC1wCgP4XvvDixXggJ2CJZvtVRkehRCH3G1N7", - "rBq7JkrEsFqW4jP5mo4RYYg2DdfLNTQxFtmXiyA7b1Bww7Bmz3fHWua6zhMruUHKfw1apjSsgGaPUtpVTRDR6rt", - "2nf8UFdpwr4wm3KFD3HjCQuNcAhYFgvKt4KhjhZ4mbuu6WJEWuCGEqyypZB6XkkGdsRdmkKod4PBSmRVKZ12cMpC", - "3D7YMtEzisFjkxeAuXFtFesYi3FAfruX4h9TeVQAb2yxnLexif6NK3oMAko5ohX5p6fLNEVm5jRgqizjkBvaHhbC" - ] - }, - "version":"legacy" -} -*/ - -/* -// console.logged txResponse -// 3ggvCQ979T5gRV56bUU4YGtYYJruAZypgTxgnrw4eoVP9ARKK8VT8j7Dy7TnBQ6r4j511yqYZM7mdkk8fJ363s9P -{ - blockTime: 1708665394, - meta: { - computeUnitsConsumed: 24859, - err: null, - fee: 7000, - innerInstructions: [ - [Object ...] - ], - loadedAddresses: { - readonly: [], - writable: [], - }, - logMessages: [ - "Program ComputeBudget111111111111111111111111111111 invoke [1]", "Program ComputeBudget111111111111111111111111111111 success", - "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN invoke [1]", "Program log: Instruction: CancelOrderByClientId", - "Program log: Observation: 3564785", "Program log: Weighted observation: 92481217255", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb invoke [2]", "Program log: Instruction: CancelOrderByClientOrderId", - "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb consumed 8391 of 185296 compute units", - "Program return: opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb AQAAAAAAAAA=", "Program opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb success", - "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN consumed 24709 of 199850 compute units", - "Program return: TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN AQAAAAAAAAA=", "Program TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN success" - ], - postBalances: [ 250122967, 633916800, 9688320, 633916800, 1614720, 6792960, 1, - 1141440, 1141440 - ], - postTokenBalances: [], - preBalances: [ 250129967, 633916800, 9688320, 633916800, 1614720, 6792960, 1, - 1141440, 1141440 - ], - preTokenBalances: [], - returnData: { - data: [ "AQAAAAAAAAA=", "base64" ], - programId: "TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN", - }, - rewards: [], - status: { - Ok: null, - }, - }, - slot: 249891238, - transaction: { - message: Message { - header: [Object ...], - accountKeys: [ - [PublicKey(8Cwx4yR2sFAC5Pdx2NgGHxCk1gJrtSTxJoyqVonqndhq) ...], [PublicKey(6GLWiqsUzXV1NJDcPkbrVq51aJmSmvZwpJTBkMmKaaaA) ...], [PublicKey(7DFk8ZwyRzEW8ysngKhybSaVtx92g7KhTZ2iqmTs5s3W) ...], [PublicKey(D9Ew92TMULsVDERnMLUjpNpCKRnDQWptS4rFYSVSjT1B) ...], [PublicKey(GpLACVBR3DMxNDfeFMKrhNnycs7ghdCwJeXSvccL5a3Z) ...], [PublicKey(4yoswUWGJ2s7Wio2tVeD7dvEEuHWxyaYTXUW5yELwX4M) ...], [PublicKey(ComputeBudget111111111111111111111111111111) ...], [PublicKey(opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb) ...], [PublicKey(TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN) ...] - ], - recentBlockhash: "9jKYzGuvqjYwnuhJmoSb5b8MEsirdqDXR3Sjvarg5VKF", - instructions: [ - [Object ...], [Object ...] - ], - indexToProgramIds: Map(2) { - 6: [PublicKey(ComputeBudget111111111111111111111111111111) ...], - 8: [PublicKey(TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN) ...], - }, - version: [Getter], - staticAccountKeys: [Getter], - compiledInstructions: [Getter], - addressTableLookups: [Getter], - getAccountKeys: [Function: getAccountKeys], - isAccountSigner: [Function: isAccountSigner], - isAccountWritable: [Function: isAccountWritable], - isProgramId: [Function: isProgramId], - programIds: [Function: programIds], - nonProgramIds: [Function: nonProgramIds], - serialize: [Function: serialize], - }, - signatures: [ "3ggvCQ979T5gRV56bUU4YGtYYJruAZypgTxgnrw4eoVP9ARKK8VT8j7Dy7TnBQ6r4j511yqYZM7mdkk8fJ363s9P" - ], - }, - version: "legacy", -} -*/ diff --git a/packages/old_indexer/src/transaction/watcher.ts b/packages/old_indexer/src/transaction/watcher.ts deleted file mode 100644 index 39eed8a3..00000000 --- a/packages/old_indexer/src/transaction/watcher.ts +++ /dev/null @@ -1,619 +0,0 @@ -import { ConfirmedSignatureInfo, PublicKey } from "@solana/web3.js"; -import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; -import { - SERIALIZED_TRANSACTION_LOGIC_VERSION, - Transaction, - getTransaction, - serialize, -} from "./serializer"; -import { getTransactionHistory } from "./history"; -import { connection } from "../connection"; -import { logger } from "../logger"; -import { Err, Ok, Result, TaggedUnion } from "../match"; -import { - InstructionType, - TransactionWatchStatus, - TransactionWatcherTransactionRecord, -} from "@metadaoproject/indexer-db/lib/schema"; -import { newTxQueue } from "../indexers/start-transaction-history-indexers"; - -/* -$ pnpm sql "select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers'" -> @metadaoproject/indexer-db@ sql /workspaces/meta-repo/repos/futarchy-indexer/packages/database -> bun src/run-sql.ts "select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers'" - -select table_catalog, table_schema, table_name, column_name, ordinal_position from information_schema.columns where table_schema='public' and table_name='transaction_watchers' -total: 6 -table_catalog table_schema table_name column_name ordinal_position ---------------------------------------------------------------------------------------------- -railway public transaction_watchers acct 1 -railway public transaction_watchers latest_tx_sig 2 -railway public transaction_watchers description 3 -railway public transaction_watchers checked_up_to_slot 4 -railway public transaction_watchers first_tx_sig 5 -railway public transaction_watchers serializer_logic_version 6 -$ pnpm sql "insert into transaction_watchers values ('TWAPrdhADy2aTKN5iFZtNnkQYXERD9NvKjPFVPMSCNN', NULL, 'openbookv2 twap watcher', 0, NULL, 0)" -*/ - -export enum WatcherBackfillError { - StoppedBackfill = "StoppedBackfill", - SlotCheckHistoryMismatch = "SlotCheckHistoryMismatch", - GetTransactionHistoryFailure = "GetTransactionHistoryFailure", - TransactionParseFailure = "TransactionParseFailure", - TransactionUpsertFailure = "TransactionUpsertFailure", - WatcherUpdateFailure = "WatcherUpdateFailure", - WatcherNotFound = "WatcherNotFound", - StartedWithPollingIntervalSet = "StartedWithPollingIntervalSet", -} - -type TransactionWatcherRecord = typeof schema.transactionWatchers._.inferSelect; -type TransactionRecord = typeof schema.transactions._.inferInsert; - -const watchers: Record = {}; -const MAX_RETRIES = 12; - -class TransactionWatcher { - private account: PublicKey; - private description: string; - private latestTxSig: string | undefined; - private checkedUpToSlot: string; - private logicVersion: number; - private pollerIntervalId: ReturnType | undefined; - private rpcWebsocket: number | undefined; - private stopped: boolean; - private backfilling: boolean; - private errorCount: number = 0; - public constructor({ - acct, - description, - latestTxSig, - checkedUpToSlot, - serializerLogicVersion, - }: TransactionWatcherRecord) { - this.account = new PublicKey(acct); - this.description = description; - this.latestTxSig = latestTxSig ?? undefined; - this.checkedUpToSlot = checkedUpToSlot; - this.logicVersion = serializerLogicVersion; - this.stopped = false; - this.backfilling = false; - this.start(); - } - - private async start() { - if (this.pollerIntervalId !== undefined) { - logger.error( - `Interval was ${ - this.pollerIntervalId - } when starting ${this.account.toBase58()}` - ); - return Err({ type: WatcherBackfillError.StartedWithPollingIntervalSet }); - } - await this.handleBackfillFromLatest(); - // TODO: add websocket for realtime updates (might be lossy, but would allow us to increase poll time meaning less rpc costs) - this.pollerIntervalId = setInterval(async () => { - await this.handleBackfillFromLatest(); - }, 10000); - return Ok(`successfully started watcher for ${this.account.toBase58()}`); - } - - private async handleBackfillFromLatest() { - const backfillRes = await this.backfillFromLatest(); - switch (backfillRes.success) { - case true: - { - if (this.account) { - logger.info( - `successfully ran backfill for acct: ${this.account.toBase58()}` - ); - } - logger.info(`success message: ${backfillRes.ok}`); - } - break; - case false: - { - logger.error( - `error running backfill from latest: ${ - backfillRes.error.type - }. For acct: ${this.account.toBase58()}` - ); - } - break; - } - } - - private async backfillFromLatest(): Promise< - | { - success: false; - error: TaggedUnion; - } - | { - success: true; - ok: string; - } - > { - if (this.stopped) - return Ok("tried to call backfillFromLatest a stopped watcher"); - if (this.backfilling) - return Ok( - "tried to call backfillFromLatest on an already backfilling watcher" - ); - this.backfilling = true; - const acct = this.account.toBase58(); - const latestFinalizedSlot = BigInt(await connection.getSlot("finalized")); - const historyRes = - await this.getTransactionHistoryFromFinalizedSlotWithRetry(); - if (!historyRes.success) { - this.errorCount += 1; - if (this.errorCount > MAX_RETRIES) { - logger.errorWithChatBotAlert("marking transaction watcher as failed"); - // update tx watcher status to failed and exit, but other tx watchers continue - const markFailedResult = await this.markTransactionWatcherAsFailed( - historyRes.error.type - ); - if (!markFailedResult?.success) { - return markFailedResult; - } - return historyRes; - } else { - return Ok("tx watcher hit an error, retrying backfill"); - } - } - // history fetch was successful - const history = historyRes.ok; - logger.info( - `history after ${this.latestTxSig} is length ${history.length}` - ); - let numIndexed = 0; - for (const signatureInfo of history) { - const res = await this.processTransactionInHistory( - acct, - signatureInfo, - numIndexed - ); - if (!res.success) { - logger.error( - "error processing transaction", - res.error, - signatureInfo.signature, - acct - ); - } - } - // Update checkedUpToSlot to latest confirmed slot. If we don't do this, then checkedUpToSlot would only be updated once there's a new - // transaction, and this would mean indexers would stall in cases where some of the dependent watchers don't have frequent transactions. - // It's possible that this might be the source of bugs if somehow new transactions come in that are before the latest confirmed slot but were - // not returned by the RPC's tx history. - // EDIT: encountered above bug so trying to resolve by switching to finalized slot rather than confirmed. - // EDIT: even switching to finalized didn't really work. This logic needs rethinking - const newCheckedUpToSlot = - BigInt(this.checkedUpToSlot) > latestFinalizedSlot - ? this.checkedUpToSlot - : latestFinalizedSlot.toString(); - if (newCheckedUpToSlot === latestFinalizedSlot.toString()) { - console.log( - `For acct ${acct}, using finalized slot of ${latestFinalizedSlot}` - ); - } - const updateResult = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - checkedUpToSlot: newCheckedUpToSlot.toString(), - updatedAt: new Date(), - }) - .where(eq(schema.transactionWatchers.acct, acct)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updateResult.length !== 1 || updateResult[0].acct !== acct) { - logger.error( - `Failed to update tx watcher for acct ${acct} at end of backfill` - ); - return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); - } - this.checkedUpToSlot = newCheckedUpToSlot; - this.backfilling = false; - return Ok(`${acct} watcher is up to date`); - } - - private async processTransactionInHistory( - acct: string, - signatureInfo: ConfirmedSignatureInfo, - numIndexed: number - ): Promise< - | { - success: true; - ok: { priorSlot: bigint; numIndexed: number }; - } - | { - success: false; - error: TaggedUnion; - } - > { - const priorSlot = this.checkedUpToSlot; - if (this.stopped) { - logger.error(`Stopped watcher for ${acct} mid backfill`); - return Err({ type: WatcherBackfillError.StoppedBackfill }); - } - const { slot: slotAsNum, signature } = signatureInfo; - const slot = BigInt(slotAsNum); - // TODO: lock should be done here. It's probably fine for now since we only have 1 instance. - // I can think of weird states though where you have this stopped watcher and another started one. - // Leaving as todo since optimistic locking might be preferred - const curWatcherRecord = ( - await usingDb((db) => - db - .select() - .from(schema.transactionWatchers) - .where(eq(schema.transactionWatchers.acct, acct)) - .execute() - ) - )?.[0]; - - if (!curWatcherRecord) - return Err({ type: WatcherBackfillError.WatcherNotFound }); - // TODO: we don't need to necessarily stop this watcher - // just because of one txn slot being less than the checked up to slo - // const { checkedUpToSlot } = curWatcherRecord; - // if (slot <= checkedUpToSlot) { - // const errorMessage = `watcher for account ${acct} supposedly checked up to slot ${checkedUpToSlot} but history returned sig ${signature} with slot ${slot}`; - // logger.error(errorMessage); - // this.stop(); - // return Err({ type: WatcherBackfillError.SlotCheckHistoryMismatch }); - // } - const maybeCurTxRecord = - (await usingDb((db) => - db - .select() - .from(schema.transactions) - .where(eq(schema.transactions.txSig, signature)) - .execute() - )) ?? []; - if ( - maybeCurTxRecord.length === 0 || - maybeCurTxRecord[0].serializerLogicVersion < - SERIALIZED_TRANSACTION_LOGIC_VERSION - ) { - const parseTxResult = await getTransaction(signature); - if (!parseTxResult.success) { - logger.error( - `Failed to parse tx ${signature}\n` + - JSON.stringify(parseTxResult.error) - ); - this.stop(); - return Err({ type: WatcherBackfillError.TransactionParseFailure }); - } - const { ok: serializableTx } = parseTxResult; - const res = await handleNewTransaction( - signature, - slot, - serializableTx, - acct - ); - if (res && !res?.success) { - return Err({ type: res.error.type }); - } - } - - // We could opt to only update slot at end, but updating it now means indexers can progress while a backfill is in progress. - // That's preferrable since the backfill could be a lot of transactions and it could stall if there are any bugs in the tx backup logic - // We can't set the checked up to slot as the current tx's slot, since there might be a tx after this one on the same slot. So we instead - // need to set it to the prior tx's slot if that slot is less than the current slot. - const newCheckedUpToSlot = - BigInt(slot) > BigInt(priorSlot) ? priorSlot : this.checkedUpToSlot; - const updateResult = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - acct, - latestTxSig: signature, - firstTxSig: curWatcherRecord.firstTxSig ?? signature, - serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, - checkedUpToSlot: newCheckedUpToSlot.toString(), - updatedAt: new Date(), - }) - .where(eq(schema.transactionWatchers.acct, acct)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updateResult.length !== 1 || updateResult[0].acct !== acct) { - logger.error( - `Failed to update tx watcher for acct ${acct} on tx ${signature}` - ); - return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); - } - this.checkedUpToSlot = newCheckedUpToSlot; - numIndexed++; - if (numIndexed % 50 === 0) { - logger.info(`(${numIndexed}) ${acct} watcher`); - } - - return Ok({ priorSlot: slot, numIndexed }); - } - - private async getTransactionHistoryFromFinalizedSlotWithRetry(): Promise< - Result - > { - const maxRetries = 3; - const retryDelay = 1000; - let maxSignatures = 0; - let responseWithMaxSignatures: ConfirmedSignatureInfo[] = []; - - for (let i = 0; i < maxRetries; i++) { - try { - const txSignatures = await getTransactionHistory( - this.account, - this.checkedUpToSlot.toString(), - { after: this.latestTxSig } - ); - - if (txSignatures.length > maxSignatures) { - maxSignatures = txSignatures.length; - responseWithMaxSignatures = txSignatures; - } - - if (i > 0 && txSignatures.length !== maxSignatures) { - console.log( - "Difference noticed in tx count during getTransactionHistory RPC call attempts. New length is", - txSignatures.length, - " vs previous length is", - maxSignatures - ); - } - } catch (error) { - if (i === maxRetries - 1) - return Err({ - type: WatcherBackfillError.GetTransactionHistoryFailure, - }); - } - - // Wait before retrying - await new Promise((resolve) => setTimeout(resolve, retryDelay)); - } - - // Return the response with the max signatures after all retries - return Ok(responseWithMaxSignatures); - } - - private async markTransactionWatcherAsFailed(failureLog: string) { - this.backfilling = false; - this.stopped = true; - const acct = this.account.toBase58(); - const updateResult = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - acct, - status: TransactionWatchStatus.Failed, - failureLog, - updatedAt: new Date(), - }) - .where(eq(schema.transactionWatchers.acct, acct)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updateResult.length !== 1 || updateResult[0].acct !== acct) { - logger.errorWithChatBotAlert( - `Failed to mark tx watcher for acct ${acct} as failed` - ); - return Err({ type: WatcherBackfillError.WatcherUpdateFailure }); - } - return Ok("successfully marked transaction watcher as failed"); - } - - public stop() { - this.stopped = true; - if (this.pollerIntervalId === undefined) { - logger.warn( - `Interval was ${ - this.pollerIntervalId - } when stopping ${this.account.toBase58()}` - ); - } - clearInterval(this.pollerIntervalId); - this.pollerIntervalId = undefined; - } -} - -let updatingWatchers = false; - -async function handleNewTransaction( - signature: string, - slot: bigint, - parsedTx: Transaction, - acct: string -) { - const transactionRecord: TransactionRecord = { - txSig: signature, - slot: slot.toString(), - blockTime: new Date(parsedTx.blockTime * 1000), // TODO need to verify if this is correct - failed: parsedTx.err !== undefined, - payload: serialize(parsedTx), - serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, - mainIxType: getMainIxTypeFromTransaction(parsedTx), - }; - const upsertResult = - (await usingDb((db) => - db - .insert(schema.transactions) - .values(transactionRecord) - .onConflictDoUpdate({ - target: schema.transactions.txSig, - set: transactionRecord, - }) - .returning({ txSig: schema.transactions.txSig }) - )) ?? []; - if (upsertResult.length !== 1 || upsertResult[0].txSig !== signature) { - logger.error( - `Failed to upsert ${signature}. ${JSON.stringify(transactionRecord)}` - ); - return Err({ type: WatcherBackfillError.TransactionUpsertFailure }); - } - - // TODO: maybe i need to validate below succeeded. I can't use returning because this isn't an upsert so it could - // be a no-op in the happy path - const watcherTxRecord: TransactionWatcherTransactionRecord = { - txSig: signature, - slot: slot.toString(), - watcherAcct: acct, - }; - const insertRes = - (await usingDb((db) => - db - .insert(schema.transactionWatcherTransactions) - .values(watcherTxRecord) - .onConflictDoNothing() - .returning({ acct: schema.transactionWatcherTransactions.watcherAcct }) - )) ?? []; - if (insertRes.length > 0) { - console.log("successfully inserted new t watch tx", insertRes[0].acct); - } - - // now insert into queue - await newTxQueue.push({ - transactions: transactionRecord, - transaction_watcher_transactions: watcherTxRecord, - }); -} - -export function getMainIxTypeFromTransaction( - tx: Transaction -): InstructionType | null { - const hasSwap = tx.instructions.some((ix) => ix.name === "swap"); - const hasMint = tx.instructions.some( - (ix) => ix.name === "mintConditionalTokens" - ); - if (hasSwap && hasMint) { - return InstructionType.VaultMintAndAmmSwap; - } - if (hasSwap) { - return InstructionType.AmmSwap; - } - if (tx.instructions.some((ix) => ix.name === "addLiquidity")) { - return InstructionType.AmmDeposit; - } - if (tx.instructions.some((ix) => ix.name === "removeLiquidity")) { - return InstructionType.AmmWithdraw; - } - if (tx.instructions.some((ix) => ix.name === "placeOrder")) { - return InstructionType.OpenbookPlaceOrder; - } - if (tx.instructions.some((ix) => ix.name === "cancelOrder")) { - return InstructionType.OpenbookCancelOrder; - } - if (hasMint) { - return InstructionType.VaultMintConditionalTokens; - } - if (tx.instructions.some((ix) => ix.name === "initializeProposal")) { - return InstructionType.AutocratInitializeProposal; - } - if (tx.instructions.some((ix) => ix.name === "finalizeProposal")) { - return InstructionType.AutocratFinalizeProposal; - } - if ( - tx.instructions.some( - (ix) => ix.name === "mergeConditionalTokensForUnderlyingTokens" - ) - ) { - return InstructionType.VaultMergeConditionalTokens; - } - if ( - tx.instructions.some( - (ix) => ix.name === "redeemConditionalTokensForUnderlyingTokens" - ) - ) { - return InstructionType.VaultRedeemConditionalTokensForUnderlyingTokens; - } - return null; -} - -export async function startTransactionWatchers() { - async function getWatchers() { - updatingWatchers = true; - const curWatchers = - (await usingDb((db) => - db - .select() - .from(schema.transactionWatchers) - .where( - eq(schema.transactionWatchers.status, TransactionWatchStatus.Active) - ) - .execute() - )) ?? []; - const curWatchersByAccount: Record = {}; - const watchersToStart: Set = new Set(); - const watchersToStop: Set = new Set(); - // TODO: we need a way to reset running watchers if they're slot or tx was rolled back - for (const watcherInDb of curWatchers) { - curWatchersByAccount[watcherInDb.acct] = watcherInDb; - const alreadyWatching = watcherInDb.acct in watchers; - if (!alreadyWatching) { - watchersToStart.add(watcherInDb.acct); - } else { - if ( - watcherInDb.serializerLogicVersion !== - SERIALIZED_TRANSACTION_LOGIC_VERSION - ) { - const { acct, serializerLogicVersion } = watcherInDb; - logger.info( - `reseting ${acct}. existing logic version of ${serializerLogicVersion} current is ${SERIALIZED_TRANSACTION_LOGIC_VERSION}` - ); - watchers[acct]?.stop(); - delete watchers[acct]; - const updated = - (await usingDb((db) => - db - .update(schema.transactionWatchers) - .set({ - serializerLogicVersion: SERIALIZED_TRANSACTION_LOGIC_VERSION, - latestTxSig: null, - checkedUpToSlot: "0", - updatedAt: new Date(), - }) - .where(eq(schema.transactionWatchers.acct, acct)) - .returning({ acct: schema.transactionWatchers.acct }) - )) ?? []; - if (updated.length !== 1 || updated[0].acct !== acct) { - const error = new Error( - `Failed to update ${acct} watcher. ${JSON.stringify(updated)}` - ); - logger.error(error.message); - throw error; - } - } - } - } - for (const runningWatcherAccount in watchers) { - if (!(runningWatcherAccount in curWatchersByAccount)) { - watchersToStop.add(runningWatcherAccount); - } - } - if (watchersToStop.size) { - logger.info(`Stopping ${watchersToStop.size} watchers:`); - let i = 0; - for (const watcherToStopAcct of watchersToStop) { - logger.info(` ${++i}. ${watcherToStopAcct}`); - watchers[watcherToStopAcct]?.stop(); - delete watchers[watcherToStopAcct]; - } - } - if (watchersToStart.size) { - logger.info(`Starting ${watchersToStart.size} watchers:`); - let i = 0; - for (const watcherToStartAcct of watchersToStart) { - const prefix = ` ${++i}. `; - logger.info(`${prefix}${watcherToStartAcct}`); - const cur = curWatchersByAccount[watcherToStartAcct]; - watchers[watcherToStartAcct] = new TransactionWatcher(cur); - } - } - updatingWatchers = false; - } - setInterval(() => { - if (!updatingWatchers) { - getWatchers(); - } - }, 5000); - getWatchers(); -} diff --git a/packages/old_indexer/src/types/errors.ts b/packages/old_indexer/src/types/errors.ts deleted file mode 100644 index 461ff265..00000000 --- a/packages/old_indexer/src/types/errors.ts +++ /dev/null @@ -1,14 +0,0 @@ -export enum AmmInstructionIndexerError { - GeneralError = "GeneralError", - MissingMarket = "MissingMarket", - FailedSwap = "FailedSwap", -} - -export enum SwapPersistableError { - GeneralError = "GeneralError", - AlreadyPersistedSwap = "AlreadyPersistedSwap", - NonSwapTransaction = "NonSwapTransaction", - TransactionParseError = "TransactionParseError", - ArbTransactionError = "ArbTransactionError", - PriceError = "PriceError", -} diff --git a/packages/old_indexer/src/types/index.ts b/packages/old_indexer/src/types/index.ts deleted file mode 100644 index 1e09b191..00000000 --- a/packages/old_indexer/src/types/index.ts +++ /dev/null @@ -1,41 +0,0 @@ - -import { - IndexerImplementation, - IndexerType, -} from "@metadaoproject/indexer-db/lib/schema"; - -export type IndexerWithAccountDeps = { - indexers: { - name: string; - implementation: IndexerImplementation; - latestSlotProcessed: string; - indexerType: IndexerType; - } | null; - indexer_account_dependencies: { - name: string; - acct: string; - latestTxSigProcessed: string | null; - } | null; -}; - -export type User = { - userAcct: string; -}; - -export type UserPerformanceTotals = { - tokensBought: number; - tokensSold: number; - volumeBought: number; - volumeSold: number; - tokensBoughtResolvingMarket: number; - tokensSoldResolvingMarket: number; - volumeBoughtResolvingMarket: number; - volumeSoldResolvingMarket: number; - buyOrderCount: number; - sellOrderCount: number; -}; - -export type UserPerformance = { - proposalAcct: string; -} & User & - UserPerformanceTotals; diff --git a/packages/old_indexer/src/types/swaps.ts b/packages/old_indexer/src/types/swaps.ts deleted file mode 100644 index 3ace4d68..00000000 --- a/packages/old_indexer/src/types/swaps.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - OrdersRecord, - TakesRecord, -} from "@metadaoproject/indexer-db/lib/schema"; - -export type SwapPersistable = { - ordersRecord: OrdersRecord; - takesRecord: TakesRecord; -}; diff --git a/packages/old_indexer/src/usecases/math.test.ts b/packages/old_indexer/src/usecases/math.test.ts deleted file mode 100644 index c62dbd66..00000000 --- a/packages/old_indexer/src/usecases/math.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { expect, test, describe } from "bun:test"; -import { getHumanPrice } from "./math"; -import { PriceMath } from "@metadaoproject/futarchy/v0.4"; -import { BN } from "@coral-xyz/anchor"; - -describe("getHumanPrice", () => { - test("decimal value", () => { - const priceFromReserves = PriceMath.getAmmPriceFromReserves( - new BN(25000000000), - new BN(10000000000) - ); - - const price = getHumanPrice(priceFromReserves, 6, 6); - - expect(price).toBe(0.4); - }); -}); diff --git a/packages/old_indexer/src/usecases/math.ts b/packages/old_indexer/src/usecases/math.ts deleted file mode 100644 index e1078b62..00000000 --- a/packages/old_indexer/src/usecases/math.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { BN } from "@coral-xyz/anchor"; -import { logger } from "../logger"; - -export function getHumanPrice( - ammPrice: BN, - baseDecimals: number, - quoteDecimals: number -): number { - const decimalScalar = new BN(10).pow( - new BN(quoteDecimals - baseDecimals).abs() - ); - const price1e12 = - quoteDecimals > baseDecimals - ? ammPrice.div(decimalScalar) - : ammPrice.mul(decimalScalar); - - try { - return price1e12.toNumber() / 1e12; - } catch (e) { - logger.warn("toNumber failed, returning div by 1e12"); - return price1e12.div(new BN(1e12)).toNumber(); - } -} diff --git a/packages/old_indexer/tsconfig.json b/packages/old_indexer/tsconfig.json deleted file mode 100644 index c69e542e..00000000 --- a/packages/old_indexer/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig-base.json", - "compilerOptions": { - "module": "ESNext", - "target": "ESNext", - "moduleResolution": "bundler", - "types": ["node", "bun-types", "inquirer"] - } -} diff --git a/packages/v4_indexer/Dockerfile b/packages/v4_indexer/Dockerfile deleted file mode 100644 index 29b666ef..00000000 --- a/packages/v4_indexer/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:alpine3.18 - -# Some of the dependencies require node-gyp -RUN apk add --no-cache python3 make g++ -RUN if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi - -# Bun requires glibc https://github.com/oven-sh/bun/issues/5545#issuecomment-1722306576 -RUN apk --no-cache add ca-certificates wget -RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk -RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk - -RUN apk add --no-cache git - -EXPOSE 8080 -RUN corepack prepare pnpm@9.11.0 --activate -RUN corepack enable -ENV REPO_DIR /home/indexer/futarchy-indexer -RUN mkdir -p $REPO_DIR -WORKDIR $REPO_DIR -COPY . . -RUN pnpm install -CMD ["pnpm", "start-service"] diff --git a/packages/v4_indexer/package.json b/packages/v4_indexer/package.json deleted file mode 100644 index c111aea3..00000000 --- a/packages/v4_indexer/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@metadaoproject/indexer-service", - "description": "indexer microservice", - "private": "true", - "scripts": { - "cli": "bun src/cli/index.ts", - "start": "bun src/index.ts", - "test": "bun test" - }, - "dependencies": { - "@coral-xyz/anchor": "^0.29.0", - "@debridge-finance/solana-transaction-parser": "^2.0.1", - "@lukasdeco/prom-client": "^15.1.4", - "@metadaoproject/futarchy": "^0.4.0-alpha.18", - "@metadaoproject/futarchy-sdk": "4.0.0-alpha.31", - "@metadaoproject/indexer-db": "workspace:*", - "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", - "@metaplex-foundation/umi-uploader-bundlr": "^0.9.1", - "@openbook-dex/openbook-v2": "^0.1.9", - "@orca-so/whirlpools-sdk": "^0.12.5", - "@solana/spl-token": "^0.3.8", - "@solana/web3.js": "^1.90.0", - "@types/cors": "^2.8.17", - "ansicolor": "^2.0.1", - "axios": "^1.7.2", - "bs58": "^4.0.1", - "commander": "^12.0.0", - "cors": "^2.8.5", - "croner": "^8.0.2", - "drizzle-orm": "^0.30.6", - "express": "^4.19.2", - "fastq": "^1.17.1", - "inquirer": "^9.2.14", - "jsonwebtoken": "^9.0.2", - "match-discriminated-union": "^1.0.0", - "tweetnacl": "^1.0.3", - "zod": "^3.22.4" - }, - "devDependencies": { - "@types/bs58": "^4.0.1", - "@types/express": "^4.17.21", - "@types/inquirer": "^9.0.7", - "@types/jsonwebtoken": "^9.0.6", - "@types/node": "^20.10.6", - "bun-types": "^1.0.30" - } -} diff --git a/packages/v4_indexer/src/adapters/telegram-bot.ts b/packages/v4_indexer/src/adapters/telegram-bot.ts deleted file mode 100644 index 07a4ea08..00000000 --- a/packages/v4_indexer/src/adapters/telegram-bot.ts +++ /dev/null @@ -1,88 +0,0 @@ -import axios, { AxiosInstance, AxiosResponse } from "axios"; - -type TelegramBotConfig = { - token: string; -}; - -export class TelegramBotAPI implements AlertChatBotInterface { - private readonly apiUrl: string; - private readonly httpClient: AxiosInstance; - - constructor(config: TelegramBotConfig) { - this.apiUrl = `https://api.telegram.org/bot${config.token}/`; - this.httpClient = axios.create({ - baseURL: this.apiUrl, - headers: { - "Content-Type": "application/json", - }, - }); - } - - private async request( - method: "GET" | "POST", - endpoint: string, - params?: object - ): Promise> { - let response: AxiosResponse>; - try { - if (method === "GET") { - response = await this.httpClient.get(endpoint, { params }); - } else { - response = await this.httpClient.post(endpoint, params); - } - return response.data; - } catch (error) { - throw new Error(`Failed to make request: ${error}`); - } - } - - public async getMe(): Promise> { - return this.request("GET", "getMe"); - } - - public async sendMessage( - chatId: number | string, - text: string - ): Promise | null> { - const params = { chat_id: chatId, text }; - try { - return this.request("POST", "sendMessage", params); - } catch (e) { - console.error(e); - return null; - } - } - - public async getUpdates( - offset?: number, - limit?: number, - timeout?: number, - allowed_updates?: string[] - ): Promise> { - const params = { offset, limit, timeout, allowed_updates }; - return this.request("GET", "getUpdates", params); - } - - // Add more methods as needed for other API endpoints -} - -type ChatbotApiResponse = { - ok: boolean; - result?: T; - description?: string; - error_code?: number; -}; - -export interface AlertChatBotInterface { - getMe(): Promise>; - sendMessage( - chatId: number | string, - text: string - ): Promise | null>; - getUpdates( - offset?: number, - limit?: number, - timeout?: number, - allowed_updates?: string[] - ): Promise>; -} diff --git a/packages/v4_indexer/src/connection.ts b/packages/v4_indexer/src/connection.ts deleted file mode 100644 index eafd196f..00000000 --- a/packages/v4_indexer/src/connection.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Connection } from "@solana/web3.js"; -import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; -import { ConditionalVaultClient, AmmClient } from "@metadaoproject/futarchy/v0.4"; - -export const RPC_ENDPOINT = process.env.RPC_ENDPOINT ?? ""; - -if (!RPC_ENDPOINT) { - throw new Error("RPC_ENDPOINT is not set"); -} - -export const connection: Connection = new Connection(RPC_ENDPOINT, "confirmed"); -// the indexer will only be reading, not writing -export const readonlyWallet: Wallet = undefined as unknown as Wallet; -export const provider = new AnchorProvider(connection, readonlyWallet, { - commitment: "confirmed", -}); - -export const ammClient = AmmClient.createClient({ provider }); -export const conditionalVaultClient = ConditionalVaultClient.createClient({ provider }); diff --git a/packages/v4_indexer/src/index.ts b/packages/v4_indexer/src/index.ts deleted file mode 100644 index a3413acd..00000000 --- a/packages/v4_indexer/src/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { indexAmmEvents, indexVaultEvents } from "./indexEvents.js"; -import { backfill, frontfill } from "./populateSignatures.js"; - -// NEW FUTARCHY INDEXER - -// To minimize complexity, the indexer is split into two parts: -// 1. signature ingestion -// 2. signature processing - -// SIGNATURE INGESTION -// Signature ingestion is responsible for fetching new signatures -// from the network and storing them in the `signatures` table. -// Today, this is done by the `populateSignatures` function. Under -// the hood, it uses the `getSignaturesForAddress` RPC endpoint. -// This is nice because it means that the indexer can fetch -// historical data. However, it is higher latency than subscribing -// to transactions via a websocket, like the below: -// https://docs.helius.dev/webhooks-and-websockets/enhanced-websockets -// We could use this to get real-time transaction data in the future. - -// SIGNATURE PROCESSING -// Signature processing is responsible for fetching the transactions -// corresponding to the signatures and parsing them to extract event data. -// This is done by the `indexAmmEvents` and `indexVaultEvents` functions. -// Today, insertion of new accounts (questions, conditional vaults, AMMs) -// works. However, updating them (when, for example, a swap happens) doesn't. - -// For it to work, we need to do the following: -// 1) Add `slot_last_applied` and `signature_last_applied` columns to the -// `amm` and `conditional_vault` tables. -// 2) When processing a signature, fetch the account from the DB and check -// if the signature's slot is greater than the account's `slot_last_applied`. -// If it isn't, skip it. If it's greater, apply it. If it's equal, we need -// to run a `getBlock` RPC call and check which transaction is latest. - - -async function main() { - // await populateSignatures(); - // await indexAmms(); - // console.log("indexAmmEvents"); - // await indexVaultEvents(); - // await indexAmmEvents(); - - await backfill(); - await Promise.all([ - frontfill(), - setInterval(async () => { - await Promise.all([ - indexAmmEvents(), - indexVaultEvents(), - ]) - }, 1000), - ]); - // await Promise.all([ - // populateSignatures(), - // indexAmmEvents(), - // ]) -} - -main(); \ No newline at end of file diff --git a/packages/v4_indexer/src/indexEvents.ts b/packages/v4_indexer/src/indexEvents.ts deleted file mode 100644 index 0b576ed8..00000000 --- a/packages/v4_indexer/src/indexEvents.ts +++ /dev/null @@ -1,505 +0,0 @@ -import { AddLiquidityEvent, AMM_PROGRAM_ID, AmmEvent, CONDITIONAL_VAULT_PROGRAM_ID, ConditionalVaultEvent, CreateAmmEvent, getVaultAddr, InitializeConditionalVaultEvent, InitializeQuestionEvent, SwapEvent, PriceMath, SplitTokensEvent, MergeTokensEvent, RemoveLiquidityEvent } from "@metadaoproject/futarchy/v0.4"; -import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; -import * as anchor from "@coral-xyz/anchor"; -import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; -import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; -import * as token from "@solana/spl-token"; - -import { connection, ammClient, conditionalVaultClient } from "./connection"; -import { Program } from "@coral-xyz/anchor"; - -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; - -type Market = { - marketAcct: string; - baseMint: string; - quoteMint: string; -} - -type DBConnection = any; // TODO: Fix typing.. - -const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); - -const parseEvents = (program: Program, transactionResponse: VersionedTransactionResponse | TransactionResponse): { name: string; data: any }[] => { - const events: { name: string; data: any }[] = []; - try { - const inner: CompiledInnerInstruction[] = - transactionResponse?.meta?.innerInstructions ?? []; - const idlProgramId = program.programId; - for (let i = 0; i < inner.length; i++) { - for (let j = 0; j < inner[i].instructions.length; j++) { - const ix = inner[i].instructions[j]; - const programPubkey = - transactionResponse?.transaction.message.staticAccountKeys[ - ix.programIdIndex - ]; - if ( - programPubkey === undefined || - !programPubkey.equals(idlProgramId) - ) { - // we are at instructions that does not match the linked program - continue; - } - - const ixData = anchor.utils.bytes.bs58.decode( - ix.data - ); - const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8)); - const event = program.coder.events.decode(eventData); - // console.log(event) - if (event) { - events.push(event); - } - } - } - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error parsing events: ${error.message}` - : "Unknown error parsing events" - ]); - } - - return events; -} - -async function fetchEligibleSignatures(programId: string, limit: number) { - try { - return await usingDb(async (db) => { - let lastSlotIndexerQuery = await db.select() - .from(schema.indexers) - .where(eq(schema.indexers.name, "v0_4_amm_indexer")); - const indexerResult = await lastSlotIndexerQuery; - if (indexerResult.length === 0) throw Error("Indexer not found in indexers table"); - const lastSlotProcessed = indexerResult[0].latestSlotProcessed; - - return db.select({signature: schema.signatures.signature, slot: schema.signatures.slot}) - .from(schema.signatures) - .innerJoin(schema.signature_accounts, eq(schema.signatures.signature, schema.signature_accounts.signature)) - .where( - and( - eq(schema.signature_accounts.account, programId), - gt(schema.signatures.slot, lastSlotProcessed) - ) - ) - .orderBy(desc(schema.signatures.slot)) - .limit(limit); - }); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error fetching eligible signatures: ${error.message}` - : "Unknown error fetching eligible signatures" - ]); - return []; - } -} - -async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { - try { - return await connection.getTransactions( - eligibleSignatures.map(s => s.signature), - { commitment: "confirmed", maxSupportedTransactionVersion: 1 } - ); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error fetching transaction responses: ${error.message}` - : "Unknown error fetching transaction responses" - ]); - return []; - } -} - -//set latestProcessedSlot in db -async function setLatestProcessedSlot(slot: number) { - try { - await usingDb(async (db) => { - await db.update(schema.indexers) - .set({ latestSlotProcessed: BigInt(slot) }) - .where(eq(schema.indexers.name, "v0_4_amm_indexer")) - .execute(); - }); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error setting latest processed slot: ${error.message}` - : "Unknown error setting latest processed slot" - ]); - } -} - -export async function indexAmmEvents() { - try { - const eligibleSignatures = await fetchEligibleSignatures(AMM_PROGRAM_ID.toString(), 100); - if (eligibleSignatures.length === 0) { - console.log("No signatures for AMM events"); - return; - } - - const transactionResponses = await fetchTransactionResponses(eligibleSignatures); - - for (const [index, transactionResponse] of transactionResponses.entries()) { - if (!transactionResponse) { - console.log("No transaction response"); - continue; - } - - const signature = eligibleSignatures[index].signature; - const events = parseEvents(ammClient.program, transactionResponse as VersionedTransactionResponse); - - for (const event of events) { - await processAmmEvent(event, signature, transactionResponse); - } - } - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error in indexAmmEvents: ${error.message}` - : "Unknown error in indexAmmEvents" - ]); - } -} - -async function processAmmEvent(event: { name: string; data: AmmEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { - switch (event.name) { - case "CreateAmmEvent": - await handleCreateAmmEvent(event.data as CreateAmmEvent); - break; - case "AddLiquidityEvent": - await handleAddLiquidityEvent(event.data as AddLiquidityEvent); - break; - case "RemoveLiquidityEvent": - await handleRemoveLiquidityEvent(event.data as RemoveLiquidityEvent); - break; - case "SwapEvent": - await handleSwapEvent(event.data as SwapEvent, signature, transactionResponse); - break; - default: - console.log("Unknown event", event); - } -} -async function handleCreateAmmEvent(event: CreateAmmEvent) { - await usingDb(async (db: DBConnection) => { - await insertTokenIfNotExists(db, event.lpMint); - await insertTokenIfNotExists(db, event.baseMint); - await insertTokenIfNotExists(db, event.quoteMint); - await insertMarketIfNotExists(db, { - marketAcct: event.common.amm.toBase58(), - baseMint: event.baseMint.toString(), - quoteMint: event.quoteMint.toString(), - }); - - await db.insert(schema.v0_4_amms).values({ - ammAddr: event.common.amm.toString(), - lpMintAddr: event.lpMint.toString(), - createdAtSlot: BigInt(event.common.slot.toString()), - baseMintAddr: event.baseMint.toString(), - quoteMintAddr: event.quoteMint.toString(), - latestAmmSeqNumApplied: 0n, - baseReserves: 0n, - quoteReserves: 0n, - }).onConflictDoNothing(); - }); -} - -async function handleAddLiquidityEvent(event: AddLiquidityEvent) { - await usingDb(async (db: DBConnection) => { - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - - console.log("Updated AMM", event.common.amm.toString()); - }); -} - -async function handleRemoveLiquidityEvent(event: RemoveLiquidityEvent) { - await usingDb(async (db: DBConnection) => { - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - - console.log("Updated AMM", event.common.amm.toString()); - }); -} - -async function handleSwapEvent(event: SwapEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - if (transactionResponse.blockTime === null || transactionResponse.blockTime === undefined) { - return; - }; - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_swaps).values({ - signature: signature, - slot: BigInt(transactionResponse.slot), - // @ts-ignore - fixed above in the if statement - blockTime: new Date(transactionResponse.blockTime * 1000), - swapType: event.swapType.buy ? V04SwapType.Buy : V04SwapType.Sell, - ammAddr: event.common.amm.toString(), - userAddr: event.common.user.toString(), - inputAmount: event.inputAmount.toString(), - outputAmount: event.outputAmount.toString(), - ammSeqNum: BigInt(event.common.seqNum.toString()) - }).onConflictDoNothing(); - - const amm = await db.select().from(schema.v0_4_amms).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())).limit(1); - - if (amm.length === 0) { - console.log("AMM not found", event.common.amm.toString()); - return; - } - - if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { - console.log("Already applied", event.common.seqNum.toString()); - return; - } - - await insertPriceIfNotDuplicate(db, amm, event); - - await db.update(schema.v0_4_amms).set({ - baseReserves: BigInt(event.common.postBaseReserves.toString()), - quoteReserves: BigInt(event.common.postQuoteReserves.toString()), - latestAmmSeqNumApplied: BigInt(event.common.seqNum.toString()), - }).where(eq(schema.v0_4_amms.ammAddr, event.common.amm.toString())); - }); -} - -async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_splits).values({ - vaultAddr: event.vault.toString(), - vaultSeqNum: BigInt(event.seqNum.toString()), - signature: signature, - slot: BigInt(transactionResponse.slot), - amount: BigInt(event.amount.toString()) - }).onConflictDoNothing(); - }); -} - -async function handleMergeEvent(event: MergeTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { - await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_merges).values({ - vaultAddr: event.vault.toString(), - vaultSeqNum: BigInt(event.seqNum.toString()), - signature: signature, - slot: BigInt(transactionResponse.slot), - amount: BigInt(event.amount.toString()) - }).onConflictDoNothing(); - }); -} - -async function insertTokenIfNotExists(db: DBConnection, mintAcct: PublicKey) { - const existingToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, mintAcct.toString())).limit(1); - if (existingToken.length === 0) { - console.log("Inserting token", mintAcct.toString()); - const mint: token.Mint = await token.getMint(connection, mintAcct); - await db.insert(schema.tokens).values({ - mintAcct: mintAcct.toString(), - symbol: mintAcct.toString().slice(0, 3), - name: mintAcct.toString().slice(0, 3), - decimals: mint.decimals, - supply: mint.supply, - updatedAt: new Date(), - }).onConflictDoNothing(); - } -} - -export async function indexVaultEvents() { - try { - const eligibleSignatures = await fetchEligibleSignatures(CONDITIONAL_VAULT_PROGRAM_ID.toString(), 1000); - - if (eligibleSignatures.length === 0) { - console.log("No signatures for Vault events"); - return; - } - - const transactionResponses = await fetchTransactionResponses(eligibleSignatures); - - for (const [index, transactionResponse] of transactionResponses.entries()) { - if (!transactionResponse) { - console.log("No transaction response"); - continue; - } - - const signature = eligibleSignatures[index].signature; - const events = parseEvents(conditionalVaultClient.vaultProgram, transactionResponse as VersionedTransactionResponse); - - for (const event of events) { - await processVaultEvent(event, signature, transactionResponse); - } - } - - //set last process slot - await setLatestProcessedSlot(Number(eligibleSignatures[0].slot)); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error in indexVaultEvents: ${error.message}` - : "Unknown error in indexVaultEvents" - ]); - } -} - -async function processVaultEvent(event: { name: string; data: ConditionalVaultEvent }, signature: string, transactionResponse: VersionedTransactionResponse) { - switch (event.name) { - case "InitializeQuestionEvent": - await handleInitializeQuestionEvent(event.data as InitializeQuestionEvent); - break; - case "InitializeConditionalVaultEvent": - await handleInitializeConditionalVaultEvent(event.data as InitializeConditionalVaultEvent); - break; - case "SplitTokensEvent": - await handleSplitEvent(event.data as SplitTokensEvent, signature, transactionResponse); - break; - case "MergeTokensEvent": - await handleMergeEvent(event.data as MergeTokensEvent, signature, transactionResponse); - break; - default: - console.log("Unknown Vault event", event.name); - } -} - -async function handleInitializeQuestionEvent(event: InitializeQuestionEvent) { - await usingDb(async (db) => { - await db.insert(schema.v0_4_questions).values({ - questionAddr: event.question.toString(), - isResolved: false, - oracleAddr: event.oracle.toString(), - numOutcomes: event.numOutcomes, - payoutNumerators: Array(event.numOutcomes).fill(0), - payoutDenominator: 0n, - questionId: event.questionId, - }).onConflictDoNothing(); - }); -} - -async function handleInitializeConditionalVaultEvent(event: InitializeConditionalVaultEvent) { - const vaultAddr = getVaultAddr(conditionalVaultClient.vaultProgram.programId, event.question, event.underlyingTokenMint)[0]; - await usingDb(async (db) => { - await db.transaction(async (trx) => { - if (!await doesQuestionExist(trx, event)) { - return; - } - await insertTokenIfNotExists(trx, event.underlyingTokenMint); - await insertTokenAccountIfNotExists(trx, event); - await insertConditionalVault(trx, event, vaultAddr); - }); - }); -} - -async function doesQuestionExist(db: DBConnection, event: InitializeConditionalVaultEvent): Promise { - const existingQuestion = await db.select().from(schema.v0_4_questions).where(eq(schema.v0_4_questions.questionAddr, event.question.toString())).limit(1); - return existingQuestion.length > 0; - // if (existingQuestion.length === 0) { - // await trx.insert(schema.v0_4_questions).values({ - // questionAddr: event.question.toString(), - // isResolved: false, - // oracleAddr: event.oracle.toString(), - // numOutcomes: event.numOutcomes, - // payoutNumerators: Array(event.numOutcomes).fill(0), - // payoutDenominator: 0n, - // questionId: event.questionId, - // }); - // } -} - -async function insertTokenAccountIfNotExists(db: DBConnection, event: InitializeConditionalVaultEvent) { - const existingTokenAcct = await db.select().from(schema.tokenAccts).where(eq(schema.tokenAccts.tokenAcct, event.vaultUnderlyingTokenAccount.toString())).limit(1); - if (existingTokenAcct.length === 0) { - await db.insert(schema.tokenAccts).values({ - tokenAcct: event.vaultUnderlyingTokenAccount.toString(), - mintAcct: event.underlyingTokenMint.toString(), - ownerAcct: event.vaultUnderlyingTokenAccount.toString(), - amount: 0n, - // Add other required fields for token_accts table - }); - } -} - -async function insertMarketIfNotExists(db: DBConnection, market: Market) { - const existingMarket = await db.select().from(schema.markets).where(eq(schema.markets.marketAcct, market.marketAcct)).limit(1); - if (existingMarket.length === 0) { - await db.insert(schema.markets).values({ - marketAcct: market.marketAcct, - baseMintAcct: market.baseMint, - quoteMintAcct: market.quoteMint, - marketType: 'amm', - createTxSig: '', - baseLotSize: 0n, - quoteLotSize: 0n, - quoteTickSize: 0n, - baseMakerFee: 0, - quoteMakerFee: 0, - baseTakerFee: 0, - quoteTakerFee: 0 - }).onConflictDoNothing(); - // TODO: I don't like this on Conflict.... - } -} - -async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { - const existingPrice = await db.select().from(schema.prices).where(and(eq(schema.prices.marketAcct, event.common.amm.toBase58()), eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())))).limit(1); - if (existingPrice.length > 0) { - console.log("Price already exists", event.common.amm.toBase58(), BigInt(event.common.slot.toString())); - return; - } - // Get's the AMM details for the current price from liquidity event or swap event - const ammPrice = PriceMath.getAmmPriceFromReserves(event.common.postBaseReserves, event.common.postQuoteReserves); - const baseToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].baseMintAddr)).limit(1); - const quoteToken = await db.select().from(schema.tokens).where(eq(schema.tokens.mintAcct, amm[0].quoteMintAddr)).limit(1); - const humanPrice = PriceMath.getHumanPrice(ammPrice, baseToken[0].decimals, quoteToken[0].decimals); - - // Inserts the price into the prices table - await db.insert(schema.prices).values({ - marketAcct: event.common.amm.toBase58(), - baseAmount: BigInt(event.common.postBaseReserves.toString()), - quoteAmount: BigInt(event.common.postQuoteReserves.toString()), - price: humanPrice.toString(), - updatedSlot: BigInt(event.common.slot.toString()), - createdBy: 'amm-market-indexer', - pricesType: PricesType.Conditional, - }).onConflictDoNothing(); -} - -async function insertConditionalVault(db: DBConnection, event: InitializeConditionalVaultEvent, vaultAddr: PublicKey) { - await db.insert(schema.v0_4_conditional_vaults).values({ - conditionalVaultAddr: vaultAddr.toString(), - questionAddr: event.question.toString(), - underlyingMintAcct: event.underlyingTokenMint.toString(), - underlyingTokenAcct: event.vaultUnderlyingTokenAccount.toString(), - pdaBump: event.pdaBump, - latestVaultSeqNumApplied: 0n, - }).onConflictDoNothing(); -} \ No newline at end of file diff --git a/packages/v4_indexer/src/logger.ts b/packages/v4_indexer/src/logger.ts deleted file mode 100644 index f9315a0b..00000000 --- a/packages/v4_indexer/src/logger.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Counter } from "@lukasdeco/prom-client"; -import { AlertChatBotInterface, TelegramBotAPI } from "./adapters/telegram-bot"; - -const TELEGRAM_ALERT_CHAT_ID = process.env.TELEGRAM_ALERT_CHAT_ID ?? ""; - -export class Logger { - // private errorCounter; - // private warnCounter; - private chatBotApi: AlertChatBotInterface; - - constructor(chatBotApi: AlertChatBotInterface) { - // this.errorCounter = new Counter({ - // name: "errors", - // help: "number of errors", - // }); - - // this.warnCounter = new Counter({ - // name: "warnings", - // help: "number of warnings", - // }); - this.chatBotApi = chatBotApi; - } - - private formatData(data: any[]): string { - return data - .map((item) => { - if (typeof item === "object") { - try { - const jsonItem = JSON.stringify(item); - if (item.message && !jsonItem.includes(item.message)) { - return jsonItem + " " + item.message; - } - return jsonItem; - } catch (error) { - return "[Circular]"; - } - } - if (typeof item === "undefined") { - return "undefined"; - } - try { - return item.toString(); - } catch (e) { - return ""; - } - }) - .join(" "); - } - - log(...data: any[]): void { - console.log(this.formatData(data)); - } - - info(...data: any[]): void { - console.info(this.formatData(data)); - } - - error(...data: any[]): void { - console.error(this.formatData(data)); - // this.errorCounter.inc(); - } - - errorWithChatBotAlert(...data: any[]): void { - const formattedData = this.formatData(data); - console.error(formattedData); - // this.errorCounter.inc(); - if (TELEGRAM_ALERT_CHAT_ID) { - this.chatBotApi.sendMessage(TELEGRAM_ALERT_CHAT_ID, formattedData); - } - } - - warn(message: string): void { - console.warn(message); - // this.warnCounter.inc(); - } -} - -// TODO: add lint rule preventing default exports (default exports are antithetical to IDE auto refactors) -const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; -const telegramBotAPI = new TelegramBotAPI({ - token: TELEGRAM_BOT_TOKEN ?? "", -}); -export const logger = new Logger(telegramBotAPI); diff --git a/packages/v4_indexer/src/populateSignatures.ts b/packages/v4_indexer/src/populateSignatures.ts deleted file mode 100644 index b47cdfe6..00000000 --- a/packages/v4_indexer/src/populateSignatures.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; -import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; -import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; -import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; - - -const RPC_ENDPOINT = process.env.RPC_ENDPOINT; - -if (!RPC_ENDPOINT) { - throw new Error("RPC_ENDPOINT is not set"); -} -const connection = new Connection(RPC_ENDPOINT); -const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); - -// it's possible that there are signatures BEFORE the oldest signature -// because the indexer may not have been running when those signatures were created - -// it's also possible that there are signatures AFTER the newest signature - -// we assume that there aren't signatures between the oldest and newest signatures - -// we split these into two functions: -// - backfillHistoricalSignatures -// - insertNewSignatures - -const backfillHistoricalSignatures = async ( - programId: PublicKey, -) => { - let backfilledSignatures: ConfirmedSignatureInfo[] = []; - let oldestSignature = await usingDb(async (db) => { - return await db.select({ signature: schema.signatures.signature }) - .from(schema.signatures) - .orderBy(asc(schema.signatures.slot)) - .limit(1) - .then(signatures => signatures[0] ? signatures[0].signature : undefined); - }); - - while (true) { - const signatures = await connection.getSignaturesForAddress( - programId, - { before: oldestSignature, limit: 1000 }, - "confirmed" - ); - - if (signatures.length === 0) break; - - await insertSignatures(signatures, programId); - - backfilledSignatures = backfilledSignatures.concat(signatures); - oldestSignature = signatures[signatures.length - 1].signature; - - console.log(`backfilled ${backfilledSignatures.length} historical signatures so far...`); - } - - console.log(`now done backfilling. backfilled ${backfilledSignatures.length} historical signatures`); - return backfilledSignatures; -}; - -const insertNewSignatures = async (programId: PublicKey) => { - let allSignatures: ConfirmedSignatureInfo[] = []; - let latestRecordedSignature = await usingDb(async (db) => { - return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) - .from(schema.signatures) - .orderBy(desc(schema.signatures.slot)) - .limit(100) - .then(signatures => { - if (signatures.length === 0) return undefined; - - const latestSlot = signatures[0].slot; - for (let i = 1; i < signatures.length; i++) { - if (signatures[i].slot < latestSlot) { - return signatures[i].signature; - } - } - return signatures[signatures.length - 1].signature; - }); - }); - - let oldestSignatureInserted: string | undefined; - - while (true) { - const signatures = await connection.getSignaturesForAddress( - programId, - { limit: 1000, until: latestRecordedSignature, before: oldestSignatureInserted }, - "confirmed" - ); - - if (signatures.length === 0) break; - - await insertSignatures(signatures, programId); - - allSignatures = allSignatures.concat(signatures); - oldestSignatureInserted = signatures[signatures.length - 1].signature; - } - - return allSignatures; -} - -const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAddr: PublicKey) => { - await usingDb(async (db) => { - await db.insert(schema.signatures).values(signatures.map(tx => ({ - signature: tx.signature, - slot: BigInt(tx.slot), - didErr: tx.err !== null, - err: tx.err ? JSON.stringify(tx.err) : null, - blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, - }))).onConflictDoNothing().execute(); - await db.insert(schema.signature_accounts).values(signatures.map(tx => ({ - signature: tx.signature, - account: queriedAddr.toString() - }))).onConflictDoNothing().execute(); - }); -} - -const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; - -export const backfill = async () => { - await Promise.all(programIds.map(async (programId) => { - try { - const backfilledSignatures = await backfillHistoricalSignatures(programId); - console.log(`backfilled ${backfilledSignatures.length} signatures for ${programId.toString()}`); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error ? - `Error in backfill for ${programId.toString()}: ${error.message}` : - `Unknown error in backfill for ${programId.toString()}` - ]); - } - })); -} - -export const frontfill = async () => { - await Promise.all(programIds.map(async (programId) => { - try { - setInterval(async () => { - const newSignatures = await insertNewSignatures(programId); - console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); - }, 1000); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error ? - `Error in backfill for ${programId.toString()}: ${error.message}` : - `Unknown error in backfill for ${programId.toString()}` - ]); - } - })); -} - -// export const populateSignatures = async () => { - -// // use promise.all so they all run concurrently -// await Promise.all(programIds.map(programId => backfillAndSubscribe(programId))); -// }; \ No newline at end of file diff --git a/packages/v4_indexer/tsconfig.json b/packages/v4_indexer/tsconfig.json deleted file mode 100644 index c69e542e..00000000 --- a/packages/v4_indexer/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig-base.json", - "compilerOptions": { - "module": "ESNext", - "target": "ESNext", - "moduleResolution": "bundler", - "types": ["node", "bun-types", "inquirer"] - } -} From 581c4fa5853e64c59b3346f8ec80bb654742ba89 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Thu, 31 Oct 2024 00:27:20 -0400 Subject: [PATCH 06/29] wip: v3 updates --- packages/indexer/readme.md | 34 +++++---------- packages/indexer/src/subscriber.ts | 14 +++---- .../indexer/src/v3_indexer/builders/swaps.ts | 42 +++++++++---------- packages/indexer/src/v3_indexer/indexer.ts | 16 +++++-- 4 files changed, 52 insertions(+), 54 deletions(-) diff --git a/packages/indexer/readme.md b/packages/indexer/readme.md index 2ce87d01..c1cc4cbb 100644 --- a/packages/indexer/readme.md +++ b/packages/indexer/readme.md @@ -1,32 +1,20 @@ New Indexer Architecture +Indexers -Transaction Indexer +Logs Subscribe Indexer - subscribes to new txns on a given program, when a txn is received, we index it -Indexes all transactions across all programs v3 and v4. Populates transactions table where the signature is the pk and transaction_accounts, -which links each signature to an account_id (program) +Account Info Update Indexer - subscribes to account info updates on programs, such as amms to update reserves -Split into 2 parts - subscriber, frontfiller, and backfiller +Fetch Interval Indexer - polls getSignaturesForAddress on an interval, populating/indexing txs in case +its missed by Logs Subscribe Indexer. -Subscriber - subscribes to txns on each program, and asynchrounously triggers processTransaction() everytime a new tx is picked up +History Indexer - gets full tx history for a program (or at least as much as the RPC can provide). +runs on startup and on long intervals -Frontfiller - checks for new transactions every second, and when a new txn is detected, first inserts into transactions table, -then asynchronously triggers processTransaction() if there is no conflict in the insert (which implies the txn has already been processed) to -process the transaction and populate other tables as necessary. This way, we process transactions as soon as they are detected, minimizing latency -as compared to having seperate workers that track the transactions table and process transactions (such as fetchEligibleSignatures in v4 indexer). -Backfiller - the purpose of this is a failsafe in case a transaction fails to be picked up by the subscriber or frontfiller. -Runs every 15 mins and fetches all signatures within the last 15 mins and adds to transactions table. -If the txn doesn't already exist in the transaction table, we process the transaction as it hasn't been indexed. +processTransaction(txn, programId) -On startup, the transaction indexer fetches all historical txns from the creation of the programs - - - -processTransaction(txn, version) - -if version is v4, we check the events emitted in the transaction and call handleAmmEvent() and/or handleVaultEvent() accordingly to populate the -appropriate tables - -if version is v3, we take the transaction response and call indexTransactin() in instruction-dispatch.ts to index the txn and populate the -appropriate tables +if the programId is V4, we process the events emitted in the txn. +if v3, we use the swapBuilder to decode the transaction and check token balance changes to +figure out if the txn is a buy or sell diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index f165edea..af7546ab 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -1,5 +1,5 @@ import { connection } from "./connection"; -import { Logs, PublicKey } from "@solana/web3.js"; +import { Context, Logs, PublicKey } from "@solana/web3.js"; import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; @@ -10,12 +10,12 @@ import { index as indexV4 } from "./v4_indexer/indexer"; import { index as indexV3 } from "./v3_indexer/indexer"; -async function processLogs(logs: Logs, programId: PublicKey) { +async function processLogs(logs: Logs, ctx: Context, programId: PublicKey) { //check if programId is v3 or v4 if (programId.equals(V4_AMM_PROGRAM_ID) || programId.equals(V4_AUTOCRAT_PROGRAM_ID) || programId.equals(V4_CONDITIONAL_VAULT_PROGRAM_ID)) { await processLogsV4(logs, programId); } else if (programId.equals(V3_AMM_PROGRAM_ID) || programId.equals(V3_AUTOCRAT_PROGRAM_ID) || programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { - await processLogsV3(logs, programId); + await processLogsV3(logs, ctx, programId); } else { logger.error(`Unknown programId ${programId.toString()}`); } @@ -26,18 +26,18 @@ async function processLogsV4(logs: Logs, programId: PublicKey) { await indexV4(signature, programId); } -async function processLogsV3(logs: Logs, programId: PublicKey) { - await indexV3(logs, programId); +async function processLogsV3(logs: Logs, ctx: Context, programId: PublicKey) { + await indexV3(logs, ctx, programId); } //subscribes to logs for a given account async function subscribe(accountPubKey: PublicKey) { - connection.onLogs(accountPubKey, async (logs: Logs) => { //TODO: maybe add commitment "confirmed" (rpc docs doesnt say if this is default) + connection.onLogs(accountPubKey, async (logs: Logs, ctx: Context) => { //TODO: maybe add commitment "confirmed" (rpc docs doesnt say if this is default) try { // wait here because we need to fetch the txn from RPC // and often we get no response if we try right after recieving the logs notification await new Promise((resolve) => setTimeout(resolve, 1500)); - processLogs(logs, accountPubKey); //trigger processing of logs + processLogs(logs, ctx, accountPubKey); //trigger processing of logs } catch (error) { logger.errorWithChatBotAlert(`Error processing logs for account ${accountPubKey.toString()}`, error); } diff --git a/packages/indexer/src/v3_indexer/builders/swaps.ts b/packages/indexer/src/v3_indexer/builders/swaps.ts index 8981a0bd..cdc96b73 100644 --- a/packages/indexer/src/v3_indexer/builders/swaps.ts +++ b/packages/indexer/src/v3_indexer/builders/swaps.ts @@ -45,27 +45,27 @@ export class SwapPersistable { async persist() { try { - const upsertResult = - (await usingDb((db) => - db - .insert(schema.transactions) - .values(this.transactionRecord) - .onConflictDoUpdate({ - target: schema.transactions.txSig, - set: this.transactionRecord, - }) - .returning({ txSig: schema.transactions.txSig }) - )) ?? []; - if ( - upsertResult.length !== 1 || - upsertResult[0].txSig !== this.transactionRecord.txSig - ) { - logger.warn( - `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( - this.transactionRecord - )}` - ); - } + // const upsertResult = + // (await usingDb((db) => + // db + // .insert(schema.transactions) + // .values(this.transactionRecord) + // .onConflictDoUpdate({ + // target: schema.transactions.txSig, + // set: this.transactionRecord, + // }) + // .returning({ txSig: schema.transactions.txSig }) + // )) ?? []; + // if ( + // upsertResult.length !== 1 || + // upsertResult[0].txSig !== this.transactionRecord.txSig + // ) { + // logger.warn( + // `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( + // this.transactionRecord + // )}` + // ); + // } // Insert user if they aren't already in the database const insertUsersResult = (await usingDb((db) => db diff --git a/packages/indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts index f272dc23..629290e9 100644 --- a/packages/indexer/src/v3_indexer/indexer.ts +++ b/packages/indexer/src/v3_indexer/indexer.ts @@ -1,6 +1,16 @@ -import { Logs, PublicKey } from "@solana/web3.js"; +import { Context, Logs, PublicKey } from "@solana/web3.js"; +import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; -export async function index(logs: Logs, programId: PublicKey) { - +export async function index(logs: Logs, ctx: Context, programId: PublicKey) { + if (programId.equals(V3_AMM_PROGRAM_ID)) { + await AmmMarketLogsSubscribeIndexer.index(logs, programId, ctx); + } else if (programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { + //TODO: implement + } else if (programId.equals(V3_AUTOCRAT_PROGRAM_ID)) { + //TODO: implement + } else { + throw new Error(`Unknown programId ${programId.toString()}`); + } } \ No newline at end of file From 4b39a51efd85c08c53dc3e9eeec3c2911a23993c Mon Sep 17 00:00:00 2001 From: Kollan House Date: Mon, 4 Nov 2024 11:22:17 -0800 Subject: [PATCH 07/29] feat: updates drizzle orm and kit --- packages/database/drizzle.config.ts | 6 + .../database/drizzle/meta/0000_snapshot.json | 734 +++++++---- .../database/drizzle/meta/0001_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0002_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0003_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0004_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0005_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0006_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0007_snapshot.json | 1110 +++++++++++------ .../database/drizzle/meta/0008_snapshot.json | 1110 +++++++++++------ packages/database/package.json | 10 +- 11 files changed, 6189 insertions(+), 3441 deletions(-) create mode 100644 packages/database/drizzle.config.ts diff --git a/packages/database/drizzle.config.ts b/packages/database/drizzle.config.ts new file mode 100644 index 00000000..35a99425 --- /dev/null +++ b/packages/database/drizzle.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "drizzle-kit"; +export default defineConfig({ + dialect: "postgresql", // "mysql" | "sqlite" | "postgresql" + schema: "./lib/schema.ts", + out: "./drizzle", +}); \ No newline at end of file diff --git a/packages/database/drizzle/meta/0000_snapshot.json b/packages/database/drizzle/meta/0000_snapshot.json index 97307556..3e9ee4a0 100644 --- a/packages/database/drizzle/meta/0000_snapshot.json +++ b/packages/database/drizzle/meta/0000_snapshot.json @@ -1,10 +1,8 @@ { - "id": "12ff8f1b-1044-4827-b918-9b5b421d14df", - "prevId": "00000000-0000-0000-0000-000000000000", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1820,74 +1890,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -1944,54 +2051,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2005,9 +2130,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2054,21 +2182,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2118,9 +2249,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2145,40 +2279,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2190,9 +2337,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2257,34 +2407,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2333,18 +2486,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2403,28 +2567,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2436,9 +2600,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2479,47 +2646,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2634,41 +2804,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2680,9 +2850,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2703,14 +2876,23 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "12ff8f1b-1044-4827-b918-9b5b421d14df", + "prevId": "00000000-0000-0000-0000-000000000000", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0001_snapshot.json b/packages/database/drizzle/meta/0001_snapshot.json index a7a0ad5b..744ecfc9 100644 --- a/packages/database/drizzle/meta/0001_snapshot.json +++ b/packages/database/drizzle/meta/0001_snapshot.json @@ -1,10 +1,8 @@ { - "id": "01dc3a22-8fb9-4ce8-b122-6b26fb0a83e2", - "prevId": "12ff8f1b-1044-4827-b918-9b5b421d14df", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3226,86 +3470,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3362,9 +3609,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3414,60 +3664,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3541,38 +3823,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "01dc3a22-8fb9-4ce8-b122-6b26fb0a83e2", + "prevId": "12ff8f1b-1044-4827-b918-9b5b421d14df", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0002_snapshot.json b/packages/database/drizzle/meta/0002_snapshot.json index 5a8abdd7..547159df 100644 --- a/packages/database/drizzle/meta/0002_snapshot.json +++ b/packages/database/drizzle/meta/0002_snapshot.json @@ -1,10 +1,8 @@ { - "id": "aa6c6b32-77eb-4d74-ada7-30fe06b4c0cc", - "prevId": "01dc3a22-8fb9-4ce8-b122-6b26fb0a83e2", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3233,86 +3477,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3369,9 +3616,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3421,60 +3671,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3548,38 +3830,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "aa6c6b32-77eb-4d74-ada7-30fe06b4c0cc", + "prevId": "01dc3a22-8fb9-4ce8-b122-6b26fb0a83e2", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0003_snapshot.json b/packages/database/drizzle/meta/0003_snapshot.json index b22d00f2..1a37268f 100644 --- a/packages/database/drizzle/meta/0003_snapshot.json +++ b/packages/database/drizzle/meta/0003_snapshot.json @@ -1,10 +1,8 @@ { - "id": "8610ddf3-59d1-4ad0-8634-0478d37c5dc9", - "prevId": "aa6c6b32-77eb-4d74-ada7-30fe06b4c0cc", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3239,86 +3483,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3375,9 +3622,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3427,60 +3677,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3554,38 +3836,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "8610ddf3-59d1-4ad0-8634-0478d37c5dc9", + "prevId": "aa6c6b32-77eb-4d74-ada7-30fe06b4c0cc", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0004_snapshot.json b/packages/database/drizzle/meta/0004_snapshot.json index fb919e3c..c43b1b2e 100644 --- a/packages/database/drizzle/meta/0004_snapshot.json +++ b/packages/database/drizzle/meta/0004_snapshot.json @@ -1,10 +1,8 @@ { - "id": "53364bb0-feb1-4180-8d4b-dc53682e0a67", - "prevId": "8610ddf3-59d1-4ad0-8634-0478d37c5dc9", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3251,86 +3495,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3387,9 +3634,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3439,60 +3689,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3566,38 +3848,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "53364bb0-feb1-4180-8d4b-dc53682e0a67", + "prevId": "8610ddf3-59d1-4ad0-8634-0478d37c5dc9", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0005_snapshot.json b/packages/database/drizzle/meta/0005_snapshot.json index 38d45e46..6ab142ec 100644 --- a/packages/database/drizzle/meta/0005_snapshot.json +++ b/packages/database/drizzle/meta/0005_snapshot.json @@ -1,10 +1,8 @@ { - "id": "8b95ac6a-476f-4c4c-ab15-2a329671556f", - "prevId": "53364bb0-feb1-4180-8d4b-dc53682e0a67", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3251,86 +3495,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3387,9 +3634,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3439,60 +3689,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3566,38 +3848,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "8b95ac6a-476f-4c4c-ab15-2a329671556f", + "prevId": "53364bb0-feb1-4180-8d4b-dc53682e0a67", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0006_snapshot.json b/packages/database/drizzle/meta/0006_snapshot.json index 1e0111cb..1bc8195b 100644 --- a/packages/database/drizzle/meta/0006_snapshot.json +++ b/packages/database/drizzle/meta/0006_snapshot.json @@ -1,10 +1,8 @@ { - "id": "cb8d59ae-d3f5-443e-bcb7-3c992a223857", - "prevId": "8b95ac6a-476f-4c4c-ab15-2a329671556f", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3251,86 +3495,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3387,9 +3634,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3439,60 +3689,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3566,38 +3848,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "cb8d59ae-d3f5-443e-bcb7-3c992a223857", + "prevId": "8b95ac6a-476f-4c4c-ab15-2a329671556f", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0007_snapshot.json b/packages/database/drizzle/meta/0007_snapshot.json index 0cb71d1a..07545325 100644 --- a/packages/database/drizzle/meta/0007_snapshot.json +++ b/packages/database/drizzle/meta/0007_snapshot.json @@ -1,10 +1,8 @@ { - "id": "2f29ee7d-b2cb-458c-9e8f-5e1278f5a691", - "prevId": "cb8d59ae-d3f5-443e-bcb7-3c992a223857", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1941,74 +2041,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2065,54 +2202,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2126,9 +2281,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2175,21 +2333,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2239,9 +2400,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2266,40 +2430,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2311,9 +2488,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2378,34 +2558,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2454,18 +2637,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2524,28 +2718,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2557,9 +2751,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2600,47 +2797,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2755,41 +2955,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2801,9 +3001,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2824,9 +3027,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2891,47 +3097,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2984,47 +3193,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3074,60 +3286,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3251,86 +3495,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3387,9 +3634,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3439,60 +3689,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3566,38 +3848,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "2f29ee7d-b2cb-458c-9e8f-5e1278f5a691", + "prevId": "cb8d59ae-d3f5-443e-bcb7-3c992a223857", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/drizzle/meta/0008_snapshot.json b/packages/database/drizzle/meta/0008_snapshot.json index 91550c92..731d8504 100644 --- a/packages/database/drizzle/meta/0008_snapshot.json +++ b/packages/database/drizzle/meta/0008_snapshot.json @@ -1,10 +1,8 @@ { - "id": "46750075-91a4-4e4d-b00a-3f3ab69abf22", - "prevId": "2f29ee7d-b2cb-458c-9e8f-5e1278f5a691", - "version": "5", - "dialect": "pg", + "version": "7", + "dialect": "postgresql", "tables": { - "candles": { + "public.candles": { "name": "candles", "schema": "", "columns": { @@ -74,15 +72,15 @@ "candles_market_acct_markets_market_acct_fk": { "name": "candles_market_acct_markets_market_acct_fk", "tableFrom": "candles", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -95,9 +93,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "comments": { + "public.comments": { "name": "comments", "schema": "", "columns": { @@ -144,42 +145,45 @@ "comments_proposal_acct_proposals_proposal_acct_fk": { "name": "comments_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "comments", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "comments_responding_comment_id_comments_comment_id_fk": { "name": "comments_responding_comment_id_comments_comment_id_fk", "tableFrom": "comments", - "tableTo": "comments", "columnsFrom": [ "responding_comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "comments_comment_id_unique": { "name": "comments_comment_id_unique", - "nullsNotDistinct": false, "columns": [ "comment_id" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "conditional_vaults": { + "public.conditional_vaults": { "name": "conditional_vaults", "schema": "", "columns": { @@ -237,21 +241,24 @@ "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "dao_details": { + "public.dao_details": { "name": "dao_details", "schema": "", "columns": { @@ -358,51 +365,54 @@ "uniqueConstraints": { "dao_details_name_unique": { "name": "dao_details_name_unique", - "nullsNotDistinct": false, "columns": [ "name" - ] + ], + "nullsNotDistinct": false }, "dao_details_slug_unique": { "name": "dao_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false }, "dao_details_url_unique": { "name": "dao_details_url_unique", - "nullsNotDistinct": false, "columns": [ "url" - ] + ], + "nullsNotDistinct": false }, "dao_details_x_account_unique": { "name": "dao_details_x_account_unique", - "nullsNotDistinct": false, "columns": [ "x_account" - ] + ], + "nullsNotDistinct": false }, "dao_details_github_unique": { "name": "dao_details_github_unique", - "nullsNotDistinct": false, "columns": [ "github" - ] + ], + "nullsNotDistinct": false }, "id_name_url": { "name": "id_name_url", - "nullsNotDistinct": false, "columns": [ "dao_id", "url", "name" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "daos": { + "public.daos": { "name": "daos", "schema": "", "columns": { @@ -498,76 +508,79 @@ "daos_program_acct_programs_program_acct_fk": { "name": "daos_program_acct_programs_program_acct_fk", "tableFrom": "daos", - "tableTo": "programs", "columnsFrom": [ "program_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_dao_id_dao_details_dao_id_fk": { "name": "daos_dao_id_dao_details_dao_id_fk", "tableFrom": "daos", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_base_acct_tokens_mint_acct_fk": { "name": "daos_base_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "base_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "daos_quote_acct_tokens_mint_acct_fk": { "name": "daos_quote_acct_tokens_mint_acct_fk", "tableFrom": "daos", - "tableTo": "tokens", "columnsFrom": [ "quote_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "daos_treasury_acct_unique": { "name": "daos_treasury_acct_unique", - "nullsNotDistinct": false, "columns": [ "treasury_acct" - ] + ], + "nullsNotDistinct": false }, "dao_acct_program": { "name": "dao_acct_program", - "nullsNotDistinct": false, "columns": [ "dao_acct", "program_acct" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexer_account_dependencies": { + "public.indexer_account_dependencies": { "name": "indexer_account_dependencies", "schema": "", "columns": { @@ -608,28 +621,28 @@ "indexer_account_dependencies_name_indexers_name_fk": { "name": "indexer_account_dependencies_name_indexers_name_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "indexers", "columnsFrom": [ "name" ], + "tableTo": "indexers", "columnsTo": [ "name" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", "tableFrom": "indexer_account_dependencies", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig_processed" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -641,9 +654,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "indexers": { + "public.indexers": { "name": "indexers", "schema": "", "columns": { @@ -675,9 +691,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "makes": { + "public.makes": { "name": "makes", "schema": "", "columns": { @@ -726,45 +745,56 @@ }, "indexes": { "market_index": { - "name": "market_index", "columns": [ - "market_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "market_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "makes_order_tx_sig_orders_order_tx_sig_fk": { "name": "makes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "makes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "makes_market_acct_markets_market_acct_fk": { "name": "makes_market_acct_markets_market_acct_fk", "tableFrom": "makes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "markets": { + "public.markets": { "name": "markets", "schema": "", "columns": { @@ -883,73 +913,76 @@ "markets_proposal_acct_proposals_proposal_acct_fk": { "name": "markets_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "markets", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_base_mint_acct_tokens_mint_acct_fk": { "name": "markets_base_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "base_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_quote_mint_acct_tokens_mint_acct_fk": { "name": "markets_quote_mint_acct_tokens_mint_acct_fk", "tableFrom": "markets", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_bids_token_acct_token_accts_token_acct_fk": { "name": "markets_bids_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "bids_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "markets_asks_token_acct_token_accts_token_acct_fk": { "name": "markets_asks_token_acct_token_accts_token_acct_fk", "tableFrom": "markets", - "tableTo": "token_accts", "columnsFrom": [ "asks_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "orders": { + "public.orders": { "name": "orders", "schema": "", "columns": { @@ -1040,59 +1073,75 @@ }, "indexes": { "actor_index": { - "name": "actor_index", "columns": [ - "market_acct", - "actor_acct" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "actor_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "orders_order_tx_sig_transactions_tx_sig_fk": { "name": "orders_order_tx_sig_transactions_tx_sig_fk", "tableFrom": "orders", - "tableTo": "transactions", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_market_acct_markets_market_acct_fk": { "name": "orders_market_acct_markets_market_acct_fk", "tableFrom": "orders", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "orders_actor_acct_users_user_acct_fk": { "name": "orders_actor_acct_users_user_acct_fk", "tableFrom": "orders", - "tableTo": "users", "columnsFrom": [ "actor_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "prices": { + "public.prices": { "name": "prices", "schema": "", "columns": { @@ -1151,15 +1200,15 @@ "prices_market_acct_markets_market_acct_fk": { "name": "prices_market_acct_markets_market_acct_fk", "tableFrom": "prices", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -1171,9 +1220,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "program_system": { + "public.program_system": { "name": "program_system", "schema": "", "columns": { @@ -1213,60 +1265,63 @@ "program_system_autocrat_acct_programs_program_acct_fk": { "name": "program_system_autocrat_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "autocrat_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_conditional_vault_acct_programs_program_acct_fk": { "name": "program_system_conditional_vault_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "conditional_vault_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_pricing_model_acct_programs_program_acct_fk": { "name": "program_system_pricing_model_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "pricing_model_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "program_system_migrator_acct_programs_program_acct_fk": { "name": "program_system_migrator_acct_programs_program_acct_fk", "tableFrom": "program_system", - "tableTo": "programs", "columnsFrom": [ "migrator_acct" ], + "tableTo": "programs", "columnsTo": [ "program_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "programs": { + "public.programs": { "name": "programs", "schema": "", "columns": { @@ -1308,15 +1363,18 @@ "uniqueConstraints": { "program_version": { "name": "program_version", - "nullsNotDistinct": false, "columns": [ "program_acct", "version" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposal_details": { + "public.proposal_details": { "name": "proposal_details", "schema": "", "columns": { @@ -1398,29 +1456,32 @@ "proposal_details_proposal_acct_proposals_proposal_acct_fk": { "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "proposal_details", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { "proposal_details_slug_unique": { "name": "proposal_details_slug_unique", - "nullsNotDistinct": false, "columns": [ "slug" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "proposals": { + "public.proposals": { "name": "proposals", "schema": "", "columns": { @@ -1582,47 +1643,50 @@ "proposals_dao_acct_daos_dao_acct_fk": { "name": "proposals_dao_acct_daos_dao_acct_fk", "tableFrom": "proposals", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "base_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", "tableFrom": "proposals", - "tableTo": "conditional_vaults", "columnsFrom": [ "quote_vault" ], + "tableTo": "conditional_vaults", "columnsTo": [ "cond_vault_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "reactions": { + "public.reactions": { "name": "reactions", "schema": "", "columns": { @@ -1669,34 +1733,37 @@ "reactions_comment_id_comments_comment_id_fk": { "name": "reactions_comment_id_comments_comment_id_fk", "tableFrom": "reactions", - "tableTo": "comments", "columnsFrom": [ "comment_id" ], + "tableTo": "comments", "columnsTo": [ "comment_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "reactions_proposal_acct_proposals_proposal_acct_fk": { "name": "reactions_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "reactions", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "sessions": { + "public.sessions": { "name": "sessions", "schema": "", "columns": { @@ -1732,21 +1799,24 @@ "sessions_user_acct_users_user_acct_fk": { "name": "sessions_user_acct_users_user_acct_fk", "tableFrom": "sessions", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "restrict", - "onUpdate": "restrict" + "onUpdate": "restrict", + "onDelete": "restrict" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signature_accounts": { + "public.signature_accounts": { "name": "signature_accounts", "schema": "", "columns": { @@ -1772,11 +1842,19 @@ }, "indexes": { "account_index": { - "name": "account_index", "columns": [ - "account" - ], - "isUnique": false + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "account_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1789,9 +1867,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "signatures": { + "public.signatures": { "name": "signatures", "schema": "", "columns": { @@ -1841,18 +1922,34 @@ }, "indexes": { "slot_index": { - "name": "slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "sequence_num_index": { - "name": "sequence_num_index", "columns": [ - "seq_num" - ], - "isUnique": false + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "sequence_num_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, @@ -1860,14 +1957,17 @@ "uniqueConstraints": { "signatures_seq_num_unique": { "name": "signatures_seq_num_unique", - "nullsNotDistinct": false, "columns": [ "seq_num" - ] + ], + "nullsNotDistinct": false } - } + }, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "takes": { + "public.takes": { "name": "takes", "schema": "", "columns": { @@ -1948,74 +2048,111 @@ }, "indexes": { "block_index": { - "name": "block_index", "columns": [ - "market_acct", - "order_block" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "block_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "time_index": { - "name": "time_index", "columns": [ - "market_acct", - "order_time" - ], - "isUnique": false + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "time_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "maker_index": { - "name": "maker_index", "columns": [ - "maker_order_tx_sig" - ], - "isUnique": false + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "maker_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "takes_order_tx_sig_orders_order_tx_sig_fk": { "name": "takes_order_tx_sig_orders_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "orders", "columnsFrom": [ "order_tx_sig" ], + "tableTo": "orders", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", "tableFrom": "takes", - "tableTo": "makes", "columnsFrom": [ "maker_order_tx_sig" ], + "tableTo": "makes", "columnsTo": [ "order_tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "takes_market_acct_markets_market_acct_fk": { "name": "takes_market_acct_markets_market_acct_fk", "tableFrom": "takes", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_acct_balances": { + "public.token_acct_balances": { "name": "token_acct_balances", "schema": "", "columns": { @@ -2072,54 +2209,72 @@ }, "indexes": { "acct_amount_created": { - "name": "acct_amount_created", "columns": [ - "token_acct", - "created_at", - "amount" - ], - "isUnique": false + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "acct_amount_created", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "token_acct_balances_token_acct_token_accts_token_acct_fk": { "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "token_accts", "columnsFrom": [ "token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_mint_acct_tokens_mint_acct_fk": { "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_acct_balances", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "token_acct_balances_tx_sig_transactions_tx_sig_fk": { "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", "tableFrom": "token_acct_balances", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2133,9 +2288,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "token_accts": { + "public.token_accts": { "name": "token_accts", "schema": "", "columns": { @@ -2182,21 +2340,24 @@ "token_accts_mint_acct_tokens_mint_acct_fk": { "name": "token_accts_mint_acct_tokens_mint_acct_fk", "tableFrom": "token_accts", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "tokens": { + "public.tokens": { "name": "tokens", "schema": "", "columns": { @@ -2246,9 +2407,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watcher_transactions": { + "public.transaction_watcher_transactions": { "name": "transaction_watcher_transactions", "schema": "", "columns": { @@ -2273,40 +2437,53 @@ }, "indexes": { "watcher_slot_index": { - "name": "watcher_slot_index", "columns": [ - "watcher_acct", - "slot" - ], - "isUnique": false + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "watcher_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transaction_watchers", "columnsFrom": [ "watcher_acct" ], + "tableTo": "transaction_watchers", "columnsTo": [ "acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watcher_transactions", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2318,9 +2495,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transaction_watchers": { + "public.transaction_watchers": { "name": "transaction_watchers", "schema": "", "columns": { @@ -2385,34 +2565,37 @@ "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "latest_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", "tableFrom": "transaction_watchers", - "tableTo": "transactions", "columnsFrom": [ "first_tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "transactions": { + "public.transactions": { "name": "transactions", "schema": "", "columns": { @@ -2461,18 +2644,29 @@ }, "indexes": { "txn_slot_index": { - "name": "txn_slot_index", "columns": [ - "slot" - ], - "isUnique": false + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "txn_slot_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "twaps": { + "public.twaps": { "name": "twaps", "schema": "", "columns": { @@ -2531,28 +2725,28 @@ "twaps_market_acct_markets_market_acct_fk": { "name": "twaps_market_acct_markets_market_acct_fk", "tableFrom": "twaps", - "tableTo": "markets", "columnsFrom": [ "market_acct" ], + "tableTo": "markets", "columnsTo": [ "market_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "twaps_proposal_acct_proposals_proposal_acct_fk": { "name": "twaps_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "twaps", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2564,9 +2758,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_deposits": { + "public.user_deposits": { "name": "user_deposits", "schema": "", "columns": { @@ -2607,47 +2804,50 @@ "user_deposits_tx_sig_transactions_tx_sig_fk": { "name": "user_deposits_tx_sig_transactions_tx_sig_fk", "tableFrom": "user_deposits", - "tableTo": "transactions", "columnsFrom": [ "tx_sig" ], + "tableTo": "transactions", "columnsTo": [ "tx_sig" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_user_acct_users_user_acct_fk": { "name": "user_deposits_user_acct_users_user_acct_fk", "tableFrom": "user_deposits", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_deposits_mint_acct_tokens_mint_acct_fk": { "name": "user_deposits_mint_acct_tokens_mint_acct_fk", "tableFrom": "user_deposits", - "tableTo": "tokens", "columnsFrom": [ "mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "user_performance": { + "public.user_performance": { "name": "user_performance", "schema": "", "columns": { @@ -2762,41 +2962,41 @@ "user_performance_proposal_acct_proposals_proposal_acct_fk": { "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", "tableFrom": "user_performance", - "tableTo": "proposals", "columnsFrom": [ "proposal_acct" ], + "tableTo": "proposals", "columnsTo": [ "proposal_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_user_acct_users_user_acct_fk": { "name": "user_performance_user_acct_users_user_acct_fk", "tableFrom": "user_performance", - "tableTo": "users", "columnsFrom": [ "user_acct" ], + "tableTo": "users", "columnsTo": [ "user_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "user_performance_dao_acct_daos_dao_acct_fk": { "name": "user_performance_dao_acct_daos_dao_acct_fk", "tableFrom": "user_performance", - "tableTo": "daos", "columnsFrom": [ "dao_acct" ], + "tableTo": "daos", "columnsTo": [ "dao_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": { @@ -2808,9 +3008,12 @@ ] } }, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "users": { + "public.users": { "name": "users", "schema": "", "columns": { @@ -2831,9 +3034,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_amms": { + "public.v0_4_amms": { "name": "v0_4_amms", "schema": "", "columns": { @@ -2898,47 +3104,50 @@ "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "lp_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "base_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", "tableFrom": "v0_4_amms", - "tableTo": "tokens", "columnsFrom": [ "quote_mint_addr" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_conditional_vaults": { + "public.v0_4_conditional_vaults": { "name": "v0_4_conditional_vaults", "schema": "", "columns": { @@ -2991,47 +3200,50 @@ "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "v0_4_questions", "columnsFrom": [ "question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "tokens", "columnsFrom": [ "underlying_mint_acct" ], + "tableTo": "tokens", "columnsTo": [ "mint_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", "tableFrom": "v0_4_conditional_vaults", - "tableTo": "token_accts", "columnsFrom": [ "underlying_token_acct" ], + "tableTo": "token_accts", "columnsTo": [ "token_acct" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_merges": { + "public.v0_4_merges": { "name": "v0_4_merges", "schema": "", "columns": { @@ -3081,60 +3293,92 @@ }, "indexes": { "merge_vault_index": { - "name": "merge_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_signature_index": { - "name": "merge_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "merge_seq_num_vault_index": { - "name": "merge_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "merge_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_merges", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_merges_signature_signatures_signature_fk": { "name": "v0_4_merges_signature_signatures_signature_fk", "tableFrom": "v0_4_merges", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_metric_decisions": { + "public.v0_4_metric_decisions": { "name": "v0_4_metric_decisions", "schema": "", "columns": { @@ -3258,86 +3502,89 @@ "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "dao_details", "columnsFrom": [ "dao_id" ], + "tableTo": "dao_details", "columnsTo": [ "dao_id" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "outcome_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_questions", "columnsFrom": [ "metric_question_addr" ], + "tableTo": "v0_4_questions", "columnsTo": [ "question_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "outcome_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "metric_vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", "tableFrom": "v0_4_metric_decisions", - "tableTo": "v0_4_amms", "columnsFrom": [ "amm_addr" ], + "tableTo": "v0_4_amms", "columnsTo": [ "amm_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_questions": { + "public.v0_4_questions": { "name": "v0_4_questions", "schema": "", "columns": { @@ -3394,9 +3641,12 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_splits": { + "public.v0_4_splits": { "name": "v0_4_splits", "schema": "", "columns": { @@ -3446,60 +3696,92 @@ }, "indexes": { "split_vault_index": { - "name": "split_vault_index", "columns": [ - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_signature_index": { - "name": "split_signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "split_seq_num_vault_index": { - "name": "split_seq_num_vault_index", "columns": [ - "vault_seq_num", - "vault_addr" - ], - "isUnique": false + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "split_seq_num_vault_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": { "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", "tableFrom": "v0_4_splits", - "tableTo": "v0_4_conditional_vaults", "columnsFrom": [ "vault_addr" ], + "tableTo": "v0_4_conditional_vaults", "columnsTo": [ "conditional_vault_addr" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" }, "v0_4_splits_signature_signatures_signature_fk": { "name": "v0_4_splits_signature_signatures_signature_fk", "tableFrom": "v0_4_splits", - "tableTo": "signatures", "columnsFrom": [ "signature" ], + "tableTo": "signatures", "columnsTo": [ "signature" ], - "onDelete": "no action", - "onUpdate": "no action" + "onUpdate": "no action", + "onDelete": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} }, - "v0_4_swaps": { + "public.v0_4_swaps": { "name": "v0_4_swaps", "schema": "", "columns": { @@ -3573,38 +3855,76 @@ }, "indexes": { "amm_index": { - "name": "amm_index", "columns": [ - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "signature_index": { - "name": "signature_index", "columns": [ - "signature" - ], - "isUnique": false + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "signature_index", + "isUnique": false, + "method": "btree", + "concurrently": false }, "seq_num_amm_index": { - "name": "seq_num_amm_index", "columns": [ - "amm_seq_num", - "amm_addr" - ], - "isUnique": false + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "with": {}, + "name": "seq_num_amm_index", + "isUnique": false, + "method": "btree", + "concurrently": false } }, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": {}, + "policies": {}, + "isRLSEnabled": false, + "checkConstraints": {} } }, "enums": {}, "schemas": {}, "_meta": { - "columns": {}, "schemas": {}, - "tables": {} - } + "tables": {}, + "columns": {} + }, + "id": "46750075-91a4-4e4d-b00a-3f3ab69abf22", + "prevId": "2f29ee7d-b2cb-458c-9e8f-5e1278f5a691", + "sequences": {}, + "policies": {}, + "views": {}, + "roles": {} } \ No newline at end of file diff --git a/packages/database/package.json b/packages/database/package.json index 90c608d8..ef4df520 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -4,15 +4,15 @@ "private": "true", "main": "lib", "scripts": { - "migrate:create": "drizzle-kit generate:pg --schema=./lib/schema.ts", + "migrate:create": "drizzle-kit generate --dialect=postgresql --schema=./lib/schema.ts", "migrate": "pnpm migrate:create && bun src/index.ts", "sync": "pnpm bun src/index.ts", "sql": "bun src/run-sql.ts" }, "dependencies": { - "drizzle-orm": "0.30.6", - "pg": "^8.11.3", - "dotenv": "16.4.5" + "dotenv": "16.4.5", + "drizzle-orm": "0.36.0", + "pg": "^8.11.3" }, "devDependencies": { "@types/inquirer": "^9.0.7", @@ -20,7 +20,7 @@ "@types/pg": "^8.10.9", "ansicolor": "^2.0.1", "as-table": "^1.0.55", - "drizzle-kit": "0.20.18", + "drizzle-kit": "0.27.0", "inquirer": "^9.2.14" } } From d0f1712467e6de3724e67875af393ea6ab75316f Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 5 Nov 2024 10:34:42 -0500 Subject: [PATCH 08/29] feat: v4 indexer logic complete --- packages/indexer/src/subscriber.ts | 13 ++----------- packages/indexer/src/v4_indexer/indexer.ts | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index af7546ab..c16cf7e9 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -13,23 +13,14 @@ import { index as indexV3 } from "./v3_indexer/indexer"; async function processLogs(logs: Logs, ctx: Context, programId: PublicKey) { //check if programId is v3 or v4 if (programId.equals(V4_AMM_PROGRAM_ID) || programId.equals(V4_AUTOCRAT_PROGRAM_ID) || programId.equals(V4_CONDITIONAL_VAULT_PROGRAM_ID)) { - await processLogsV4(logs, programId); + await indexV4(logs, ctx, programId); } else if (programId.equals(V3_AMM_PROGRAM_ID) || programId.equals(V3_AUTOCRAT_PROGRAM_ID) || programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { - await processLogsV3(logs, ctx, programId); + await indexV3(logs, ctx, programId); } else { logger.error(`Unknown programId ${programId.toString()}`); } } -async function processLogsV4(logs: Logs, programId: PublicKey) { - let signature = logs.signature; - await indexV4(signature, programId); -} - -async function processLogsV3(logs: Logs, ctx: Context, programId: PublicKey) { - await indexV3(logs, ctx, programId); -} - //subscribes to logs for a given account async function subscribe(accountPubKey: PublicKey) { connection.onLogs(accountPubKey, async (logs: Logs, ctx: Context) => { //TODO: maybe add commitment "confirmed" (rpc docs doesnt say if this is default) diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index 2ac4a39b..a4efdaf0 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -2,8 +2,10 @@ import { AMM_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/fu import * as anchor from "@coral-xyz/anchor"; import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; +import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; import { connection, ammClient, conditionalVaultClient } from "./connection"; import { Program } from "@coral-xyz/anchor"; +import { Context, Logs, PublicKey } from "@solana/web3.js"; import { TelegramBotAPI } from "./adapters/telegram-bot"; import { Logger } from "./logger"; @@ -11,6 +13,7 @@ import { Logger } from "./logger"; import { processAmmEvent, processVaultEvent } from "./processor"; const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); +type DBConnection = any; // TODO: Fix typing.. const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { const ammEvents: { name: string; data: any }[] = []; @@ -75,13 +78,15 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac } //indexes signature -export async function index(signature: string, programId: PublicKey) { +export async function index(logs: Logs, ctx: Context, programId: PublicKey) { try { + let signature = logs.signature; if (!programId.equals(AMM_PROGRAM_ID) && !programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { //autocrat program id, we aren't indexing these for now console.log("Unknown program id: ", programId.toBase58()); return; - } + } + const transactionResponse = await connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 1 }); if (!transactionResponse) { console.log("No transaction response"); @@ -99,6 +104,15 @@ export async function index(signature: string, programId: PublicKey) { Promise.all(vaultEvents.map(async (event) => { await processVaultEvent(event, signature, transactionResponse); })); + + await usingDb(async (db: DBConnection) => { + await db.insert(schema.transactions).values({ + signature, + slot: transactionResponse.slot, + blockTime: transactionResponse.blockTime, + failed: transactionResponse.meta.err, + }); + }); } catch (error) { logger.errorWithChatBotAlert([ From f82af2a89be5922152fd3cd2aa5de0679f1327e4 Mon Sep 17 00:00:00 2001 From: Kollan House Date: Tue, 5 Nov 2024 07:38:24 -0800 Subject: [PATCH 09/29] feat: updates for new native queries --- .../hasura/metadata/databases/databases.yaml | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/packages/hasura/metadata/databases/databases.yaml b/packages/hasura/metadata/databases/databases.yaml index b88b89e8..b08430d0 100644 --- a/packages/hasura/metadata/databases/databases.yaml +++ b/packages/hasura/metadata/databases/databases.yaml @@ -24,6 +24,100 @@ - total_volume filter: {} role: anonymous + - fields: + - name: base_amount + type: + nullable: true + scalar: numeric + - name: quote_amount + type: + nullable: true + scalar: numeric + - name: price + type: + nullable: true + scalar: numeric + - name: prices_type + type: + nullable: true + scalar: text + - name: interv + type: + nullable: true + scalar: timestamptz + name: price_chart_data_unique + select_permissions: + - permission: + columns: + - base_amount + - quote_amount + - price + - prices_type + - interv + filter: {} + role: anonymous + - fields: + - name: proposal_acct + type: + nullable: true + scalar: text + - name: bar_size + type: + nullable: true + scalar: interval + - name: bar_start_time + type: + nullable: true + scalar: timestamptz + - name: pass_market_acct + type: + nullable: true + scalar: text + - name: pass_price + type: + nullable: true + scalar: numeric + - name: pass_base_amount + type: + nullable: true + scalar: numeric + - name: pass_quote_amount + type: + nullable: true + scalar: numeric + - name: fail_market_acct + type: + nullable: true + scalar: text + - name: fail_price + type: + nullable: true + scalar: numeric + - name: fail_base_amount + type: + nullable: true + scalar: numeric + - name: fail_quote_amount + type: + nullable: true + scalar: numeric + name: proposal_bars_unique + select_permissions: + - permission: + columns: + - proposal_acct + - bar_size + - bar_start_time + - pass_market_acct + - pass_price + - pass_base_amount + - pass_quote_amount + - fail_market_acct + - fail_price + - fail_base_amount + - fail_quote_amount + filter: {} + role: anonymous - fields: - name: proposal_acct type: @@ -55,6 +149,38 @@ code: "select up.user_acct::TEXT, sum(up.total_volume)::BIGINT as \"total_volume\" from user_performance up\r\njoin proposals p on up.proposal_acct = p.proposal_acct \r\njoin daos d on p.dao_acct = d.dao_acct\r\njoin dao_details dd on dd.dao_id = d.dao_id \r\nwhere dd.slug = {{dao_slug}}\r\ngroup by dd.slug, up.user_acct\r\norder by sum(up.total_volume) desc;" returns: dao_trader root_field_name: top_dao_traders + - arguments: + end_date: + description: "" + nullable: true + type: text + market_acct: + description: "" + nullable: false + type: text + start_date: + description: "" + nullable: true + type: text + code: "WITH changes AS (\n SELECT \n *,\n LAG(price) OVER w AS prev_price,\n LAG(prices_type) OVER w AS prev_prices_type,\n LAG(base_amount) OVER w AS prev_base_amount,\n LAG(quote_amount) OVER w AS prev_quote_amount,\n LEAD(price) OVER w AS next_price,\n LEAD(prices_type) OVER w AS next_prices_type,\n LEAD(base_amount) OVER w AS next_base_amount,\n LEAD(quote_amount) OVER w AS next_quote_amount\n FROM prices_chart_data\n WHERE market_acct = {{market_acct}}\n AND ({{start_date}}::timestamptz IS NULL OR interv >= {{start_date}}::timestamptz)\n AND ({{end_date}}::timestamptz IS NULL OR interv <= {{end_date}}::timestamptz)\n WINDOW w AS (ORDER BY interv)\n)\nSELECT interv, price, base_amount, quote_amount, prices_type::text\nFROM changes\nWHERE \n -- First row\n prev_price IS NULL\n -- Last row\n OR next_price IS NULL\n -- Or where any value changes\n OR price != prev_price\n OR prices_type != prev_prices_type\n OR base_amount != prev_base_amount\n OR quote_amount != prev_quote_amount;" + returns: price_chart_data_unique + root_field_name: unique_price_chart_data + - arguments: + end_date: + description: "" + nullable: true + type: text + proposal_acct: + description: "" + nullable: false + type: text + start_date: + description: "" + nullable: true + type: text + code: "WITH changes AS (\n SELECT \n *,\n LAG(pass_price) OVER w AS prev_pass_price,\n LAG(pass_base_amount) OVER w AS prev_pass_base_amount,\n LAG(pass_quote_amount) OVER w AS prev_pass_quote_amount,\n LAG(fail_price) OVER w AS prev_fail_price,\n LAG(fail_base_amount) OVER w AS prev_fail_base_amount,\n LAG(fail_quote_amount) OVER w AS prev_fail_quote_amount,\n LEAD(pass_price) OVER w AS next_pass_price,\n LEAD(pass_base_amount) OVER w AS next_pass_base_amount,\n LEAD(pass_quote_amount) OVER w AS next_pass_quote_amount,\n LEAD(fail_price) OVER w AS next_fail_price,\n LEAD(fail_base_amount) OVER w AS next_fail_base_amount,\n LEAD(fail_quote_amount) OVER w AS next_fail_quote_amount\n FROM proposal_bars\n WHERE proposal_acct = {{proposal_acct}}\n AND ({{start_date}}::timestamptz IS NULL OR bar_start_time >= {{start_date}}::timestamptz)\n AND ({{end_date}}::timestamptz IS NULL OR bar_start_time <= {{end_date}}::timestamptz)\n WINDOW w AS (ORDER BY bar_start_time)\n), agg AS(\nSELECT \n proposal_acct::text, bar_size, bar_start_time::timestamptz,\n pass_market_acct::text, pass_price::numeric, pass_base_amount::numeric, pass_quote_amount::numeric,\n fail_market_acct::text, fail_price::numeric, fail_base_amount::numeric, fail_quote_amount::numeric\nFROM changes\nWHERE \n -- First row - no previous values\n prev_pass_price IS NULL\n\n -- Last row - no next values\n OR next_pass_price IS NULL\n\n -- Price changes - handle nulls in both current and previous\n OR (pass_price IS NULL AND prev_pass_price IS NOT NULL)\n OR (pass_price IS NOT NULL AND prev_pass_price IS NULL)\n OR (pass_price != prev_pass_price AND pass_price IS NOT NULL AND prev_pass_price IS NOT NULL)\n\n -- Quote amount changes\n OR (pass_quote_amount IS NULL AND prev_pass_quote_amount IS NOT NULL)\n OR (pass_quote_amount IS NOT NULL AND prev_pass_quote_amount IS NULL)\n OR (pass_quote_amount != prev_pass_quote_amount AND pass_quote_amount IS NOT NULL AND prev_pass_quote_amount IS NOT NULL)\n\n -- Base amount changes\n OR (pass_base_amount IS NULL AND prev_pass_base_amount IS NOT NULL)\n OR (pass_base_amount IS NOT NULL AND prev_pass_base_amount IS NULL)\n OR (pass_base_amount != prev_pass_base_amount AND pass_base_amount IS NOT NULL AND prev_pass_base_amount IS NOT NULL)\n)\nSELECT * FROM agg WHERE pass_price IS NOT NULL AND fail_price IS NOT NULL;" + returns: proposal_bars_unique + root_field_name: unique_proposal_bars_data - arguments: proposal_acct: description: the proposal account From f65da234529fd6484eceb15123f4461356848317 Mon Sep 17 00:00:00 2001 From: Kollan House Date: Tue, 5 Nov 2024 07:41:26 -0800 Subject: [PATCH 10/29] fix: pnpm --- pnpm-lock.yaml | 416 +++++++++++++------------------------------------ 1 file changed, 109 insertions(+), 307 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c033694e..33f667fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: 16.4.5 version: 16.4.5 drizzle-orm: - specifier: 0.30.6 - version: 0.30.6(@opentelemetry/api@1.8.0)(@types/pg@8.11.0)(@types/react@18.2.55)(bun-types@1.1.6)(pg@8.11.3)(react@18.2.0) + specifier: 0.36.0 + version: 0.36.0(@opentelemetry/api@1.8.0)(@types/pg@8.11.0)(@types/react@18.2.55)(bun-types@1.1.6)(pg@8.11.3)(react@18.2.0) pg: specifier: ^8.11.3 version: 8.11.3 @@ -40,8 +40,8 @@ importers: specifier: ^1.0.55 version: 1.0.55 drizzle-kit: - specifier: 0.20.18 - version: 0.20.18 + specifier: 0.27.0 + version: 0.27.0 inquirer: specifier: ^9.2.14 version: 9.2.14 @@ -132,7 +132,7 @@ importers: specifier: ^15.1.4 version: 15.1.4 '@metadaoproject/futarchy': - specifier: ^0.4.0-alpha.21 + specifier: ^0.4.0-alpha.18 version: 0.4.0-alpha.21(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@metadaoproject/futarchy-sdk': specifier: 4.0.0-alpha.31 @@ -280,11 +280,16 @@ packages: '@solana/buffer-layout': ^4.0.0 '@solana/buffer-layout-utils': ^0.2.0 + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} @@ -833,16 +838,6 @@ packages: '@hasura/metadata@1.0.2': resolution: {integrity: sha512-bVDwRWC7g/NfLVUwP8HBV07+37g07UAbF+XEujfRmgr8839sH7Q2iwa2M8oQFQXwg4dj5Sn+WRt4/UWXKN7naQ==} - '@hono/node-server@1.12.0': - resolution: {integrity: sha512-e6oHjNiErRxsZRZBmc2KucuvY3btlO/XPncIpP2X75bRdTilF9GLjm3NHvKKunpJbbJJj31/FoPTksTf8djAVw==} - engines: {node: '>=18.14.1'} - - '@hono/zod-validator@0.2.2': - resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - '@irys/arweave@0.0.2': resolution: {integrity: sha512-ddE5h4qXbl0xfGlxrtBIwzflaxZUDlDs43TuT0u1OMfyobHul4AA1VEX72Rpzw2bOh4vzoytSqA1jCM7x9YtHg==} @@ -1660,9 +1655,6 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} engines: {node: '>=0.10.0'} @@ -1741,10 +1733,6 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - capability@0.2.5: resolution: {integrity: sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==} @@ -1770,10 +1758,6 @@ packages: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} engines: {node: '>=0.10.0'} - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} - engines: {node: '>=0.10'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -1840,10 +1824,6 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - component-emitter@1.3.1: resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} @@ -1865,10 +1845,6 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -1926,10 +1902,6 @@ packages: resolution: {integrity: sha512-gRh3yiT9bHBA5ka2yOpyFqAVu/ZpwWzajMUR/es0ljevAE88WyHBuMUy7jzd2o5j6LYQesEO/AyhbQ9BhbDXUA==} engines: {node: '>= 0.1.90'} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - dayjs@1.11.11: resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} @@ -2000,9 +1972,6 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - dir-glob@2.2.2: resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} engines: {node: '>=4'} @@ -2022,12 +1991,8 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} - dreamopt@0.8.0: - resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} - engines: {node: '>=0.4.0'} - - drizzle-kit@0.20.18: - resolution: {integrity: sha512-fLTwcnLqtBxGd+51H/dEm9TC0FW6+cIX/RVPyNcitBO77X9+nkogEfMAJebpd/8Yl4KucmePHRYRWWvUlW0rqg==} + drizzle-kit@0.27.0: + resolution: {integrity: sha512-vJJCPvKGLFcmOFBELKqcRng3Fc6qTOaKNAqetLEoysD7HjlSlJOWwM54FJlhpqA+cZcIdsL8r9/7v9JIFfs3MA==} hasBin: true drizzle-orm@0.30.6: @@ -2110,6 +2075,98 @@ packages: sqlite3: optional: true + drizzle-orm@0.36.0: + resolution: {integrity: sha512-6BETYPdKSR7cDHC0ZfqZk2VrKJ8n/Rfd3ajFPsAbc69gi87nwZ6oBA2wUGMELHA0tQE4kUKN0Ds00LUZQ6Z69A==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=3' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.1' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/react': '>=18' + '@types/sql.js': '*' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=13.2.0' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + react: '>=18' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/react': + optional: true + '@types/sql.js': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + react: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2135,10 +2192,6 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - error-polyfill@0.1.3: resolution: {integrity: sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==} @@ -2146,26 +2199,12 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - esbuild-register@3.5.0: resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} peerDependencies: @@ -2193,10 +2232,6 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -2215,9 +2250,6 @@ packages: resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} engines: {node: '>=6.5.0', npm: '>=3'} - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -2235,9 +2267,6 @@ packages: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -2374,11 +2403,6 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported - globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2409,9 +2433,6 @@ packages: resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - hanji@0.0.5: - resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} - has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -2463,19 +2484,12 @@ packages: engines: {node: '>=8'} hasBin: true - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - hi-base32@0.5.1: resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - hono@4.5.3: - resolution: {integrity: sha512-r26WwwbKD3BAYdfB294knNnegNda7VfV1tVn66D9Kvl9WQTdrR+5eKdoeaQNHQcC3Gr0KBikzAtjd6VsRGVSaw==} - engines: {node: '>=16.0.0'} - http-errors@1.8.1: resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} engines: {node: '>= 0.6'} @@ -2587,17 +2601,10 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -2638,10 +2645,6 @@ packages: json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - json-diff@0.9.0: - resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} - hasBin: true - json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -2727,9 +2730,6 @@ packages: lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -2748,9 +2748,6 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - lru-queue@0.1.0: - resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} - map-cache@0.2.2: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} @@ -2769,10 +2766,6 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - memoizee@0.4.17: - resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} - engines: {node: '>=0.12'} - merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} @@ -2830,14 +2823,6 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2898,9 +2883,6 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -3321,9 +3303,6 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@2.0.0: resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} engines: {node: '>=6'} @@ -3423,10 +3402,6 @@ packages: resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} engines: {node: '>=6.5.0', npm: '>=3'} - superjson@2.2.1: - resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} - engines: {node: '>=16'} - superstruct@0.14.2: resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} @@ -3450,10 +3425,6 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - timers-ext@0.1.8: - resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} - engines: {node: '>=0.12'} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -3524,9 +3495,6 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typescript-collections@1.3.3: resolution: {integrity: sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==} @@ -3618,9 +3586,6 @@ packages: which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -3806,6 +3771,8 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@drizzle-team/brocli@0.10.2': {} + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -4351,13 +4318,6 @@ snapshots: '@hasura/metadata@1.0.2': {} - '@hono/node-server@1.12.0': {} - - '@hono/zod-validator@0.2.2(hono@4.5.3)(zod@3.22.4)': - dependencies: - hono: 4.5.3 - zod: 3.22.4 - '@irys/arweave@0.0.2(debug@4.3.4)': dependencies: asn1.js: 5.4.1 @@ -5809,10 +5769,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - braces@2.3.2: dependencies: arr-flatten: 1.1.0 @@ -5913,8 +5869,6 @@ snapshots: camelcase@6.3.0: {} - camelcase@7.0.1: {} - capability@0.2.5: {} chalk@2.4.2: @@ -5944,14 +5898,6 @@ snapshots: isobject: 3.0.1 static-extend: 0.1.2 - cli-color@2.0.4: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.17 - timers-ext: 0.1.8 - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -6008,8 +5954,6 @@ snapshots: commander@8.3.0: {} - commander@9.5.0: {} - component-emitter@1.3.1: {} concat-map@0.0.1: {} @@ -6024,10 +5968,6 @@ snapshots: cookie@0.6.0: {} - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - copy-descriptor@0.1.1: {} cors@2.8.5: @@ -6092,11 +6032,6 @@ snapshots: csv-stringify: 6.4.6 stream-transform: 3.3.1 - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - dayjs@1.11.11: {} debug@2.6.9: @@ -6147,10 +6082,6 @@ snapshots: destroy@1.2.0: {} - difflib@0.2.4: - dependencies: - heap: 0.2.7 - dir-glob@2.2.2: dependencies: path-type: 3.0.0 @@ -6168,29 +6099,12 @@ snapshots: dotenv@16.4.5: {} - dreamopt@0.8.0: - dependencies: - wordwrap: 1.0.0 - - drizzle-kit@0.20.18: + drizzle-kit@0.27.0: dependencies: + '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 - '@hono/node-server': 1.12.0 - '@hono/zod-validator': 0.2.2(hono@4.5.3)(zod@3.22.4) - camelcase: 7.0.1 - chalk: 5.3.0 - commander: 9.5.0 - env-paths: 3.0.0 esbuild: 0.19.12 esbuild-register: 3.5.0(esbuild@0.19.12) - glob: 8.1.0 - hanji: 0.0.5 - hono: 4.5.3 - json-diff: 0.9.0 - minimatch: 7.4.6 - semver: 7.6.3 - superjson: 2.2.1 - zod: 3.22.4 transitivePeerDependencies: - supports-color @@ -6203,7 +6117,7 @@ snapshots: pg: 8.11.3 react: 18.2.0 - drizzle-orm@0.30.6(@opentelemetry/api@1.8.0)(@types/pg@8.11.0)(@types/react@18.2.55)(bun-types@1.1.6)(pg@8.11.3)(react@18.2.0): + drizzle-orm@0.36.0(@opentelemetry/api@1.8.0)(@types/pg@8.11.0)(@types/react@18.2.55)(bun-types@1.1.6)(pg@8.11.3)(react@18.2.0): optionalDependencies: '@opentelemetry/api': 1.8.0 '@types/pg': 8.11.0 @@ -6246,8 +6160,6 @@ snapshots: encodeurl@1.0.2: {} - env-paths@3.0.0: {} - error-polyfill@0.1.3: dependencies: capability: 0.2.5 @@ -6256,37 +6168,12 @@ snapshots: es-errors@1.3.0: {} - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - es6-promise@4.2.8: {} es6-promisify@5.0.0: dependencies: es6-promise: 4.2.8 - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esbuild-register@3.5.0(esbuild@0.19.12): dependencies: debug: 4.3.4 @@ -6374,13 +6261,6 @@ snapshots: escape-string-regexp@1.0.5: {} - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - etag@1.8.1: {} ethereum-bloom-filters@1.1.0: @@ -6435,11 +6315,6 @@ snapshots: bn.js: 4.11.6 number-to-bn: 1.7.0 - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - eventemitter3@4.0.7: {} eventemitter3@5.0.1: {} @@ -6494,10 +6369,6 @@ snapshots: transitivePeerDependencies: - supports-color - ext@1.7.0: - dependencies: - type: 2.7.3 - extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -6657,14 +6528,6 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - globby@11.1.0: dependencies: array-union: 2.1.0 @@ -6703,11 +6566,6 @@ snapshots: graphql@16.8.1: {} - hanji@0.0.5: - dependencies: - lodash.throttle: 4.1.1 - sisteransi: 1.0.5 - has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -6761,8 +6619,6 @@ snapshots: transitivePeerDependencies: - debug - heap@0.2.7: {} - hi-base32@0.5.1: {} hmac-drbg@1.0.1: @@ -6771,8 +6627,6 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - hono@4.5.3: {} - http-errors@1.8.1: dependencies: depd: 1.1.2 @@ -6902,12 +6756,8 @@ snapshots: dependencies: isobject: 3.0.1 - is-promise@2.2.2: {} - is-unicode-supported@0.1.0: {} - is-what@4.1.16: {} - is-windows@1.0.2: {} isarray@1.0.0: {} @@ -6952,12 +6802,6 @@ snapshots: dependencies: bignumber.js: 9.1.2 - json-diff@0.9.0: - dependencies: - cli-color: 2.0.4 - difflib: 0.2.4 - dreamopt: 0.8.0 - json-stringify-safe@5.0.1: {} json5@2.2.3: {} @@ -7043,8 +6887,6 @@ snapshots: lodash.once@4.1.1: {} - lodash.throttle@4.1.1: {} - lodash@4.17.21: {} log-symbols@4.1.0: @@ -7068,10 +6910,6 @@ snapshots: dependencies: tslib: 2.6.2 - lru-queue@0.1.0: - dependencies: - es5-ext: 0.10.64 - map-cache@0.2.2: {} map-visit@1.0.0: @@ -7088,17 +6926,6 @@ snapshots: media-typer@0.3.0: {} - memoizee@0.4.17: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.8 - merge-descriptors@1.0.1: {} merge2@1.4.1: {} @@ -7158,14 +6985,6 @@ snapshots: dependencies: brace-expansion: 1.1.11 - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - minimist@1.2.8: {} mixin-deep@1.3.2: @@ -7247,8 +7066,6 @@ snapshots: negotiator@0.6.3: {} - next-tick@1.1.0: {} - no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -7660,8 +7477,6 @@ snapshots: signal-exit@3.0.7: {} - sisteransi@1.0.5: {} - slash@2.0.0: {} slash@3.0.0: {} @@ -7769,10 +7584,6 @@ snapshots: dependencies: is-hex-prefixed: 1.0.0 - superjson@2.2.1: - dependencies: - copy-anything: 3.0.5 - superstruct@0.14.2: {} superstruct@0.15.5: {} @@ -7793,11 +7604,6 @@ snapshots: through@2.3.8: {} - timers-ext@0.1.8: - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - tiny-invariant@1.3.3: {} tmp-promise@3.0.3: @@ -7864,8 +7670,6 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - type@2.7.3: {} - typescript-collections@1.3.3: {} typescript@5.6.3: {} @@ -7945,8 +7749,6 @@ snapshots: which-module@2.0.1: {} - wordwrap@1.0.0: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 From 07bb7de7f34441640e605eb58a5ad8986e979033 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 5 Nov 2024 12:22:42 -0500 Subject: [PATCH 11/29] feat: v3 subscribe logic in progress --- packages/database/lib/schema.ts | 102 +++++++--------- .../src/v3_indexer/autocrat_program.rs | 111 ++++++++++++++++++ packages/indexer/src/v3_indexer/indexer.ts | 24 +++- packages/indexer/src/v4_indexer/indexer.ts | 19 ++- 4 files changed, 192 insertions(+), 64 deletions(-) create mode 100644 packages/indexer/src/v3_indexer/autocrat_program.rs diff --git a/packages/database/lib/schema.ts b/packages/database/lib/schema.ts index 0604ac97..c77e37fc 100644 --- a/packages/database/lib/schema.ts +++ b/packages/database/lib/schema.ts @@ -295,6 +295,22 @@ export enum InstructionType { VaultRedeemConditionalTokensForUnderlyingTokens = "vault_redeem_conditional_tokens_for_underlying_tokens", } +export const transactions = pgTable( + "transactions", + { + txSig: transaction("tx_sig").primaryKey(), + slot: biggerSlot("slot").notNull(), + blockTime: timestamp("block_time", { withTimezone: true }).notNull(), + failed: boolean("failed").notNull(), + payload: text("payload").notNull(), + serializerLogicVersion: smallint("serializer_logic_version").notNull(), + mainIxType: pgEnum("main_ix_type", InstructionType), + }, + (table) => ({ + slotIdx: index("txn_slot_index").on(table.slot), + }) +); + // These are responsible for getting all signatures involving an account // historically and real time, and writing them to the transactions table for processing. // Each proposal / spot market / autocrat version upgrade will result in another entry. @@ -308,13 +324,13 @@ export enum TransactionWatchStatus { export const transactionWatchers = pgTable("transaction_watchers", { acct: pubkey("acct").primaryKey(), latestTxSig: transaction("latest_tx_sig").references( - () => transactions.signature + () => transactions.txSig ), /** * We can use this to monitor if the transaction history is being cleared by the rpc. * Ideally this should not change once set. */ - firstTxSig: transaction("first_tx_sig").references(() => transactions.signature), + firstTxSig: transaction("first_tx_sig").references(() => transactions.txSig), /** * This may be significantly higher than the slot of the latest signature. The invariant here * is that no new transaction observed by the watcher may be less than or equal to the checkedUpToSlot @@ -336,7 +352,7 @@ export const transactionWatcherTransactions = pgTable( .references(() => transactionWatchers.acct) .notNull(), txSig: transaction("tx_sig") - .references(() => transactions.signature) + .references(() => transactions.txSig) .notNull(), slot: biggerSlot("slot").notNull(), }, @@ -358,7 +374,6 @@ export enum IndexerImplementation { AutocratDaoIndexer = "AutocratDaoIndexer", AutocratProposalIndexer = "AutocratProposalIndexer", TokenMintIndexer = "TokenMintIndexer", - } export enum IndexerType { TXHistory = "TXHistory", @@ -388,7 +403,7 @@ export const indexerAccountDependencies = pgTable( .notNull(), acct: pubkey("acct").notNull(), latestTxSigProcessed: transaction("latest_tx_sig_processed").references( - () => transactions.signature + () => transactions.txSig ), status: pgEnum("status", IndexerAccountDependencyStatus).default( IndexerAccountDependencyStatus.Active @@ -441,7 +456,7 @@ export const tokenAcctBalances = pgTable( .notNull() .default(sql`0`), slot: biggerSlot("slot"), - txSig: transaction("tx_sig").references(() => transactions.signature), + txSig: transaction("tx_sig").references(() => transactions.txSig), }, (table) => ({ pk: primaryKey( @@ -479,7 +494,7 @@ export const orders = pgTable( { orderTxSig: transaction("order_tx_sig") .primaryKey() - .references(() => transactions.signature), + .references(() => transactions.txSig), marketAcct: pubkey("market_acct") .references(() => markets.marketAcct) .notNull(), @@ -857,23 +872,7 @@ export const userPerformance = pgTable( } ); -export const transactions = pgTable( - "transactions", - { - signature: transaction("signature").primaryKey(), - slot: biggerSlot("slot").notNull(), - blockTime: timestamp("block_time", { withTimezone: true }).notNull(), - failed: boolean("failed").notNull(), - insertedAt: timestamp("inserted_at", { withTimezone: true }) - .notNull() - .defaultNow(), - }, - (table) => ({ - slotIdx: index("txn_slot_index").on(table.slot), - }) -); - -export const transaction_accounts = pgTable("transaction_accounts", { +export const signature_accounts = pgTable("signature_accounts", { signature: transaction("signature").notNull(), account: pubkey("account").notNull(), insertedAt: timestamp("inserted_at", { withTimezone: true }) @@ -884,35 +883,24 @@ export const transaction_accounts = pgTable("transaction_accounts", { accountIdx: index("account_index").on(table.account), })); -// export const transactionSequenceNumbers = pgTable( -// "transactions_seqnums", -// { -// signature: transaction("signature").notNull().references(() => transactions.signature), -// seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), -// }, -// (table) => ({ -// pk: primaryKey({ columns: [table.signature, table.seqNum] }), -// sequenceNumIdx: index("sequence_num_index").on(table.seqNum), -// }) -// ) -// export const signatures = pgTable( -// "signatures", -// { -// signature: transaction("signature").primaryKey(), -// slot: biggerSlot("slot").notNull(), -// didErr: boolean("did_err").notNull(), -// err: text("err"), -// blockTime: timestamp("block_time", { withTimezone: true }), -// insertedAt: timestamp("inserted_at", { withTimezone: true }) -// .notNull() -// .defaultNow(), -// seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), -// }, -// (table) => ({ -// slotIdx: index("slot_index").on(table.slot), -// sequenceNumIdx: index("sequence_num_index").on(table.seqNum), -// }) -// ); +export const signatures = pgTable( + "signatures", + { + signature: transaction("signature").primaryKey(), + slot: biggerSlot("slot").notNull(), + didErr: boolean("did_err").notNull(), + err: text("err"), + blockTime: timestamp("block_time", { withTimezone: true }), + insertedAt: timestamp("inserted_at", { withTimezone: true }) + .notNull() + .defaultNow(), + seqNum: bigserial("seq_num", { mode: "bigint" }).notNull().unique(), + }, + (table) => ({ + slotIdx: index("slot_index").on(table.slot), + sequenceNumIdx: index("sequence_num_index").on(table.seqNum), + }) +); export const v0_4_amms = pgTable("v0_4_amms", { ammAddr: pubkey("amm_addr").primaryKey(), @@ -1015,7 +1003,7 @@ export const v0_4_splits = pgTable( id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), - signature: transaction("signature").notNull().references(() => transactions.signature), + signature: transaction("signature").notNull().references(() => signatures.signature), slot: biggerSlot("slot").notNull(), amount: bigint("amount", { mode: "bigint" }).notNull(), createdAt: timestamp("created_at", { withTimezone: true }) @@ -1033,7 +1021,7 @@ export const v0_4_merges = pgTable("v0_4_merges", { id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), - signature: transaction("signature").notNull().references(() => transactions.signature), + signature: transaction("signature").notNull().references(() => signatures.signature), slot: biggerSlot("slot").notNull(), amount: bigint("amount", { mode: "bigint" }).notNull(), createdAt: timestamp("created_at", { withTimezone: true }) @@ -1178,7 +1166,7 @@ export const proposalTotalTradeVolume = pgView("proposal_total_trade_volume", { export const userDeposits = pgTable("user_deposits", { txSig: transaction("tx_sig") - .references(() => transactions.signature) + .references(() => transactions.txSig) .notNull(), userAcct: pubkey("user_acct") @@ -1212,4 +1200,4 @@ export type DaoRecord = typeof daos._.inferInsert; export type ProposalRecord = typeof proposals._.inferInsert; export type ConditionalVaultRecord = typeof conditionalVaults._.inferInsert; export type TokenAcctRecord = typeof tokenAccts._.inferInsert; -export type UserPerformanceRecord = typeof userPerformance._.inferInsert; +export type UserPerformanceRecord = typeof userPerformance._.inferInsert; \ No newline at end of file diff --git a/packages/indexer/src/v3_indexer/autocrat_program.rs b/packages/indexer/src/v3_indexer/autocrat_program.rs new file mode 100644 index 00000000..49149df9 --- /dev/null +++ b/packages/indexer/src/v3_indexer/autocrat_program.rs @@ -0,0 +1,111 @@ +//! The orchestrator of a futarchy. Equivalent to the 'governor' of Compound's +//! governance system. +//! +//! Autocrat has two types of accounts: DAOs and proposals. Every DAO has its +//! own token, its own treasury account, and list of configs. Proposals are +//! created for a specific DAO, and contain an SVM instruction and a URL that +//! should point to a description and justification of that instruction. +//! +//! Proposals pass through various states in their lifecycle. Here's a description +//! of these states: +//! - Pre-creation: this is when you initialize the accounts needed for a proposal, +//! including the vaults and the AMM accounts. The proposer will also deposit to +//! create their LP during this time. +//! - Trading: to create a proposal, the proposer must call +//! `initialize_proposal`, which requires them to lock up some LP tokens in each +//! of the markets. Once a proposal is created, anyone can trade its markets. +//! Prices of these markets are aggregated into a time-weighted average price +//! oracle. +//! - Pass or fail: if the TWAP of the pass market is sufficiently higher than the +//! TWAP of the fail market, the proposal will pass. If it's not, the proposal will +//! fail. If it passes, both vaults will be finalized, allowing pTOKEN holders to +//! redeem. If it fails, both vaults will be reverted, allowing fTOKEN holders to +//! redeem. +//! - Executed: if a proposal passes, anyone can make autocrat execute its SVM +//! instruction by calling `execute_proposal`. +use anchor_lang::prelude::*; +use anchor_lang::solana_program; +use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; +// use conditional_vault::cpi::accounts::SettleConditionalVault; +use conditional_vault::program::ConditionalVault as ConditionalVaultProgram; +use conditional_vault::ConditionalVault as ConditionalVaultAccount; +use conditional_vault::Question; +// use conditional_vault::VaultStatus; + +pub mod error; +pub mod instructions; +pub mod state; + +pub use crate::error::AutocratError; +pub use crate::instructions::*; +pub use crate::state::*; + +use amm::state::Amm; + +use solana_program::instruction::Instruction; +#[cfg(not(feature = "no-entrypoint"))] +use solana_security_txt::security_txt; +use std::borrow::Borrow; + +#[cfg(not(feature = "no-entrypoint"))] +security_txt! { + name: "autocrat", + project_url: "https://metadao.fi", + contacts: "email:metaproph3t@protonmail.com", + policy: "The market will decide whether we pay a bug bounty.", + source_code: "https://github.com/metaDAOproject/futarchy", + source_release: "v0.4", + auditors: "Neodyme", + acknowledgements: "DCF = (CF1 / (1 + r)^1) + (CF2 / (1 + r)^2) + ... (CFn / (1 + r)^n)" +} + +declare_id!("autowMzCbM29YXMgVG3T62Hkgo7RcyrvgQQkd54fDQL"); + +pub const SLOTS_PER_10_SECS: u64 = 25; +pub const THREE_DAYS_IN_SLOTS: u64 = 3 * 24 * 60 * 6 * SLOTS_PER_10_SECS; + +pub const TEN_DAYS_IN_SECONDS: i64 = 10 * 24 * 60 * 60; + +// by default, the pass price needs to be 3% higher than the fail price +pub const DEFAULT_PASS_THRESHOLD_BPS: u16 = 300; + +pub const MAX_BPS: u16 = 10_000; + +// the index of the fail and pass outcomes in the question and the index of +// the pass and fail conditional tokens in the conditional vault +pub const FAIL_INDEX: usize = 0; +pub const PASS_INDEX: usize = 1; + +// TWAP can only move by $5 per slot +pub const DEFAULT_MAX_OBSERVATION_CHANGE_PER_UPDATE_LOTS: u64 = 5_000; + +#[program] +pub mod autocrat { + use super::*; + + pub fn initialize_dao(ctx: Context, params: InitializeDaoParams) -> Result<()> { + InitializeDAO::handle(ctx, params) + } + + #[access_control(ctx.accounts.validate())] + pub fn initialize_proposal( + ctx: Context, + params: InitializeProposalParams, + ) -> Result<()> { + InitializeProposal::handle(ctx, params) + } + + #[access_control(ctx.accounts.validate())] + pub fn finalize_proposal(ctx: Context) -> Result<()> { + FinalizeProposal::handle(ctx) + } + + #[access_control(ctx.accounts.validate())] + pub fn execute_proposal(ctx: Context) -> Result<()> { + ExecuteProposal::handle(ctx) + } + + pub fn update_dao(ctx: Context, dao_params: UpdateDaoParams) -> Result<()> { + UpdateDao::handle(ctx, dao_params) + } +} \ No newline at end of file diff --git a/packages/indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts index 629290e9..479e99d5 100644 --- a/packages/indexer/src/v3_indexer/indexer.ts +++ b/packages/indexer/src/v3_indexer/indexer.ts @@ -1,6 +1,8 @@ import { Context, Logs, PublicKey } from "@solana/web3.js"; import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; +import { AutocratDaoIndexer } from "./autocrat/autocrat-dao-indexer"; +import { AutocratProposalIndexer } from "./autocrat/autocrat-proposal-indexer"; export async function index(logs: Logs, ctx: Context, programId: PublicKey) { @@ -9,7 +11,27 @@ export async function index(logs: Logs, ctx: Context, programId: PublicKey) { } else if (programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { //TODO: implement } else if (programId.equals(V3_AUTOCRAT_PROGRAM_ID)) { - //TODO: implement + // Parse logs to find instruction type + const instructionLog = logs.logs.find(log => + log.includes("Instruction:") && + (log.includes("InitializeDao") || + log.includes("InitializeProposal") || + log.includes("FinalizeProposal") || + log.includes("ExecuteProposal") || + log.includes("UpdateDao")) + ); + + if (instructionLog) { + if (instructionLog.includes("InitializeDao") || instructionLog.includes("UpdateDao")) { + // Trigger DAO indexer to update/insert new DAO + await AutocratDaoIndexer.index(); + } else if (instructionLog.includes("InitializeProposal") || + instructionLog.includes("FinalizeProposal") || + instructionLog.includes("ExecuteProposal")) { + // Trigger Proposal indexer to update/insert new proposal or update status + await AutocratProposalIndexer.index(); + } + } } else { throw new Error(`Unknown programId ${programId.toString()}`); } diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index a4efdaf0..6dd71dea 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -77,6 +77,8 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac }; } + + //indexes signature export async function index(logs: Logs, ctx: Context, programId: PublicKey) { try { @@ -106,12 +108,17 @@ export async function index(logs: Logs, ctx: Context, programId: PublicKey) { })); await usingDb(async (db: DBConnection) => { - await db.insert(schema.transactions).values({ - signature, - slot: transactionResponse.slot, - blockTime: transactionResponse.blockTime, - failed: transactionResponse.meta.err, - }); + await db.insert(schema.signatures).values({ + signature: transactionResponse.signature, + slot: BigInt(transactionResponse.slot), + didErr: transactionResponse.err !== null, + err: transactionResponse.err ? JSON.stringify(transactionResponse.err) : null, + blockTime: transactionResponse.blockTime ? new Date(transactionResponse.blockTime * 1000) : null, + }).onConflictDoNothing().execute(); + await db.insert(schema.signature_accounts).values({ + signature: transactionResponse.signature, + account: programId.toString() + }).onConflictDoNothing().execute(); }); } catch (error) { From 05fda0e289f5c8d51c5fff4a550460533e5ea4cf Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 5 Nov 2024 12:28:25 -0500 Subject: [PATCH 12/29] feat: added indexing directly from logs for v3 autocrat --- .../indexers/autocrat/autocrat-dao-indexer.ts | 100 ++++++++++++++ .../autocrat/autocrat-proposal-indexer.ts | 127 ++++++++++++++++++ .../indexers/interval-fetch-indexer.ts | 8 ++ 3 files changed, 235 insertions(+) diff --git a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts index a055e517..2606f343 100644 --- a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts @@ -131,4 +131,104 @@ export const AutocratDaoIndexer: IntervalFetchIndexer = { return Err({ type: AutocratDaoIndexerError.GeneralError }); } }, + + indexFromLogs: async (logs: string[]) => { + try { + // Find the relevant log that contains the DAO data + const daoLog = logs.find(log => + log.includes("Instruction:") && + (log.includes("InitializeDao") || log.includes("UpdateDao")) + ); + + if (!daoLog) { + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + // Extract DAO account from logs + const daoAcctMatch = logs.find(log => log.includes("Dao:")); + if (!daoAcctMatch) { + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + const daoAcct = new PublicKey(daoAcctMatch.split(": ")[1]); + + // Fetch the DAO data directly since we need the full account data + const dao = await rpcReadClient.daos.fetchDao(daoAcct); + if (!dao) { + return Err({ type: AutocratDaoIndexerError.NotFoundError }); + } + + // Update database using the same logic as the main indexer + if (dao.baseToken.publicKey == null || dao.quoteToken.publicKey == null) { + logger.error("Unable to determine public key for dao tokens"); + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + const baseTokenMint = await getMint( + connection, + new PublicKey(dao.baseToken.publicKey) + ); + + let token: TokenRecord = { + symbol: dao.baseToken.symbol, + name: dao.baseToken.name ? dao.baseToken.name : dao.baseToken.symbol, + decimals: dao.baseToken.decimals, + mintAcct: dao.baseToken.publicKey, + supply: baseTokenMint.supply.toString(), + updatedAt: new Date(), + }; + + await usingDb((db) => + db.insert(schema.tokens).values(token).onConflictDoNothing().execute() + ); + + let daoToInsert: DaoRecord = { + daoAcct: dao.publicKey.toBase58(), + programAcct: dao.protocol.autocrat.programId.toString(), + baseAcct: dao.baseToken.publicKey, + quoteAcct: dao.quoteToken.publicKey, + slotsPerProposal: dao.daoAccount.slotsPerProposal.toString(), + treasuryAcct: dao.daoAccount.treasury.toBase58(), + minBaseFutarchicLiquidity: + dao.daoAccount.minBaseFutarchicLiquidity + ? dao.daoAccount.minBaseFutarchicLiquidity.toString() + : 0, + minQuoteFutarchicLiquidity: + dao.daoAccount.minQuoteFutarchicLiquidity + ? dao.daoAccount.minQuoteFutarchicLiquidity.toString() + : 0, + passThresholdBps: BigInt(dao.daoAccount.passThresholdBps), + twapInitialObservation: + dao.daoAccount.twapInitialObservation + ? dao.daoAccount.twapInitialObservation.toString() + : 0, + twapMaxObservationChangePerUpdate: + dao.daoAccount.twapMaxObservationChangePerUpdate + ? dao.daoAccount.twapMaxObservationChangePerUpdate.toString() + : 0, + }; + + await usingDb((db) => + db + .insert(schema.daos) + .values(daoToInsert) + .onConflictDoUpdate({ + set: { + minBaseFutarchicLiquidity: daoToInsert.minBaseFutarchicLiquidity, + minQuoteFutarchicLiquidity: daoToInsert.minQuoteFutarchicLiquidity, + twapInitialObservation: daoToInsert.twapInitialObservation, + twapMaxObservationChangePerUpdate: daoToInsert.twapMaxObservationChangePerUpdate, + passThresholdBps: daoToInsert.passThresholdBps, + }, + target: schema.daos.daoAcct, + }) + .execute() + ); + + return Ok({ acct: "Updated dao from logs" }); + } catch (err) { + logger.errorWithChatBotAlert(err); + return Err({ type: AutocratDaoIndexerError.GeneralError }); + } + } }; diff --git a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts index ae20f316..c84cc958 100644 --- a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts @@ -440,8 +440,135 @@ export const AutocratProposalIndexer: IntervalFetchIndexer = { return Err({ type: AutocratDaoIndexerError.GeneralError }); } }, + + indexFromLogs: async (logs: string[]) => { + try { + // Find the relevant log that contains the proposal data + const proposalLog = logs.find(log => + log.includes("Instruction:") && + (log.includes("InitializeProposal") || + log.includes("FinalizeProposal") || + log.includes("ExecuteProposal")) + ); + + if (!proposalLog) { + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + // Extract proposal account from logs + const proposalAcctMatch = logs.find(log => log.includes("Proposal:")); + if (!proposalAcctMatch) { + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + const proposalAcct = new PublicKey(proposalAcctMatch.split(": ")[1]); + + // Fetch the proposal data since we need the full account data + const protocolV0_3 = rpcReadClient.futarchyProtocols.find( + (protocol) => protocol.deploymentVersion == "V0.3" + ); + + if (!protocolV0_3) { + return Err({ type: AutocratDaoIndexerError.MissingProtocolError }); + } + + const proposal = await protocolV0_3.autocrat.account.proposal.fetch(proposalAcct); + if (!proposal) { + return Err({ type: AutocratDaoIndexerError.NotFoundError }); + } + + // Get current slot and time for calculations + const { currentSlot, currentTime } = ( + await usingDb((db) => + db + .select({ + currentSlot: schema.prices.updatedSlot, + currentTime: schema.prices.createdAt, + }) + .from(schema.prices) + .orderBy(sql`${schema.prices.updatedSlot} DESC`) + .limit(1) + .execute() + ) + )?.[0] ?? {}; + + if (!currentSlot || !currentTime) { + return Err({ type: AutocratDaoIndexerError.MissingParamError }); + } + + // Handle different proposal states + if (proposal.state.pending) { + // Update proposal as pending + await updateProposalStatus(proposalAcct, ProposalStatus.Pending, currentTime); + } else if (proposal.state.passed) { + // Update proposal as passed + await updateProposalStatus(proposalAcct, ProposalStatus.Passed, currentTime); + await updateVaultStatuses(proposal.baseVault, proposal.quoteVault, "finalized"); + await calculateUserPerformance({ publicKey: proposalAcct, account: proposal }); + } else if (proposal.state.failed) { + // Update proposal as failed + await updateProposalStatus(proposalAcct, ProposalStatus.Failed, currentTime); + await updateVaultStatuses(proposal.baseVault, proposal.quoteVault, "reverted"); + await calculateUserPerformance({ publicKey: proposalAcct, account: proposal }); + } + + // If this is a new proposal, insert associated accounts data + if (proposalLog.includes("InitializeProposal")) { + await insertAssociatedAccountsDataForProposal( + { publicKey: proposalAcct, account: proposal }, + currentTime + ); + } + + return Ok({ acct: "Updated proposal from logs" }); + } catch (err) { + logger.error("error with proposal indexer:", err); + return Err({ type: AutocratDaoIndexerError.GeneralError }); + } + } }; +// Helper function to update proposal status +async function updateProposalStatus( + proposalAcct: PublicKey, + status: ProposalStatus, + currentTime: Date +) { + await usingDb((db) => + db + .update(schema.proposals) + .set({ + status, + completedAt: status !== ProposalStatus.Pending ? currentTime : null, + updatedAt: sql`NOW()` + }) + .where( + eq(schema.proposals.proposalAcct, proposalAcct.toString()) + ) + .execute() + ); +} + +// Helper function to update vault statuses +async function updateVaultStatuses( + baseVault: PublicKey, + quoteVault: PublicKey, + status: "finalized" | "reverted" +) { + await usingDb((db) => + db + .update(schema.conditionalVaults) + .set({ status }) + .where( + or( + eq(schema.conditionalVaults.condVaultAcct, baseVault.toString()), + eq(schema.conditionalVaults.condVaultAcct, quoteVault.toString()) + ) + ) + .execute() + ); +} + async function insertAssociatedAccountsDataForProposal( proposal: ProposalAccountWithKey, currentTime: Date diff --git a/packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts b/packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts index ce983ffc..1cc376a4 100644 --- a/packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/interval-fetch-indexer.ts @@ -10,4 +10,12 @@ export type IntervalFetchIndexer = { TaggedUnion > >; + indexFromLogs(logs: string[]): Promise< + Result< + { + acct: string; + }, + TaggedUnion + > + >; }; From f051c90ba009310958e2a18721db32d78fe30b25 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 6 Nov 2024 10:54:39 -0500 Subject: [PATCH 13/29] feat: fixed crash on staging --- packages/indexer/src/index.ts | 65 +-- packages/indexer/src/v3_indexer/cli/index.ts | 5 + .../cli/txw/common/select-account.ts | 21 + .../indexer/src/v3_indexer/cli/txw/create.ts | 4 + .../indexer/src/v3_indexer/cli/txw/index.ts | 16 + .../src/v3_indexer/cli/txw/populate.ts | 473 ++++++++++++++++++ .../indexer/src/v3_indexer/cli/txw/reset.ts | 79 +++ .../src/v3_indexer/cli/txw/validate.ts | 40 ++ .../indexer/src/v3_indexer/local-cache.ts | 40 ++ 9 files changed, 686 insertions(+), 57 deletions(-) create mode 100644 packages/indexer/src/v3_indexer/cli/index.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/common/select-account.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/create.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/index.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/populate.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/reset.ts create mode 100644 packages/indexer/src/v3_indexer/cli/txw/validate.ts create mode 100644 packages/indexer/src/v3_indexer/local-cache.ts diff --git a/packages/indexer/src/index.ts b/packages/indexer/src/index.ts index a3413acd..de656eff 100644 --- a/packages/indexer/src/index.ts +++ b/packages/indexer/src/index.ts @@ -1,60 +1,11 @@ -import { indexAmmEvents, indexVaultEvents } from "./indexEvents.js"; -import { backfill, frontfill } from "./populateSignatures.js"; +import { startIndexers } from "./v3_indexer/indexers"; +import { startIndexerAccountDependencyPopulation } from "./v3_indexer/cli/txw/populate"; +import { startTransactionWatchers } from "./v3_indexer/transaction/watcher"; +import { subscribeAll } from "./subscriber"; -// NEW FUTARCHY INDEXER -// To minimize complexity, the indexer is split into two parts: -// 1. signature ingestion -// 2. signature processing +// startIndexerAccountDependencyPopulation(); +subscribeAll(); -// SIGNATURE INGESTION -// Signature ingestion is responsible for fetching new signatures -// from the network and storing them in the `signatures` table. -// Today, this is done by the `populateSignatures` function. Under -// the hood, it uses the `getSignaturesForAddress` RPC endpoint. -// This is nice because it means that the indexer can fetch -// historical data. However, it is higher latency than subscribing -// to transactions via a websocket, like the below: -// https://docs.helius.dev/webhooks-and-websockets/enhanced-websockets -// We could use this to get real-time transaction data in the future. - -// SIGNATURE PROCESSING -// Signature processing is responsible for fetching the transactions -// corresponding to the signatures and parsing them to extract event data. -// This is done by the `indexAmmEvents` and `indexVaultEvents` functions. -// Today, insertion of new accounts (questions, conditional vaults, AMMs) -// works. However, updating them (when, for example, a swap happens) doesn't. - -// For it to work, we need to do the following: -// 1) Add `slot_last_applied` and `signature_last_applied` columns to the -// `amm` and `conditional_vault` tables. -// 2) When processing a signature, fetch the account from the DB and check -// if the signature's slot is greater than the account's `slot_last_applied`. -// If it isn't, skip it. If it's greater, apply it. If it's equal, we need -// to run a `getBlock` RPC call and check which transaction is latest. - - -async function main() { - // await populateSignatures(); - // await indexAmms(); - // console.log("indexAmmEvents"); - // await indexVaultEvents(); - // await indexAmmEvents(); - - await backfill(); - await Promise.all([ - frontfill(), - setInterval(async () => { - await Promise.all([ - indexAmmEvents(), - indexVaultEvents(), - ]) - }, 1000), - ]); - // await Promise.all([ - // populateSignatures(), - // indexAmmEvents(), - // ]) -} - -main(); \ No newline at end of file +await startTransactionWatchers(); +await startIndexers(); diff --git a/packages/indexer/src/v3_indexer/cli/index.ts b/packages/indexer/src/v3_indexer/cli/index.ts new file mode 100644 index 00000000..210f8a59 --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/index.ts @@ -0,0 +1,5 @@ +import { program } from 'commander'; +import { txw } from './txw'; + +txw(program.command('txw')) +program.parse(); diff --git a/packages/indexer/src/v3_indexer/cli/txw/common/select-account.ts b/packages/indexer/src/v3_indexer/cli/txw/common/select-account.ts new file mode 100644 index 00000000..91b29e6a --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/common/select-account.ts @@ -0,0 +1,21 @@ +import { usingDb, schema } from "@metadaoproject/indexer-db"; +import inquirer from "inquirer"; + +export async function selectAccount(): Promise { + const accounts = ( + (await usingDb((db) => db.select().from(schema.transactionWatchers))) ?? [] + ).map(({ acct }) => acct); + const prompt = inquirer.createPromptModule(); + const ACCOUNT_ANSWER = "account"; + const account: string = ( + await prompt([ + { + type: "list", + name: ACCOUNT_ANSWER, + message: "Select account to reset:", + choices: accounts, + }, + ]) + )[ACCOUNT_ANSWER]; + return account; +} diff --git a/packages/indexer/src/v3_indexer/cli/txw/create.ts b/packages/indexer/src/v3_indexer/cli/txw/create.ts new file mode 100644 index 00000000..69210eb7 --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/create.ts @@ -0,0 +1,4 @@ +export async function create() { + // TODO: implement creation of a tx watcher + console.log('creatooooor'); +} \ No newline at end of file diff --git a/packages/indexer/src/v3_indexer/cli/txw/index.ts b/packages/indexer/src/v3_indexer/cli/txw/index.ts new file mode 100644 index 00000000..7722099a --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/index.ts @@ -0,0 +1,16 @@ +import { Command } from 'commander'; +import { create } from './create'; +import { reset } from './reset'; +import { validate } from './validate'; + +export function txw(cmd: Command) { + cmd + .command('reset') + .action(reset); + cmd + .command('create') + .action(create); + cmd + .command('validate') + .action(validate); +} diff --git a/packages/indexer/src/v3_indexer/cli/txw/populate.ts b/packages/indexer/src/v3_indexer/cli/txw/populate.ts new file mode 100644 index 00000000..1458c3df --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/populate.ts @@ -0,0 +1,473 @@ +import { + usingDb, + schema, + eq, + notInArray, + and, + notIlike, +} from "@metadaoproject/indexer-db"; +import { + MarketRecord, + MarketType, + TokenRecord, +} from "@metadaoproject/indexer-db/lib/schema"; +import { + ORCA_WHIRLPOOLS_CONFIG, + ORCA_WHIRLPOOL_PROGRAM_ID, + PDAUtil, + WhirlpoolContext, + buildWhirlpoolClient, +} from "@orca-so/whirlpools-sdk"; +import { PublicKey } from "@solana/web3.js"; +import { connection, readonlyWallet } from "../../connection"; +import { Err, Ok } from "../../match"; +import { + JupiterQuoteIndexingError, + fetchQuoteFromJupe, +} from "../../indexers/jupiter/jupiter-quotes-indexer"; + +import Cron from "croner"; +import { logger } from "../../logger"; + +type IndexerAccountDependency = + typeof schema.indexerAccountDependencies._.inferInsert; + +export function startIndexerAccountDependencyPopulation() { + const job = Cron("*/5 * * * *", () => { + populateIndexerAccountDependencies(); + }); + console.log("populating indexers at ", job.nextRun()); +} + +async function populateIndexerAccountDependencies() { + // populating market indexers + try { + await populateTokenMintIndexerAccountDependencies(); + await populateAmmMarketIndexerAccountDependencies(); + await populateOpenbookMarketIndexerAccountDependencies(); + await populateSpotPriceMarketIndexerAccountDependencies(); + } catch (e) { + logger.error("error populating indexers", e); + } +} +async function populateTokenMintIndexerAccountDependencies() { + const mints: TokenRecord[] = + (await usingDb((db) => db.select().from(schema.tokens).execute())) ?? []; + + for (const mint of mints) { + const newTokenMintIndexerDep: IndexerAccountDependency = { + acct: mint.mintAcct, + name: "token-mint-accounts", + latestTxSigProcessed: null, + }; + const insertRes = + (await usingDb((db) => + db + .insert(schema.indexerAccountDependencies) + .values([newTokenMintIndexerDep]) + .onConflictDoNothing() + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + if (insertRes.length > 0) { + console.log( + "successfully populated indexer dependency for token mint account:", + insertRes[0].acct + ); + } + } + + console.log("Successfully populated token mint indexers"); +} + +async function populateAmmMarketIndexerAccountDependencies() { + const ammMarkets = + (await usingDb((db) => + db + .select() + .from(schema.markets) + .where(and(eq(schema.markets.marketType, MarketType.FUTARCHY_AMM))) + .execute() + )) ?? []; + + for (const ammMarket of ammMarkets) { + const newAmmIndexerDep: IndexerAccountDependency = { + acct: ammMarket.marketAcct.toString(), + name: "amm-market-accounts", + latestTxSigProcessed: null, + }; + const newAmmIntervalIndexerDep: IndexerAccountDependency = { + acct: ammMarket.marketAcct.toString(), + name: "amm-market-accounts-fetch", + latestTxSigProcessed: null, + }; + const newAmmLogsSubscribeIndexerDep: IndexerAccountDependency = { + acct: ammMarket.marketAcct.toString(), + name: "amm-markets-logs-subscribe-indexer", + latestTxSigProcessed: null, + }; + + const ammInsertResult = + (await usingDb((db) => + db + .insert(schema.indexerAccountDependencies) + .values([ + newAmmIndexerDep, + newAmmIntervalIndexerDep, + newAmmLogsSubscribeIndexerDep, + ]) + .onConflictDoNothing() + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + if (ammInsertResult.length > 0) { + console.log( + "successfully populated indexer dependency for amm market account:", + ammInsertResult[0].acct + ); + } + } + + console.log(`Successfully populated AMM indexers`); +} + +async function populateOpenbookMarketIndexerAccountDependencies() { + const indexerAccountsQuery = + (await usingDb((db) => + db + .select({ acct: schema.indexerAccountDependencies.acct }) + .from(schema.indexerAccountDependencies) + )) ?? []; + const openbookMarkets = + (await usingDb((db) => + db + .select() + .from(schema.markets) + .where( + and( + eq(schema.markets.marketType, MarketType.OPEN_BOOK_V2), + notInArray( + schema.markets.marketAcct, + indexerAccountsQuery.map((ai) => ai.acct) + ) + ) + ) + .execute() + )) ?? []; + + for (const openbookMarket of openbookMarkets) { + const newopenbookIndexerDep: IndexerAccountDependency = { + acct: openbookMarket.marketAcct.toString(), + name: "openbook-market-accounts", + latestTxSigProcessed: null, + }; + + const openbookInsertResult = + (await usingDb((db) => + db + .insert(schema.indexerAccountDependencies) + .values(newopenbookIndexerDep) + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + if (openbookInsertResult.length > 0) { + logger.log( + "successfully populated indexer dependency for openbook market account:", + openbookInsertResult[0].acct + ); + } else { + logger.error( + "error with inserting indexer dependency for openbook market:", + openbookMarket.marketAcct + ); + } + } + + logger.log("Successfully populated openbook market indexers"); +} + +enum PopulateSpotPriceMarketErrors { + NotSupportedByJup = "NotSupportedByJup", + GeneralJupError = "GeneralJupError", +} + +async function populateSpotPriceMarketIndexerAccountDependencies() { + const baseDaoTokens = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where( + and( + notIlike(schema.tokens.name, "%proposal%"), + notInArray(schema.tokens.symbol, ["USDC", "mUSDC"]) + ) + ) + .execute() + )) ?? []; + + // Loop through each token to find its corresponding USDC market address + for (const token of baseDaoTokens) { + const result = await populateJupQuoteIndexerAndMarket(token); + // for ones that don't work on jup, do birdeye + if (!result.success) { + await populateBirdEyePricesIndexerAndMarket(token); + } + // Not enough coverage on orca for now so disabling + // await populateOrcaWhirlpoolMarket(token); + } +} + +async function populateJupQuoteIndexerAndMarket(token: { + symbol: string; + name: string; + imageUrl: string | null; + mintAcct: string; + supply: bigint; + decimals: number; + updatedAt: Date; +}) { + const { mintAcct } = token; + try { + //check to see if jupiter can support this token + const number = await fetchQuoteFromJupe(mintAcct); + if (!number) { + return Err({ type: JupiterQuoteIndexingError.JupiterFetchError }); + } + + // it is supported, so let's continue on + const [usdcToken] = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.symbol, "USDC")) + .execute() + )) ?? []; + if (!usdcToken) + return Err({ + type: JupiterQuoteIndexingError.GeneralJupiterQuoteIndexError, + }); + + const baseTokenDependency: IndexerAccountDependency = { + acct: mintAcct, + name: "jupiter-quotes", + }; + + const insertRes = + (await usingDb((db) => + db + .insert(schema.indexerAccountDependencies) + .values(baseTokenDependency) + .onConflictDoNothing() + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + + if (insertRes.length > 0) { + console.log( + "successfully inserted jupiter quote acct dep for tracking", + insertRes[0].acct + ); + } + + const jupMarket: MarketRecord = { + marketAcct: mintAcct, + baseLotSize: BigInt(0), + baseMakerFee: 0, + baseMintAcct: mintAcct, + baseTakerFee: 0, + marketType: MarketType.JUPITER_QUOTE, + quoteMintAcct: usdcToken.mintAcct, + quoteLotSize: BigInt(0), + quoteTickSize: BigInt(0), + quoteMakerFee: 0, + quoteTakerFee: 0, + createTxSig: "", + activeSlot: null, + inactiveSlot: null, + createdAt: new Date(), + }; + + const marketInserRes = + (await usingDb((db) => + db + .insert(schema.markets) + .values(jupMarket) + .onConflictDoNothing() + .returning({ acct: schema.markets.marketAcct }) + )) ?? []; + + if (marketInserRes.length > 0) { + console.log( + "successfully inserted jupiter market, markets record for tracking", + marketInserRes[0].acct + ); + } + return Ok(null); + } catch (error) { + logger.warn( + `Error populating jupiter quote indexer and market for USDC/${token.symbol}: ${error}` + ); + return Err({ type: PopulateSpotPriceMarketErrors.GeneralJupError }); + } +} + +async function populateBirdEyePricesIndexerAndMarket(token: { + symbol: string; + name: string; + imageUrl: string | null; + mintAcct: string; + supply: bigint; + decimals: number; + updatedAt: Date; +}) { + const { mintAcct } = token; + try { + const [usdcToken] = + (await usingDb((db) => + db + .select() + .from(schema.tokens) + .where(eq(schema.tokens.symbol, "USDC")) + .execute() + )) ?? []; + + if (!usdcToken) return; + + const baseTokenDependency: IndexerAccountDependency = { + acct: mintAcct, + name: "birdeye-prices", + }; + + const insertRes = + (await usingDb((db) => + db + .insert(schema.indexerAccountDependencies) + .values(baseTokenDependency) + .onConflictDoNothing() + .returning({ acct: schema.indexerAccountDependencies.acct }) + )) ?? []; + + if (insertRes.length > 0) { + console.log( + "successfully inserted birdeye prices acct dep for tracking", + insertRes[0].acct + ); + } + + const birdeyeMarket: MarketRecord = { + marketAcct: mintAcct, + baseLotSize: BigInt(0), + baseMakerFee: 0, + baseMintAcct: mintAcct, + baseTakerFee: 0, + marketType: MarketType.BIRDEYE_PRICES, + quoteMintAcct: usdcToken.mintAcct, + quoteLotSize: BigInt(0), + quoteTickSize: BigInt(0), + quoteMakerFee: 0, + quoteTakerFee: 0, + createTxSig: "", + activeSlot: null, + inactiveSlot: null, + createdAt: new Date(), + }; + + const marketInserRes = + (await usingDb((db) => + db + .insert(schema.markets) + .values(birdeyeMarket) + .onConflictDoNothing() + .returning({ acct: schema.markets.marketAcct }) + )) ?? []; + + if (marketInserRes.length > 0) { + console.log( + "successfully inserted birdeye market, markets record for tracking", + marketInserRes[0].acct + ); + } + } catch (error) { + logger.error( + `Error populating birdeye quote indexer and market for USDC/${token.symbol}: ${error}` + ); + } + + console.log("successfully populate birdeye spot indexer for", token.symbol); +} + +/** + * NOT BEING USED FOR NOW. DOESN'T SUPPORT MANY PRICES WE NEED. + * @param token + */ +// async function populateOrcaWhirlpoolMarket(token: { +// symbol: string; +// name: string; +// imageUrl: string | null; +// mintAcct: string; +// supply: bigint; +// decimals: number; +// updatedAt: Date; +// }) { +// try { +// const [usdcToken] = await usingDb((db) => +// db +// .select() +// .from(schema.tokens) +// .where(eq(schema.tokens.symbol, "USDC")) +// .execute() +// ); + +// const pda = PDAUtil.getWhirlpool( +// ORCA_WHIRLPOOL_PROGRAM_ID, +// ORCA_WHIRLPOOLS_CONFIG, +// new PublicKey(token.mintAcct), +// // new PublicKey(usdcToken[0].mintAcct), +// new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), +// 128 +// ); + +// const ctx = WhirlpoolContext.from( +// connection, +// readonlyWallet, +// ORCA_WHIRLPOOL_PROGRAM_ID +// ); +// const client = buildWhirlpoolClient(ctx); +// const pool = await client.getPool(pda.publicKey); +// console.log("orca pool", pool); + +// const orcaWhirlpoolMarket: MarketRecord = { +// asksTokenAcct: token.mintAcct, +// baseLotSize: BigInt(10 ** token.decimals), +// baseMakerFee: 0, +// baseMintAcct: token.mintAcct, +// baseTakerFee: 0, +// bidsTokenAcct: usdcToken.mintAcct, +// createTxSig: "", +// marketAcct: pool.getAddress().toString(), +// marketType: MarketType.ORCA_WHIRLPOOL, +// quoteLotSize: BigInt(10 ** usdcToken.decimals), +// quoteMakerFee: 0, +// quoteMintAcct: usdcToken.mintAcct, +// quoteTakerFee: 0, +// quoteTickSize: BigInt(0), +// }; + +// const insertRes = await usingDb((db) => +// db +// .insert(schema.markets) +// .values(orcaWhirlpoolMarket) +// .onConflictDoNothing() +// .returning({ acct: schema.markets.marketAcct }) +// ); + +// if (insertRes.length > 0) { +// console.log( +// "successfully inserted whirlpool market for tracking", +// insertRes[0].acct +// ); +// } +// } catch (error) { +// logger.error( +// `Error fetching market address for USDC/${token.symbol}: ${error}` +// ); +// } +// } diff --git a/packages/indexer/src/v3_indexer/cli/txw/reset.ts b/packages/indexer/src/v3_indexer/cli/txw/reset.ts new file mode 100644 index 00000000..e275eaa3 --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/reset.ts @@ -0,0 +1,79 @@ +import { usingDb, schema, eq } from "@metadaoproject/indexer-db"; +import inquirer from "inquirer"; +import { selectAccount } from "./common/select-account"; +import { getTransaction } from "../../transaction/serializer"; + +export async function reset() { + const account = await selectAccount(); + const prompt = inquirer.createPromptModule(); + const TX_ANSWER = "tx"; + const transaction: string = ( + await prompt([ + { + type: "input", + name: TX_ANSWER, + message: `Reset ${account} back to transaction (empty for full reset):`, + }, + ]) + )[TX_ANSWER]; + const fullReset = !transaction; + let slotToResetTo = 0; + let txToResetTo = fullReset ? null : transaction; + if (fullReset) { + console.log(`Full reset for tx watcher on ${account}`); + const updateResult = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + latestTxSig: null, + firstTxSig: null, + checkedUpToSlot: BigInt(slotToResetTo), + }) + .where(eq(schema.transactionWatchers.acct, account)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updateResult.length !== 1) { + console.log("Failed to update record"); + console.log(JSON.stringify(updateResult)); + return; + } + } else { + const txResult = await getTransaction(transaction); + if (!txResult.success) { + console.log(`Transaction ${transaction} is invalid`); + console.log(JSON.stringify(txResult.error)); + return; + } + if (!txResult.ok.accounts.map(({ pubkey }) => pubkey).includes(account)) { + console.log( + `Transaction ${transaction} does not reference account ${account}` + ); + return; + } + // TODO: another edge case is the supplied transaction is after the progress of the watcher. That should also not be allowed. + // Until that's solved it'll probably just require another reset operation but with a valid transaction + slotToResetTo = txResult.ok.slot; + console.log( + `Resetting tx watcher on ${account} to tx ${transaction} (slot ${slotToResetTo})` + ); + txToResetTo = transaction; + const updateResult = + (await usingDb((db) => + db + .update(schema.transactionWatchers) + .set({ + latestTxSig: txToResetTo, + checkedUpToSlot: BigInt(slotToResetTo), + }) + .where(eq(schema.transactionWatchers.acct, account)) + .returning({ acct: schema.transactionWatchers.acct }) + )) ?? []; + if (updateResult.length !== 1) { + console.log("Failed to update record"); + console.log(JSON.stringify(updateResult)); + return; + } + } + console.log(`Successfully reset`); +} diff --git a/packages/indexer/src/v3_indexer/cli/txw/validate.ts b/packages/indexer/src/v3_indexer/cli/txw/validate.ts new file mode 100644 index 00000000..977556fd --- /dev/null +++ b/packages/indexer/src/v3_indexer/cli/txw/validate.ts @@ -0,0 +1,40 @@ +import { PublicKey } from "@solana/web3.js"; +import { getTransactionHistory } from "../../transaction/history"; +import { selectAccount } from "./common/select-account"; +import { usingDb, schema, desc, count, lte } from "@metadaoproject/indexer-db"; +import { logger } from "../../logger"; + +export async function validate() { + const account = await selectAccount(); + const accountPk = new PublicKey(account); + // First we start by simply validating the counts + const latestTxResult = + (await usingDb((db) => + db + .select() + .from(schema.transactionWatcherTransactions) + .orderBy(desc(schema.transactionWatcherTransactions.slot)) + .limit(1) + )) ?? []; + const [latestTx] = latestTxResult; + if (!latestTx) { + logger.log(`No latest transaction for account ${account}`); + return; + } + const txCount = + (await usingDb((db) => + db + .select({ count: count() }) + .from(schema.transactionWatcherTransactions) + .where(lte(schema.transactionWatcherTransactions.slot, latestTx.slot)) + )) ?? []; + const totalCached = txCount[0].count; + logger.log(`Cached: ${totalCached} for ${account}`); + const history = await getTransactionHistory(accountPk, BigInt(0), { + before: latestTx.txSig, + }); + const totalFromHistory = history.length + 1; // +1 for the latest tx sig + logger.log(`History: ${totalFromHistory}`); + logger.log(totalFromHistory === totalCached ? "Match" : `No match`); + // TODO: go through history and cached and find missing ones +} diff --git a/packages/indexer/src/v3_indexer/local-cache.ts b/packages/indexer/src/v3_indexer/local-cache.ts new file mode 100644 index 00000000..c845545e --- /dev/null +++ b/packages/indexer/src/v3_indexer/local-cache.ts @@ -0,0 +1,40 @@ +import * as fs from "fs"; +import * as path from "path"; +import { logger } from "./logger"; + +const CACHE_DIR = path.resolve(__dirname, "cache"); +const CACHE_LOCALLY = false; // TODO: turn off when ready to actually start indexing + +if (!fs.existsSync(CACHE_DIR)) { + await fs.promises.mkdir(CACHE_DIR); +} + +function getFileAndDirPath(key: string[]): { file: string; dir: string } { + if (key.length === 0) { + const error = new Error("Invalid empty key"); + logger.error(error.message); + throw error; + } + const keyCopy = [...key]; + const filename = keyCopy.pop()!; + const dir = path.resolve(CACHE_DIR, keyCopy.join("/")); + const file = path.resolve(dir, filename); + return { file, dir }; +} + +export async function get(key: string[]): Promise { + if (!CACHE_LOCALLY) return undefined; + const { file } = getFileAndDirPath(key); + if (fs.existsSync(file)) { + logger.log(`Cache hit on ${key.join("/")}`); + return (await fs.promises.readFile(file)).toString().split("\n"); + } + return undefined; +} + +export async function set(key: string[], value: string[]): Promise { + if (!CACHE_LOCALLY) return; + const { file, dir } = getFileAndDirPath(key); + await fs.promises.mkdir(dir, { recursive: true }); + await fs.promises.writeFile(file, value.join("\n")); +} From 13398697ba273f648a94e86efd81592a30025819 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 6 Nov 2024 11:39:27 -0500 Subject: [PATCH 14/29] feat: v4 forward/backward filling --- packages/indexer/src/backfiller.ts | 0 packages/indexer/src/subscriber.ts | 4 +- packages/indexer/src/v3_indexer/indexer.ts | 8 +- .../autocrat/autocrat-proposal-indexer.ts | 1 + packages/indexer/src/v4_indexer/filler.ts | 149 ++++++++++++++++++ packages/indexer/src/v4_indexer/indexer.ts | 4 +- 6 files changed, 156 insertions(+), 10 deletions(-) delete mode 100644 packages/indexer/src/backfiller.ts create mode 100644 packages/indexer/src/v4_indexer/filler.ts diff --git a/packages/indexer/src/backfiller.ts b/packages/indexer/src/backfiller.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index c16cf7e9..7d315e1d 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -6,8 +6,8 @@ import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; import { AccountLogsIndexer } from "./account-logs-indexer"; import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; import { logger } from "../logger"; -import { index as indexV4 } from "./v4_indexer/indexer"; -import { index as indexV3 } from "./v3_indexer/indexer"; +import { indexFromLogs as indexV4 } from "./v4_indexer/indexer"; +import { indexFromLogs as indexV3 } from "./v3_indexer/indexer"; async function processLogs(logs: Logs, ctx: Context, programId: PublicKey) { diff --git a/packages/indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts index 479e99d5..1125fefb 100644 --- a/packages/indexer/src/v3_indexer/indexer.ts +++ b/packages/indexer/src/v3_indexer/indexer.ts @@ -5,7 +5,7 @@ import { AutocratDaoIndexer } from "./autocrat/autocrat-dao-indexer"; import { AutocratProposalIndexer } from "./autocrat/autocrat-proposal-indexer"; -export async function index(logs: Logs, ctx: Context, programId: PublicKey) { +export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { if (programId.equals(V3_AMM_PROGRAM_ID)) { await AmmMarketLogsSubscribeIndexer.index(logs, programId, ctx); } else if (programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { @@ -23,13 +23,11 @@ export async function index(logs: Logs, ctx: Context, programId: PublicKey) { if (instructionLog) { if (instructionLog.includes("InitializeDao") || instructionLog.includes("UpdateDao")) { - // Trigger DAO indexer to update/insert new DAO - await AutocratDaoIndexer.index(); + await AutocratDaoIndexer.indexFromLogs(logs.logs); } else if (instructionLog.includes("InitializeProposal") || instructionLog.includes("FinalizeProposal") || instructionLog.includes("ExecuteProposal")) { - // Trigger Proposal indexer to update/insert new proposal or update status - await AutocratProposalIndexer.index(); + await AutocratProposalIndexer.indexFromLogs(logs.logs); } } } else { diff --git a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts index c84cc958..81179873 100644 --- a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-proposal-indexer.ts @@ -443,6 +443,7 @@ export const AutocratProposalIndexer: IntervalFetchIndexer = { indexFromLogs: async (logs: string[]) => { try { + console.log("indexFromLogs::logs", logs); // Find the relevant log that contains the proposal data const proposalLog = logs.find(log => log.includes("Instruction:") && diff --git a/packages/indexer/src/v4_indexer/filler.ts b/packages/indexer/src/v4_indexer/filler.ts new file mode 100644 index 00000000..9f3eabb4 --- /dev/null +++ b/packages/indexer/src/v4_indexer/filler.ts @@ -0,0 +1,149 @@ +import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; +import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; +import { TelegramBotAPI } from "../adapters/telegram-bot"; +import { Logger } from "../logger"; + + +const RPC_ENDPOINT = process.env.RPC_ENDPOINT; + +if (!RPC_ENDPOINT) { + throw new Error("RPC_ENDPOINT is not set"); +} +const connection = new Connection(RPC_ENDPOINT); +const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); + +// it's possible that there are signatures BEFORE the oldest signature +// because the indexer may not have been running when those signatures were created + +// it's also possible that there are signatures AFTER the newest signature + +// we assume that there aren't signatures between the oldest and newest signatures + +// we split these into two functions: +// - backfillHistoricalSignatures +// - insertNewSignatures + +const backfillHistoricalSignatures = async ( + programId: PublicKey, +) => { + let backfilledSignatures: ConfirmedSignatureInfo[] = []; + let oldestSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature }) + .from(schema.signatures) + .orderBy(asc(schema.signatures.slot)) + .limit(1) + .then(signatures => signatures[0] ? signatures[0].signature : undefined); + }); + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { before: oldestSignature, limit: 1000 }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + backfilledSignatures = backfilledSignatures.concat(signatures); + oldestSignature = signatures[signatures.length - 1].signature; + + console.log(`backfilled ${backfilledSignatures.length} historical signatures so far...`); + } + + console.log(`now done backfilling. backfilled ${backfilledSignatures.length} historical signatures`); + return backfilledSignatures; +}; + +const insertNewSignatures = async (programId: PublicKey) => { + let allSignatures: ConfirmedSignatureInfo[] = []; + let latestRecordedSignature = await usingDb(async (db) => { + return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) + .from(schema.signatures) + .orderBy(desc(schema.signatures.slot)) + .limit(100) + .then(signatures => { + if (signatures.length === 0) return undefined; + + const latestSlot = signatures[0].slot; + for (let i = 1; i < signatures.length; i++) { + if (signatures[i].slot < latestSlot) { + return signatures[i].signature; + } + } + return signatures[signatures.length - 1].signature; + }); + }); + + let oldestSignatureInserted: string | undefined; + + while (true) { + const signatures = await connection.getSignaturesForAddress( + programId, + { limit: 1000, until: latestRecordedSignature, before: oldestSignatureInserted }, + "confirmed" + ); + + if (signatures.length === 0) break; + + await insertSignatures(signatures, programId); + + allSignatures = allSignatures.concat(signatures); + oldestSignatureInserted = signatures[signatures.length - 1].signature; + } + + return allSignatures; +} + +const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAddr: PublicKey) => { + await usingDb(async (db) => { + await db.insert(schema.signatures).values(signatures.map(tx => ({ + signature: tx.signature, + slot: BigInt(tx.slot), + didErr: tx.err !== null, + err: tx.err ? JSON.stringify(tx.err) : null, + blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, + }))).onConflictDoNothing().execute(); + await db.insert(schema.signature_accounts).values(signatures.map(tx => ({ + signature: tx.signature, + account: queriedAddr.toString() + }))).onConflictDoNothing().execute(); + }); +} + +const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; + +export const backfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + const backfilledSignatures = await backfillHistoricalSignatures(programId); + console.log(`backfilled ${backfilledSignatures.length} signatures for ${programId.toString()}`); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} + +export const frontfill = async () => { + await Promise.all(programIds.map(async (programId) => { + try { + setInterval(async () => { + const newSignatures = await insertNewSignatures(programId); + console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); + }, 30000); //every 30s + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error ? + `Error in backfill for ${programId.toString()}: ${error.message}` : + `Unknown error in backfill for ${programId.toString()}` + ]); + } + })); +} diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index 6dd71dea..9872ceef 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -77,10 +77,8 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac }; } - - //indexes signature -export async function index(logs: Logs, ctx: Context, programId: PublicKey) { +export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { try { let signature = logs.signature; if (!programId.equals(AMM_PROGRAM_ID) && !programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { From e9d09bd1700ac5e1311ec0986df64ff0a35cda63 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 6 Nov 2024 12:25:55 -0500 Subject: [PATCH 15/29] feat: v4 forward/backward filling --- packages/indexer/src/v4_indexer/filler.ts | 13 ++++++++++-- packages/indexer/src/v4_indexer/indexer.ts | 24 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/indexer/src/v4_indexer/filler.ts b/packages/indexer/src/v4_indexer/filler.ts index 9f3eabb4..3c3cc1df 100644 --- a/packages/indexer/src/v4_indexer/filler.ts +++ b/packages/indexer/src/v4_indexer/filler.ts @@ -4,7 +4,7 @@ import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; import { TelegramBotAPI } from "../adapters/telegram-bot"; import { Logger } from "../logger"; - +import { index } from "./indexer"; const RPC_ENDPOINT = process.env.RPC_ENDPOINT; @@ -48,6 +48,11 @@ const backfillHistoricalSignatures = async ( await insertSignatures(signatures, programId); + //trigger indexing + Promise.all(signatures.map(async (signature: ConfirmedSignatureInfo) => { + await index(signature.signature, programId); + })); + backfilledSignatures = backfilledSignatures.concat(signatures); oldestSignature = signatures[signatures.length - 1].signature; @@ -79,7 +84,6 @@ const insertNewSignatures = async (programId: PublicKey) => { }); let oldestSignatureInserted: string | undefined; - while (true) { const signatures = await connection.getSignaturesForAddress( programId, @@ -91,6 +95,11 @@ const insertNewSignatures = async (programId: PublicKey) => { await insertSignatures(signatures, programId); + //trigger indexing + Promise.all(signatures.map(async (signature: ConfirmedSignatureInfo) => { + await index(signature.signature, programId); + })); + allSignatures = allSignatures.concat(signatures); oldestSignatureInserted = signatures[signatures.length - 1].signature; } diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index 9872ceef..e8bc5992 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -78,9 +78,8 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac } //indexes signature -export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { +export async function index(signature: string, programId: PublicKey) { try { - let signature = logs.signature; if (!programId.equals(AMM_PROGRAM_ID) && !programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { //autocrat program id, we aren't indexing these for now console.log("Unknown program id: ", programId.toBase58()); @@ -128,3 +127,24 @@ export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicK } } +//indexes signature from logs +export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { + try { + let signature = logs.signature; + if (!signature) { + console.log("No signature found in logs"); + logger.errorWithChatBotAlert([ + "No signature found in logs" + ]); + return; + } + await index(signature, programId); + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error processing signature: ${error.message}` + : "Unknown error processing signature" + ]); + } +} + From 55f7d19e4b348a4ada554e2ea0f9d62e2a0f7a40 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Thu, 7 Nov 2024 11:39:39 -0500 Subject: [PATCH 16/29] feat: v4 + v3 AMM logsSubscribe indexing + fixes --- package.json | 3 +- packages/indexer/src/subscriber.ts | 6 +- .../indexer/src/v3_indexer/builders/swaps.ts | 2 +- packages/indexer/src/v3_indexer/indexer.ts | 10 +- .../indexers/autocrat/autocrat-dao-indexer.ts | 2 +- .../src/v3_indexer/transaction/history.ts | 2 +- .../src/v3_indexer/transaction/serializer.ts | 2 +- .../src/v3_indexer/transaction/watcher.ts | 2 +- .../src/v3_indexer/usecases/math.test.ts | 17 + .../indexer/src/v3_indexer/usecases/math.ts | 23 + packages/indexer/src/v4_indexer/indexer.ts | 6 +- packages/indexer/src/v4_indexer/processor.ts | 6 +- pnpm-lock.yaml | 948 +----------------- 13 files changed, 72 insertions(+), 957 deletions(-) create mode 100644 packages/indexer/src/v3_indexer/usecases/math.test.ts create mode 100644 packages/indexer/src/v3_indexer/usecases/math.ts diff --git a/package.json b/package.json index d5730b94..bdb6ed5a 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,6 @@ }, "devDependencies": { "bun": "1.0.26" - } + }, + "packageManager": "pnpm@9.12.0+sha512.4abf725084d7bcbafbd728bfc7bee61f2f791f977fd87542b3579dcb23504d170d46337945e4c66485cd12d588a0c0e570ed9c477e7ccdd8507cf05f3f92eaca" } diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index 7d315e1d..ab7787ae 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -1,11 +1,11 @@ import { connection } from "./connection"; import { Context, Logs, PublicKey } from "@solana/web3.js"; -import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; -import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { AMM_PROGRAM_ID as V4_AMM_PROGRAM_ID, AUTOCRAT_PROGRAM_ID as V4_AUTOCRAT_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID as V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; +import { AMM_PROGRAM_ID as V3_AMM_PROGRAM_ID, AUTOCRAT_PROGRAM_ID as V3_AUTOCRAT_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID as V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; import { IndexerImplementation } from "@metadaoproject/indexer-db/lib/schema"; import { AccountLogsIndexer } from "./account-logs-indexer"; import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; -import { logger } from "../logger"; +import { logger } from "./logger"; import { indexFromLogs as indexV4 } from "./v4_indexer/indexer"; import { indexFromLogs as indexV3 } from "./v3_indexer/indexer"; diff --git a/packages/indexer/src/v3_indexer/builders/swaps.ts b/packages/indexer/src/v3_indexer/builders/swaps.ts index cdc96b73..1350a066 100644 --- a/packages/indexer/src/v3_indexer/builders/swaps.ts +++ b/packages/indexer/src/v3_indexer/builders/swaps.ts @@ -22,7 +22,7 @@ import { parseFormattedInstructionArgsData, serialize, } from "../transaction/serializer"; -import { logger } from "../logger"; +import { logger } from "../../logger"; import { getMainIxTypeFromTransaction } from "../transaction/watcher"; import { getHumanPrice } from "../usecases/math"; diff --git a/packages/indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts index 1125fefb..4e5606d1 100644 --- a/packages/indexer/src/v3_indexer/indexer.ts +++ b/packages/indexer/src/v3_indexer/indexer.ts @@ -1,8 +1,8 @@ import { Context, Logs, PublicKey } from "@solana/web3.js"; -import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; -import { AmmMarketLogsSubscribeIndexer } from "./amm-market/amm-market-logs-subscribe-indexer"; -import { AutocratDaoIndexer } from "./autocrat/autocrat-dao-indexer"; -import { AutocratProposalIndexer } from "./autocrat/autocrat-proposal-indexer"; +import { AMM_PROGRAM_ID as V3_AMM_PROGRAM_ID, AUTOCRAT_PROGRAM_ID as V3_AUTOCRAT_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID as V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { AmmMarketLogsSubscribeIndexer } from "./indexers/amm-market/amm-market-logs-subscribe-indexer"; +import { AutocratDaoIndexer } from "./indexers/autocrat/autocrat-dao-indexer"; +import { AutocratProposalIndexer } from "./indexers/autocrat/autocrat-proposal-indexer"; export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { @@ -10,7 +10,9 @@ export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicK await AmmMarketLogsSubscribeIndexer.index(logs, programId, ctx); } else if (programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { //TODO: implement + return; } else if (programId.equals(V3_AUTOCRAT_PROGRAM_ID)) { + return; // Parse logs to find instruction type const instructionLog = logs.logs.find(log => log.includes("Instruction:") && diff --git a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts index 2606f343..d7f11d32 100644 --- a/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/autocrat/autocrat-dao-indexer.ts @@ -1,5 +1,5 @@ import { IntervalFetchIndexer } from "../interval-fetch-indexer"; -import { rpcReadClient, connection } from "../../.connection"; +import { rpcReadClient, connection } from "../../connection"; import { usingDb, schema } from "@metadaoproject/indexer-db"; import { Dao } from "@metadaoproject/futarchy-sdk"; import { Err, Ok } from "../../match"; diff --git a/packages/indexer/src/v3_indexer/transaction/history.ts b/packages/indexer/src/v3_indexer/transaction/history.ts index 9a54da42..cd41d9f1 100644 --- a/packages/indexer/src/v3_indexer/transaction/history.ts +++ b/packages/indexer/src/v3_indexer/transaction/history.ts @@ -1,6 +1,6 @@ import { connection } from "../connection"; import { PublicKey } from "@solana/web3.js"; -import { logger } from "../logger"; +import { logger } from "../../logger"; export type TransactionMeta = Awaited< ReturnType<(typeof connection)["getSignaturesForAddress"]> diff --git a/packages/indexer/src/v3_indexer/transaction/serializer.ts b/packages/indexer/src/v3_indexer/transaction/serializer.ts index 06e68da9..460ce085 100644 --- a/packages/indexer/src/v3_indexer/transaction/serializer.ts +++ b/packages/indexer/src/v3_indexer/transaction/serializer.ts @@ -18,7 +18,7 @@ import { InstructionDisplay, Instruction as AnchorInstruction, } from "@coral-xyz/anchor/dist/cjs/coder/borsh/instruction"; -import { logger } from "../logger"; +import { logger } from "../../logger"; /** * This version should be bumped every time we update this file. diff --git a/packages/indexer/src/v3_indexer/transaction/watcher.ts b/packages/indexer/src/v3_indexer/transaction/watcher.ts index 39eed8a3..cda8183a 100644 --- a/packages/indexer/src/v3_indexer/transaction/watcher.ts +++ b/packages/indexer/src/v3_indexer/transaction/watcher.ts @@ -8,7 +8,7 @@ import { } from "./serializer"; import { getTransactionHistory } from "./history"; import { connection } from "../connection"; -import { logger } from "../logger"; +import { logger } from "../../logger"; import { Err, Ok, Result, TaggedUnion } from "../match"; import { InstructionType, diff --git a/packages/indexer/src/v3_indexer/usecases/math.test.ts b/packages/indexer/src/v3_indexer/usecases/math.test.ts new file mode 100644 index 00000000..c62dbd66 --- /dev/null +++ b/packages/indexer/src/v3_indexer/usecases/math.test.ts @@ -0,0 +1,17 @@ +import { expect, test, describe } from "bun:test"; +import { getHumanPrice } from "./math"; +import { PriceMath } from "@metadaoproject/futarchy/v0.4"; +import { BN } from "@coral-xyz/anchor"; + +describe("getHumanPrice", () => { + test("decimal value", () => { + const priceFromReserves = PriceMath.getAmmPriceFromReserves( + new BN(25000000000), + new BN(10000000000) + ); + + const price = getHumanPrice(priceFromReserves, 6, 6); + + expect(price).toBe(0.4); + }); +}); diff --git a/packages/indexer/src/v3_indexer/usecases/math.ts b/packages/indexer/src/v3_indexer/usecases/math.ts new file mode 100644 index 00000000..2e2e5416 --- /dev/null +++ b/packages/indexer/src/v3_indexer/usecases/math.ts @@ -0,0 +1,23 @@ +import { BN } from "@coral-xyz/anchor"; +import { logger } from "../../logger"; + +export function getHumanPrice( + ammPrice: BN, + baseDecimals: number, + quoteDecimals: number +): number { + const decimalScalar = new BN(10).pow( + new BN(quoteDecimals - baseDecimals).abs() + ); + const price1e12 = + quoteDecimals > baseDecimals + ? ammPrice.div(decimalScalar) + : ammPrice.mul(decimalScalar); + + try { + return price1e12.toNumber() / 1e12; + } catch (e) { + logger.warn("toNumber failed, returning div by 1e12"); + return price1e12.div(new BN(1e12)).toNumber(); + } +} diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index e8bc5992..0e98d8ac 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -3,12 +3,12 @@ import * as anchor from "@coral-xyz/anchor"; import { CompiledInnerInstruction, PublicKey, TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js"; import { schema, usingDb, eq, and, desc, gt } from "@metadaoproject/indexer-db"; -import { connection, ammClient, conditionalVaultClient } from "./connection"; +import { connection, ammClient, conditionalVaultClient } from "../connection"; import { Program } from "@coral-xyz/anchor"; import { Context, Logs, PublicKey } from "@solana/web3.js"; -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; +import { TelegramBotAPI } from "../adapters/telegram-bot"; +import { Logger } from "../logger"; import { processAmmEvent, processVaultEvent } from "./processor"; diff --git a/packages/indexer/src/v4_indexer/processor.ts b/packages/indexer/src/v4_indexer/processor.ts index 00779f47..70c5a64b 100644 --- a/packages/indexer/src/v4_indexer/processor.ts +++ b/packages/indexer/src/v4_indexer/processor.ts @@ -4,10 +4,10 @@ import { PublicKey, VersionedTransactionResponse } from "@solana/web3.js"; import { PricesType, V04SwapType } from "@metadaoproject/indexer-db/lib/schema"; import * as token from "@solana/spl-token"; -import { connection, conditionalVaultClient } from "./connection"; +import { connection, conditionalVaultClient } from "../connection"; -import { TelegramBotAPI } from "./adapters/telegram-bot"; -import { Logger } from "./logger"; +import { TelegramBotAPI } from "../adapters/telegram-bot"; +import { Logger } from "../logger"; const logger = new Logger(new TelegramBotAPI({token: process.env.TELEGRAM_BOT_API_KEY ?? ''})); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33f667fd..264bc2e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,61 +46,6 @@ importers: specifier: ^9.2.14 version: 9.2.14 - packages/futarchy-sdk: - dependencies: - '@coral-xyz/anchor': - specifier: ^0.28.1-beta.2 - version: 0.28.1-beta.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@metadaoproject/futarchy-ts': - specifier: ^1.4.0 - version: 1.6.0(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) - '@metaplex-foundation/js': - specifier: ^0.20.1 - version: 0.20.1(arweave@1.15.0)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) - '@metaplex-foundation/mpl-token-metadata': - specifier: ^3.2.1 - version: 3.2.1(@metaplex-foundation/umi@0.9.2) - '@metaplex-foundation/umi': - specifier: ^0.9.1 - version: 0.9.2 - '@openbook-dex/openbook-v2': - specifier: ^0.2.6 - version: 0.2.6(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) - '@solana/spl-token': - specifier: ^0.3.11 - version: 0.3.11(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-base': - specifier: ^0.9.23 - version: 0.9.23(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/web3.js': - specifier: ^1.91.7 - version: 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@types/bun': - specifier: ^1.1.0 - version: 1.1.1 - '@types/numeral': - specifier: ^2.0.4 - version: 2.0.5 - graphql-ws: - specifier: ^5.16.0 - version: 5.16.0(graphql@16.8.1) - numeral: - specifier: ^2.0.6 - version: 2.0.6 - rxjs: - specifier: ^7.8.1 - version: 7.8.1 - devDependencies: - tsconfig-paths: - specifier: ^4.2.0 - version: 4.2.0 - tscpaths: - specifier: ^0.0.9 - version: 0.0.9 - typescript: - specifier: ^5.4.5 - version: 5.6.3 - packages/hasura: dependencies: '@hasura/metadata': @@ -127,16 +72,16 @@ importers: version: 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@debridge-finance/solana-transaction-parser': specifier: ^2.0.1 - version: 2.0.1(@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/buffer-layout@4.0.1)(bufferutil@4.0.8)(utf-8-validate@5.0.10) + version: 2.0.1(@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/buffer-layout@4.0.1)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@lukasdeco/prom-client': specifier: ^15.1.4 version: 15.1.4 '@metadaoproject/futarchy': specifier: ^0.4.0-alpha.18 - version: 0.4.0-alpha.21(bufferutil@4.0.8)(utf-8-validate@5.0.10) + version: 0.4.0-alpha.21(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@metadaoproject/futarchy-sdk': specifier: 4.0.0-alpha.31 - version: 4.0.0-alpha.31(arweave@1.15.0)(bufferutil@4.0.8)(graphql@16.8.1)(utf-8-validate@5.0.10) + version: 4.0.0-alpha.31(arweave@1.15.0)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(graphql@16.8.1)(utf-8-validate@5.0.10) '@metadaoproject/indexer-db': specifier: workspace:* version: link:../database @@ -862,9 +807,6 @@ packages: '@metadaoproject/futarchy-sdk@4.0.0-alpha.31': resolution: {integrity: sha512-uugimbCdzZTW7b+mvecFsd5EYSRVT5h9E3gm/NMq4PoKn14fqtpHt9PkgiAtbNcyYc+aR1B0VRb7sPSo6nZ3Mw==} - '@metadaoproject/futarchy-ts@1.6.0': - resolution: {integrity: sha512-Ib64AOPav4vylhP517nM58esmnIZ9ndB8sVTnCzTHUaf0Zt7JEn62JR3bqCmw4Wt238I7Vx67Ht60QjONmo4oQ==} - '@metadaoproject/futarchy-ts@4.1.0': resolution: {integrity: sha512-qI8EvXXKkwXMdGEISy6GlZ4uG5o3WZDHBWtXhJLs+59uklJTr4tfXpm4YF6q3UgV4052MiJBS5aN6bTKlFvKKw==} @@ -1070,10 +1012,6 @@ packages: '@metaplex-foundation/umi@0.9.2': resolution: {integrity: sha512-9i4Acm4pruQfJcpRrc2EauPBwkfDN0I9QTvJyZocIlKgoZwD6A6wH0PViH1AjOVG5CQCd1YI3tJd5XjYE1ElBw==} - '@mrmlnc/readdir-enhanced@2.2.1': - resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} - engines: {node: '>=4'} - '@native-to-anchor/buffer-layout@0.1.0': resolution: {integrity: sha512-7Ykz9KRAm53XqHj5blDUKPX+OXAPO4GZBW4zJhfHGIAbzmqsUFh9kMqR66Bak3mp6wyv1OVTwSr8ZGHKswPxDg==} @@ -1143,10 +1081,6 @@ packages: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} - '@nodelib/fs.stat@1.1.3': - resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} - engines: {node: '>= 6'} - '@nodelib/fs.stat@2.0.5': resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} @@ -1360,9 +1294,6 @@ packages: '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - '@types/glob@7.2.0': - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - '@types/http-errors@2.0.4': resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} @@ -1378,9 +1309,6 @@ packages: '@types/mime@3.0.4': resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/node@11.11.6': resolution: {integrity: sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==} @@ -1504,37 +1432,13 @@ packages: arconnect@0.4.2: resolution: {integrity: sha512-Jkpd4QL3TVqnd3U683gzXmZUVqBUy17DdJDuL/3D9rkysLgX6ymJ2e+sR+xyZF5Rh42CBqDXWNMmCjBXeP7Gbw==} - arr-diff@4.0.0: - resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} - engines: {node: '>=0.10.0'} - - arr-flatten@1.1.0: - resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} - engines: {node: '>=0.10.0'} - - arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} - array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-union@1.0.2: - resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} - engines: {node: '>=0.10.0'} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - - array-unique@0.3.2: - resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} - engines: {node: '>=0.10.0'} - arweave-stream-tx@1.2.2: resolution: {integrity: sha512-bNt9rj0hbAEzoUZEF2s6WJbIz8nasZlZpxIw03Xm8fzb9gRiiZlZGW3lxQLjfc9Z0VRUWDzwtqoYeEoB/JDToQ==} peerDependencies: @@ -1550,21 +1454,12 @@ packages: asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} - assign-symbols@1.0.0: - resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} - engines: {node: '>=0.10.0'} - async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atob@2.1.2: - resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} - engines: {node: '>= 4.5.0'} - hasBin: true - avsc@https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef: resolution: {tarball: https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef} version: 5.4.7 @@ -1598,10 +1493,6 @@ packages: resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} engines: {node: '>=6.0.0'} - base@0.11.2: - resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} - engines: {node: '>=0.10.0'} - bech32@1.1.4: resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} @@ -1655,10 +1546,6 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - braces@2.3.2: - resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} - engines: {node: '>=0.10.0'} - braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -1714,17 +1601,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cache-base@1.0.1: - resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} - engines: {node: '>=0.10.0'} - call-bind@1.0.6: resolution: {integrity: sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==} engines: {node: '>= 0.4'} - call-me-maybe@1.0.2: - resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} - camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -1754,10 +1634,6 @@ packages: cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - class-utils@0.3.6: - resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} - engines: {node: '>=0.10.0'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -1789,10 +1665,6 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} - color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1824,9 +1696,6 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1845,10 +1714,6 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - copy-descriptor@0.1.1: - resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} - engines: {node: '>=0.10.0'} - cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -1929,10 +1794,6 @@ packages: decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -1940,18 +1801,6 @@ packages: resolution: {integrity: sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==} engines: {node: '>= 0.4'} - define-property@0.2.5: - resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} - engines: {node: '>=0.10.0'} - - define-property@1.0.0: - resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} - engines: {node: '>=0.10.0'} - - define-property@2.0.2: - resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} - engines: {node: '>=0.10.0'} - delay@5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -1972,10 +1821,6 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dir-glob@2.2.2: - resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} - engines: {node: '>=4'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2256,10 +2101,6 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - expand-brackets@2.1.4: - resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} - engines: {node: '>=0.10.0'} - exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} @@ -2267,30 +2108,14 @@ packages: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} - extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - - extend-shallow@3.0.2: - resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} - engines: {node: '>=0.10.0'} - external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} - extglob@2.0.4: - resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} - engines: {node: '>=0.10.0'} - eyes@0.1.8: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} engines: {node: '> 0.1.90'} - fast-glob@2.2.7: - resolution: {integrity: sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==} - engines: {node: '>=4.0.0'} - fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2311,10 +2136,6 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@4.0.0: - resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} - engines: {node: '>=0.10.0'} - fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -2345,10 +2166,6 @@ packages: debug: optional: true - for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} - form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -2357,10 +2174,6 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fragment-cache@0.2.1: - resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} - engines: {node: '>=0.10.0'} - fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -2386,20 +2199,10 @@ packages: get-tsconfig@4.7.2: resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - get-value@2.0.6: - resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} - engines: {node: '>=0.10.0'} - - glob-parent@3.1.0: - resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-to-regexp@0.3.0: - resolution: {integrity: sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==} - glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -2407,10 +2210,6 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - globby@9.2.0: - resolution: {integrity: sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==} - engines: {node: '>=6'} - gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -2452,22 +2251,6 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - has-value@0.3.1: - resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} - engines: {node: '>=0.10.0'} - - has-value@1.0.0: - resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} - engines: {node: '>=0.10.0'} - - has-values@0.1.4: - resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} - engines: {node: '>=0.10.0'} - - has-values@1.0.0: - resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} - engines: {node: '>=0.10.0'} - hash-base@3.1.0: resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} engines: {node: '>=4'} @@ -2508,10 +2291,6 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -2534,33 +2313,6 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - is-accessor-descriptor@1.0.1: - resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} - engines: {node: '>= 0.10'} - - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - - is-data-descriptor@1.0.1: - resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} - engines: {node: '>= 0.4'} - - is-descriptor@0.1.7: - resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} - engines: {node: '>= 0.4'} - - is-descriptor@1.0.3: - resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} - engines: {node: '>= 0.4'} - - is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - - is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2573,10 +2325,6 @@ packages: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} - is-glob@3.1.0: - resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} - engines: {node: '>=0.10.0'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2589,37 +2337,14 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - is-number@3.0.0: - resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} - engines: {node: '>=0.10.0'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isobject@2.1.0: - resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} - engines: {node: '>=0.10.0'} - - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - isomorphic-ws@4.0.1: resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} peerDependencies: @@ -2648,11 +2373,6 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -2674,18 +2394,6 @@ packages: resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} engines: {node: '>=10.0.0'} - kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} - - kind-of@4.0.0: - resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} - engines: {node: '>=0.10.0'} - - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -2748,14 +2456,6 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - map-cache@0.2.2: - resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} - engines: {node: '>=0.10.0'} - - map-visit@1.0.0: - resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} - engines: {node: '>=0.10.0'} - match-discriminated-union@1.0.0: resolution: {integrity: sha512-1P7vVC8pwb3NEIRdYz8YSq5Mdnjx/xMH/D8FAqKuDMMbuiGN4LQMtX8YcwUpd3mXRd6ORjnSnibrK/Iq+ObHZw==} @@ -2784,10 +2484,6 @@ packages: micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - micromatch@3.1.10: - resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} - engines: {node: '>=0.10.0'} - micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -2826,10 +2522,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - mixin-deep@1.3.2: - resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} - engines: {node: '>=0.10.0'} - mixme@0.5.10: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} @@ -2861,10 +2553,6 @@ packages: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - nanomatch@1.2.13: - resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} - engines: {node: '>=0.10.0'} - native-fetch@4.0.2: resolution: {integrity: sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==} peerDependencies: @@ -2923,21 +2611,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-copy@0.1.0: - resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} - engines: {node: '>=0.10.0'} - object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - object-visit@1.0.1: - resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} - engines: {node: '>=0.10.0'} - - object.pick@1.3.0: - resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} - engines: {node: '>=0.10.0'} - obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} @@ -2986,13 +2662,6 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - pascalcase@0.1.1: - resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} - engines: {node: '>=0.10.0'} - - path-dirname@1.0.2: - resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3004,10 +2673,6 @@ packages: path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-type@3.0.0: - resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} - engines: {node: '>=4'} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3062,18 +2727,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - posix-character-classes@0.1.1: - resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} - engines: {node: '>=0.10.0'} - postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -3161,21 +2814,9 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regex-not@1.0.2: - resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} - engines: {node: '>=0.10.0'} - remove-trailing-separator@1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} - repeat-element@1.1.4: - resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} - engines: {node: '>=0.10.0'} - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -3190,10 +2831,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve-url@0.2.1: - resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated - restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -3202,10 +2839,6 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - ret@0.1.15: - resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} - engines: {node: '>=0.12'} - retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -3248,9 +2881,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex@1.1.0: - resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -3285,10 +2915,6 @@ packages: resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} engines: {node: '>= 0.4'} - set-value@2.0.1: - resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} - engines: {node: '>=0.10.0'} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -3303,10 +2929,6 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - slash@2.0.0: - resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} - engines: {node: '>=6'} - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3318,49 +2940,17 @@ packages: snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} - snapdragon-node@2.1.1: - resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} - engines: {node: '>=0.10.0'} - - snapdragon-util@3.0.1: - resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} - engines: {node: '>=0.10.0'} - - snapdragon@0.8.2: - resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} - engines: {node: '>=0.10.0'} - - source-map-resolve@0.5.3: - resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated - source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - source-map-url@0.4.1: - resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated - - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - split-string@3.1.0: - resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} - engines: {node: '>=0.10.0'} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - static-extend@0.1.2: - resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} - engines: {node: '>=0.10.0'} - statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -3394,10 +2984,6 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - strip-hex-prefix@1.0.0: resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} engines: {node: '>=6.5.0', npm: '>=3'} @@ -3439,22 +3025,10 @@ packages: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} - to-object-path@0.3.0: - resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} - engines: {node: '>=0.10.0'} - - to-regex-range@2.1.1: - resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} - engines: {node: '>=0.10.0'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - to-regex@3.0.2: - resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} - engines: {node: '>=0.10.0'} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -3469,14 +3043,6 @@ packages: resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} engines: {node: '>=0.6'} - tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - - tscpaths@0.0.9: - resolution: {integrity: sha512-tz4qimSJTCjYtHVsoY7pvxLcxhmhgmwzm7fyMEiL3/kPFFVyUuZOwuwcWwjkAsIrSUKJK22A7fNuJUwxzQ+H+w==} - hasBin: true - tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -3498,11 +3064,6 @@ packages: typescript-collections@1.3.3: resolution: {integrity: sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==} - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} - engines: {node: '>=14.17'} - hasBin: true - u3@0.1.1: resolution: {integrity: sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==} @@ -3513,10 +3074,6 @@ packages: resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} engines: {node: '>=14.0'} - union-value@1.0.1: - resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} - engines: {node: '>=0.10.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -3529,18 +3086,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unset-value@1.0.0: - resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} - engines: {node: '>=0.10.0'} - - urix@0.1.0: - resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated - - use@3.1.1: - resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} - engines: {node: '>=0.10.0'} - utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} @@ -3756,7 +3301,7 @@ snapshots: - encoding - utf-8-validate - '@debridge-finance/solana-transaction-parser@2.0.1(@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/buffer-layout@4.0.1)(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@debridge-finance/solana-transaction-parser@2.0.1(@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/buffer-layout@4.0.1)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@coral-xyz/spl-token': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -4378,11 +3923,11 @@ snapshots: '@opentelemetry/api': 1.8.0 tdigest: 0.1.2 - '@metadaoproject/futarchy-sdk@4.0.0-alpha.31(arweave@1.15.0)(bufferutil@4.0.8)(graphql@16.8.1)(utf-8-validate@5.0.10)': + '@metadaoproject/futarchy-sdk@4.0.0-alpha.31(arweave@1.15.0)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(graphql@16.8.1)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.28.1-beta.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@metadaoproject/futarchy': 0.3.0-alpha.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@metadaoproject/futarchy-ts': 4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@metadaoproject/futarchy': 0.3.0-alpha.10(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) + '@metadaoproject/futarchy-ts': 4.1.0(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@metaplex-foundation/js': 0.20.1(arweave@1.15.0)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@metaplex-foundation/mpl-token-metadata': 3.2.1(@metaplex-foundation/umi@0.9.2) '@metaplex-foundation/umi': 0.9.2 @@ -4409,21 +3954,7 @@ snapshots: - supports-color - utf-8-validate - '@metadaoproject/futarchy-ts@1.6.0(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': - dependencies: - '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) - bn.js: 5.2.1 - decimal.js: 10.4.3 - esbuild: 0.17.19 - transitivePeerDependencies: - - bufferutil - - encoding - - fastestsmallesttextencoderdecoder - - utf-8-validate - - '@metadaoproject/futarchy-ts@4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@metadaoproject/futarchy-ts@4.1.0(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) @@ -4437,7 +3968,7 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@metadaoproject/futarchy@0.3.0-alpha.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@metadaoproject/futarchy@0.3.0-alpha.10(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) @@ -4451,7 +3982,7 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@metadaoproject/futarchy@0.4.0-alpha.21(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@metadaoproject/futarchy@0.4.0-alpha.21(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@metaplex-foundation/umi': 0.9.2 @@ -4902,11 +4433,6 @@ snapshots: '@metaplex-foundation/umi-public-keys': 0.8.9 '@metaplex-foundation/umi-serializers': 0.9.0 - '@mrmlnc/readdir-enhanced@2.2.1': - dependencies: - call-me-maybe: 1.0.2 - glob-to-regexp: 0.3.0 - '@native-to-anchor/buffer-layout@0.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.0 @@ -5033,8 +4559,6 @@ snapshots: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - '@nodelib/fs.stat@1.1.3': {} - '@nodelib/fs.stat@2.0.5': {} '@nodelib/fs.walk@1.2.8': @@ -5385,11 +4909,6 @@ snapshots: '@types/qs': 6.9.14 '@types/serve-static': 1.15.5 - '@types/glob@7.2.0': - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 20.11.16 - '@types/http-errors@2.0.4': {} '@types/inquirer@9.0.7': @@ -5405,8 +4924,6 @@ snapshots: '@types/mime@3.0.4': {} - '@types/minimatch@5.1.2': {} - '@types/node@11.11.6': {} '@types/node@12.20.55': {} @@ -5591,24 +5108,10 @@ snapshots: dependencies: arweave: 1.15.0 - arr-diff@4.0.0: {} - - arr-flatten@1.1.0: {} - - arr-union@3.1.0: {} - array-flatten@1.1.1: {} - array-union@1.0.2: - dependencies: - array-uniq: 1.0.3 - array-union@2.1.0: {} - array-uniq@1.0.3: {} - - array-unique@0.3.2: {} - arweave-stream-tx@1.2.2(arweave@1.15.0): dependencies: arweave: 1.15.0 @@ -5632,16 +5135,12 @@ snapshots: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 - assign-symbols@1.0.0: {} - async-retry@1.3.3: dependencies: retry: 0.13.1 asynckit@0.4.0: {} - atob@2.1.2: {} - avsc@https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef: {} axios@0.21.4: @@ -5683,16 +5182,6 @@ snapshots: base64url@3.0.1: {} - base@0.11.2: - dependencies: - cache-base: 1.0.1 - class-utils: 0.3.6 - component-emitter: 1.3.1 - define-property: 1.0.0 - isobject: 3.0.1 - mixin-deep: 1.3.2 - pascalcase: 0.1.1 - bech32@1.1.4: {} big.js@6.2.1: {} @@ -5769,21 +5258,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - braces@2.3.2: - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2 - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - braces@3.0.2: dependencies: fill-range: 7.0.1 @@ -5844,18 +5318,6 @@ snapshots: bytes@3.1.2: {} - cache-base@1.0.1: - dependencies: - collection-visit: 1.0.0 - component-emitter: 1.3.1 - get-value: 2.0.6 - has-value: 1.0.0 - isobject: 3.0.1 - set-value: 2.0.1 - to-object-path: 0.3.0 - union-value: 1.0.1 - unset-value: 1.0.0 - call-bind@1.0.6: dependencies: es-errors: 1.3.0 @@ -5863,8 +5325,6 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.1 - call-me-maybe@1.0.2: {} - camelcase@5.3.1: {} camelcase@6.3.0: {} @@ -5891,13 +5351,6 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 - class-utils@0.3.6: - dependencies: - arr-union: 3.1.0 - define-property: 0.2.5 - isobject: 3.0.1 - static-extend: 0.1.2 - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -5925,11 +5378,6 @@ snapshots: clone@1.0.4: {} - collection-visit@1.0.0: - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -5954,8 +5402,6 @@ snapshots: commander@8.3.0: {} - component-emitter@1.3.1: {} - concat-map@0.0.1: {} content-disposition@0.5.4: @@ -5968,8 +5414,6 @@ snapshots: cookie@0.6.0: {} - copy-descriptor@0.1.1: {} - cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -6046,8 +5490,6 @@ snapshots: decimal.js@10.4.3: {} - decode-uri-component@0.2.2: {} - defaults@1.0.4: dependencies: clone: 1.0.4 @@ -6059,19 +5501,6 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.1 - define-property@0.2.5: - dependencies: - is-descriptor: 0.1.7 - - define-property@1.0.0: - dependencies: - is-descriptor: 1.0.3 - - define-property@2.0.2: - dependencies: - is-descriptor: 1.0.3 - isobject: 3.0.1 - delay@5.0.0: {} delayed-stream@1.0.0: {} @@ -6082,10 +5511,6 @@ snapshots: destroy@1.2.0: {} - dir-glob@2.2.2: - dependencies: - path-type: 3.0.0 - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -6319,18 +5744,6 @@ snapshots: eventemitter3@5.0.1: {} - expand-brackets@2.1.4: - dependencies: - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - exponential-backoff@3.1.1: {} express@4.19.2: @@ -6369,47 +5782,14 @@ snapshots: transitivePeerDependencies: - supports-color - extend-shallow@2.0.1: - dependencies: - is-extendable: 0.1.1 - - extend-shallow@3.0.2: - dependencies: - assign-symbols: 1.0.0 - is-extendable: 1.0.1 - external-editor@3.1.0: dependencies: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - extglob@2.0.4: - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4 - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - eyes@0.1.8: {} - fast-glob@2.2.7: - dependencies: - '@mrmlnc/readdir-enhanced': 2.2.1 - '@nodelib/fs.stat': 1.1.3 - glob-parent: 3.1.0 - is-glob: 4.0.3 - merge2: 1.4.1 - micromatch: 3.1.10 - transitivePeerDependencies: - - supports-color - fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6432,13 +5812,6 @@ snapshots: file-uri-to-path@1.0.0: {} - fill-range@4.0.0: - dependencies: - extend-shallow: 2.0.1 - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range: 2.1.1 - fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 @@ -6466,8 +5839,6 @@ snapshots: optionalDependencies: debug: 4.3.4 - for-in@1.0.2: {} - form-data@4.0.0: dependencies: asynckit: 0.4.0 @@ -6476,10 +5847,6 @@ snapshots: forwarded@0.2.0: {} - fragment-cache@0.2.1: - dependencies: - map-cache: 0.2.2 - fresh@0.5.2: {} fs-extra@10.1.0: @@ -6506,19 +5873,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - get-value@2.0.6: {} - - glob-parent@3.1.0: - dependencies: - is-glob: 3.1.0 - path-dirname: 1.0.2 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.3.0: {} - glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -6537,19 +5895,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@9.2.0: - dependencies: - '@types/glob': 7.2.0 - array-union: 1.0.2 - dir-glob: 2.2.2 - fast-glob: 2.2.7 - glob: 7.2.3 - ignore: 4.0.6 - pify: 4.0.1 - slash: 2.0.0 - transitivePeerDependencies: - - supports-color - gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 @@ -6578,25 +5923,6 @@ snapshots: has-symbols@1.0.3: {} - has-value@0.3.1: - dependencies: - get-value: 2.0.6 - has-values: 0.1.4 - isobject: 2.1.0 - - has-value@1.0.0: - dependencies: - get-value: 2.0.6 - has-values: 1.0.0 - isobject: 3.0.1 - - has-values@0.1.4: {} - - has-values@1.0.0: - dependencies: - is-number: 3.0.0 - kind-of: 4.0.0 - hash-base@3.1.0: dependencies: inherits: 2.0.4 @@ -6653,8 +5979,6 @@ snapshots: ieee754@1.2.1: {} - ignore@4.0.6: {} - ignore@5.3.1: {} inflight@1.0.6: @@ -6702,42 +6026,12 @@ snapshots: ipaddr.js@1.9.1: {} - is-accessor-descriptor@1.0.1: - dependencies: - hasown: 2.0.0 - - is-buffer@1.1.6: {} - - is-data-descriptor@1.0.1: - dependencies: - hasown: 2.0.0 - - is-descriptor@0.1.7: - dependencies: - is-accessor-descriptor: 1.0.1 - is-data-descriptor: 1.0.1 - - is-descriptor@1.0.3: - dependencies: - is-accessor-descriptor: 1.0.1 - is-data-descriptor: 1.0.1 - - is-extendable@0.1.1: {} - - is-extendable@1.0.1: - dependencies: - is-plain-object: 2.0.4 - is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} - is-glob@3.1.0: - dependencies: - is-extglob: 2.1.1 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -6746,28 +6040,10 @@ snapshots: is-interactive@1.0.0: {} - is-number@3.0.0: - dependencies: - kind-of: 3.2.2 - is-number@7.0.0: {} - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - is-unicode-supported@0.1.0: {} - is-windows@1.0.2: {} - - isarray@1.0.0: {} - - isobject@2.1.0: - dependencies: - isarray: 1.0.0 - - isobject@3.0.1: {} - isomorphic-ws@4.0.1(ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -6804,8 +6080,6 @@ snapshots: json-stringify-safe@5.0.1: {} - json5@2.2.3: {} - jsonfile@6.1.0: dependencies: universalify: 2.0.1 @@ -6844,16 +6118,6 @@ snapshots: node-gyp-build: 4.8.0 readable-stream: 3.6.2 - kind-of@3.2.2: - dependencies: - is-buffer: 1.1.6 - - kind-of@4.0.0: - dependencies: - is-buffer: 1.1.6 - - kind-of@6.0.3: {} - kleur@4.1.5: {} listr2@6.6.1: @@ -6910,12 +6174,6 @@ snapshots: dependencies: tslib: 2.6.2 - map-cache@0.2.2: {} - - map-visit@1.0.0: - dependencies: - object-visit: 1.0.1 - match-discriminated-union@1.0.0: {} md5.js@1.3.5: @@ -6942,24 +6200,6 @@ snapshots: micro-ftch@0.3.1: {} - micromatch@3.1.10: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4 - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - micromatch@4.0.5: dependencies: braces: 3.0.2 @@ -6987,11 +6227,6 @@ snapshots: minimist@1.2.8: {} - mixin-deep@1.3.2: - dependencies: - for-in: 1.0.2 - is-extendable: 1.0.1 - mixme@0.5.10: {} mkdirp@0.5.6: @@ -7015,22 +6250,6 @@ snapshots: mute-stream@1.0.0: {} - nanomatch@1.2.13: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - native-fetch@4.0.2(undici@5.28.3): dependencies: undici: 5.28.3 @@ -7098,22 +6317,8 @@ snapshots: object-assign@4.1.1: {} - object-copy@0.1.0: - dependencies: - copy-descriptor: 0.1.1 - define-property: 0.2.5 - kind-of: 3.2.2 - object-inspect@1.13.1: {} - object-visit@1.0.1: - dependencies: - isobject: 3.0.1 - - object.pick@1.3.0: - dependencies: - isobject: 3.0.1 - obuf@1.1.2: {} on-finished@2.4.1: @@ -7162,20 +6367,12 @@ snapshots: parseurl@1.3.3: {} - pascalcase@0.1.1: {} - - path-dirname@1.0.2: {} - path-exists@4.0.0: {} path-is-absolute@1.0.1: {} path-to-regexp@0.1.7: {} - path-type@3.0.0: - dependencies: - pify: 3.0.0 - path-type@4.0.0: {} pbkdf2@3.1.2: @@ -7237,12 +6434,6 @@ snapshots: picomatch@2.3.1: {} - pify@3.0.0: {} - - pify@4.0.1: {} - - posix-character-classes@0.1.1: {} - postgres-array@2.0.0: {} postgres-array@3.0.2: {} @@ -7313,17 +6504,8 @@ snapshots: regenerator-runtime@0.14.1: {} - regex-not@1.0.2: - dependencies: - extend-shallow: 3.0.2 - safe-regex: 1.1.0 - remove-trailing-separator@1.1.0: {} - repeat-element@1.1.4: {} - - repeat-string@1.6.1: {} - require-directory@2.1.1: {} require-main-filename@2.0.0: {} @@ -7332,8 +6514,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-url@0.2.1: {} - restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -7344,8 +6524,6 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - ret@0.1.15: {} - retry@0.13.1: {} reusify@1.0.4: {} @@ -7394,10 +6572,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-regex@1.1.0: - dependencies: - ret: 0.1.15 - safer-buffer@2.1.2: {} scrypt-js@3.0.1: {} @@ -7454,13 +6628,6 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.1 - set-value@2.0.1: - dependencies: - extend-shallow: 2.0.1 - is-extendable: 0.1.1 - is-plain-object: 2.0.4 - split-string: 3.1.0 - setprototypeof@1.2.0: {} sha.js@2.4.11: @@ -7477,8 +6644,6 @@ snapshots: signal-exit@3.0.7: {} - slash@2.0.0: {} - slash@3.0.0: {} slice-ansi@5.0.0: @@ -7491,59 +6656,15 @@ snapshots: dot-case: 3.0.4 tslib: 2.6.2 - snapdragon-node@2.1.1: - dependencies: - define-property: 1.0.0 - isobject: 3.0.1 - snapdragon-util: 3.0.1 - - snapdragon-util@3.0.1: - dependencies: - kind-of: 3.2.2 - - snapdragon@0.8.2: - dependencies: - base: 0.11.2 - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - - source-map-resolve@0.5.3: - dependencies: - atob: 2.1.2 - decode-uri-component: 0.2.2 - resolve-url: 0.2.1 - source-map-url: 0.4.1 - urix: 0.1.0 - source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - source-map-url@0.4.1: {} - - source-map@0.5.7: {} - source-map@0.6.1: {} - split-string@3.1.0: - dependencies: - extend-shallow: 3.0.2 - split2@4.2.0: {} - static-extend@0.1.2: - dependencies: - define-property: 0.2.5 - object-copy: 0.1.0 - statuses@1.5.0: {} statuses@2.0.1: {} @@ -7578,8 +6699,6 @@ snapshots: dependencies: ansi-regex: 6.0.1 - strip-bom@3.0.0: {} - strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed: 1.0.0 @@ -7616,26 +6735,10 @@ snapshots: tmp@0.2.3: {} - to-object-path@0.3.0: - dependencies: - kind-of: 3.2.2 - - to-regex-range@2.1.1: - dependencies: - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - to-regex@3.0.2: - dependencies: - define-property: 2.0.2 - extend-shallow: 3.0.2 - regex-not: 1.0.2 - safe-regex: 1.1.0 - toidentifier@1.0.1: {} toml@3.0.0: {} @@ -7644,19 +6747,6 @@ snapshots: treeify@1.1.0: {} - tsconfig-paths@4.2.0: - dependencies: - json5: 2.2.3 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tscpaths@0.0.9: - dependencies: - commander: 2.20.3 - globby: 9.2.0 - transitivePeerDependencies: - - supports-color - tslib@2.6.2: {} tweetnacl@1.0.3: {} @@ -7672,8 +6762,6 @@ snapshots: typescript-collections@1.3.3: {} - typescript@5.6.3: {} - u3@0.1.1: {} undici-types@5.26.5: {} @@ -7682,13 +6770,6 @@ snapshots: dependencies: '@fastify/busboy': 2.1.0 - union-value@1.0.1: - dependencies: - arr-union: 3.1.0 - get-value: 2.0.6 - is-extendable: 0.1.1 - set-value: 2.0.1 - universalify@2.0.1: {} unixify@1.0.0: @@ -7697,15 +6778,6 @@ snapshots: unpipe@1.0.0: {} - unset-value@1.0.0: - dependencies: - has-value: 0.3.1 - isobject: 3.0.1 - - urix@0.1.0: {} - - use@3.1.1: {} - utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.0 From fa3487670e02d05e54a2c9e386051ecca76203b2 Mon Sep 17 00:00:00 2001 From: Kollan House Date: Thu, 7 Nov 2024 17:27:52 -0800 Subject: [PATCH 17/29] feat: adds more native queries and optimization --- .../hasura/metadata/databases/databases.yaml | 36 ++++++++++++++++++- .../futarchy/tables/public_takes.yaml | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/hasura/metadata/databases/databases.yaml b/packages/hasura/metadata/databases/databases.yaml index b08430d0..9054801d 100644 --- a/packages/hasura/metadata/databases/databases.yaml +++ b/packages/hasura/metadata/databases/databases.yaml @@ -24,6 +24,28 @@ - total_volume filter: {} role: anonymous + - fields: + - name: total_volume + type: + nullable: true + scalar: numeric + - name: unique_accounts + type: + nullable: true + scalar: numeric + - name: total_trades + type: + nullable: true + scalar: numeric + name: performance_stats + select_permissions: + - permission: + columns: + - total_volume + - unique_accounts + - total_trades + filter: {} + role: anonymous - fields: - name: base_amount type: @@ -141,6 +163,18 @@ filter: {} role: anonymous native_queries: + - arguments: + dao_slug: + description: "" + nullable: true + type: text + proposal_acct: + description: "" + nullable: true + type: text + code: "WITH base_trades AS (\n SELECT \n t.market_acct,\n o.actor_acct,\n (t.base_amount / POW(10, tokens.decimals)) * t.quote_price AS trade_volume,\n dd.slug,\n m.proposal_acct,\n COUNT(*) OVER () as total_takes -- Count all takes that match our filters\n FROM \n takes t\n INNER JOIN orders o \n ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx \n ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN markets m \n ON m.market_acct = o.market_acct\n INNER JOIN proposals p \n ON p.proposal_acct = m.proposal_acct\n INNER JOIN daos d \n ON d.dao_acct = p.dao_acct\n INNER JOIN tokens \n ON tokens.mint_acct = d.base_acct\n INNER JOIN dao_details dd \n ON dd.dao_id = d.dao_id\n WHERE \n -- Optional filters that can be commented out or dynamically included\n (NULLIF({{dao_slug}}, '') IS NULL OR dd.slug = {{dao_slug}})\n AND (NULLIF({{proposal_acct}}, '') IS NULL OR m.proposal_acct = {{proposal_acct}})\n),\naggregated_stats AS (\n SELECT \n COUNT(DISTINCT actor_acct) AS unique_trader_count,\n SUM(trade_volume) AS total_volume,\n MAX(total_takes) AS total_trades, -- Use MAX since the value is the same for all rows\n -- Include these in output for verification/grouping if needed\n NULLIF({{dao_slug}}, '') AS filtered_dao_slug,\n NULLIF({{proposal_acct}}, '') AS filtered_proposal_acct\n FROM base_trades\n)\nSELECT \n total_volume::numeric, \n unique_trader_count::numeric AS unique_accounts,\n total_trades::numeric\nFROM aggregated_stats;" + returns: performance_stats + root_field_name: performance_stats - arguments: dao_slug: description: Slug of the DAO @@ -186,7 +220,7 @@ description: the proposal account nullable: true type: varchar - code: "WITH market_actors AS (\n SELECT \n market_acct,\n actor_acct,\n COUNT(*) AS countOrders\n FROM \n orders\n GROUP BY \n market_acct, actor_acct\n), distinct_users_by_proposal AS (\n SELECT\n proposal_acct,\n COUNT(DISTINCT actor_acct) AS uniqueUsersCount,\n SUM(countOrders) AS totalTrades\n FROM market_actors\n JOIN markets ON markets.market_acct = market_actors.market_acct\n GROUP BY proposal_acct\n)\nSELECT\n\tproposal_acct,\n\tuniqueUsersCount AS user_count,\n\ttotalTrades AS trade_count\nFROM distinct_users_by_proposal\nWHERE \n CASE \n WHEN {{proposal_acct}} IS NOT NULL \n THEN proposal_acct = {{proposal_acct}} \n ELSE 1 = 1 \n END;" + code: "WITH market_actors AS (\n SELECT \n t.market_acct,\n actor_acct,\n COUNT(*) AS countOrders\n FROM \n takes t\n JOIN orders o ON o.order_tx_sig = t.order_tx_sig\n JOIN transactions tx ON tx.tx_sig = o.order_tx_sig\n WHERE tx.failed IS FALSE\n AND o.quote_price > 0\n GROUP BY \n t.market_acct, actor_acct\n), distinct_users_by_proposal AS (\n SELECT\n proposal_acct,\n COUNT(DISTINCT actor_acct) AS uniqueUsersCount,\n SUM(countOrders) AS totalTrades\n FROM market_actors\n JOIN markets ON markets.market_acct = market_actors.market_acct\n GROUP BY proposal_acct\n)\nSELECT\n\tproposal_acct,\n\tuniqueUsersCount AS user_count,\n\ttotalTrades AS trade_count\nFROM distinct_users_by_proposal\nWHERE \n CASE \n WHEN {{proposal_acct}} IS NOT NULL \n THEN proposal_acct = {{proposal_acct}} \n ELSE 1 = 1 \n END;" returns: proposal_statistics root_field_name: user_count_and_trade_count_per_proposal tables: "!include futarchy/tables/tables.yaml" diff --git a/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml b/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml index 61c00a9e..74a1515d 100644 --- a/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml +++ b/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml @@ -27,4 +27,5 @@ select_permissions: - order_tx_sig - order_time filter: {} + allow_aggregations: true comment: "" From 375416da2c5c5f02246900631b9aa7815aa1c118 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 11 Nov 2024 16:55:08 -0500 Subject: [PATCH 18/29] feat: unified schema, v4 working perfecto, v3 cleanup in progress --- packages/database/lib/index.ts | 1 + packages/database/lib/schema.ts | 3 +- packages/indexer/src/index.ts | 14 ++++- packages/indexer/src/subscriber.ts | 3 + packages/indexer/src/v3_indexer/indexer.ts | 4 +- packages/indexer/src/v4_indexer/filler.ts | 3 +- packages/indexer/src/v4_indexer/indexer.ts | 64 +++++++++++--------- packages/indexer/src/v4_indexer/processor.ts | 34 ++++++++--- 8 files changed, 82 insertions(+), 44 deletions(-) diff --git a/packages/database/lib/index.ts b/packages/database/lib/index.ts index 441e011b..e68c5abf 100644 --- a/packages/database/lib/index.ts +++ b/packages/database/lib/index.ts @@ -91,6 +91,7 @@ export const schema = schemaDefs; export { eq, sql, + asc, desc, count, lte, diff --git a/packages/database/lib/schema.ts b/packages/database/lib/schema.ts index c77e37fc..6a0fff5c 100644 --- a/packages/database/lib/schema.ts +++ b/packages/database/lib/schema.ts @@ -1000,7 +1000,6 @@ export const v0_4_swaps = pgTable("v0_4_swaps", { export const v0_4_splits = pgTable( "v0_4_splits", { - id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), signature: transaction("signature").notNull().references(() => signatures.signature), @@ -1018,7 +1017,6 @@ export const v0_4_splits = pgTable( ); export const v0_4_merges = pgTable("v0_4_merges", { - id: bigserial("id", { mode: "bigint" }).primaryKey(), vaultAddr: pubkey("vault_addr").notNull().references(() => v0_4_conditional_vaults.conditionalVaultAddr), vaultSeqNum: bigint("vault_seq_num", { mode: "bigint" }), signature: transaction("signature").notNull().references(() => signatures.signature), @@ -1028,6 +1026,7 @@ export const v0_4_merges = pgTable("v0_4_merges", { .notNull() .default(sql`now()`), }, (table) => ({ + pk: primaryKey({ columns: [table.vaultAddr, table.vaultSeqNum]}), vaultIdx: index("merge_vault_index").on(table.vaultAddr), signatureIdx: index("merge_signature_index").on(table.signature), seqNumVaultIdx: index("merge_seq_num_vault_index").on(table.vaultSeqNum, table.vaultAddr), diff --git a/packages/indexer/src/index.ts b/packages/indexer/src/index.ts index de656eff..75d99816 100644 --- a/packages/indexer/src/index.ts +++ b/packages/indexer/src/index.ts @@ -2,10 +2,20 @@ import { startIndexers } from "./v3_indexer/indexers"; import { startIndexerAccountDependencyPopulation } from "./v3_indexer/cli/txw/populate"; import { startTransactionWatchers } from "./v3_indexer/transaction/watcher"; import { subscribeAll } from "./subscriber"; +import { frontfill, backfill } from "./v4_indexer/filler"; // startIndexerAccountDependencyPopulation(); subscribeAll(); -await startTransactionWatchers(); -await startIndexers(); +// await startTransactionWatchers(); +// await startIndexers(); + +// await Promise.all([ +// frontfill() +// ]); + +// await Promise.all([ +// frontfill(), +// backfill(), +// ]); diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index ab7787ae..0ff9ef61 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -27,6 +27,8 @@ async function subscribe(accountPubKey: PublicKey) { try { // wait here because we need to fetch the txn from RPC // and often we get no response if we try right after recieving the logs notification + console.log("Logs received for account", accountPubKey.toString()); + console.log("Logs", logs); await new Promise((resolve) => setTimeout(resolve, 1500)); processLogs(logs, ctx, accountPubKey); //trigger processing of logs } catch (error) { @@ -45,6 +47,7 @@ export async function subscribeAll() { V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID ]; + console.log("Subscribing to logs"); Promise.all(programIds.map(async (programId) => subscribe(programId))); } diff --git a/packages/indexer/src/v3_indexer/indexer.ts b/packages/indexer/src/v3_indexer/indexer.ts index 4e5606d1..2f58c376 100644 --- a/packages/indexer/src/v3_indexer/indexer.ts +++ b/packages/indexer/src/v3_indexer/indexer.ts @@ -10,9 +10,11 @@ export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicK await AmmMarketLogsSubscribeIndexer.index(logs, programId, ctx); } else if (programId.equals(V3_CONDITIONAL_VAULT_PROGRAM_ID)) { //TODO: implement + console.log("Conditional vault logs received"); + console.log(logs); return; } else if (programId.equals(V3_AUTOCRAT_PROGRAM_ID)) { - return; + // return; // Parse logs to find instruction type const instructionLog = logs.logs.find(log => log.includes("Instruction:") && diff --git a/packages/indexer/src/v4_indexer/filler.ts b/packages/indexer/src/v4_indexer/filler.ts index 3c3cc1df..520bd854 100644 --- a/packages/indexer/src/v4_indexer/filler.ts +++ b/packages/indexer/src/v4_indexer/filler.ts @@ -1,6 +1,5 @@ import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js"; -import { V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID, V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; -import { V3_AMM_PROGRAM_ID, V3_AUTOCRAT_PROGRAM_ID, V3_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.3"; +import { AMM_PROGRAM_ID as V4_AMM_PROGRAM_ID, AUTOCRAT_PROGRAM_ID as V4_AUTOCRAT_PROGRAM_ID, CONDITIONAL_VAULT_PROGRAM_ID as V4_CONDITIONAL_VAULT_PROGRAM_ID } from "@metadaoproject/futarchy/v0.4"; import { usingDb, schema, eq, asc, desc } from "@metadaoproject/indexer-db"; import { TelegramBotAPI } from "../adapters/telegram-bot"; import { Logger } from "../logger"; diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index 0e98d8ac..78558f5c 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -18,10 +18,10 @@ type DBConnection = any; // TODO: Fix typing.. const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { const ammEvents: { name: string; data: any }[] = []; const vaultEvents: { name: string; data: any }[] = []; - try { + // try { const inner: CompiledInnerInstruction[] = transactionResponse?.meta?.innerInstructions ?? []; - const ammIdlProgramId = ammClient.programId; + const ammIdlProgramId = ammClient.program.programId; const vaultIdlProgramId = conditionalVaultClient.vaultProgram.programId; for (let i = 0; i < inner.length; i++) { for (let j = 0; j < inner[i].instructions.length; j++) { @@ -36,7 +36,10 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac } // get which program the instruction belongs to - let program: Program; + let program: Program; + console.log("programPubkey", programPubkey.toBase58()); + console.log("ammIdlProgramId", ammIdlProgramId.toBase58()); + console.log("vaultIdlProgramId", vaultIdlProgramId.toBase58()); if (programPubkey.equals(ammIdlProgramId)) { program = ammClient.program; const ixData = anchor.utils.bytes.bs58.decode( @@ -49,6 +52,7 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac ammEvents.push(event); } } else if (programPubkey.equals(vaultIdlProgramId)) { + program = conditionalVaultClient.vaultProgram; const ixData = anchor.utils.bytes.bs58.decode( ix.data ); @@ -63,13 +67,13 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac } } } - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error parsing events: ${error.message}` - : "Unknown error parsing events" - ]); - } + // } catch (error) { + // logger.errorWithChatBotAlert([ + // error instanceof Error + // ? `Error parsing events: ${error.message}` + // : "Unknown error parsing events" + // ]); + // } return { ammEvents, @@ -79,7 +83,7 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac //indexes signature export async function index(signature: string, programId: PublicKey) { - try { + // try { if (!programId.equals(AMM_PROGRAM_ID) && !programId.equals(CONDITIONAL_VAULT_PROGRAM_ID)) { //autocrat program id, we aren't indexing these for now console.log("Unknown program id: ", programId.toBase58()); @@ -106,30 +110,30 @@ export async function index(signature: string, programId: PublicKey) { await usingDb(async (db: DBConnection) => { await db.insert(schema.signatures).values({ - signature: transactionResponse.signature, + signature: transactionResponse.transaction.signatures[0], slot: BigInt(transactionResponse.slot), - didErr: transactionResponse.err !== null, - err: transactionResponse.err ? JSON.stringify(transactionResponse.err) : null, + didErr: transactionResponse.meta?.err !== null, + err: transactionResponse.meta?.err ? JSON.stringify(transactionResponse.meta.err) : null, blockTime: transactionResponse.blockTime ? new Date(transactionResponse.blockTime * 1000) : null, }).onConflictDoNothing().execute(); await db.insert(schema.signature_accounts).values({ - signature: transactionResponse.signature, + signature: transactionResponse.transaction.signatures[0], account: programId.toString() }).onConflictDoNothing().execute(); }); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error processing signature: ${error.message}` - : "Unknown error processing signature" - ]); - } + // } catch (error) { + // logger.errorWithChatBotAlert([ + // error instanceof Error + // ? `Error processing signature: ${error.message}` + // : "Unknown error processing signature" + // ]); + // } } //indexes signature from logs export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { - try { + // try { let signature = logs.signature; if (!signature) { console.log("No signature found in logs"); @@ -139,12 +143,12 @@ export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicK return; } await index(signature, programId); - } catch (error) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error processing signature: ${error.message}` - : "Unknown error processing signature" - ]); - } + // } catch (error) { + // logger.errorWithChatBotAlert([ + // error instanceof Error + // ? `Error processing signature: ${error.message}` + // : "Unknown error processing signature" + // ]); + // } } diff --git a/packages/indexer/src/v4_indexer/processor.ts b/packages/indexer/src/v4_indexer/processor.ts index 70c5a64b..a74ae982 100644 --- a/packages/indexer/src/v4_indexer/processor.ts +++ b/packages/indexer/src/v4_indexer/processor.ts @@ -189,16 +189,36 @@ async function handleSwapEvent(event: SwapEvent, signature: string, transactionR async function handleSplitEvent(event: SplitTokensEvent, signature: string, transactionResponse: VersionedTransactionResponse) { try { + const insertValues = { + vaultAddr: event.vault.toString(), + vaultSeqNum: BigInt(event.seqNum.toString()), + signature: signature, + slot: BigInt(transactionResponse.slot), + amount: BigInt(event.amount.toString()) + // Note: createdAt will be set automatically by the default value + }; + + console.log("Attempting to insert with values:", insertValues); + await usingDb(async (db: DBConnection) => { - await db.insert(schema.v0_4_splits).values({ - vaultAddr: event.vault.toString(), - vaultSeqNum: BigInt(event.seqNum.toString()), - signature: signature, - slot: BigInt(transactionResponse.slot), - amount: BigInt(event.amount.toString()) - }).onConflictDoNothing(); + // First verify the vault exists + const vault = await db.select() + .from(schema.v0_4_conditional_vaults) + .where(eq(schema.v0_4_conditional_vaults.conditionalVaultAddr, event.vault.toString())) + .limit(1); + + if (vault.length === 0) { + console.log("Warning: Referenced vault does not exist:", event.vault.toString()); + } else { + console.log("Vault exists:", event.vault.toString()); + } + + await db.insert(schema.v0_4_splits) + .values(insertValues) + .onConflictDoNothing(); }); } catch (error) { + console.error("Full error details:", error); logger.errorWithChatBotAlert([ error instanceof Error ? `Error in handleSplitEvent: ${error.message}` From f6d6d4f9b0b3006ae9c6b1bb946b4f4921fa3900 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 12 Nov 2024 00:10:36 -0500 Subject: [PATCH 19/29] feat: filler should never have gaps/lapses --- packages/database/lib/schema.ts | 1 + packages/indexer/src/index.ts | 9 +- .../src/v3_indexer/autocrat_program.rs | 111 ------------------ packages/indexer/src/v4_indexer/filler.ts | 88 +++++++++++--- packages/indexer/src/v4_indexer/indexer.ts | 16 +-- packages/indexer/src/v4_indexer/processor.ts | 52 +++----- 6 files changed, 98 insertions(+), 179 deletions(-) delete mode 100644 packages/indexer/src/v3_indexer/autocrat_program.rs diff --git a/packages/database/lib/schema.ts b/packages/database/lib/schema.ts index 6a0fff5c..d568fbdd 100644 --- a/packages/database/lib/schema.ts +++ b/packages/database/lib/schema.ts @@ -386,6 +386,7 @@ export const indexers = pgTable("indexers", { name: varchar("name", { length: 100 }).primaryKey(), implementation: pgEnum("implementation", IndexerImplementation).notNull(), latestSlotProcessed: biggerSlot("latest_slot_processed").notNull(), + latestTxSigProcessed: transaction("latest_tx_sig_processed"), //TODO: unify transactions and signatures table and add reference here indexerType: pgEnum("indexer_type", IndexerType).notNull(), }); diff --git a/packages/indexer/src/index.ts b/packages/indexer/src/index.ts index 75d99816..eb060ed0 100644 --- a/packages/indexer/src/index.ts +++ b/packages/indexer/src/index.ts @@ -11,11 +11,6 @@ subscribeAll(); // await startTransactionWatchers(); // await startIndexers(); -// await Promise.all([ -// frontfill() -// ]); -// await Promise.all([ -// frontfill(), -// backfill(), -// ]); +backfill(); +frontfill(); diff --git a/packages/indexer/src/v3_indexer/autocrat_program.rs b/packages/indexer/src/v3_indexer/autocrat_program.rs deleted file mode 100644 index 49149df9..00000000 --- a/packages/indexer/src/v3_indexer/autocrat_program.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! The orchestrator of a futarchy. Equivalent to the 'governor' of Compound's -//! governance system. -//! -//! Autocrat has two types of accounts: DAOs and proposals. Every DAO has its -//! own token, its own treasury account, and list of configs. Proposals are -//! created for a specific DAO, and contain an SVM instruction and a URL that -//! should point to a description and justification of that instruction. -//! -//! Proposals pass through various states in their lifecycle. Here's a description -//! of these states: -//! - Pre-creation: this is when you initialize the accounts needed for a proposal, -//! including the vaults and the AMM accounts. The proposer will also deposit to -//! create their LP during this time. -//! - Trading: to create a proposal, the proposer must call -//! `initialize_proposal`, which requires them to lock up some LP tokens in each -//! of the markets. Once a proposal is created, anyone can trade its markets. -//! Prices of these markets are aggregated into a time-weighted average price -//! oracle. -//! - Pass or fail: if the TWAP of the pass market is sufficiently higher than the -//! TWAP of the fail market, the proposal will pass. If it's not, the proposal will -//! fail. If it passes, both vaults will be finalized, allowing pTOKEN holders to -//! redeem. If it fails, both vaults will be reverted, allowing fTOKEN holders to -//! redeem. -//! - Executed: if a proposal passes, anyone can make autocrat execute its SVM -//! instruction by calling `execute_proposal`. -use anchor_lang::prelude::*; -use anchor_lang::solana_program; -use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; -// use conditional_vault::cpi::accounts::SettleConditionalVault; -use conditional_vault::program::ConditionalVault as ConditionalVaultProgram; -use conditional_vault::ConditionalVault as ConditionalVaultAccount; -use conditional_vault::Question; -// use conditional_vault::VaultStatus; - -pub mod error; -pub mod instructions; -pub mod state; - -pub use crate::error::AutocratError; -pub use crate::instructions::*; -pub use crate::state::*; - -use amm::state::Amm; - -use solana_program::instruction::Instruction; -#[cfg(not(feature = "no-entrypoint"))] -use solana_security_txt::security_txt; -use std::borrow::Borrow; - -#[cfg(not(feature = "no-entrypoint"))] -security_txt! { - name: "autocrat", - project_url: "https://metadao.fi", - contacts: "email:metaproph3t@protonmail.com", - policy: "The market will decide whether we pay a bug bounty.", - source_code: "https://github.com/metaDAOproject/futarchy", - source_release: "v0.4", - auditors: "Neodyme", - acknowledgements: "DCF = (CF1 / (1 + r)^1) + (CF2 / (1 + r)^2) + ... (CFn / (1 + r)^n)" -} - -declare_id!("autowMzCbM29YXMgVG3T62Hkgo7RcyrvgQQkd54fDQL"); - -pub const SLOTS_PER_10_SECS: u64 = 25; -pub const THREE_DAYS_IN_SLOTS: u64 = 3 * 24 * 60 * 6 * SLOTS_PER_10_SECS; - -pub const TEN_DAYS_IN_SECONDS: i64 = 10 * 24 * 60 * 60; - -// by default, the pass price needs to be 3% higher than the fail price -pub const DEFAULT_PASS_THRESHOLD_BPS: u16 = 300; - -pub const MAX_BPS: u16 = 10_000; - -// the index of the fail and pass outcomes in the question and the index of -// the pass and fail conditional tokens in the conditional vault -pub const FAIL_INDEX: usize = 0; -pub const PASS_INDEX: usize = 1; - -// TWAP can only move by $5 per slot -pub const DEFAULT_MAX_OBSERVATION_CHANGE_PER_UPDATE_LOTS: u64 = 5_000; - -#[program] -pub mod autocrat { - use super::*; - - pub fn initialize_dao(ctx: Context, params: InitializeDaoParams) -> Result<()> { - InitializeDAO::handle(ctx, params) - } - - #[access_control(ctx.accounts.validate())] - pub fn initialize_proposal( - ctx: Context, - params: InitializeProposalParams, - ) -> Result<()> { - InitializeProposal::handle(ctx, params) - } - - #[access_control(ctx.accounts.validate())] - pub fn finalize_proposal(ctx: Context) -> Result<()> { - FinalizeProposal::handle(ctx) - } - - #[access_control(ctx.accounts.validate())] - pub fn execute_proposal(ctx: Context) -> Result<()> { - ExecuteProposal::handle(ctx) - } - - pub fn update_dao(ctx: Context, dao_params: UpdateDaoParams) -> Result<()> { - UpdateDao::handle(ctx, dao_params) - } -} \ No newline at end of file diff --git a/packages/indexer/src/v4_indexer/filler.ts b/packages/indexer/src/v4_indexer/filler.ts index 520bd854..5af92738 100644 --- a/packages/indexer/src/v4_indexer/filler.ts +++ b/packages/indexer/src/v4_indexer/filler.ts @@ -64,23 +64,25 @@ const backfillHistoricalSignatures = async ( const insertNewSignatures = async (programId: PublicKey) => { let allSignatures: ConfirmedSignatureInfo[] = []; - let latestRecordedSignature = await usingDb(async (db) => { - return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) - .from(schema.signatures) - .orderBy(desc(schema.signatures.slot)) - .limit(100) - .then(signatures => { - if (signatures.length === 0) return undefined; - - const latestSlot = signatures[0].slot; - for (let i = 1; i < signatures.length; i++) { - if (signatures[i].slot < latestSlot) { - return signatures[i].signature; - } - } - return signatures[signatures.length - 1].signature; - }); - }); + //get latest signature from db indexers table latestTxSigProcessed + let latestRecordedSignature = await getLatestTxSigProcessed(); + + //TODO: this should never happen in theory so im commenting it out for now + // if (!latestRecordedSignature) { + // //fallback just in case + // latestRecordedSignature = await usingDb(async (db) => { + // return await db.select({ signature: schema.signatures.signature, slot: schema.signatures.slot }) + // .from(schema.signatures) + // .orderBy(desc(schema.signatures.slot)) + // .limit(1) + // .then(signatures => { + // if (signatures.length === 0) return undefined; + // return signatures[0].signature; + // }); + // }); + // } + + console.log(`insertNewSignatures::latestRecordedSignature: ${latestRecordedSignature}`); let oldestSignatureInserted: string | undefined; while (true) { @@ -95,11 +97,13 @@ const insertNewSignatures = async (programId: PublicKey) => { await insertSignatures(signatures, programId); //trigger indexing + //TODO: maybe only index if signature doesnt exist in signatures table (which would mean it wasnt indexed yet) Promise.all(signatures.map(async (signature: ConfirmedSignatureInfo) => { await index(signature.signature, programId); })); allSignatures = allSignatures.concat(signatures); + if (!oldestSignatureInserted) setLatestTxSigProcessed(signatures[0].signature); //since getSignaturesForAddress is a backwards walk, this should be the latest signature oldestSignatureInserted = signatures[signatures.length - 1].signature; } @@ -110,7 +114,7 @@ const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAdd await usingDb(async (db) => { await db.insert(schema.signatures).values(signatures.map(tx => ({ signature: tx.signature, - slot: BigInt(tx.slot), + slot: tx.slot.toString(), didErr: tx.err !== null, err: tx.err ? JSON.stringify(tx.err) : null, blockTime: tx.blockTime ? new Date(tx.blockTime * 1000) : null, @@ -122,6 +126,52 @@ const insertSignatures = async (signatures: ConfirmedSignatureInfo[], queriedAdd }); } +//set latestProcessedSlot in db +async function setLatestProcessedSlot(slot: number) { + try { + await usingDb(async (db) => { + await db.update(schema.indexers) + .set({ latestSlotProcessed: slot.toString() }) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .execute(); + }); + } catch (error: unknown) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error setting latest processed slot: ${error.message}` + : "Unknown error setting latest processed slot" + ]); + } +} + +//get latestProcessedSlot from db +async function getLatestProcessedSlot() { + return await usingDb(async (db) => { + return await db.select({ slot: schema.indexers.latestSlotProcessed }) + .from(schema.indexers) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .then(slots => slots[0] ? slots[0].slot : undefined); + }); +} + +//set latestTxSigProcessed +async function setLatestTxSigProcessed(signature: string) { + await usingDb(async (db) => { + await db.update(schema.indexers).set({ latestTxSigProcessed: signature }).where(eq(schema.indexers.name, "v0_4_amm_indexer")).execute(); + }); +} + +//get latestTxSigProcessed +async function getLatestTxSigProcessed() { + return await usingDb(async (db) => { + return await db.select({ signature: schema.indexers.latestTxSigProcessed }) + .from(schema.indexers) + .where(eq(schema.indexers.name, "v0_4_amm_indexer")) + .then(signatures => signatures[0] ? signatures[0].signature as string : undefined); + }); +} + + const programIds = [V4_CONDITIONAL_VAULT_PROGRAM_ID, V4_AMM_PROGRAM_ID, V4_AUTOCRAT_PROGRAM_ID]; export const backfill = async () => { @@ -145,7 +195,7 @@ export const frontfill = async () => { setInterval(async () => { const newSignatures = await insertNewSignatures(programId); console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); - }, 30000); //every 30s + }, 3000); //every 3s } catch (error) { logger.errorWithChatBotAlert([ error instanceof Error ? diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index 78558f5c..d5487a32 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -133,7 +133,7 @@ export async function index(signature: string, programId: PublicKey) { //indexes signature from logs export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicKey) { - // try { + try { let signature = logs.signature; if (!signature) { console.log("No signature found in logs"); @@ -143,12 +143,12 @@ export async function indexFromLogs(logs: Logs, ctx: Context, programId: PublicK return; } await index(signature, programId); - // } catch (error) { - // logger.errorWithChatBotAlert([ - // error instanceof Error - // ? `Error processing signature: ${error.message}` - // : "Unknown error processing signature" - // ]); - // } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error processing signature: ${error.message}` + : "Unknown error processing signature" + ]); + } } diff --git a/packages/indexer/src/v4_indexer/processor.ts b/packages/indexer/src/v4_indexer/processor.ts index a74ae982..807f1edf 100644 --- a/packages/indexer/src/v4_indexer/processor.ts +++ b/packages/indexer/src/v4_indexer/processor.ts @@ -165,6 +165,8 @@ async function handleSwapEvent(event: SwapEvent, signature: string, transactionR return; } + console.log("latestAmmSeqNumApplied", amm[0].latestAmmSeqNumApplied.toString()); + console.log("event.common.seqNum", event.common.seqNum.toString()); if (amm[0].latestAmmSeqNumApplied >= BigInt(event.common.seqNum.toString())) { console.log("Already applied", event.common.seqNum.toString()); return; @@ -388,7 +390,7 @@ async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: Ad .from(schema.prices) .where(and( eq(schema.prices.marketAcct, event.common.amm.toBase58()), - eq(schema.prices.updatedSlot, BigInt(event.common.slot.toString())) + eq(schema.prices.updatedSlot, event.common.slot.toString()) )) .limit(1); @@ -436,36 +438,18 @@ async function insertConditionalVault(db: DBConnection, event: InitializeConditi } -async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { - try { - return await connection.getTransactions( - eligibleSignatures.map(s => s.signature), - { commitment: "confirmed", maxSupportedTransactionVersion: 1 } - ); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error fetching transaction responses: ${error.message}` - : "Unknown error fetching transaction responses" - ]); - return []; - } -} - -//set latestProcessedSlot in db -async function setLatestProcessedSlot(slot: number) { - try { - await usingDb(async (db) => { - await db.update(schema.indexers) - .set({ latestSlotProcessed: BigInt(slot) }) - .where(eq(schema.indexers.name, "v0_4_amm_indexer")) - .execute(); - }); - } catch (error: unknown) { - logger.errorWithChatBotAlert([ - error instanceof Error - ? `Error setting latest processed slot: ${error.message}` - : "Unknown error setting latest processed slot" - ]); - } -} \ No newline at end of file +// async function fetchTransactionResponses(eligibleSignatures: { signature: string }[]) { +// try { +// return await connection.getTransactions( +// eligibleSignatures.map(s => s.signature), +// { commitment: "confirmed", maxSupportedTransactionVersion: 1 } +// ); +// } catch (error: unknown) { +// logger.errorWithChatBotAlert([ +// error instanceof Error +// ? `Error fetching transaction responses: ${error.message}` +// : "Unknown error fetching transaction responses" +// ]); +// return []; +// } +// } From aad984573fe22b0562ce3aa9a17aaf83fb96edf1 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 12 Nov 2024 11:59:27 -0500 Subject: [PATCH 20/29] feat: db migration wip --- .../database/drizzle/0009_brainy_karma.sql | 59 + .../database/drizzle/meta/0009_snapshot.json | 4036 +++++++++++++++++ packages/database/drizzle/meta/_journal.json | 7 + packages/database/lib/schema.ts | 2 +- 4 files changed, 4103 insertions(+), 1 deletion(-) create mode 100644 packages/database/drizzle/0009_brainy_karma.sql create mode 100644 packages/database/drizzle/meta/0009_snapshot.json diff --git a/packages/database/drizzle/0009_brainy_karma.sql b/packages/database/drizzle/0009_brainy_karma.sql new file mode 100644 index 00000000..dfe2e8ef --- /dev/null +++ b/packages/database/drizzle/0009_brainy_karma.sql @@ -0,0 +1,59 @@ +ALTER TABLE "indexers" ADD COLUMN "latest_tx_sig_processed" varchar(88);--> statement-breakpoint +ALTER TABLE "v0_4_merges" DROP COLUMN IF EXISTS "id";--> statement-breakpoint +ALTER TABLE "v0_4_splits" DROP COLUMN IF EXISTS "id";--> statement-breakpoint +CREATE VIEW "public"."prices_chart_data" AS ( + SELECT + TIME_BUCKET('30 SECONDS'::INTERVAL, prices.created_at) AS interv, + last(price, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS price, + last(base_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS base_amount, + last(quote_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS quote_amount, + prices_type, + prices.market_acct AS market_acct + FROM prices + JOIN markets ON markets.market_acct = prices.market_acct + WHERE CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END + GROUP BY interv, prices.market_acct, prices_type + );--> statement-breakpoint +CREATE VIEW "public"."proposal_total_trade_volume" AS ( + WITH pass_market AS ( + SELECT + proposal_acct, + orders.market_acct AS pass_market_acct, + TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, + SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS pass_volume + FROM proposals + JOIN orders + ON proposals.pass_market_acct = orders.market_acct + GROUP BY proposal_acct, interv, orders.market_acct + ), + fail_market AS ( + SELECT + proposal_acct, + orders.market_acct AS fail_market_acct, + TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, + SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS fail_volume + FROM proposals + JOIN orders + ON proposals.fail_market_acct = orders.market_acct + GROUP BY proposal_acct, interv, orders.market_acct + ) + SELECT + pass_market.proposal_acct AS proposal_acct, + pass_market_acct, + fail_market_acct, + SUM(pass_volume) AS pass_volume, + SUM(fail_volume) AS fail_volume + FROM pass_market + JOIN fail_market ON fail_market.proposal_acct = pass_market.proposal_acct + GROUP BY pass_market.proposal_acct, pass_market_acct, fail_market_acct + );--> statement-breakpoint +CREATE VIEW "public"."twap_chart_data" AS ( + SELECT + TIME_BUCKET('30 SECONDS'::INTERVAL, "twaps"."created_at") AS interv, + last(token_amount, "twaps"."created_at") FILTER(WHERE "twaps"."created_at" IS NOT NULL AND "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL) AS token_amount, + "twaps"."market_acct" AS market_acct + FROM "twaps" + JOIN "markets" ON "markets"."market_acct" = "twaps"."market_acct" + WHERE "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL + GROUP BY interv, "twaps"."market_acct" + ); \ No newline at end of file diff --git a/packages/database/drizzle/meta/0009_snapshot.json b/packages/database/drizzle/meta/0009_snapshot.json new file mode 100644 index 00000000..b0540cb5 --- /dev/null +++ b/packages/database/drizzle/meta/0009_snapshot.json @@ -0,0 +1,4036 @@ +{ + "id": "65af4022-ecf9-46c1-9bae-811755bf4197", + "prevId": "46750075-91a4-4e4d-b00a-3f3ab69abf22", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.candles": { + "name": "candles", + "schema": "", + "columns": { + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "candle_duration": { + "name": "candle_duration", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "volume": { + "name": "volume", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "open": { + "name": "open", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "high": { + "name": "high", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "low": { + "name": "low", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "close": { + "name": "close", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "candle_average": { + "name": "candle_average", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "cond_market_twap": { + "name": "cond_market_twap", + "type": "numeric", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "candles_market_acct_markets_market_acct_fk": { + "name": "candles_market_acct_markets_market_acct_fk", + "tableFrom": "candles", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "candles_market_acct_candle_duration_timestamp_pk": { + "name": "candles_market_acct_candle_duration_timestamp_pk", + "columns": [ + "market_acct", + "candle_duration", + "timestamp" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "comment_id": { + "name": "comment_id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "commentor_acct": { + "name": "commentor_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "responding_comment_id": { + "name": "responding_comment_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_proposal_acct_proposals_proposal_acct_fk": { + "name": "comments_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "comments", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_responding_comment_id_comments_comment_id_fk": { + "name": "comments_responding_comment_id_comments_comment_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "responding_comment_id" + ], + "columnsTo": [ + "comment_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "comments_comment_id_unique": { + "name": "comments_comment_id_unique", + "nullsNotDistinct": false, + "columns": [ + "comment_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conditional_vaults": { + "name": "conditional_vaults", + "schema": "", + "columns": { + "cond_vault_acct": { + "name": "cond_vault_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "settlement_authority": { + "name": "settlement_authority", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "underlying_mint_acct": { + "name": "underlying_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "underlying_token_acct": { + "name": "underlying_token_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "nonce": { + "name": "nonce", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "cond_finalize_token_mint_acct": { + "name": "cond_finalize_token_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "cond_revert_token_mint_acct": { + "name": "cond_revert_token_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { + "name": "conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", + "tableFrom": "conditional_vaults", + "tableTo": "tokens", + "columnsFrom": [ + "underlying_mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dao_details": { + "name": "dao_details", + "schema": "", + "columns": { + "dao_id": { + "name": "dao_id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "x_account": { + "name": "x_account", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "github": { + "name": "github", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "creator_acct": { + "name": "creator_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "admin_accts": { + "name": "admin_accts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "token_image_url": { + "name": "token_image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "pass_token_image_url": { + "name": "pass_token_image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fail_token_image_url": { + "name": "fail_token_image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "lp_token_image_url": { + "name": "lp_token_image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "is_hide": { + "name": "is_hide", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "socials": { + "name": "socials", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "dao_details_name_unique": { + "name": "dao_details_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + }, + "dao_details_slug_unique": { + "name": "dao_details_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + }, + "dao_details_url_unique": { + "name": "dao_details_url_unique", + "nullsNotDistinct": false, + "columns": [ + "url" + ] + }, + "dao_details_x_account_unique": { + "name": "dao_details_x_account_unique", + "nullsNotDistinct": false, + "columns": [ + "x_account" + ] + }, + "dao_details_github_unique": { + "name": "dao_details_github_unique", + "nullsNotDistinct": false, + "columns": [ + "github" + ] + }, + "id_name_url": { + "name": "id_name_url", + "nullsNotDistinct": false, + "columns": [ + "dao_id", + "url", + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.daos": { + "name": "daos", + "schema": "", + "columns": { + "dao_acct": { + "name": "dao_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "program_acct": { + "name": "program_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "dao_id": { + "name": "dao_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "base_acct": { + "name": "base_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "quote_acct": { + "name": "quote_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "treasury_acct": { + "name": "treasury_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "slots_per_proposal": { + "name": "slots_per_proposal", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "pass_threshold_bps": { + "name": "pass_threshold_bps", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "twap_initial_observation": { + "name": "twap_initial_observation", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "twap_max_observation_change_per_update": { + "name": "twap_max_observation_change_per_update", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "min_quote_futarchic_liquidity": { + "name": "min_quote_futarchic_liquidity", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "min_base_futarchic_liquidity": { + "name": "min_base_futarchic_liquidity", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "daos_program_acct_programs_program_acct_fk": { + "name": "daos_program_acct_programs_program_acct_fk", + "tableFrom": "daos", + "tableTo": "programs", + "columnsFrom": [ + "program_acct" + ], + "columnsTo": [ + "program_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "daos_dao_id_dao_details_dao_id_fk": { + "name": "daos_dao_id_dao_details_dao_id_fk", + "tableFrom": "daos", + "tableTo": "dao_details", + "columnsFrom": [ + "dao_id" + ], + "columnsTo": [ + "dao_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "daos_base_acct_tokens_mint_acct_fk": { + "name": "daos_base_acct_tokens_mint_acct_fk", + "tableFrom": "daos", + "tableTo": "tokens", + "columnsFrom": [ + "base_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "daos_quote_acct_tokens_mint_acct_fk": { + "name": "daos_quote_acct_tokens_mint_acct_fk", + "tableFrom": "daos", + "tableTo": "tokens", + "columnsFrom": [ + "quote_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "daos_treasury_acct_unique": { + "name": "daos_treasury_acct_unique", + "nullsNotDistinct": false, + "columns": [ + "treasury_acct" + ] + }, + "dao_acct_program": { + "name": "dao_acct_program", + "nullsNotDistinct": false, + "columns": [ + "dao_acct", + "program_acct" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.indexer_account_dependencies": { + "name": "indexer_account_dependencies", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "acct": { + "name": "acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "latest_tx_sig_processed": { + "name": "latest_tx_sig_processed", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'active'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "indexer_account_dependencies_name_indexers_name_fk": { + "name": "indexer_account_dependencies_name_indexers_name_fk", + "tableFrom": "indexer_account_dependencies", + "tableTo": "indexers", + "columnsFrom": [ + "name" + ], + "columnsTo": [ + "name" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk": { + "name": "indexer_account_dependencies_latest_tx_sig_processed_transactions_tx_sig_fk", + "tableFrom": "indexer_account_dependencies", + "tableTo": "transactions", + "columnsFrom": [ + "latest_tx_sig_processed" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "indexer_account_dependencies_name_acct_pk": { + "name": "indexer_account_dependencies_name_acct_pk", + "columns": [ + "name", + "acct" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.indexers": { + "name": "indexers", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": true, + "notNull": true + }, + "implementation": { + "name": "implementation", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "latest_slot_processed": { + "name": "latest_slot_processed", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "latest_tx_sig_processed": { + "name": "latest_tx_sig_processed", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "indexer_type": { + "name": "indexer_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.makes": { + "name": "makes", + "schema": "", + "columns": { + "order_tx_sig": { + "name": "order_tx_sig", + "type": "varchar(88)", + "primaryKey": true, + "notNull": true + }, + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "unfilled_base_amount": { + "name": "unfilled_base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "filled_base_amount": { + "name": "filled_base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "quote_price": { + "name": "quote_price", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "market_index": { + "name": "market_index", + "columns": [ + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "makes_order_tx_sig_orders_order_tx_sig_fk": { + "name": "makes_order_tx_sig_orders_order_tx_sig_fk", + "tableFrom": "makes", + "tableTo": "orders", + "columnsFrom": [ + "order_tx_sig" + ], + "columnsTo": [ + "order_tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "makes_market_acct_markets_market_acct_fk": { + "name": "makes_market_acct_markets_market_acct_fk", + "tableFrom": "makes", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.markets": { + "name": "markets", + "schema": "", + "columns": { + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "market_type": { + "name": "market_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "create_tx_sig": { + "name": "create_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "base_mint_acct": { + "name": "base_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "quote_mint_acct": { + "name": "quote_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "base_lot_size": { + "name": "base_lot_size", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "quote_lot_size": { + "name": "quote_lot_size", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "quote_tick_size": { + "name": "quote_tick_size", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "bids_token_acct": { + "name": "bids_token_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "asks_token_acct": { + "name": "asks_token_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "base_maker_fee": { + "name": "base_maker_fee", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "base_taker_fee": { + "name": "base_taker_fee", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "quote_maker_fee": { + "name": "quote_maker_fee", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "quote_taker_fee": { + "name": "quote_taker_fee", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "active_slot": { + "name": "active_slot", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "inactive_slot": { + "name": "inactive_slot", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "markets_proposal_acct_proposals_proposal_acct_fk": { + "name": "markets_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "markets", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "markets_base_mint_acct_tokens_mint_acct_fk": { + "name": "markets_base_mint_acct_tokens_mint_acct_fk", + "tableFrom": "markets", + "tableTo": "tokens", + "columnsFrom": [ + "base_mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "markets_quote_mint_acct_tokens_mint_acct_fk": { + "name": "markets_quote_mint_acct_tokens_mint_acct_fk", + "tableFrom": "markets", + "tableTo": "tokens", + "columnsFrom": [ + "quote_mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "markets_bids_token_acct_token_accts_token_acct_fk": { + "name": "markets_bids_token_acct_token_accts_token_acct_fk", + "tableFrom": "markets", + "tableTo": "token_accts", + "columnsFrom": [ + "bids_token_acct" + ], + "columnsTo": [ + "token_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "markets_asks_token_acct_token_accts_token_acct_fk": { + "name": "markets_asks_token_acct_token_accts_token_acct_fk", + "tableFrom": "markets", + "tableTo": "token_accts", + "columnsFrom": [ + "asks_token_acct" + ], + "columnsTo": [ + "token_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.orders": { + "name": "orders", + "schema": "", + "columns": { + "order_tx_sig": { + "name": "order_tx_sig", + "type": "varchar(88)", + "primaryKey": true, + "notNull": true + }, + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "actor_acct": { + "name": "actor_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "side": { + "name": "side", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "unfilled_base_amount": { + "name": "unfilled_base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "filled_base_amount": { + "name": "filled_base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "quote_price": { + "name": "quote_price", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "order_block": { + "name": "order_block", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "order_time": { + "name": "order_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "cancel_tx_sig": { + "name": "cancel_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "cancel_block": { + "name": "cancel_block", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "cancel_time": { + "name": "cancel_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "actor_index": { + "name": "actor_index", + "columns": [ + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "orders_order_tx_sig_transactions_tx_sig_fk": { + "name": "orders_order_tx_sig_transactions_tx_sig_fk", + "tableFrom": "orders", + "tableTo": "transactions", + "columnsFrom": [ + "order_tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "orders_market_acct_markets_market_acct_fk": { + "name": "orders_market_acct_markets_market_acct_fk", + "tableFrom": "orders", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "orders_actor_acct_users_user_acct_fk": { + "name": "orders_actor_acct_users_user_acct_fk", + "tableFrom": "orders", + "tableTo": "users", + "columnsFrom": [ + "actor_acct" + ], + "columnsTo": [ + "user_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.prices": { + "name": "prices", + "schema": "", + "columns": { + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "updated_slot": { + "name": "updated_slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "base_amount": { + "name": "base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "quote_amount": { + "name": "quote_amount", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "price": { + "name": "price", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prices_type": { + "name": "prices_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "prices_market_acct_markets_market_acct_fk": { + "name": "prices_market_acct_markets_market_acct_fk", + "tableFrom": "prices", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "prices_created_at_market_acct_pk": { + "name": "prices_created_at_market_acct_pk", + "columns": [ + "created_at", + "market_acct" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.program_system": { + "name": "program_system", + "schema": "", + "columns": { + "system_version": { + "name": "system_version", + "type": "double precision", + "primaryKey": true, + "notNull": true + }, + "autocrat_acct": { + "name": "autocrat_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "conditional_vault_acct": { + "name": "conditional_vault_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "pricing_model_acct": { + "name": "pricing_model_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "migrator_acct": { + "name": "migrator_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "program_system_autocrat_acct_programs_program_acct_fk": { + "name": "program_system_autocrat_acct_programs_program_acct_fk", + "tableFrom": "program_system", + "tableTo": "programs", + "columnsFrom": [ + "autocrat_acct" + ], + "columnsTo": [ + "program_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "program_system_conditional_vault_acct_programs_program_acct_fk": { + "name": "program_system_conditional_vault_acct_programs_program_acct_fk", + "tableFrom": "program_system", + "tableTo": "programs", + "columnsFrom": [ + "conditional_vault_acct" + ], + "columnsTo": [ + "program_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "program_system_pricing_model_acct_programs_program_acct_fk": { + "name": "program_system_pricing_model_acct_programs_program_acct_fk", + "tableFrom": "program_system", + "tableTo": "programs", + "columnsFrom": [ + "pricing_model_acct" + ], + "columnsTo": [ + "program_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "program_system_migrator_acct_programs_program_acct_fk": { + "name": "program_system_migrator_acct_programs_program_acct_fk", + "tableFrom": "program_system", + "tableTo": "programs", + "columnsFrom": [ + "migrator_acct" + ], + "columnsTo": [ + "program_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.programs": { + "name": "programs", + "schema": "", + "columns": { + "program_acct": { + "name": "program_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "version": { + "name": "version", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "program_name": { + "name": "program_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "program_version": { + "name": "program_version", + "nullsNotDistinct": false, + "columns": [ + "program_acct", + "version" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.proposal_details": { + "name": "proposal_details", + "schema": "", + "columns": { + "proposal_id": { + "name": "proposal_id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "proposer_acct": { + "name": "proposer_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "base_cond_vault_acct": { + "name": "base_cond_vault_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "quote_cond_vault_acct": { + "name": "quote_cond_vault_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "pass_market_acct": { + "name": "pass_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "fail_market_acct": { + "name": "fail_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "proposal_details_proposal_acct_proposals_proposal_acct_fk": { + "name": "proposal_details_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "proposal_details", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "proposal_details_slug_unique": { + "name": "proposal_details_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.proposals": { + "name": "proposals", + "schema": "", + "columns": { + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "dao_acct": { + "name": "dao_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "proposal_num": { + "name": "proposal_num", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "autocrat_version": { + "name": "autocrat_version", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "proposer_acct": { + "name": "proposer_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "initial_slot": { + "name": "initial_slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "end_slot": { + "name": "end_slot", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description_url": { + "name": "description_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "pricing_model_pass_acct": { + "name": "pricing_model_pass_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "pricing_model_fail_acct": { + "name": "pricing_model_fail_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "pass_market_acct": { + "name": "pass_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "fail_market_acct": { + "name": "fail_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "base_vault": { + "name": "base_vault", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "quote_vault": { + "name": "quote_vault", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "duration_in_slots": { + "name": "duration_in_slots", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "pass_threshold_bps": { + "name": "pass_threshold_bps", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "twap_initial_observation": { + "name": "twap_initial_observation", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "twap_max_observation_change_per_update": { + "name": "twap_max_observation_change_per_update", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "min_quote_futarchic_liquidity": { + "name": "min_quote_futarchic_liquidity", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "min_base_futarchic_liquidity": { + "name": "min_base_futarchic_liquidity", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "proposals_dao_acct_daos_dao_acct_fk": { + "name": "proposals_dao_acct_daos_dao_acct_fk", + "tableFrom": "proposals", + "tableTo": "daos", + "columnsFrom": [ + "dao_acct" + ], + "columnsTo": [ + "dao_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "proposals_base_vault_conditional_vaults_cond_vault_acct_fk": { + "name": "proposals_base_vault_conditional_vaults_cond_vault_acct_fk", + "tableFrom": "proposals", + "tableTo": "conditional_vaults", + "columnsFrom": [ + "base_vault" + ], + "columnsTo": [ + "cond_vault_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk": { + "name": "proposals_quote_vault_conditional_vaults_cond_vault_acct_fk", + "tableFrom": "proposals", + "tableTo": "conditional_vaults", + "columnsFrom": [ + "quote_vault" + ], + "columnsTo": [ + "cond_vault_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reactions": { + "name": "reactions", + "schema": "", + "columns": { + "reaction_id": { + "name": "reaction_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "reactor_acct": { + "name": "reactor_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "comment_id": { + "name": "comment_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "reaction": { + "name": "reaction", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "reactions_comment_id_comments_comment_id_fk": { + "name": "reactions_comment_id_comments_comment_id_fk", + "tableFrom": "reactions", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "comment_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "reactions_proposal_acct_proposals_proposal_acct_fk": { + "name": "reactions_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "reactions", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_acct": { + "name": "user_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_acct_users_user_acct_fk": { + "name": "sessions_user_acct_users_user_acct_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_acct" + ], + "columnsTo": [ + "user_acct" + ], + "onDelete": "restrict", + "onUpdate": "restrict" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.signature_accounts": { + "name": "signature_accounts", + "schema": "", + "columns": { + "signature": { + "name": "signature", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "account": { + "name": "account", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "inserted_at": { + "name": "inserted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "account_index": { + "name": "account_index", + "columns": [ + { + "expression": "account", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "signature_accounts_signature_account_pk": { + "name": "signature_accounts_signature_account_pk", + "columns": [ + "signature", + "account" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.signatures": { + "name": "signatures", + "schema": "", + "columns": { + "signature": { + "name": "signature", + "type": "varchar(88)", + "primaryKey": true, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "did_err": { + "name": "did_err", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "err": { + "name": "err", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_time": { + "name": "block_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "inserted_at": { + "name": "inserted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "seq_num": { + "name": "seq_num", + "type": "bigserial", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "slot_index": { + "name": "slot_index", + "columns": [ + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sequence_num_index": { + "name": "sequence_num_index", + "columns": [ + { + "expression": "seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "signatures_seq_num_unique": { + "name": "signatures_seq_num_unique", + "nullsNotDistinct": false, + "columns": [ + "seq_num" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.takes": { + "name": "takes", + "schema": "", + "columns": { + "take_id": { + "name": "take_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "order_tx_sig": { + "name": "order_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "base_amount": { + "name": "base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "quote_price": { + "name": "quote_price", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "taker_base_fee": { + "name": "taker_base_fee", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "taker_quote_fee": { + "name": "taker_quote_fee", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "maker_order_tx_sig": { + "name": "maker_order_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "maker_base_fee": { + "name": "maker_base_fee", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "maker_quote_fee": { + "name": "maker_quote_fee", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "order_block": { + "name": "order_block", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "order_time": { + "name": "order_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "block_index": { + "name": "block_index", + "columns": [ + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_block", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "time_index": { + "name": "time_index", + "columns": [ + { + "expression": "market_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "maker_index": { + "name": "maker_index", + "columns": [ + { + "expression": "maker_order_tx_sig", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "takes_order_tx_sig_orders_order_tx_sig_fk": { + "name": "takes_order_tx_sig_orders_order_tx_sig_fk", + "tableFrom": "takes", + "tableTo": "orders", + "columnsFrom": [ + "order_tx_sig" + ], + "columnsTo": [ + "order_tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "takes_maker_order_tx_sig_makes_order_tx_sig_fk": { + "name": "takes_maker_order_tx_sig_makes_order_tx_sig_fk", + "tableFrom": "takes", + "tableTo": "makes", + "columnsFrom": [ + "maker_order_tx_sig" + ], + "columnsTo": [ + "order_tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "takes_market_acct_markets_market_acct_fk": { + "name": "takes_market_acct_markets_market_acct_fk", + "tableFrom": "takes", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.token_acct_balances": { + "name": "token_acct_balances", + "schema": "", + "columns": { + "token_acct": { + "name": "token_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "mint_acct": { + "name": "mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "owner_acct": { + "name": "owner_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "delta": { + "name": "delta", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "0" + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "tx_sig": { + "name": "tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "acct_amount_created": { + "name": "acct_amount_created", + "columns": [ + { + "expression": "token_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amount", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "token_acct_balances_token_acct_token_accts_token_acct_fk": { + "name": "token_acct_balances_token_acct_token_accts_token_acct_fk", + "tableFrom": "token_acct_balances", + "tableTo": "token_accts", + "columnsFrom": [ + "token_acct" + ], + "columnsTo": [ + "token_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "token_acct_balances_mint_acct_tokens_mint_acct_fk": { + "name": "token_acct_balances_mint_acct_tokens_mint_acct_fk", + "tableFrom": "token_acct_balances", + "tableTo": "tokens", + "columnsFrom": [ + "mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "token_acct_balances_tx_sig_transactions_tx_sig_fk": { + "name": "token_acct_balances_tx_sig_transactions_tx_sig_fk", + "tableFrom": "token_acct_balances", + "tableTo": "transactions", + "columnsFrom": [ + "tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "token_acct_balances_token_acct_mint_acct_amount_created_at_pk": { + "name": "token_acct_balances_token_acct_mint_acct_amount_created_at_pk", + "columns": [ + "token_acct", + "mint_acct", + "amount", + "created_at" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.token_accts": { + "name": "token_accts", + "schema": "", + "columns": { + "amount": { + "name": "amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "mint_acct": { + "name": "mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "owner_acct": { + "name": "owner_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'enabled'" + }, + "token_acct": { + "name": "token_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "token_accts_mint_acct_tokens_mint_acct_fk": { + "name": "token_accts_mint_acct_tokens_mint_acct_fk", + "tableFrom": "token_accts", + "tableTo": "tokens", + "columnsFrom": [ + "mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tokens": { + "name": "tokens", + "schema": "", + "columns": { + "mint_acct": { + "name": "mint_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true + }, + "symbol": { + "name": "symbol", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "supply": { + "name": "supply", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "decimals": { + "name": "decimals", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transaction_watcher_transactions": { + "name": "transaction_watcher_transactions", + "schema": "", + "columns": { + "watcher_acct": { + "name": "watcher_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "tx_sig": { + "name": "tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "watcher_slot_index": { + "name": "watcher_slot_index", + "columns": [ + { + "expression": "watcher_acct", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk": { + "name": "transaction_watcher_transactions_watcher_acct_transaction_watchers_acct_fk", + "tableFrom": "transaction_watcher_transactions", + "tableTo": "transaction_watchers", + "columnsFrom": [ + "watcher_acct" + ], + "columnsTo": [ + "acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk": { + "name": "transaction_watcher_transactions_tx_sig_transactions_tx_sig_fk", + "tableFrom": "transaction_watcher_transactions", + "tableTo": "transactions", + "columnsFrom": [ + "tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "transaction_watcher_transactions_watcher_acct_tx_sig_pk": { + "name": "transaction_watcher_transactions_watcher_acct_tx_sig_pk", + "columns": [ + "watcher_acct", + "tx_sig" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transaction_watchers": { + "name": "transaction_watchers", + "schema": "", + "columns": { + "acct": { + "name": "acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "latest_tx_sig": { + "name": "latest_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "first_tx_sig": { + "name": "first_tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": false + }, + "checked_up_to_slot": { + "name": "checked_up_to_slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "serializer_logic_version": { + "name": "serializer_logic_version", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'disabled'" + }, + "failure_log": { + "name": "failure_log", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk": { + "name": "transaction_watchers_latest_tx_sig_transactions_tx_sig_fk", + "tableFrom": "transaction_watchers", + "tableTo": "transactions", + "columnsFrom": [ + "latest_tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "transaction_watchers_first_tx_sig_transactions_tx_sig_fk": { + "name": "transaction_watchers_first_tx_sig_transactions_tx_sig_fk", + "tableFrom": "transaction_watchers", + "tableTo": "transactions", + "columnsFrom": [ + "first_tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transactions": { + "name": "transactions", + "schema": "", + "columns": { + "tx_sig": { + "name": "tx_sig", + "type": "varchar(88)", + "primaryKey": true, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "block_time": { + "name": "block_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "failed": { + "name": "failed", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serializer_logic_version": { + "name": "serializer_logic_version", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "main_ix_type": { + "name": "main_ix_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "txn_slot_index": { + "name": "txn_slot_index", + "columns": [ + { + "expression": "slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.twaps": { + "name": "twaps", + "schema": "", + "columns": { + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": false + }, + "updated_slot": { + "name": "updated_slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "observation_agg": { + "name": "observation_agg", + "type": "numeric(40, 0)", + "primaryKey": false, + "notNull": true + }, + "last_observation": { + "name": "last_observation", + "type": "numeric(40, 0)", + "primaryKey": false, + "notNull": false + }, + "last_price": { + "name": "last_price", + "type": "numeric(40, 0)", + "primaryKey": false, + "notNull": false + }, + "token_amount": { + "name": "token_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "twaps_market_acct_markets_market_acct_fk": { + "name": "twaps_market_acct_markets_market_acct_fk", + "tableFrom": "twaps", + "tableTo": "markets", + "columnsFrom": [ + "market_acct" + ], + "columnsTo": [ + "market_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "twaps_proposal_acct_proposals_proposal_acct_fk": { + "name": "twaps_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "twaps", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "twaps_updated_slot_market_acct_pk": { + "name": "twaps_updated_slot_market_acct_pk", + "columns": [ + "updated_slot", + "market_acct" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_deposits": { + "name": "user_deposits", + "schema": "", + "columns": { + "tx_sig": { + "name": "tx_sig", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "user_acct": { + "name": "user_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "token_amount": { + "name": "token_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "mint_acct": { + "name": "mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_deposits_tx_sig_transactions_tx_sig_fk": { + "name": "user_deposits_tx_sig_transactions_tx_sig_fk", + "tableFrom": "user_deposits", + "tableTo": "transactions", + "columnsFrom": [ + "tx_sig" + ], + "columnsTo": [ + "tx_sig" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_deposits_user_acct_users_user_acct_fk": { + "name": "user_deposits_user_acct_users_user_acct_fk", + "tableFrom": "user_deposits", + "tableTo": "users", + "columnsFrom": [ + "user_acct" + ], + "columnsTo": [ + "user_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_deposits_mint_acct_tokens_mint_acct_fk": { + "name": "user_deposits_mint_acct_tokens_mint_acct_fk", + "tableFrom": "user_deposits", + "tableTo": "tokens", + "columnsFrom": [ + "mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_performance": { + "name": "user_performance", + "schema": "", + "columns": { + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "user_acct": { + "name": "user_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "dao_acct": { + "name": "dao_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "tokens_bought": { + "name": "tokens_bought", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "tokens_sold": { + "name": "tokens_sold", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "volume_bought": { + "name": "volume_bought", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "volume_sold": { + "name": "volume_sold", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "total_volume": { + "name": "total_volume", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "tokens_bought_resolving_market": { + "name": "tokens_bought_resolving_market", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "tokens_sold_resolving_market": { + "name": "tokens_sold_resolving_market", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "volume_bought_resolving_market": { + "name": "volume_bought_resolving_market", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "volume_sold_resolving_market": { + "name": "volume_sold_resolving_market", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "buy_orders_count": { + "name": "buy_orders_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "sell_orders_count": { + "name": "sell_orders_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_performance_proposal_acct_proposals_proposal_acct_fk": { + "name": "user_performance_proposal_acct_proposals_proposal_acct_fk", + "tableFrom": "user_performance", + "tableTo": "proposals", + "columnsFrom": [ + "proposal_acct" + ], + "columnsTo": [ + "proposal_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_performance_user_acct_users_user_acct_fk": { + "name": "user_performance_user_acct_users_user_acct_fk", + "tableFrom": "user_performance", + "tableTo": "users", + "columnsFrom": [ + "user_acct" + ], + "columnsTo": [ + "user_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_performance_dao_acct_daos_dao_acct_fk": { + "name": "user_performance_dao_acct_daos_dao_acct_fk", + "tableFrom": "user_performance", + "tableTo": "daos", + "columnsFrom": [ + "dao_acct" + ], + "columnsTo": [ + "dao_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_performance_proposal_acct_user_acct_pk": { + "name": "user_performance_proposal_acct_user_acct_pk", + "columns": [ + "proposal_acct", + "user_acct" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "user_acct": { + "name": "user_acct", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_amms": { + "name": "v0_4_amms", + "schema": "", + "columns": { + "amm_addr": { + "name": "amm_addr", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "created_at_slot": { + "name": "created_at_slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "lp_mint_addr": { + "name": "lp_mint_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "base_mint_addr": { + "name": "base_mint_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "quote_mint_addr": { + "name": "quote_mint_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "base_reserves": { + "name": "base_reserves", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "quote_reserves": { + "name": "quote_reserves", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "latest_amm_seq_num_applied": { + "name": "latest_amm_seq_num_applied", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "inserted_at": { + "name": "inserted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk": { + "name": "v0_4_amms_lp_mint_addr_tokens_mint_acct_fk", + "tableFrom": "v0_4_amms", + "tableTo": "tokens", + "columnsFrom": [ + "lp_mint_addr" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_amms_base_mint_addr_tokens_mint_acct_fk": { + "name": "v0_4_amms_base_mint_addr_tokens_mint_acct_fk", + "tableFrom": "v0_4_amms", + "tableTo": "tokens", + "columnsFrom": [ + "base_mint_addr" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk": { + "name": "v0_4_amms_quote_mint_addr_tokens_mint_acct_fk", + "tableFrom": "v0_4_amms", + "tableTo": "tokens", + "columnsFrom": [ + "quote_mint_addr" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_conditional_vaults": { + "name": "v0_4_conditional_vaults", + "schema": "", + "columns": { + "conditional_vault_addr": { + "name": "conditional_vault_addr", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "question_addr": { + "name": "question_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "underlying_mint_acct": { + "name": "underlying_mint_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "underlying_token_acct": { + "name": "underlying_token_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "pda_bump": { + "name": "pda_bump", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "latest_vault_seq_num_applied": { + "name": "latest_vault_seq_num_applied", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk": { + "name": "v0_4_conditional_vaults_question_addr_v0_4_questions_question_addr_fk", + "tableFrom": "v0_4_conditional_vaults", + "tableTo": "v0_4_questions", + "columnsFrom": [ + "question_addr" + ], + "columnsTo": [ + "question_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk": { + "name": "v0_4_conditional_vaults_underlying_mint_acct_tokens_mint_acct_fk", + "tableFrom": "v0_4_conditional_vaults", + "tableTo": "tokens", + "columnsFrom": [ + "underlying_mint_acct" + ], + "columnsTo": [ + "mint_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk": { + "name": "v0_4_conditional_vaults_underlying_token_acct_token_accts_token_acct_fk", + "tableFrom": "v0_4_conditional_vaults", + "tableTo": "token_accts", + "columnsFrom": [ + "underlying_token_acct" + ], + "columnsTo": [ + "token_acct" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_merges": { + "name": "v0_4_merges", + "schema": "", + "columns": { + "vault_addr": { + "name": "vault_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "vault_seq_num": { + "name": "vault_seq_num", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "signature": { + "name": "signature", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "merge_vault_index": { + "name": "merge_vault_index", + "columns": [ + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "merge_signature_index": { + "name": "merge_signature_index", + "columns": [ + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "merge_seq_num_vault_index": { + "name": "merge_seq_num_vault_index", + "columns": [ + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { + "name": "v0_4_merges_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", + "tableFrom": "v0_4_merges", + "tableTo": "v0_4_conditional_vaults", + "columnsFrom": [ + "vault_addr" + ], + "columnsTo": [ + "conditional_vault_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_merges_signature_signatures_signature_fk": { + "name": "v0_4_merges_signature_signatures_signature_fk", + "tableFrom": "v0_4_merges", + "tableTo": "signatures", + "columnsFrom": [ + "signature" + ], + "columnsTo": [ + "signature" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_metric_decisions": { + "name": "v0_4_metric_decisions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "dao_id": { + "name": "dao_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "recipient": { + "name": "recipient", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "outcome_question_addr": { + "name": "outcome_question_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "metric_question_addr": { + "name": "metric_question_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "outcome_vault_addr": { + "name": "outcome_vault_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "metric_vault_addr": { + "name": "metric_vault_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "amm_addr": { + "name": "amm_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "market_opened": { + "name": "market_opened", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "grant_awarded": { + "name": "grant_awarded", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "committee_evaluation": { + "name": "committee_evaluation", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "score_term": { + "name": "score_term", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'effective'" + }, + "score_unit": { + "name": "score_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "score_max_value": { + "name": "score_max_value", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": false + }, + "score_min_value": { + "name": "score_min_value", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk": { + "name": "v0_4_metric_decisions_dao_id_dao_details_dao_id_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "dao_details", + "columnsFrom": [ + "dao_id" + ], + "columnsTo": [ + "dao_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk": { + "name": "v0_4_metric_decisions_outcome_question_addr_v0_4_questions_question_addr_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "v0_4_questions", + "columnsFrom": [ + "outcome_question_addr" + ], + "columnsTo": [ + "question_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk": { + "name": "v0_4_metric_decisions_metric_question_addr_v0_4_questions_question_addr_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "v0_4_questions", + "columnsFrom": [ + "metric_question_addr" + ], + "columnsTo": [ + "question_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { + "name": "v0_4_metric_decisions_outcome_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "v0_4_conditional_vaults", + "columnsFrom": [ + "outcome_vault_addr" + ], + "columnsTo": [ + "conditional_vault_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { + "name": "v0_4_metric_decisions_metric_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "v0_4_conditional_vaults", + "columnsFrom": [ + "metric_vault_addr" + ], + "columnsTo": [ + "conditional_vault_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk": { + "name": "v0_4_metric_decisions_amm_addr_v0_4_amms_amm_addr_fk", + "tableFrom": "v0_4_metric_decisions", + "tableTo": "v0_4_amms", + "columnsFrom": [ + "amm_addr" + ], + "columnsTo": [ + "amm_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_questions": { + "name": "v0_4_questions", + "schema": "", + "columns": { + "question_addr": { + "name": "question_addr", + "type": "varchar(44)", + "primaryKey": true, + "notNull": true + }, + "is_resolved": { + "name": "is_resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "oracle_addr": { + "name": "oracle_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "num_outcomes": { + "name": "num_outcomes", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "payout_numerators": { + "name": "payout_numerators", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "payout_denominator": { + "name": "payout_denominator", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_splits": { + "name": "v0_4_splits", + "schema": "", + "columns": { + "vault_addr": { + "name": "vault_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "vault_seq_num": { + "name": "vault_seq_num", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "signature": { + "name": "signature", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "split_vault_index": { + "name": "split_vault_index", + "columns": [ + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "split_signature_index": { + "name": "split_signature_index", + "columns": [ + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "split_seq_num_vault_index": { + "name": "split_seq_num_vault_index", + "columns": [ + { + "expression": "vault_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vault_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk": { + "name": "v0_4_splits_vault_addr_v0_4_conditional_vaults_conditional_vault_addr_fk", + "tableFrom": "v0_4_splits", + "tableTo": "v0_4_conditional_vaults", + "columnsFrom": [ + "vault_addr" + ], + "columnsTo": [ + "conditional_vault_addr" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "v0_4_splits_signature_signatures_signature_fk": { + "name": "v0_4_splits_signature_signatures_signature_fk", + "tableFrom": "v0_4_splits", + "tableTo": "signatures", + "columnsFrom": [ + "signature" + ], + "columnsTo": [ + "signature" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.v0_4_swaps": { + "name": "v0_4_swaps", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "signature": { + "name": "signature", + "type": "varchar(88)", + "primaryKey": false, + "notNull": true + }, + "slot": { + "name": "slot", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "block_time": { + "name": "block_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "swap_type": { + "name": "swap_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "amm_addr": { + "name": "amm_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "user_addr": { + "name": "user_addr", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "amm_seq_num": { + "name": "amm_seq_num", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "input_amount": { + "name": "input_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "output_amount": { + "name": "output_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "amm_index": { + "name": "amm_index", + "columns": [ + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "signature_index": { + "name": "signature_index", + "columns": [ + { + "expression": "signature", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "seq_num_amm_index": { + "name": "seq_num_amm_index", + "columns": [ + { + "expression": "amm_seq_num", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "amm_addr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": { + "public.prices_chart_data": { + "columns": { + "interv": { + "name": "interv", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "price": { + "name": "price", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "base_amount": { + "name": "base_amount", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "quote_amount": { + "name": "quote_amount", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "prices_type": { + "name": "prices_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + } + }, + "definition": "\n SELECT\n TIME_BUCKET('30 SECONDS'::INTERVAL, prices.created_at) AS interv,\n last(price, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS price,\n last(base_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS base_amount,\n last(quote_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS quote_amount,\n prices_type,\n prices.market_acct AS market_acct\n FROM prices\n JOIN markets ON markets.market_acct = prices.market_acct\n WHERE CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END\n GROUP BY interv, prices.market_acct, prices_type\n ", + "name": "prices_chart_data", + "schema": "public", + "isExisting": false, + "materialized": false + }, + "public.proposal_total_trade_volume": { + "columns": { + "proposal_acct": { + "name": "proposal_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "pass_volume": { + "name": "pass_volume", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "fail_volume": { + "name": "fail_volume", + "type": "numeric(40, 20)", + "primaryKey": false, + "notNull": true + }, + "pass_market_acct": { + "name": "pass_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "fail_market_acct": { + "name": "fail_market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + } + }, + "definition": "\n WITH pass_market AS (\n SELECT\n \t proposal_acct,\n \t orders.market_acct AS pass_market_acct,\n TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv,\n SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS pass_volume\n FROM proposals\n JOIN orders\n ON proposals.pass_market_acct = orders.market_acct\n GROUP BY proposal_acct, interv, orders.market_acct\n ),\n fail_market AS (\n SELECT\n \t proposal_acct,\n \t orders.market_acct AS fail_market_acct,\n TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv,\n SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS fail_volume\n FROM proposals\n JOIN orders\n ON proposals.fail_market_acct = orders.market_acct\n GROUP BY proposal_acct, interv, orders.market_acct\n )\n SELECT\n pass_market.proposal_acct AS proposal_acct,\n pass_market_acct,\n fail_market_acct,\n SUM(pass_volume) AS pass_volume,\n SUM(fail_volume) AS fail_volume\n FROM pass_market\n JOIN fail_market ON fail_market.proposal_acct = pass_market.proposal_acct\n GROUP BY pass_market.proposal_acct, pass_market_acct, fail_market_acct\n ", + "name": "proposal_total_trade_volume", + "schema": "public", + "isExisting": false, + "materialized": false + }, + "public.twap_chart_data": { + "columns": { + "interv": { + "name": "interv", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "token_amount": { + "name": "token_amount", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "market_acct": { + "name": "market_acct", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + } + }, + "definition": "\n SELECT\n TIME_BUCKET('30 SECONDS'::INTERVAL, \"twaps\".\"created_at\") AS interv,\n last(token_amount, \"twaps\".\"created_at\") FILTER(WHERE \"twaps\".\"created_at\" IS NOT NULL AND \"twaps\".\"created_at\" <= \"markets\".\"created_at\" + '5 DAYS'::INTERVAL) AS token_amount,\n \"twaps\".\"market_acct\" AS market_acct\n FROM \"twaps\"\n JOIN \"markets\" ON \"markets\".\"market_acct\" = \"twaps\".\"market_acct\"\n WHERE \"twaps\".\"created_at\" <= \"markets\".\"created_at\" + '5 DAYS'::INTERVAL\n GROUP BY interv, \"twaps\".\"market_acct\"\n ", + "name": "twap_chart_data", + "schema": "public", + "isExisting": false, + "materialized": false + } + }, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/database/drizzle/meta/_journal.json b/packages/database/drizzle/meta/_journal.json index 76675b2d..25605255 100644 --- a/packages/database/drizzle/meta/_journal.json +++ b/packages/database/drizzle/meta/_journal.json @@ -64,6 +64,13 @@ "when": 1729791097640, "tag": "0008_stormy_spirit", "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1731430722593, + "tag": "0009_brainy_karma", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/database/lib/schema.ts b/packages/database/lib/schema.ts index d568fbdd..4bcdd77d 100644 --- a/packages/database/lib/schema.ts +++ b/packages/database/lib/schema.ts @@ -1027,7 +1027,7 @@ export const v0_4_merges = pgTable("v0_4_merges", { .notNull() .default(sql`now()`), }, (table) => ({ - pk: primaryKey({ columns: [table.vaultAddr, table.vaultSeqNum]}), + // pk: primaryKey({ columns: [table.vaultAddr, table.vaultSeqNum]}), vaultIdx: index("merge_vault_index").on(table.vaultAddr), signatureIdx: index("merge_signature_index").on(table.signature), seqNumVaultIdx: index("merge_seq_num_vault_index").on(table.vaultSeqNum, table.vaultAddr), From 8ba6488ead52feb7bd4a17a97636d9064b72c20c Mon Sep 17 00:00:00 2001 From: advaith101 Date: Tue, 12 Nov 2024 12:09:07 -0500 Subject: [PATCH 21/29] feat: db migration done (i think) --- .../database/drizzle/0009_brainy_karma.sql | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/database/drizzle/0009_brainy_karma.sql b/packages/database/drizzle/0009_brainy_karma.sql index dfe2e8ef..dd191579 100644 --- a/packages/database/drizzle/0009_brainy_karma.sql +++ b/packages/database/drizzle/0009_brainy_karma.sql @@ -1,59 +1,59 @@ ALTER TABLE "indexers" ADD COLUMN "latest_tx_sig_processed" varchar(88);--> statement-breakpoint ALTER TABLE "v0_4_merges" DROP COLUMN IF EXISTS "id";--> statement-breakpoint ALTER TABLE "v0_4_splits" DROP COLUMN IF EXISTS "id";--> statement-breakpoint -CREATE VIEW "public"."prices_chart_data" AS ( - SELECT - TIME_BUCKET('30 SECONDS'::INTERVAL, prices.created_at) AS interv, - last(price, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS price, - last(base_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS base_amount, - last(quote_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS quote_amount, - prices_type, - prices.market_acct AS market_acct - FROM prices - JOIN markets ON markets.market_acct = prices.market_acct - WHERE CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END - GROUP BY interv, prices.market_acct, prices_type - );--> statement-breakpoint -CREATE VIEW "public"."proposal_total_trade_volume" AS ( - WITH pass_market AS ( - SELECT - proposal_acct, - orders.market_acct AS pass_market_acct, - TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, - SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS pass_volume - FROM proposals - JOIN orders - ON proposals.pass_market_acct = orders.market_acct - GROUP BY proposal_acct, interv, orders.market_acct - ), - fail_market AS ( - SELECT - proposal_acct, - orders.market_acct AS fail_market_acct, - TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, - SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS fail_volume - FROM proposals - JOIN orders - ON proposals.fail_market_acct = orders.market_acct - GROUP BY proposal_acct, interv, orders.market_acct - ) - SELECT - pass_market.proposal_acct AS proposal_acct, - pass_market_acct, - fail_market_acct, - SUM(pass_volume) AS pass_volume, - SUM(fail_volume) AS fail_volume - FROM pass_market - JOIN fail_market ON fail_market.proposal_acct = pass_market.proposal_acct - GROUP BY pass_market.proposal_acct, pass_market_acct, fail_market_acct - );--> statement-breakpoint -CREATE VIEW "public"."twap_chart_data" AS ( - SELECT - TIME_BUCKET('30 SECONDS'::INTERVAL, "twaps"."created_at") AS interv, - last(token_amount, "twaps"."created_at") FILTER(WHERE "twaps"."created_at" IS NOT NULL AND "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL) AS token_amount, - "twaps"."market_acct" AS market_acct - FROM "twaps" - JOIN "markets" ON "markets"."market_acct" = "twaps"."market_acct" - WHERE "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL - GROUP BY interv, "twaps"."market_acct" - ); \ No newline at end of file +-- CREATE VIEW "public"."prices_chart_data" AS ( +-- SELECT +-- TIME_BUCKET('30 SECONDS'::INTERVAL, prices.created_at) AS interv, +-- last(price, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS price, +-- last(base_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS base_amount, +-- last(quote_amount, prices.created_at) FILTER(WHERE prices.created_at IS NOT NULL AND CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END) AS quote_amount, +-- prices_type, +-- prices.market_acct AS market_acct +-- FROM prices +-- JOIN markets ON markets.market_acct = prices.market_acct +-- WHERE CASE WHEN prices_type = 'spot' THEN TRUE ELSE prices.created_at <= markets.created_at + '5 DAYS'::INTERVAL END +-- GROUP BY interv, prices.market_acct, prices_type +-- );--> statement-breakpoint +-- CREATE VIEW "public"."proposal_total_trade_volume" AS ( +-- WITH pass_market AS ( +-- SELECT +-- proposal_acct, +-- orders.market_acct AS pass_market_acct, +-- TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, +-- SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS pass_volume +-- FROM proposals +-- JOIN orders +-- ON proposals.pass_market_acct = orders.market_acct +-- GROUP BY proposal_acct, interv, orders.market_acct +-- ), +-- fail_market AS ( +-- SELECT +-- proposal_acct, +-- orders.market_acct AS fail_market_acct, +-- TIME_BUCKET('1 DAYS'::INTERVAL, orders.order_time) AS interv, +-- SUM(filled_base_amount * quote_price) FILTER(WHERE orders.order_time IS NOT NULL) AS fail_volume +-- FROM proposals +-- JOIN orders +-- ON proposals.fail_market_acct = orders.market_acct +-- GROUP BY proposal_acct, interv, orders.market_acct +-- ) +-- SELECT +-- pass_market.proposal_acct AS proposal_acct, +-- pass_market_acct, +-- fail_market_acct, +-- SUM(pass_volume) AS pass_volume, +-- SUM(fail_volume) AS fail_volume +-- FROM pass_market +-- JOIN fail_market ON fail_market.proposal_acct = pass_market.proposal_acct +-- GROUP BY pass_market.proposal_acct, pass_market_acct, fail_market_acct +-- );--> statement-breakpoint +-- CREATE VIEW "public"."twap_chart_data" AS ( +-- SELECT +-- TIME_BUCKET('30 SECONDS'::INTERVAL, "twaps"."created_at") AS interv, +-- last(token_amount, "twaps"."created_at") FILTER(WHERE "twaps"."created_at" IS NOT NULL AND "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL) AS token_amount, +-- "twaps"."market_acct" AS market_acct +-- FROM "twaps" +-- JOIN "markets" ON "markets"."market_acct" = "twaps"."market_acct" +-- WHERE "twaps"."created_at" <= "markets"."created_at" + '5 DAYS'::INTERVAL +-- GROUP BY interv, "twaps"."market_acct" +-- ); \ No newline at end of file From d6dfc0c99f0ea7d2bb4a3a4f7768732c195c8016 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Wed, 13 Nov 2024 17:14:46 -0500 Subject: [PATCH 22/29] feat: index price/twap from logs, minor improvements/fixes --- packages/indexer/src/frontfiller.ts | 0 packages/indexer/src/index.ts | 10 +-- .../indexer/src/v3_indexer/builders/swaps.ts | 73 +++++++++++++------ .../src/v3_indexer/cli/txw/populate.ts | 2 +- .../amm-market-account-interval-indexer.ts | 5 ++ packages/indexer/src/v4_indexer/filler.ts | 4 +- packages/indexer/src/v4_indexer/indexer.ts | 24 +++--- packages/indexer/src/v4_indexer/processor.ts | 1 + 8 files changed, 78 insertions(+), 41 deletions(-) delete mode 100644 packages/indexer/src/frontfiller.ts diff --git a/packages/indexer/src/frontfiller.ts b/packages/indexer/src/frontfiller.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/indexer/src/index.ts b/packages/indexer/src/index.ts index eb060ed0..8ff85246 100644 --- a/packages/indexer/src/index.ts +++ b/packages/indexer/src/index.ts @@ -2,15 +2,15 @@ import { startIndexers } from "./v3_indexer/indexers"; import { startIndexerAccountDependencyPopulation } from "./v3_indexer/cli/txw/populate"; import { startTransactionWatchers } from "./v3_indexer/transaction/watcher"; import { subscribeAll } from "./subscriber"; -import { frontfill, backfill } from "./v4_indexer/filler"; +import { frontfill as v4_frontfill, backfill as v4_backfill } from "./v4_indexer/filler"; // startIndexerAccountDependencyPopulation(); subscribeAll(); -// await startTransactionWatchers(); -// await startIndexers(); +// startTransactionWatchers(); +// startIndexers(); -backfill(); -frontfill(); +// v4_backfill(); +// v4_frontfill(); diff --git a/packages/indexer/src/v3_indexer/builders/swaps.ts b/packages/indexer/src/v3_indexer/builders/swaps.ts index 1350a066..c290e705 100644 --- a/packages/indexer/src/v3_indexer/builders/swaps.ts +++ b/packages/indexer/src/v3_indexer/builders/swaps.ts @@ -25,6 +25,10 @@ import { import { logger } from "../../logger"; import { getMainIxTypeFromTransaction } from "../transaction/watcher"; import { getHumanPrice } from "../usecases/math"; +import { connection } from "../connection"; +import { AmmMarketAccountUpdateIndexer } from '../indexers/amm-market/amm-market-account-indexer'; +import { PublicKey } from "@solana/web3.js"; + export class SwapPersistable { private ordersRecord: OrdersRecord; @@ -45,27 +49,29 @@ export class SwapPersistable { async persist() { try { - // const upsertResult = - // (await usingDb((db) => - // db - // .insert(schema.transactions) - // .values(this.transactionRecord) - // .onConflictDoUpdate({ - // target: schema.transactions.txSig, - // set: this.transactionRecord, - // }) - // .returning({ txSig: schema.transactions.txSig }) - // )) ?? []; - // if ( - // upsertResult.length !== 1 || - // upsertResult[0].txSig !== this.transactionRecord.txSig - // ) { - // logger.warn( - // `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( - // this.transactionRecord - // )}` - // ); - // } + // First insert the transaction record + const upsertResult = + (await usingDb((db) => + db + .insert(schema.transactions) + .values(this.transactionRecord) + .onConflictDoUpdate({ + target: schema.transactions.txSig, + set: this.transactionRecord, + }) + .returning({ txSig: schema.transactions.txSig }) + )) ?? []; + if ( + upsertResult.length !== 1 || + upsertResult[0].txSig !== this.transactionRecord.txSig + ) { + logger.warn( + `Failed to upsert ${this.transactionRecord.txSig}. ${JSON.stringify( + this.transactionRecord + )}` + ); + } + // Insert user if they aren't already in the database const insertUsersResult = (await usingDb((db) => db @@ -244,6 +250,28 @@ export class SwapBuilder { } } + async indexPriceAndTWAPForAccount(account: PublicKey) { + console.log("indexing price and twap for account", account.toBase58()); + const accountInfo = await connection.getAccountInfoAndContext( + account + ); + + //index refresh on startup + if (accountInfo.value) { + const res = await AmmMarketAccountUpdateIndexer.index( + accountInfo.value, + account, + accountInfo.context + ); + if (!res.success) { + logger.error( + "error indexing account initial fetch", + account.toString() + ); + } + } + } + async buildOrderFromSwapIx( swapIx: Instruction, tx: Transaction, @@ -255,8 +283,11 @@ export class SwapBuilder { const marketAcct = swapIx.accountsWithData.find((a) => a.name === "amm"); if (!marketAcct) return Err({ type: "missing data" }); + const marketAcctPubKey = new PublicKey(marketAcct.pubkey); + this.indexPriceAndTWAPForAccount(marketAcctPubKey); const userAcct = swapIx.accountsWithData.find((a) => a.name === "user"); if (!userAcct) return Err({ type: "missing data" }); + const userAcctPubKey = new PublicKey(userAcct.pubkey); // TODO fix const userBaseAcct = swapIx.accountsWithData.find( (a) => a.name === "userBaseAccount" diff --git a/packages/indexer/src/v3_indexer/cli/txw/populate.ts b/packages/indexer/src/v3_indexer/cli/txw/populate.ts index 1458c3df..adca2d51 100644 --- a/packages/indexer/src/v3_indexer/cli/txw/populate.ts +++ b/packages/indexer/src/v3_indexer/cli/txw/populate.ts @@ -27,7 +27,7 @@ import { } from "../../indexers/jupiter/jupiter-quotes-indexer"; import Cron from "croner"; -import { logger } from "../../logger"; +import { logger } from "../../../logger"; type IndexerAccountDependency = typeof schema.indexerAccountDependencies._.inferInsert; diff --git a/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts index d935d7ec..89724448 100644 --- a/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts +++ b/packages/indexer/src/v3_indexer/indexers/amm-market/amm-market-account-interval-indexer.ts @@ -62,4 +62,9 @@ export const AmmMarketAccountIntervalFetchIndexer: IntervalFetchIndexer = { return Err({ type: AmmAccountIntervalIndexerError.General }); } }, + + indexFromLogs: async (logs: string[]) => { + //TODO: implement if needed + return Err({ type: AmmAccountIntervalIndexerError.General }); + }, }; diff --git a/packages/indexer/src/v4_indexer/filler.ts b/packages/indexer/src/v4_indexer/filler.ts index 5af92738..1bd3fdd9 100644 --- a/packages/indexer/src/v4_indexer/filler.ts +++ b/packages/indexer/src/v4_indexer/filler.ts @@ -82,7 +82,7 @@ const insertNewSignatures = async (programId: PublicKey) => { // }); // } - console.log(`insertNewSignatures::latestRecordedSignature: ${latestRecordedSignature}`); + // console.log(`insertNewSignatures::latestRecordedSignature: ${latestRecordedSignature}`); let oldestSignatureInserted: string | undefined; while (true) { @@ -195,7 +195,7 @@ export const frontfill = async () => { setInterval(async () => { const newSignatures = await insertNewSignatures(programId); console.log(`inserted up to ${newSignatures.length} new signatures for ${programId.toString()}`); - }, 3000); //every 3s + }, 30000); //every 30s } catch (error) { logger.errorWithChatBotAlert([ error instanceof Error ? diff --git a/packages/indexer/src/v4_indexer/indexer.ts b/packages/indexer/src/v4_indexer/indexer.ts index d5487a32..c42bb405 100644 --- a/packages/indexer/src/v4_indexer/indexer.ts +++ b/packages/indexer/src/v4_indexer/indexer.ts @@ -18,7 +18,7 @@ type DBConnection = any; // TODO: Fix typing.. const parseEvents = (transactionResponse: VersionedTransactionResponse | TransactionResponse): { ammEvents: any, vaultEvents: any } => { const ammEvents: { name: string; data: any }[] = []; const vaultEvents: { name: string; data: any }[] = []; - // try { + try { const inner: CompiledInnerInstruction[] = transactionResponse?.meta?.innerInstructions ?? []; const ammIdlProgramId = ammClient.program.programId; @@ -37,9 +37,9 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac // get which program the instruction belongs to let program: Program; - console.log("programPubkey", programPubkey.toBase58()); - console.log("ammIdlProgramId", ammIdlProgramId.toBase58()); - console.log("vaultIdlProgramId", vaultIdlProgramId.toBase58()); + // console.log("programPubkey", programPubkey.toBase58()); + // console.log("ammIdlProgramId", ammIdlProgramId.toBase58()); + // console.log("vaultIdlProgramId", vaultIdlProgramId.toBase58()); if (programPubkey.equals(ammIdlProgramId)) { program = ammClient.program; const ixData = anchor.utils.bytes.bs58.decode( @@ -63,17 +63,17 @@ const parseEvents = (transactionResponse: VersionedTransactionResponse | Transac vaultEvents.push(event); } } else { - console.log("Unknown program pubkey", programPubkey.toBase58()); + // console.log("Unknown program pubkey", programPubkey.toBase58()); } } } - // } catch (error) { - // logger.errorWithChatBotAlert([ - // error instanceof Error - // ? `Error parsing events: ${error.message}` - // : "Unknown error parsing events" - // ]); - // } + } catch (error) { + logger.errorWithChatBotAlert([ + error instanceof Error + ? `Error parsing events: ${error.message}` + : "Unknown error parsing events" + ]); + } return { ammEvents, diff --git a/packages/indexer/src/v4_indexer/processor.ts b/packages/indexer/src/v4_indexer/processor.ts index 807f1edf..d5cd89fe 100644 --- a/packages/indexer/src/v4_indexer/processor.ts +++ b/packages/indexer/src/v4_indexer/processor.ts @@ -386,6 +386,7 @@ async function insertMarketIfNotExists(db: DBConnection, market: Market) { } async function insertPriceIfNotDuplicate(db: DBConnection, amm: any[], event: AddLiquidityEvent | SwapEvent | RemoveLiquidityEvent) { + console.log("insertPriceIfNotDuplicate::event", event); const existingPrice = await db.select() .from(schema.prices) .where(and( From 215b622758542fa07302ed6cea74960c5dc0f897 Mon Sep 17 00:00:00 2001 From: Kollan House Date: Thu, 14 Nov 2024 08:10:18 -0800 Subject: [PATCH 23/29] feat: extends queries and API --- .../hasura/metadata/databases/databases.yaml | 87 +++++++++++++++++++ .../hasura/metadata/query_collections.yaml | 25 ++++++ packages/hasura/metadata/rest_endpoints.yaml | 18 ++++ 3 files changed, 130 insertions(+) diff --git a/packages/hasura/metadata/databases/databases.yaml b/packages/hasura/metadata/databases/databases.yaml index 9054801d..6b4a6887 100644 --- a/packages/hasura/metadata/databases/databases.yaml +++ b/packages/hasura/metadata/databases/databases.yaml @@ -162,7 +162,90 @@ - trade_count filter: {} role: anonymous + - fields: + - name: dao_image + type: + nullable: true + scalar: text + - name: proposal_title + type: + nullable: true + scalar: text + - name: trade_count + type: + nullable: true + scalar: numeric + - name: volume_traded + type: + nullable: true + scalar: numeric + - name: proposal_status + type: + nullable: true + scalar: text + - name: chart_data + type: + nullable: true + scalar: jsonb + name: website_latest_four_proposals + select_permissions: + - permission: + columns: + - dao_image + - proposal_title + - trade_count + - volume_traded + - proposal_status + - chart_data + filter: {} + role: anonymous + - fields: + - name: volume_traded + type: + nullable: true + scalar: numeric + - name: profits_earned + type: + nullable: true + scalar: numeric + - name: unique_traders + type: + nullable: true + scalar: numeric + - name: number_of_daos + type: + nullable: true + scalar: numeric + - name: total_proposals + type: + nullable: true + scalar: numeric + - name: total_markets + type: + nullable: true + scalar: numeric + - name: total_trades + type: + nullable: true + scalar: numeric + name: website_stats + select_permissions: + - permission: + columns: + - volume_traded + - profits_earned + - unique_traders + - number_of_daos + - total_proposals + - total_markets + - total_trades + filter: {} + role: anonymous native_queries: + - arguments: {} + code: "WITH recent_proposals AS (\n SELECT DISTINCT ON (p.proposal_acct)\n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status as proposal_status,\n pd.title as proposal_title,\n d.dao_acct,\n d.base_acct as spot_market_acct,\n dd.image_url as dao_image,\n string_agg(m.market_acct::text, ',') as market_accts\n FROM \n proposals p\n INNER JOIN proposal_details pd ON pd.proposal_acct = p.proposal_acct\n INNER JOIN daos d ON d.dao_acct = p.dao_acct\n INNER JOIN dao_details dd ON dd.dao_id = d.dao_id\n INNER JOIN markets m ON m.proposal_acct = p.proposal_acct\n WHERE \n \tp.status != 'Pending'\n GROUP BY \n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status,\n pd.title,\n d.dao_acct,\n d.base_acct,\n dd.image_url\n ORDER BY p.proposal_acct, p.created_at DESC\n LIMIT 4\n),\nproposal_trades AS (\n SELECT \n rp.proposal_acct,\n COUNT(*) as trade_count,\n SUM((t.base_amount / POW(10, tokens.decimals)) * t.quote_price) AS volume_traded\n FROM \n recent_proposals rp\n CROSS JOIN LATERAL unnest(string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN takes t ON t.market_acct = m.market_acct::text\n INNER JOIN orders o ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN daos d ON d.dao_acct = rp.dao_acct\n INNER JOIN tokens ON tokens.mint_acct = d.base_acct\n GROUP BY rp.proposal_acct\n),\nprice_data AS (\n SELECT DISTINCT ON (rp.proposal_acct, c.market_acct)\n c.market_acct,\n rp.proposal_acct,\n jsonb_build_object(\n 'intervals', jsonb_agg(\n jsonb_build_object(\n 'interv', c.interv,\n 'price', c.price,\n 'type', c.prices_type::text\n ) ORDER BY c.interv\n )\n ) as chart_data\n FROM recent_proposals rp\n CROSS JOIN LATERAL unnest(array[rp.spot_market_acct] || string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN (\n SELECT \n pcd.*\n FROM \n prices_chart_data pcd\n INNER JOIN (\n SELECT \n pcd2.market_acct,\n pcd2.interv,\n pcd2.price,\n pcd2.prices_type,\n LAG(pcd2.price) OVER w AS prev_price,\n LAG(pcd2.prices_type) OVER w AS prev_prices_type\n FROM prices_chart_data pcd2\n WINDOW w AS (PARTITION BY market_acct ORDER BY interv)\n ) changes ON changes.market_acct = pcd.market_acct \n AND changes.interv = pcd.interv\n WHERE \n (prev_price IS NULL\n OR changes.price != changes.prev_price\n OR changes.prices_type != changes.prev_prices_type)\n ) c ON c.market_acct = m.market_acct::text\n WHERE \n c.interv >= rp.created_at\n AND c.interv <= COALESCE(rp.completed_at, NOW())\n GROUP BY rp.proposal_acct, c.market_acct\n)\nSELECT DISTINCT ON (rp.proposal_acct)\n rp.dao_image::text,\n rp.proposal_title::text,\n COALESCE(pt.trade_count, 0)::numeric as trade_count,\n COALESCE(pt.volume_traded, 0)::numeric as volume_traded,\n rp.proposal_status::text,\n jsonb_build_object(\n 'spot', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = rp.spot_market_acct\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'pass', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[1]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'fail', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[2]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n )\n ) as chart_data\nFROM \n recent_proposals rp\n LEFT JOIN proposal_trades pt ON pt.proposal_acct = rp.proposal_acct\nORDER BY rp.proposal_acct, rp.created_at DESC;" + returns: website_latest_four_proposals + root_field_name: latest_finished_proposals - arguments: dao_slug: description: "" @@ -223,4 +306,8 @@ code: "WITH market_actors AS (\n SELECT \n t.market_acct,\n actor_acct,\n COUNT(*) AS countOrders\n FROM \n takes t\n JOIN orders o ON o.order_tx_sig = t.order_tx_sig\n JOIN transactions tx ON tx.tx_sig = o.order_tx_sig\n WHERE tx.failed IS FALSE\n AND o.quote_price > 0\n GROUP BY \n t.market_acct, actor_acct\n), distinct_users_by_proposal AS (\n SELECT\n proposal_acct,\n COUNT(DISTINCT actor_acct) AS uniqueUsersCount,\n SUM(countOrders) AS totalTrades\n FROM market_actors\n JOIN markets ON markets.market_acct = market_actors.market_acct\n GROUP BY proposal_acct\n)\nSELECT\n\tproposal_acct,\n\tuniqueUsersCount AS user_count,\n\ttotalTrades AS trade_count\nFROM distinct_users_by_proposal\nWHERE \n CASE \n WHEN {{proposal_acct}} IS NOT NULL \n THEN proposal_acct = {{proposal_acct}} \n ELSE 1 = 1 \n END;" returns: proposal_statistics root_field_name: user_count_and_trade_count_per_proposal + - arguments: {} + code: "WITH base_trades AS (\n SELECT \n t.market_acct,\n o.actor_acct,\n (t.base_amount / POW(10, tokens.decimals)) * t.quote_price AS trade_volume,\n dd.slug,\n m.proposal_acct,\n COUNT(*) OVER () as total_takes -- Count all takes that match our filters\n FROM \n takes t\n INNER JOIN orders o \n ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx \n ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN markets m \n ON m.market_acct = o.market_acct\n INNER JOIN proposals p \n ON p.proposal_acct = m.proposal_acct\n INNER JOIN daos d \n ON d.dao_acct = p.dao_acct\n INNER JOIN tokens \n ON tokens.mint_acct = d.base_acct\n INNER JOIN dao_details dd \n ON dd.dao_id = d.dao_id\n),\naggregated_stats AS (\n SELECT \n COUNT(DISTINCT actor_acct) AS unique_trader_count,\n COUNT(DISTINCT proposal_acct) AS proposal_count,\n COUNT(DISTINCT market_acct) AS market_count,\n SUM(trade_volume) AS total_volume,\n MAX(total_takes) AS total_trades, -- Use MAX since the value is the same for all rows\n COUNT(DISTINCT slug) AS dao_count\n FROM base_trades\n)\nSELECT \n total_volume::numeric AS volume_traded,\n NULL::numeric AS profits_earned,\n unique_trader_count::numeric AS unique_traders,\n dao_count::numeric AS number_of_daos,\n proposal_count::numeric AS total_proposals,\n market_count::numeric AS total_markets,\n total_trades::numeric\nFROM aggregated_stats;" + returns: website_stats + root_field_name: website_stats tables: "!include futarchy/tables/tables.yaml" diff --git a/packages/hasura/metadata/query_collections.yaml b/packages/hasura/metadata/query_collections.yaml index fe360a07..4c38719f 100644 --- a/packages/hasura/metadata/query_collections.yaml +++ b/packages/hasura/metadata/query_collections.yaml @@ -23,3 +23,28 @@ name } } + - name: fetchAggregateStats + query: | + query fetchAggregateStats { + website_stats { + total_trades + total_markets + total_proposals + unique_traders + profits_earned + number_of_daos + volume_traded + } + } + - name: fetchLatestFourProposals + query: | + query fetchLatestFourProposals { + latest_finished_proposals { + dao_image + proposal_title + trade_count + volume_traded + proposal_status + chart_data + } + } diff --git a/packages/hasura/metadata/rest_endpoints.yaml b/packages/hasura/metadata/rest_endpoints.yaml index 95bcda36..935c3306 100644 --- a/packages/hasura/metadata/rest_endpoints.yaml +++ b/packages/hasura/metadata/rest_endpoints.yaml @@ -7,6 +7,24 @@ - GET name: getDaoNameFromSlug url: dao-name/:slug +- comment: just for use with website data + definition: + query: + collection_name: allowed-queries + query_name: fetchAggregateStats + methods: + - GET + name: fetchAggregateStats + url: fetchaggregatestats +- comment: "" + definition: + query: + collection_name: allowed-queries + query_name: fetchLatestFourProposals + methods: + - GET + name: fetchLatestFourProposals + url: fetchlatestfourproposals - comment: "" definition: query: From 71b72870bfe0666a992c1f43ba1a974a56016c26 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 18 Nov 2024 12:41:47 -0500 Subject: [PATCH 24/29] feat: error handling + reduce latency on v4 --- packages/indexer/src/index.ts | 48 ++++++++++++++++++++++++++---- packages/indexer/src/subscriber.ts | 2 +- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/packages/indexer/src/index.ts b/packages/indexer/src/index.ts index 8ff85246..5eda9554 100644 --- a/packages/indexer/src/index.ts +++ b/packages/indexer/src/index.ts @@ -3,14 +3,50 @@ import { startIndexerAccountDependencyPopulation } from "./v3_indexer/cli/txw/po import { startTransactionWatchers } from "./v3_indexer/transaction/watcher"; import { subscribeAll } from "./subscriber"; import { frontfill as v4_frontfill, backfill as v4_backfill } from "./v4_indexer/filler"; +import { logger } from "./logger"; +async function main() { + try { + // Start all indexing processes + await Promise.all([ + startIndexerAccountDependencyPopulation(), -// startIndexerAccountDependencyPopulation(); -subscribeAll(); + subscribeAll().catch(err => { + logger.errorWithChatBotAlert("Error in subscribeAll:", err); + }), + + v4_backfill().catch(err => { + logger.errorWithChatBotAlert("Error in v4_backfill:", err); + }), + + v4_frontfill().catch(err => { + logger.errorWithChatBotAlert("Error in v4_frontfill:", err); + }), -// startTransactionWatchers(); -// startIndexers(); + startTransactionWatchers().catch(err => { + logger.errorWithChatBotAlert("Error in startTransactionWatchers:", err); + }), + + startIndexers().catch(err => { + logger.errorWithChatBotAlert("Error in startIndexers:", err); + }) + ]); + // Keep process running + process.on('uncaughtException', (err) => { + logger.errorWithChatBotAlert("Uncaught exception:", err); + }); -// v4_backfill(); -// v4_frontfill(); + process.on('unhandledRejection', (err) => { + logger.errorWithChatBotAlert("Unhandled rejection:", err); + }); + + } catch (error) { + logger.errorWithChatBotAlert("Critical error in indexer:", error); + } +} + +main().catch(err => { + logger.errorWithChatBotAlert("Fatal error starting indexer:", err); + process.exit(1); +}); diff --git a/packages/indexer/src/subscriber.ts b/packages/indexer/src/subscriber.ts index 0ff9ef61..68709e63 100644 --- a/packages/indexer/src/subscriber.ts +++ b/packages/indexer/src/subscriber.ts @@ -29,7 +29,7 @@ async function subscribe(accountPubKey: PublicKey) { // and often we get no response if we try right after recieving the logs notification console.log("Logs received for account", accountPubKey.toString()); console.log("Logs", logs); - await new Promise((resolve) => setTimeout(resolve, 1500)); + await new Promise((resolve) => setTimeout(resolve, 500)); processLogs(logs, ctx, accountPubKey); //trigger processing of logs } catch (error) { logger.errorWithChatBotAlert(`Error processing logs for account ${accountPubKey.toString()}`, error); From d16c0c74e73ea636f2ca8c4dff31938f5eaccb4e Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 18 Nov 2024 14:34:51 -0500 Subject: [PATCH 25/29] feat: prepend env in error logging --- packages/indexer/src/logger.ts | 3 ++- packages/indexer/src/v3_indexer/builders/swaps.ts | 2 +- packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/indexer/src/logger.ts b/packages/indexer/src/logger.ts index f9315a0b..04b78934 100644 --- a/packages/indexer/src/logger.ts +++ b/packages/indexer/src/logger.ts @@ -2,6 +2,7 @@ import { Counter } from "@lukasdeco/prom-client"; import { AlertChatBotInterface, TelegramBotAPI } from "./adapters/telegram-bot"; const TELEGRAM_ALERT_CHAT_ID = process.env.TELEGRAM_ALERT_CHAT_ID ?? ""; +const DEPLOY_ENVIRONMENT = process.env.DEPLOY_ENVIRONMENT ?? "STAGING"; export class Logger { // private errorCounter; @@ -61,7 +62,7 @@ export class Logger { } errorWithChatBotAlert(...data: any[]): void { - const formattedData = this.formatData(data); + const formattedData = DEPLOY_ENVIRONMENT + "::" + this.formatData(data); console.error(formattedData); // this.errorCounter.inc(); if (TELEGRAM_ALERT_CHAT_ID) { diff --git a/packages/indexer/src/v3_indexer/builders/swaps.ts b/packages/indexer/src/v3_indexer/builders/swaps.ts index c290e705..59c21e3f 100644 --- a/packages/indexer/src/v3_indexer/builders/swaps.ts +++ b/packages/indexer/src/v3_indexer/builders/swaps.ts @@ -284,7 +284,7 @@ export class SwapBuilder { const marketAcct = swapIx.accountsWithData.find((a) => a.name === "amm"); if (!marketAcct) return Err({ type: "missing data" }); const marketAcctPubKey = new PublicKey(marketAcct.pubkey); - this.indexPriceAndTWAPForAccount(marketAcctPubKey); + // this.indexPriceAndTWAPForAccount(marketAcctPubKey); const userAcct = swapIx.accountsWithData.find((a) => a.name === "user"); if (!userAcct) return Err({ type: "missing data" }); const userAcctPubKey = new PublicKey(userAcct.pubkey); diff --git a/packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts b/packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts index 01829792..d1b71bb8 100644 --- a/packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts +++ b/packages/indexer/src/v3_indexer/indexers/amm-market/utils.ts @@ -80,6 +80,7 @@ export async function indexAmmMarketAccountWithContext( try{ // TODO batch commits across inserts - maybe with event queue + console.log("utils::indexAmmMarketAccountWithContext::upserting twap", newTwap); const twapUpsertResult = await usingDb((db) => db .insert(schema.twaps) From 60bf81ca2e9a3552358914abf6855bd4c891a814 Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 18 Nov 2024 14:47:39 -0500 Subject: [PATCH 26/29] feat: creating PR, exported hasura metadata --- .../hasura/metadata/databases/databases.yaml | 54 ++++++++++++++++++- .../hasura/metadata/query_collections.yaml | 2 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/hasura/metadata/databases/databases.yaml b/packages/hasura/metadata/databases/databases.yaml index 6b4a6887..09133119 100644 --- a/packages/hasura/metadata/databases/databases.yaml +++ b/packages/hasura/metadata/databases/databases.yaml @@ -24,6 +24,48 @@ - total_volume filter: {} role: anonymous + - fields: + - name: dao_image + type: + nullable: true + scalar: text + - name: proposal_title + type: + nullable: true + scalar: text + - name: proposal_account + type: + nullable: true + scalar: text + - name: trade_count + type: + nullable: true + scalar: numeric + - name: volume_traded + type: + nullable: true + scalar: numeric + - name: proposal_status + type: + nullable: true + scalar: text + - name: chart_data + type: + nullable: true + scalar: jsonb + name: linked_recent_proposals + select_permissions: + - permission: + columns: + - dao_image + - proposal_title + - proposal_account + - trade_count + - volume_traded + - proposal_status + - chart_data + filter: {} + role: anonymous - fields: - name: total_volume type: @@ -187,6 +229,14 @@ type: nullable: true scalar: jsonb + - name: proposal_account + type: + nullable: true + scalar: text + - name: dao_slug + type: + nullable: true + scalar: text name: website_latest_four_proposals select_permissions: - permission: @@ -197,6 +247,8 @@ - volume_traded - proposal_status - chart_data + - proposal_account + - dao_slug filter: {} role: anonymous - fields: @@ -243,7 +295,7 @@ role: anonymous native_queries: - arguments: {} - code: "WITH recent_proposals AS (\n SELECT DISTINCT ON (p.proposal_acct)\n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status as proposal_status,\n pd.title as proposal_title,\n d.dao_acct,\n d.base_acct as spot_market_acct,\n dd.image_url as dao_image,\n string_agg(m.market_acct::text, ',') as market_accts\n FROM \n proposals p\n INNER JOIN proposal_details pd ON pd.proposal_acct = p.proposal_acct\n INNER JOIN daos d ON d.dao_acct = p.dao_acct\n INNER JOIN dao_details dd ON dd.dao_id = d.dao_id\n INNER JOIN markets m ON m.proposal_acct = p.proposal_acct\n WHERE \n \tp.status != 'Pending'\n GROUP BY \n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status,\n pd.title,\n d.dao_acct,\n d.base_acct,\n dd.image_url\n ORDER BY p.proposal_acct, p.created_at DESC\n LIMIT 4\n),\nproposal_trades AS (\n SELECT \n rp.proposal_acct,\n COUNT(*) as trade_count,\n SUM((t.base_amount / POW(10, tokens.decimals)) * t.quote_price) AS volume_traded\n FROM \n recent_proposals rp\n CROSS JOIN LATERAL unnest(string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN takes t ON t.market_acct = m.market_acct::text\n INNER JOIN orders o ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN daos d ON d.dao_acct = rp.dao_acct\n INNER JOIN tokens ON tokens.mint_acct = d.base_acct\n GROUP BY rp.proposal_acct\n),\nprice_data AS (\n SELECT DISTINCT ON (rp.proposal_acct, c.market_acct)\n c.market_acct,\n rp.proposal_acct,\n jsonb_build_object(\n 'intervals', jsonb_agg(\n jsonb_build_object(\n 'interv', c.interv,\n 'price', c.price,\n 'type', c.prices_type::text\n ) ORDER BY c.interv\n )\n ) as chart_data\n FROM recent_proposals rp\n CROSS JOIN LATERAL unnest(array[rp.spot_market_acct] || string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN (\n SELECT \n pcd.*\n FROM \n prices_chart_data pcd\n INNER JOIN (\n SELECT \n pcd2.market_acct,\n pcd2.interv,\n pcd2.price,\n pcd2.prices_type,\n LAG(pcd2.price) OVER w AS prev_price,\n LAG(pcd2.prices_type) OVER w AS prev_prices_type\n FROM prices_chart_data pcd2\n WINDOW w AS (PARTITION BY market_acct ORDER BY interv)\n ) changes ON changes.market_acct = pcd.market_acct \n AND changes.interv = pcd.interv\n WHERE \n (prev_price IS NULL\n OR changes.price != changes.prev_price\n OR changes.prices_type != changes.prev_prices_type)\n ) c ON c.market_acct = m.market_acct::text\n WHERE \n c.interv >= rp.created_at\n AND c.interv <= COALESCE(rp.completed_at, NOW())\n GROUP BY rp.proposal_acct, c.market_acct\n)\nSELECT DISTINCT ON (rp.proposal_acct)\n rp.dao_image::text,\n rp.proposal_title::text,\n COALESCE(pt.trade_count, 0)::numeric as trade_count,\n COALESCE(pt.volume_traded, 0)::numeric as volume_traded,\n rp.proposal_status::text,\n jsonb_build_object(\n 'spot', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = rp.spot_market_acct\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'pass', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[1]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'fail', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[2]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n )\n ) as chart_data\nFROM \n recent_proposals rp\n LEFT JOIN proposal_trades pt ON pt.proposal_acct = rp.proposal_acct\nORDER BY rp.proposal_acct, rp.created_at DESC;" + code: "WITH recent_proposals AS (\n SELECT DISTINCT ON (p.proposal_acct)\n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status as proposal_status,\n pd.title as proposal_title,\n d.dao_acct,\n dd.slug,\n d.base_acct as spot_market_acct,\n dd.image_url as dao_image,\n string_agg(m.market_acct::text, ',') as market_accts\n FROM \n proposals p\n INNER JOIN proposal_details pd ON pd.proposal_acct = p.proposal_acct\n INNER JOIN daos d ON d.dao_acct = p.dao_acct\n INNER JOIN dao_details dd ON dd.dao_id = d.dao_id\n INNER JOIN markets m ON m.proposal_acct = p.proposal_acct\n WHERE \n \tp.status != 'Pending'\n GROUP BY \n p.proposal_acct,\n p.created_at,\n p.completed_at,\n p.status,\n pd.title,\n d.dao_acct,\n dd.slug,\n d.base_acct,\n dd.image_url\n ORDER BY p.proposal_acct, p.created_at DESC\n LIMIT 4\n),\nproposal_trades AS (\n SELECT \n rp.proposal_acct,\n COUNT(*) as trade_count,\n SUM((t.base_amount / POW(10, tokens.decimals)) * t.quote_price) AS volume_traded\n FROM \n recent_proposals rp\n CROSS JOIN LATERAL unnest(string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN takes t ON t.market_acct = m.market_acct::text\n INNER JOIN orders o ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN daos d ON d.dao_acct = rp.dao_acct\n INNER JOIN tokens ON tokens.mint_acct = d.base_acct\n GROUP BY rp.proposal_acct\n),\nprice_data AS (\n SELECT DISTINCT ON (rp.proposal_acct, c.market_acct)\n c.market_acct,\n rp.proposal_acct,\n jsonb_build_object(\n 'intervals', jsonb_agg(\n jsonb_build_object(\n 'interv', c.interv,\n 'price', c.price,\n 'type', c.prices_type::text\n ) ORDER BY c.interv\n )\n ) as chart_data\n FROM recent_proposals rp\n CROSS JOIN LATERAL unnest(array[rp.spot_market_acct] || string_to_array(rp.market_accts, ',')) as m(market_acct)\n INNER JOIN (\n SELECT \n pcd.*\n FROM \n prices_chart_data pcd\n INNER JOIN (\n SELECT \n pcd2.market_acct,\n pcd2.interv,\n pcd2.price,\n pcd2.prices_type,\n LAG(pcd2.price) OVER w AS prev_price,\n LAG(pcd2.prices_type) OVER w AS prev_prices_type\n FROM prices_chart_data pcd2\n WINDOW w AS (PARTITION BY market_acct ORDER BY interv)\n ) changes ON changes.market_acct = pcd.market_acct \n AND changes.interv = pcd.interv\n WHERE \n (prev_price IS NULL\n OR changes.price != changes.prev_price\n OR changes.prices_type != changes.prev_prices_type)\n ) c ON c.market_acct = m.market_acct::text\n WHERE \n c.interv >= rp.created_at\n AND c.interv <= COALESCE(rp.completed_at, NOW())\n GROUP BY rp.proposal_acct, c.market_acct\n)\nSELECT DISTINCT ON (rp.proposal_acct)\n rp.dao_image::text,\n rp.proposal_title::text,\n rp.proposal_acct::text AS proposal_account,\n rp.slug::text AS dao_slug,\n COALESCE(pt.trade_count, 0)::numeric as trade_count,\n COALESCE(pt.volume_traded, 0)::numeric as volume_traded,\n rp.proposal_status::text,\n jsonb_build_object(\n 'spot', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = rp.spot_market_acct\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'pass', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[1]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n ),\n 'fail', COALESCE(\n (SELECT chart_data\n FROM price_data pd2\n WHERE pd2.market_acct = (string_to_array(rp.market_accts, ','))[2]\n AND pd2.proposal_acct = rp.proposal_acct\n LIMIT 1),\n jsonb_build_object('intervals', '[]'::jsonb)\n )\n ) as chart_data\nFROM \n recent_proposals rp\n LEFT JOIN proposal_trades pt ON pt.proposal_acct = rp.proposal_acct\nORDER BY rp.proposal_acct, rp.created_at DESC;" returns: website_latest_four_proposals root_field_name: latest_finished_proposals - arguments: diff --git a/packages/hasura/metadata/query_collections.yaml b/packages/hasura/metadata/query_collections.yaml index 4c38719f..707a289b 100644 --- a/packages/hasura/metadata/query_collections.yaml +++ b/packages/hasura/metadata/query_collections.yaml @@ -46,5 +46,7 @@ volume_traded proposal_status chart_data + proposal_account + dao_slug } } From 38d3e0db0783c2e76133afcf75480bf81482c0a6 Mon Sep 17 00:00:00 2001 From: Kollan House Date: Mon, 18 Nov 2024 11:55:39 -0800 Subject: [PATCH 27/29] fix: sync metadata --- packages/hasura/metadata/databases/databases.yaml | 2 +- .../hasura/metadata/databases/futarchy/tables/public_takes.yaml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/hasura/metadata/databases/databases.yaml b/packages/hasura/metadata/databases/databases.yaml index 9a3c3fdb..09133119 100644 --- a/packages/hasura/metadata/databases/databases.yaml +++ b/packages/hasura/metadata/databases/databases.yaml @@ -362,4 +362,4 @@ code: "WITH base_trades AS (\n SELECT \n t.market_acct,\n o.actor_acct,\n (t.base_amount / POW(10, tokens.decimals)) * t.quote_price AS trade_volume,\n dd.slug,\n m.proposal_acct,\n COUNT(*) OVER () as total_takes -- Count all takes that match our filters\n FROM \n takes t\n INNER JOIN orders o \n ON o.order_tx_sig = t.order_tx_sig\n AND o.market_acct IS NOT NULL \n AND o.quote_price > 0\n INNER JOIN transactions tx \n ON tx.tx_sig = o.order_tx_sig\n AND tx.failed IS FALSE\n INNER JOIN markets m \n ON m.market_acct = o.market_acct\n INNER JOIN proposals p \n ON p.proposal_acct = m.proposal_acct\n INNER JOIN daos d \n ON d.dao_acct = p.dao_acct\n INNER JOIN tokens \n ON tokens.mint_acct = d.base_acct\n INNER JOIN dao_details dd \n ON dd.dao_id = d.dao_id\n),\naggregated_stats AS (\n SELECT \n COUNT(DISTINCT actor_acct) AS unique_trader_count,\n COUNT(DISTINCT proposal_acct) AS proposal_count,\n COUNT(DISTINCT market_acct) AS market_count,\n SUM(trade_volume) AS total_volume,\n MAX(total_takes) AS total_trades, -- Use MAX since the value is the same for all rows\n COUNT(DISTINCT slug) AS dao_count\n FROM base_trades\n)\nSELECT \n total_volume::numeric AS volume_traded,\n NULL::numeric AS profits_earned,\n unique_trader_count::numeric AS unique_traders,\n dao_count::numeric AS number_of_daos,\n proposal_count::numeric AS total_proposals,\n market_count::numeric AS total_markets,\n total_trades::numeric\nFROM aggregated_stats;" returns: website_stats root_field_name: website_stats - tables: "!include futarchy/tables/tables.yaml" \ No newline at end of file + tables: "!include futarchy/tables/tables.yaml" diff --git a/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml b/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml index 27736448..74a1515d 100644 --- a/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml +++ b/packages/hasura/metadata/databases/futarchy/tables/public_takes.yaml @@ -29,4 +29,3 @@ select_permissions: filter: {} allow_aggregations: true comment: "" - From 6a0565b672bcaa93d52bde1c3ec59f01dbdcddac Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 18 Nov 2024 16:32:34 -0500 Subject: [PATCH 28/29] fix: downgrading futarchy version --- packages/indexer/package.json | 2 +- pnpm-lock.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/indexer/package.json b/packages/indexer/package.json index c111aea3..0cce1384 100644 --- a/packages/indexer/package.json +++ b/packages/indexer/package.json @@ -11,7 +11,7 @@ "@coral-xyz/anchor": "^0.29.0", "@debridge-finance/solana-transaction-parser": "^2.0.1", "@lukasdeco/prom-client": "^15.1.4", - "@metadaoproject/futarchy": "^0.4.0-alpha.18", + "@metadaoproject/futarchy": "^0.4.0-alpha.21", "@metadaoproject/futarchy-sdk": "4.0.0-alpha.31", "@metadaoproject/indexer-db": "workspace:*", "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 264bc2e1..975f9cf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,7 +77,7 @@ importers: specifier: ^15.1.4 version: 15.1.4 '@metadaoproject/futarchy': - specifier: ^0.4.0-alpha.18 + specifier: ^0.4.0-alpha.21 version: 0.4.0-alpha.21(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@metadaoproject/futarchy-sdk': specifier: 4.0.0-alpha.31 From 00462fd74fe2ca7423b2484b130948d525cab4fe Mon Sep 17 00:00:00 2001 From: advaith101 Date: Mon, 18 Nov 2024 16:35:11 -0500 Subject: [PATCH 29/29] fix: pnpm version --- packages/indexer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/indexer/Dockerfile b/packages/indexer/Dockerfile index 29b666ef..f7f978a6 100644 --- a/packages/indexer/Dockerfile +++ b/packages/indexer/Dockerfile @@ -13,7 +13,7 @@ RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk RUN apk add --no-cache git EXPOSE 8080 -RUN corepack prepare pnpm@9.11.0 --activate +RUN corepack prepare pnpm@9.12.1 --activate RUN corepack enable ENV REPO_DIR /home/indexer/futarchy-indexer RUN mkdir -p $REPO_DIR