apps/keeper/src/jobs/common.ts
What the vault owes, from the ledger. Shown whole, as it was in the repository when this site was built. Line numbers link: add #L12 to the address.
apps/keeper/src/jobs/common.ts99 lines
1// Helpers shared by the Solana jobs: the coins this keeper handles and typed settings.2import { eq, sql } from 'drizzle-orm';3import { coins, collections } from '@solary/db';4import { getSetting, type JobCtx } from '../ctx';5import type { CoinRef } from '../solana/adapter';6 7export interface CoinRow {8 mint: string;9 name: string;10 symbol: string;11 collection: string | null;12 collectionName: string | null;13 collectionStatus: string | null;14 deployer: string;15 holdersBps: number;16 creatorBps: number;17 buybackBps: number;18 platformBps: number;19 official: boolean;20 status: 'active' | 'paused' | 'alert';21 graduated: boolean;22 accIndex: string;23 holdersLamports: bigint;24 holdersPaidLamports: bigint;25 lastClaimAt: Date | null;26 lastPayoutAt: Date | null;27 marketAt: Date | null;28 createdAt: Date;29}30 31/** Fake mode handles demo coins (FAKE… mints) only; real mode never touches them. */32export const handles = (ctx: Pick<JobCtx, 'sol'>, mint: string) => (ctx.sol.mode === 'fake') === mint.startsWith('FAKE');33 34export async function keeperCoins(ctx: JobCtx): Promise<CoinRow[]> {35 const rows = await ctx.db36 .select({37 mint: coins.mint,38 name: coins.name,39 symbol: coins.symbol,40 collection: coins.collection,41 collectionName: collections.name,42 collectionStatus: collections.status,43 deployer: coins.deployer,44 holdersBps: coins.holdersBps,45 creatorBps: coins.creatorBps,46 buybackBps: coins.buybackBps,47 platformBps: coins.platformBps,48 official: coins.official,49 status: coins.status,50 graduated: coins.graduated,51 accIndex: coins.accIndex,52 holdersLamports: coins.holdersLamports,53 holdersPaidLamports: coins.holdersPaidLamports,54 lastClaimAt: coins.lastClaimAt,55 lastPayoutAt: coins.lastPayoutAt,56 marketAt: coins.marketAt,57 createdAt: coins.createdAt,58 })59 .from(coins)60 .leftJoin(collections, eq(collections.address, coins.collection))61 .orderBy(coins.createdAt);62 return rows.filter((r) => handles(ctx, r.mint));63}64 65export const coinRef = (c: CoinRow): CoinRef => ({ mint: c.mint, creatorBps: c.creatorBps, deployer: c.deployer, graduated: c.graduated });66 67export async function settingBig(ctx: JobCtx, key: string, fallback: bigint): Promise<bigint> {68 const v = await getSetting<string | number | null>(ctx.db, key, null);69 try {70 return v === null ? fallback : BigInt(v);71 } catch {72 return fallback;73 }74}75 76export async function settingNum(ctx: JobCtx, key: string, fallback: number): Promise<number> {77 const v = await getSetting<string | number | null>(ctx.db, key, null);78 const n = Number(v);79 return v === null || !Number.isFinite(n) ? fallback : n;80}81 82/** What the vault owes, from the ledger: unpaid holder rewards, unspent buyback, unswept platform income. */83export async function vaultObligations(ctx: JobCtx): Promise<{ holders: bigint; buyback: bigint; platform: bigint; total: bigint }> {84 const fake = ctx.sol.mode === 'fake';85 const like = fake ? sql`LIKE 'FAKE%'` : sql`NOT LIKE 'FAKE%'`;86 const [r] = (await ctx.db.execute(sql`87 SELECT88 COALESCE((SELECT SUM(holders_lamports - holders_paid_lamports) FROM coins WHERE mint ${like}), 0)::text AS holders,89 COALESCE((SELECT SUM(buyback_lamports) FROM coins WHERE mint ${like}), 0)::text AS buyback_in,90 COALESCE((SELECT SUM(lamports) FROM buybacks WHERE COALESCE(buy_tx, '') ${like}), 0)::text AS buyback_out,91 COALESCE((SELECT SUM(platform_lamports) FROM coins WHERE mint ${like}), 0)::text AS platform_in,92 COALESCE((SELECT SUM(lamports) FROM sweeps WHERE COALESCE(tx, '') ${like}), 0)::text AS platform_out93 `)) as unknown as Array<Record<string, string>>;94 const holders = BigInt(r!.holders!);95 const buyback = BigInt(r!.buyback_in!) - BigInt(r!.buyback_out!);96 const platform = BigInt(r!.platform_in!) - BigInt(r!.platform_out!);97 const pos = (x: bigint) => (x > 0n ? x : 0n);98 return { holders: pos(holders), buyback: pos(buyback), platform: pos(platform), total: pos(holders) + pos(buyback) + pos(platform) };99}