117 lines
5.6 KiB
TypeScript
117 lines
5.6 KiB
TypeScript
import {
|
|
bigint,
|
|
boolean,
|
|
decimal,
|
|
int,
|
|
mysqlEnum,
|
|
mysqlTable,
|
|
text,
|
|
timestamp,
|
|
varchar,
|
|
} from "drizzle-orm/mysql-core";
|
|
|
|
/**
|
|
* Core user table backing auth flow.
|
|
* Extend this file with additional tables as your product grows.
|
|
* Columns use camelCase to match both database fields and generated types.
|
|
*/
|
|
export const users = mysqlTable("users", {
|
|
/**
|
|
* Surrogate primary key. Auto-incremented numeric value managed by the database.
|
|
* Use this for relations between tables.
|
|
*/
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Manus OAuth identifier (openId) returned from the OAuth callback. Unique per user. */
|
|
openId: varchar("openId", { length: 64 }).notNull().unique(),
|
|
name: text("name"),
|
|
email: varchar("email", { length: 320 }),
|
|
loginMethod: varchar("loginMethod", { length: 64 }),
|
|
role: mysqlEnum("role", ["user", "admin"]).default("user").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
lastSignedIn: timestamp("lastSignedIn").defaultNow().notNull(),
|
|
});
|
|
|
|
export type User = typeof users.$inferSelect;
|
|
export type InsertUser = typeof users.$inferInsert;
|
|
|
|
// TRC20 purchase records — monitored from TRON network
|
|
export const trc20Purchases = mysqlTable("trc20_purchases", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
txHash: varchar("txHash", { length: 128 }).notNull().unique(),
|
|
fromAddress: varchar("fromAddress", { length: 64 }).notNull(),
|
|
usdtAmount: decimal("usdtAmount", { precision: 20, scale: 6 }).notNull(),
|
|
xicAmount: decimal("xicAmount", { precision: 30, scale: 6 }).notNull(),
|
|
blockNumber: bigint("blockNumber", { mode: "number" }),
|
|
status: mysqlEnum("status", ["pending", "confirmed", "distributed", "failed"])
|
|
.default("pending")
|
|
.notNull(),
|
|
distributedAt: timestamp("distributedAt"),
|
|
distributeTxHash: varchar("distributeTxHash", { length: 128 }),
|
|
evmAddress: varchar("evmAddress", { length: 64 }), // EVM address provided by buyer for token distribution
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Trc20Purchase = typeof trc20Purchases.$inferSelect;
|
|
export type InsertTrc20Purchase = typeof trc20Purchases.$inferInsert;
|
|
|
|
// Presale stats cache — refreshed from on-chain every 60 seconds
|
|
export const presaleStatsCache = mysqlTable("presale_stats_cache", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
chain: varchar("chain", { length: 16 }).notNull(),
|
|
usdtRaised: decimal("usdtRaised", { precision: 30, scale: 6 }).default("0"),
|
|
tokensSold: decimal("tokensSold", { precision: 30, scale: 6 }).default("0"),
|
|
weiRaised: decimal("weiRaised", { precision: 30, scale: 6 }).default("0"),
|
|
lastUpdated: timestamp("lastUpdated").defaultNow().notNull(),
|
|
});
|
|
|
|
export type PresaleStatsCache = typeof presaleStatsCache.$inferSelect;
|
|
|
|
// TRC20 purchase intents — user pre-registers EVM address before sending USDT
|
|
// When TRC20 Monitor detects a TX from the same TRON address, it auto-fills evmAddress
|
|
export const trc20Intents = mysqlTable("trc20_intents", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
tronAddress: varchar("tronAddress", { length: 64 }), // TRON sender address (optional, for matching)
|
|
evmAddress: varchar("evmAddress", { length: 64 }).notNull(), // BSC/ETH address to receive XIC
|
|
expectedUsdt: decimal("expectedUsdt", { precision: 20, scale: 6 }), // Expected USDT amount (optional)
|
|
matched: boolean("matched").default(false).notNull(), // Whether this intent has been matched to a purchase
|
|
matchedPurchaseId: int("matchedPurchaseId"), // ID of matched trc20_purchases record
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type Trc20Intent = typeof trc20Intents.$inferSelect;
|
|
export type InsertTrc20Intent = typeof trc20Intents.$inferInsert;
|
|
|
|
// Presale configuration — editable by admin from the admin panel
|
|
// Each row is a key-value pair (e.g. presaleEndDate, tokenPrice, hardCap, etc.)
|
|
export const presaleConfig = mysqlTable("presale_config", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
key: varchar("key", { length: 64 }).notNull().unique(),
|
|
value: text("value").notNull(),
|
|
label: varchar("label", { length: 128 }), // Human-readable label for admin UI
|
|
description: varchar("description", { length: 256 }), // Help text
|
|
type: varchar("type", { length: 32 }).default("text"), // text | number | date | boolean | url
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type PresaleConfig = typeof presaleConfig.$inferSelect;
|
|
export type InsertPresaleConfig = typeof presaleConfig.$inferInsert;
|
|
// Cross-chain bridge orders — recorded when user completes a Li.Fi cross-chain purchase
|
|
export const bridgeOrders = mysqlTable("bridge_orders", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
txHash: varchar("txHash", { length: 128 }).notNull().unique(),
|
|
walletAddress: varchar("walletAddress", { length: 64 }).notNull(),
|
|
fromChainId: int("fromChainId").notNull(),
|
|
fromToken: varchar("fromToken", { length: 32 }).notNull(),
|
|
fromAmount: decimal("fromAmount", { precision: 30, scale: 6 }).notNull(),
|
|
toChainId: int("toChainId").notNull(),
|
|
toToken: varchar("toToken", { length: 32 }).notNull(),
|
|
toAmount: decimal("toAmount", { precision: 30, scale: 6 }).notNull(),
|
|
status: mysqlEnum("status", ["pending", "completed", "failed"]).default("completed").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type BridgeOrder = typeof bridgeOrders.$inferSelect;
|
|
export type InsertBridgeOrder = typeof bridgeOrders.$inferInsert;
|