init: 初始化 AssetX 项目仓库
包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、 antdesign(管理后台)、landingpage(营销落地页)、 数据库 SQL 和配置文件。
This commit is contained in:
205
webapp-back/models/asset.go
Normal file
205
webapp-back/models/asset.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Asset represents the assets table
|
||||
type Asset struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetCode string `gorm:"size:20;not null;unique;index" json:"asset_code"`
|
||||
Name string `gorm:"size:255;not null" json:"name"`
|
||||
Subtitle string `gorm:"type:text" json:"subtitle"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
TokenSymbol string `gorm:"size:20" json:"token_symbol"`
|
||||
Decimals int `gorm:"default:18" json:"decimals"`
|
||||
ChainID int `gorm:"default:97" json:"chain_id"`
|
||||
ContractAddress string `gorm:"size:42" json:"contract_address"`
|
||||
DeployBlock *uint64 `json:"deploy_block"`
|
||||
Category string `gorm:"size:100" json:"category"`
|
||||
CategoryColor string `gorm:"size:50" json:"category_color"`
|
||||
IconURL string `gorm:"type:text" json:"icon_url"`
|
||||
UnderlyingAssets string `gorm:"size:255" json:"underlying_assets"`
|
||||
TargetAPY float64 `gorm:"type:decimal(10,2)" json:"target_apy"`
|
||||
PoolCapUSD float64 `gorm:"type:decimal(30,2)" json:"pool_cap_usd"`
|
||||
RiskLevel int `json:"risk_level"`
|
||||
RiskLabel string `gorm:"size:50" json:"risk_label"`
|
||||
TokenRole string `gorm:"size:20;default:'product'" json:"token_role"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
IsFeatured bool `gorm:"default:false" json:"is_featured"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Asset) TableName() string {
|
||||
return "assets"
|
||||
}
|
||||
|
||||
// AssetPerformance represents the asset_performance table
|
||||
type AssetPerformance struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index" json:"asset_id"`
|
||||
CurrentAPY float64 `gorm:"type:decimal(10,2)" json:"current_apy"`
|
||||
TVLUSD float64 `gorm:"type:decimal(30,2)" json:"tvl_usd"`
|
||||
TotalInvestedUSD float64 `gorm:"type:decimal(30,2)" json:"total_invested_usd"`
|
||||
InvestorCount int `gorm:"default:0" json:"investor_count"`
|
||||
CumulativeYieldUSD float64 `gorm:"type:decimal(30,2)" json:"cumulative_yield_usd"`
|
||||
Yield24hUSD float64 `gorm:"type:decimal(30,2)" json:"yield_24h_usd"`
|
||||
PoolCapacityPercent float64 `gorm:"type:decimal(10,4)" json:"pool_capacity_percent"`
|
||||
CirculatingSupply float64 `gorm:"type:decimal(30,18)" json:"circulating_supply"`
|
||||
YTPrice float64 `gorm:"column:yt_price;type:decimal(30,18);default:0" json:"yt_price"`
|
||||
Volume24hUSD float64 `gorm:"column:volume_24h_usd;type:decimal(30,2);default:0" json:"volume_24h_usd"`
|
||||
SnapshotDate time.Time `gorm:"not null" json:"snapshot_date"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (AssetPerformance) TableName() string {
|
||||
return "asset_performance"
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ProductResponse is the response format for fund market products
|
||||
type ProductResponse struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
TokenSymbol string `json:"tokenSymbol"`
|
||||
Decimals int `json:"decimals"`
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
ChainID int `json:"chainId"`
|
||||
TokenRole string `json:"token_role"`
|
||||
Category string `json:"category"`
|
||||
CategoryColor string `json:"categoryColor"`
|
||||
IconURL string `json:"iconUrl"`
|
||||
YieldAPY string `json:"yieldAPY"`
|
||||
PoolCap string `json:"poolCap"`
|
||||
Risk string `json:"risk"`
|
||||
RiskLevel int `json:"riskLevel"`
|
||||
CirculatingSupply string `json:"circulatingSupply"`
|
||||
PoolCapacityPercent float64 `json:"poolCapacityPercent"`
|
||||
}
|
||||
|
||||
// StatsResponse is the response format for fund market stats
|
||||
type StatsResponse struct {
|
||||
Label string `json:"label"`
|
||||
Value string `json:"value"`
|
||||
Change string `json:"change"`
|
||||
IsPositive bool `json:"isPositive"`
|
||||
}
|
||||
|
||||
// AssetCustody represents the asset_custody table
|
||||
type AssetCustody struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index" json:"asset_id"`
|
||||
CustodianName string `gorm:"size:255" json:"custodian_name"`
|
||||
CustodianAddress string `gorm:"type:text" json:"custodian_address"`
|
||||
CustodianLicense string `gorm:"size:255" json:"custodian_license"`
|
||||
CustodyType string `gorm:"size:100" json:"custody_type"`
|
||||
CustodyLocation string `gorm:"size:255" json:"custody_location"`
|
||||
AuditorName string `gorm:"size:255" json:"auditor_name"`
|
||||
LastAuditDate NullTime `json:"last_audit_date"`
|
||||
AuditReportURL string `gorm:"type:text" json:"audit_report_url"`
|
||||
AdditionalInfo string `gorm:"type:json" json:"additional_info"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (AssetCustody) TableName() string {
|
||||
return "asset_custody"
|
||||
}
|
||||
|
||||
// AssetAuditReport represents the asset_audit_reports table
|
||||
type AssetAuditReport struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index" json:"asset_id"`
|
||||
ReportType string `gorm:"size:50;not null" json:"report_type"`
|
||||
ReportTitle string `gorm:"size:255;not null" json:"report_title"`
|
||||
ReportDate time.Time `gorm:"not null" json:"report_date"`
|
||||
ReportURL string `gorm:"type:text" json:"report_url"`
|
||||
AuditorName string `gorm:"size:255" json:"auditor_name"`
|
||||
Summary string `gorm:"type:text" json:"summary"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
DisplayOrder int `gorm:"default:0" json:"display_order"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (AssetAuditReport) TableName() string {
|
||||
return "asset_audit_reports"
|
||||
}
|
||||
|
||||
// ProductDetailResponse is the detailed response for a single product
|
||||
type ProductDetailResponse struct {
|
||||
// Basic Info
|
||||
ID int `json:"id"`
|
||||
AssetCode string `json:"assetCode"`
|
||||
Name string `json:"name"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Description string `json:"description"`
|
||||
TokenSymbol string `json:"tokenSymbol"`
|
||||
Decimals int `json:"decimals"`
|
||||
|
||||
// Investment Parameters
|
||||
UnderlyingAssets string `json:"underlyingAssets"`
|
||||
PoolCapUSD float64 `json:"poolCapUsd"`
|
||||
RiskLevel int `json:"riskLevel"`
|
||||
RiskLabel string `json:"riskLabel"`
|
||||
TargetAPY float64 `json:"targetApy"`
|
||||
|
||||
// Contract Info
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
ChainID int `json:"chainId"`
|
||||
|
||||
// Display Info
|
||||
Category string `json:"category"`
|
||||
CategoryColor string `json:"categoryColor"`
|
||||
IconURL string `json:"iconUrl"`
|
||||
|
||||
// Performance Data (from blockchain/database)
|
||||
CurrentAPY float64 `json:"currentApy"`
|
||||
TVLUSD float64 `json:"tvlUsd"`
|
||||
Volume24hUSD float64 `json:"volume24hUsd"`
|
||||
VolumeChangeVsAvg float64 `json:"volumeChangeVsAvg"`
|
||||
CirculatingSupply float64 `json:"circulatingSupply"`
|
||||
PoolCapacityPercent float64 `json:"poolCapacityPercent"`
|
||||
CurrentPrice float64 `json:"currentPrice"` // e.g., 1.04 USDC per token
|
||||
|
||||
// Custody Info
|
||||
Custody *CustodyInfo `json:"custody,omitempty"`
|
||||
|
||||
// Audit Reports
|
||||
AuditReports []AuditReportInfo `json:"auditReports"`
|
||||
|
||||
// Product Links
|
||||
ProductLinks []ProductLinkInfo `json:"productLinks"`
|
||||
}
|
||||
|
||||
// ProductLinkInfo represents a single product link item
|
||||
type ProductLinkInfo struct {
|
||||
LinkText string `json:"linkText"`
|
||||
LinkURL string `json:"linkUrl"`
|
||||
Description string `json:"description"`
|
||||
DisplayArea string `json:"displayArea"`
|
||||
DisplayOrder int `json:"displayOrder"`
|
||||
}
|
||||
|
||||
// CustodyInfo represents custody information
|
||||
type CustodyInfo struct {
|
||||
CustodianName string `json:"custodianName"`
|
||||
CustodyType string `json:"custodyType"`
|
||||
CustodyLocation string `json:"custodyLocation"`
|
||||
AuditorName string `json:"auditorName"`
|
||||
LastAuditDate string `json:"lastAuditDate"`
|
||||
AuditReportURL string `json:"auditReportUrl,omitempty"`
|
||||
AdditionalInfo map[string]interface{} `json:"additionalInfo,omitempty"`
|
||||
}
|
||||
|
||||
// AuditReportInfo represents audit report information
|
||||
type AuditReportInfo struct {
|
||||
ReportType string `json:"reportType"`
|
||||
ReportTitle string `json:"reportTitle"`
|
||||
ReportDate string `json:"reportDate"`
|
||||
AuditorName string `json:"auditorName"`
|
||||
Summary string `json:"summary"`
|
||||
ReportURL string `json:"reportUrl"`
|
||||
}
|
||||
22
webapp-back/models/collateral_buy.go
Normal file
22
webapp-back/models/collateral_buy.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// CollateralBuyRecord records each collateral purchase made by the buyer bot
|
||||
type CollateralBuyRecord struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
ChainID int `gorm:"index" json:"chain_id"`
|
||||
TxHash string `gorm:"size:66;uniqueIndex" json:"tx_hash"`
|
||||
BuyerAddr string `gorm:"size:42" json:"buyer_addr"`
|
||||
AssetAddr string `gorm:"size:42;index" json:"asset_addr"`
|
||||
AssetSymbol string `gorm:"size:50" json:"asset_symbol"`
|
||||
PaidAmount string `gorm:"size:78" json:"paid_amount"` // USDC paid, base units
|
||||
ReceivedAmount string `gorm:"size:78" json:"received_amount"` // collateral received, base units
|
||||
GasUsed uint64 `json:"gas_used"`
|
||||
BlockNumber uint64 `json:"block_number"`
|
||||
Status string `gorm:"size:20;default:'success'" json:"status"` // success / failed
|
||||
ErrorMessage string `gorm:"type:text" json:"error_message,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (CollateralBuyRecord) TableName() string { return "collateral_buy_records" }
|
||||
217
webapp-back/models/config.go
Normal file
217
webapp-back/models/config.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
// ALPSnapshot records periodic ALP pool stats for APR calculation
|
||||
type ALPSnapshot struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
PoolValue float64 `gorm:"type:decimal(30,18)" json:"pool_value"` // getAumInUsdy(true), 18 dec
|
||||
UsdySupply float64 `gorm:"type:decimal(30,18)" json:"usdy_supply"` // USDY.totalSupply(), 18 dec
|
||||
FeeSurplus float64 `gorm:"type:decimal(30,18)" json:"fee_surplus"` // poolValue - usdySupply
|
||||
ALPPrice float64 `gorm:"type:decimal(30,18)" json:"alp_price"` // getPrice(false), 30 dec
|
||||
SnapshotTime time.Time `gorm:"not null;index" json:"snapshot_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (ALPSnapshot) TableName() string {
|
||||
return "alp_snapshots"
|
||||
}
|
||||
|
||||
// APYSnapshot represents the apy_snapshots table
|
||||
type APYSnapshot struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index:idx_asset_time" json:"asset_id"`
|
||||
ChainID int `gorm:"not null" json:"chain_id"`
|
||||
ContractAddress string `gorm:"size:42" json:"contract_address"`
|
||||
APYValue float64 `gorm:"type:decimal(10,4)" json:"apy_value"`
|
||||
SupplyAPY float64 `gorm:"type:decimal(20,4)" json:"supply_apy"`
|
||||
BorrowAPY float64 `gorm:"type:decimal(20,4)" json:"borrow_apy"`
|
||||
TotalAssets float64 `gorm:"type:decimal(30,18)" json:"total_assets"`
|
||||
TotalSupply float64 `gorm:"type:decimal(30,18)" json:"total_supply"`
|
||||
Price float64 `gorm:"type:decimal(30,18)" json:"price"`
|
||||
SnapshotTime time.Time `gorm:"not null;index:idx_asset_time" json:"snapshot_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (APYSnapshot) TableName() string {
|
||||
return "apy_snapshots"
|
||||
}
|
||||
|
||||
// ProductLink represents the product_links table — per-asset links shown on the product detail page
|
||||
type ProductLink struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index" json:"asset_id"`
|
||||
LinkText string `gorm:"size:100;not null" json:"link_text"`
|
||||
LinkURL string `gorm:"type:text;not null" json:"link_url"`
|
||||
Description string `gorm:"size:500" json:"description"`
|
||||
DisplayArea string `gorm:"size:20;default:protocol" json:"display_area"`
|
||||
DisplayOrder int `gorm:"default:0" json:"display_order"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (ProductLink) TableName() string {
|
||||
return "product_links"
|
||||
}
|
||||
|
||||
// KLineData represents the kline_data table
|
||||
type KLineData struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AssetID uint `gorm:"not null;index:idx_asset_time" json:"asset_id"`
|
||||
ChainID int `gorm:"not null" json:"chain_id"`
|
||||
ContractAddress string `gorm:"size:42" json:"contract_address"`
|
||||
Timeframe string `gorm:"size:10;not null" json:"timeframe"`
|
||||
OpenTime time.Time `gorm:"not null;index:idx_asset_time" json:"open_time"`
|
||||
CloseTime time.Time `gorm:"not null" json:"close_time"`
|
||||
OpenPrice float64 `gorm:"type:decimal(30,18);not null" json:"open_price"`
|
||||
HighPrice float64 `gorm:"type:decimal(30,18);not null" json:"high_price"`
|
||||
LowPrice float64 `gorm:"type:decimal(30,18);not null" json:"low_price"`
|
||||
ClosePrice float64 `gorm:"type:decimal(30,18);not null" json:"close_price"`
|
||||
Volume float64 `gorm:"type:decimal(30,18)" json:"volume"`
|
||||
Trades int `json:"trades"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (KLineData) TableName() string {
|
||||
return "kline_data"
|
||||
}
|
||||
|
||||
|
||||
// PointsRule represents the points_rules table
|
||||
type PointsRule struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
RuleName string `gorm:"size:100;not null;unique" json:"rule_name"`
|
||||
RuleType string `gorm:"size:50;not null" json:"rule_type"`
|
||||
BasePoints int `gorm:"not null" json:"base_points"`
|
||||
Multiplier float64 `gorm:"type:decimal(10,4);default:1.0000" json:"multiplier"`
|
||||
Conditions string `gorm:"type:json" json:"conditions"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
ValidFrom NullTime `json:"valid_from"`
|
||||
ValidUntil NullTime `json:"valid_until"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
Priority int `gorm:"default:0" json:"priority"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (PointsRule) TableName() string {
|
||||
return "points_rules"
|
||||
}
|
||||
|
||||
// Role represents the roles table
|
||||
type Role struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
RoleName string `gorm:"size:50;not null;unique" json:"role_name"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
Permissions string `gorm:"type:json" json:"permissions"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Role) TableName() string {
|
||||
return "roles"
|
||||
}
|
||||
|
||||
// UserRole represents the user_roles table
|
||||
type UserRole struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
UserID uint `gorm:"not null;uniqueIndex:uk_user_role" json:"user_id"`
|
||||
RoleID uint `gorm:"not null;uniqueIndex:uk_user_role" json:"role_id"`
|
||||
AssignedAt time.Time `gorm:"not null" json:"assigned_at"`
|
||||
AssignedBy uint `json:"assigned_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (UserRole) TableName() string {
|
||||
return "user_roles"
|
||||
}
|
||||
|
||||
// Session represents the sessions table
|
||||
type Session struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
UserID uint `gorm:"not null;index" json:"user_id"`
|
||||
SessionToken string `gorm:"size:255;not null;unique" json:"session_token"`
|
||||
WalletAddress string `gorm:"size:42;not null" json:"wallet_address"`
|
||||
SignMessage string `gorm:"type:text" json:"sign_message"`
|
||||
Signature string `gorm:"size:132" json:"signature"`
|
||||
SignatureHash string `gorm:"size:66" json:"signature_hash"`
|
||||
IPAddress string `gorm:"size:45" json:"ip_address"`
|
||||
UserAgent string `gorm:"type:text" json:"user_agent"`
|
||||
ExpiresAt *time.Time `gorm:"index" json:"expires_at"`
|
||||
LastActivityAt *time.Time `json:"last_activity_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (Session) TableName() string {
|
||||
return "sessions"
|
||||
}
|
||||
|
||||
// Transaction represents the transactions table
|
||||
type Transaction struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
UserID uint `gorm:"not null;index:idx_user_time" json:"user_id"`
|
||||
TxHash string `gorm:"size:66;not null;unique" json:"tx_hash"`
|
||||
ChainID int `gorm:"not null" json:"chain_id"`
|
||||
BlockNumber int64 `gorm:"not null" json:"block_number"`
|
||||
TxType string `gorm:"size:50;not null" json:"tx_type"`
|
||||
AssetID *uint `json:"asset_id"`
|
||||
FromAddress string `gorm:"size:42;not null" json:"from_address"`
|
||||
ToAddress string `gorm:"size:42;not null" json:"to_address"`
|
||||
Amount float64 `gorm:"type:decimal(30,18)" json:"amount"`
|
||||
TokenSymbol string `gorm:"size:20" json:"token_symbol"`
|
||||
GasUsed int64 `json:"gas_used"`
|
||||
GasPrice float64 `gorm:"type:decimal(30,18)" json:"gas_price"`
|
||||
Status string `gorm:"size:20;not null" json:"status"`
|
||||
ErrorMessage string `gorm:"type:text" json:"error_message"`
|
||||
Metadata string `gorm:"type:json" json:"metadata"`
|
||||
ConfirmedAt time.Time `gorm:"not null;index:idx_user_time" json:"confirmed_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (Transaction) TableName() string {
|
||||
return "transactions"
|
||||
}
|
||||
|
||||
// OperationLog represents the operation_logs table
|
||||
type OperationLog struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
UserID *uint `gorm:"index" json:"user_id"`
|
||||
OperationType string `gorm:"size:50;not null" json:"operation_type"`
|
||||
TargetType string `gorm:"size:50" json:"target_type"`
|
||||
TargetID *uint `json:"target_id"`
|
||||
Action string `gorm:"size:100;not null" json:"action"`
|
||||
Changes string `gorm:"type:json" json:"changes"`
|
||||
IPAddress string `gorm:"size:45" json:"ip_address"`
|
||||
UserAgent string `gorm:"type:text" json:"user_agent"`
|
||||
Status string `gorm:"size:20;not null" json:"status"`
|
||||
ErrorMessage string `gorm:"type:text" json:"error_message"`
|
||||
CreatedAt time.Time `gorm:"index" json:"created_at"`
|
||||
}
|
||||
|
||||
func (OperationLog) TableName() string {
|
||||
return "operation_logs"
|
||||
}
|
||||
|
||||
// UserActivity represents the user_activities table
|
||||
type UserActivity struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
UserID uint `gorm:"not null;index:idx_user_time" json:"user_id"`
|
||||
ActivityType string `gorm:"size:50;not null" json:"activity_type"`
|
||||
ActivityData string `gorm:"type:json" json:"activity_data"`
|
||||
AssetID *uint `json:"asset_id"`
|
||||
Amount float64 `gorm:"type:decimal(30,18)" json:"amount"`
|
||||
PointsEarned int `gorm:"default:0" json:"points_earned"`
|
||||
ReferenceType string `gorm:"size:50" json:"reference_type"`
|
||||
ReferenceID *uint `json:"reference_id"`
|
||||
IPAddress string `gorm:"size:45" json:"ip_address"`
|
||||
CreatedAt time.Time `gorm:"index:idx_user_time" json:"created_at"`
|
||||
}
|
||||
|
||||
func (UserActivity) TableName() string {
|
||||
return "user_activities"
|
||||
}
|
||||
43
webapp-back/models/holder.go
Normal file
43
webapp-back/models/holder.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// HolderSnapshot represents token holders data from blockchain
|
||||
type HolderSnapshot struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
HolderAddress string `gorm:"size:42;not null;index:idx_holder_token" json:"holder_address"`
|
||||
TokenType string `gorm:"size:50;not null;index:idx_holder_token,idx_token_time" json:"token_type"`
|
||||
TokenAddress string `gorm:"size:42;not null" json:"token_address"`
|
||||
Balance string `gorm:"type:varchar(78);not null" json:"balance"`
|
||||
ChainID int `gorm:"not null" json:"chain_id"`
|
||||
FirstSeen int64 `gorm:"not null" json:"first_seen"`
|
||||
LastUpdated int64 `gorm:"not null;index:idx_token_time" json:"last_updated"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (HolderSnapshot) TableName() string {
|
||||
return "holder_snapshots"
|
||||
}
|
||||
|
||||
// HolderStats represents aggregated statistics for each token type
|
||||
type HolderStats struct {
|
||||
TokenType string `json:"token_type"`
|
||||
HolderCount int `json:"holder_count"`
|
||||
TotalBalance string `json:"total_balance,omitempty"`
|
||||
}
|
||||
|
||||
// ScannerState persists scanner progress so it can resume after restart
|
||||
type ScannerState struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
ScannerType string `gorm:"column:scanner_type;not null;default:'holder';uniqueIndex:idx_chain_scanner"`
|
||||
ChainID int `gorm:"column:chain_id;uniqueIndex:idx_chain_scanner;not null"`
|
||||
LastScannedBlock uint64 `gorm:"column:last_scanned_block;not null;default:0"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at"`
|
||||
}
|
||||
|
||||
func (ScannerState) TableName() string {
|
||||
return "scanner_state"
|
||||
}
|
||||
17
webapp-back/models/known_borrower.go
Normal file
17
webapp-back/models/known_borrower.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// KnownBorrower stores every address that has ever interacted with the lending contract.
|
||||
// The liquidation bot checks ALL known borrowers for isLiquidatable on every tick,
|
||||
// so accounts whose health factor drops due to oracle price changes are still caught
|
||||
// even if they haven't had a recent on-chain transaction.
|
||||
type KnownBorrower struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
ChainID int `gorm:"uniqueIndex:idx_known_borrower" json:"chain_id"`
|
||||
Address string `gorm:"size:42;uniqueIndex:idx_known_borrower" json:"address"`
|
||||
FirstSeenAt time.Time `json:"first_seen_at"`
|
||||
LastSeenAt time.Time `json:"last_seen_at"`
|
||||
}
|
||||
|
||||
func (KnownBorrower) TableName() string { return "known_borrowers" }
|
||||
22
webapp-back/models/liquidation.go
Normal file
22
webapp-back/models/liquidation.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// LiquidationRecord stores each batch liquidation execution
|
||||
type LiquidationRecord struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
ChainID int `gorm:"index" json:"chain_id"`
|
||||
TxHash string `gorm:"size:66;uniqueIndex" json:"tx_hash"`
|
||||
LiquidatorAddr string `gorm:"size:42" json:"liquidator_addr"`
|
||||
AccountCount int `json:"account_count"`
|
||||
Accounts string `gorm:"type:text" json:"accounts"` // JSON array of addresses
|
||||
GasUsed uint64 `json:"gas_used"`
|
||||
BlockNumber uint64 `json:"block_number"`
|
||||
Status string `gorm:"size:20;default:'success'" json:"status"` // success / failed
|
||||
ErrorMessage string `gorm:"type:text" json:"error_message,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (LiquidationRecord) TableName() string {
|
||||
return "liquidation_records"
|
||||
}
|
||||
67
webapp-back/models/nulltime.go
Normal file
67
webapp-back/models/nulltime.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NullTime wraps *time.Time with custom JSON and GORM handling:
|
||||
// - JSON marshal: nil → "1970-01-01T00:00:00Z", non-nil → RFC3339
|
||||
// - JSON unmarshal: null / "" / "1970-01-01..." → nil (stored as NULL in DB)
|
||||
// - GORM Scan/Value: nil ↔ NULL column
|
||||
type NullTime struct {
|
||||
Time *time.Time
|
||||
}
|
||||
|
||||
func (nt NullTime) MarshalJSON() ([]byte, error) {
|
||||
if nt.Time == nil {
|
||||
return []byte(`"1970-01-01T00:00:00Z"`), nil
|
||||
}
|
||||
return json.Marshal(nt.Time.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
func (nt *NullTime) UnmarshalJSON(data []byte) error {
|
||||
if string(data) == "null" {
|
||||
nt.Time = nil
|
||||
return nil
|
||||
}
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
if s == "" || strings.HasPrefix(s, "1970-01-01") {
|
||||
nt.Time = nil
|
||||
return nil
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nt.Time = &t
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements driver.Valuer so GORM writes NULL for nil.
|
||||
func (nt NullTime) Value() (driver.Value, error) {
|
||||
if nt.Time == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return *nt.Time, nil
|
||||
}
|
||||
|
||||
// Scan implements sql.Scanner so GORM reads NULL as nil.
|
||||
func (nt *NullTime) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
nt.Time = nil
|
||||
return nil
|
||||
}
|
||||
t, ok := value.(time.Time)
|
||||
if !ok {
|
||||
nt.Time = nil
|
||||
return nil
|
||||
}
|
||||
nt.Time = &t
|
||||
return nil
|
||||
}
|
||||
262
webapp-back/models/points.go
Normal file
262
webapp-back/models/points.go
Normal file
@@ -0,0 +1,262 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Season represents the seasons table
|
||||
type Season struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
SeasonNumber int `gorm:"not null;unique;index" json:"season_number"`
|
||||
SeasonName string `gorm:"size:100;not null" json:"season_name"`
|
||||
StartTime time.Time `gorm:"not null" json:"start_time"`
|
||||
EndTime time.Time `gorm:"not null" json:"end_time"`
|
||||
Status string `gorm:"size:20;default:'upcoming'" json:"status"` // upcoming, active, ended
|
||||
TotalRewards float64 `gorm:"type:decimal(30,2)" json:"total_rewards"`
|
||||
Multiplier float64 `gorm:"type:decimal(10,4);default:1.0000" json:"multiplier"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Season) TableName() string {
|
||||
return "seasons"
|
||||
}
|
||||
|
||||
// VIPTier represents the vip_tiers table
|
||||
type VIPTier struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
TierName string `gorm:"size:50;not null" json:"tier_name"`
|
||||
TierLevel int `gorm:"not null;unique;index" json:"tier_level"`
|
||||
MinPoints int64 `gorm:"not null;index" json:"min_points"`
|
||||
MaxPoints *int64 `json:"max_points"`
|
||||
Multiplier float64 `gorm:"type:decimal(10,4);default:1.0000" json:"multiplier"`
|
||||
Perks string `gorm:"type:json" json:"perks"`
|
||||
Icon string `gorm:"size:255" json:"icon"`
|
||||
Color string `gorm:"size:50" json:"color"`
|
||||
DisplayOrder int `gorm:"default:0" json:"display_order"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (VIPTier) TableName() string {
|
||||
return "vip_tiers"
|
||||
}
|
||||
|
||||
// UserTeam represents the user_teams table
|
||||
type UserTeam struct {
|
||||
WalletAddress string `gorm:"primaryKey;size:42" json:"wallet_address"`
|
||||
TeamTVLUSD float64 `gorm:"type:decimal(30,2);default:0.00" json:"team_tvl_usd"`
|
||||
TeamTargetTVLUSD float64 `gorm:"type:decimal(30,2);default:10000000.00" json:"team_target_tvl_usd"`
|
||||
TeamMembersCount int `gorm:"default:0" json:"team_members_count"`
|
||||
WhalesCount int `gorm:"default:0" json:"whales_count"`
|
||||
WhalesTarget int `gorm:"default:3" json:"whales_target"`
|
||||
TradersCount int `gorm:"default:0" json:"traders_count"`
|
||||
TradersTarget int `gorm:"default:3" json:"traders_target"`
|
||||
UsersCount int `gorm:"default:0" json:"users_count"`
|
||||
UsersTarget int `gorm:"default:3" json:"users_target"`
|
||||
LastCalculatedAt *time.Time `json:"last_calculated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (UserTeam) TableName() string {
|
||||
return "user_teams"
|
||||
}
|
||||
|
||||
// UserPointsSummary represents the user_points_summary table
|
||||
type UserPointsSummary struct {
|
||||
WalletAddress string `gorm:"primaryKey;size:42" json:"wallet_address"`
|
||||
TotalPoints int64 `gorm:"default:0" json:"total_points"`
|
||||
HoldingPoints int64 `gorm:"default:0" json:"holding_points"`
|
||||
LpPoints int64 `gorm:"default:0" json:"lp_points"`
|
||||
LendingPoints int64 `gorm:"default:0" json:"lending_points"`
|
||||
TradingPoints int64 `gorm:"default:0" json:"trading_points"`
|
||||
InvitationPoints int64 `gorm:"default:0" json:"invitation_points"`
|
||||
BonusPoints int64 `gorm:"default:0" json:"bonus_points"`
|
||||
GlobalRank *int `json:"global_rank"`
|
||||
SeasonRank *int `json:"season_rank"`
|
||||
CurrentSeason int `gorm:"default:1" json:"current_season"`
|
||||
TotalTrades int `gorm:"default:0" json:"total_trades"`
|
||||
TotalHoldingDays int `gorm:"default:0" json:"total_holding_days"`
|
||||
TotalInvites int `gorm:"default:0" json:"total_invites"`
|
||||
LastCalculatedAt *time.Time `json:"last_calculated_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (UserPointsSummary) TableName() string {
|
||||
return "user_points_summary"
|
||||
}
|
||||
|
||||
// UserPointsRecord represents the user_points_records table
|
||||
type UserPointsRecord struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
WalletAddress string `gorm:"size:42;not null;index" json:"wallet_address"`
|
||||
PointsChange int `gorm:"not null" json:"points_change"`
|
||||
PointsBefore int `gorm:"not null" json:"points_before"`
|
||||
PointsAfter int `gorm:"not null" json:"points_after"`
|
||||
SourceType string `gorm:"size:50;not null" json:"source_type"`
|
||||
MultiplierApplied float64 `gorm:"type:decimal(10,4);default:1.0000" json:"multiplier_applied"`
|
||||
SourceID *uint `json:"source_id"`
|
||||
RuleID *uint `json:"rule_id"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
Metadata string `gorm:"type:json" json:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (UserPointsRecord) TableName() string {
|
||||
return "user_points_records"
|
||||
}
|
||||
|
||||
// Invitation represents the invitations table
|
||||
type Invitation struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
ReferrerWallet string `gorm:"size:42;not null;index" json:"referrer_wallet"`
|
||||
RefereeWallet string `gorm:"size:42;not null;unique;index" json:"referee_wallet"`
|
||||
InviteCode string `gorm:"size:20;not null" json:"invite_code"`
|
||||
BindSignature string `gorm:"type:text" json:"bind_signature"`
|
||||
BindHash string `gorm:"size:66" json:"bind_hash"`
|
||||
Status string `gorm:"size:50;default:'active'" json:"status"`
|
||||
ReferrerRewardPoints int `gorm:"default:0" json:"referrer_reward_points"`
|
||||
RefereeRewardPoints int `gorm:"default:0" json:"referee_reward_points"`
|
||||
BoundAt time.Time `gorm:"not null" json:"bound_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (Invitation) TableName() string {
|
||||
return "invitations"
|
||||
}
|
||||
|
||||
// InviteCode represents the invite_codes table
|
||||
type InviteCode struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
WalletAddress string `gorm:"size:42;not null;unique;index" json:"wallet_address"`
|
||||
Code string `gorm:"size:20;not null;unique;index" json:"code"`
|
||||
MaxUses int `gorm:"default:-1" json:"max_uses"` // -1 = unlimited
|
||||
UsedCount int `gorm:"default:0" json:"used_count"`
|
||||
ExpiresAt NullTime `json:"expires_at"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (InviteCode) TableName() string {
|
||||
return "invite_codes"
|
||||
}
|
||||
|
||||
// =====================
|
||||
// Response DTOs
|
||||
// =====================
|
||||
|
||||
// DashboardResponse is the response for GET /api/points/dashboard
|
||||
type DashboardResponse struct {
|
||||
TotalPoints int64 `json:"totalPoints"`
|
||||
GlobalRank int `json:"globalRank"`
|
||||
TopPercentage string `json:"topPercentage"`
|
||||
MemberTier string `json:"memberTier"`
|
||||
VIPLevel int `json:"vipLevel"`
|
||||
PointsToNextTier int64 `json:"pointsToNextTier"`
|
||||
NextTier string `json:"nextTier"`
|
||||
Season SeasonInfo `json:"season"`
|
||||
}
|
||||
|
||||
// SeasonInfo contains season information
|
||||
type SeasonInfo struct {
|
||||
SeasonNumber int `json:"seasonNumber"`
|
||||
SeasonName string `json:"seasonName"`
|
||||
IsLive bool `json:"isLive"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
DaysRemaining int `json:"daysRemaining"`
|
||||
HoursRemaining int `json:"hoursRemaining"`
|
||||
}
|
||||
|
||||
// LeaderboardResponse is the response for GET /api/points/leaderboard
|
||||
type LeaderboardResponse struct {
|
||||
TopUsers []LeaderboardUser `json:"topUsers"`
|
||||
MyRank int `json:"myRank"`
|
||||
MyPoints int64 `json:"myPoints"`
|
||||
}
|
||||
|
||||
// LeaderboardUser represents a user in the leaderboard
|
||||
type LeaderboardUser struct {
|
||||
Rank int `json:"rank"`
|
||||
WalletAddress string `json:"address"`
|
||||
Points int64 `json:"points"`
|
||||
}
|
||||
|
||||
// InviteCodeResponse is the response for GET /api/points/invite-code
|
||||
type InviteCodeResponse struct {
|
||||
Code string `json:"code"`
|
||||
UsedCount int `json:"usedCount"`
|
||||
MaxUses int `json:"maxUses"`
|
||||
}
|
||||
|
||||
// TeamTVLResponse is the response for GET /api/points/team
|
||||
type TeamTVLResponse struct {
|
||||
CurrentTVL string `json:"currentTVL"`
|
||||
TargetTVL string `json:"targetTVL"`
|
||||
ProgressPercent float64 `json:"progressPercent"`
|
||||
TotalMembers int `json:"totalMembers"`
|
||||
Roles []RoleCount `json:"roles"`
|
||||
}
|
||||
|
||||
// RoleCount represents count for each role
|
||||
type RoleCount struct {
|
||||
Icon string `json:"icon"`
|
||||
Label string `json:"label"`
|
||||
Current int `json:"current"`
|
||||
Target int `json:"target"`
|
||||
}
|
||||
|
||||
// ActivitiesResponse is the response for GET /api/points/activities
|
||||
type ActivitiesResponse struct {
|
||||
Activities []ActivityRecord `json:"activities"`
|
||||
Pagination PaginationInfo `json:"pagination"`
|
||||
}
|
||||
|
||||
// ActivityRecord represents a single activity
|
||||
type ActivityRecord struct {
|
||||
Type string `json:"type"`
|
||||
UserAddress string `json:"userAddress"`
|
||||
FriendAddress string `json:"friendAddress,omitempty"`
|
||||
InviteCode string `json:"inviteCode,omitempty"`
|
||||
Points int `json:"points"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// PaginationInfo contains pagination metadata
|
||||
type PaginationInfo struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Total int `json:"total"`
|
||||
TotalPage int `json:"totalPage"`
|
||||
}
|
||||
|
||||
// BindInviteRequest is the request body for POST /api/points/bind-invite
|
||||
type BindInviteRequest struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
Signature string `json:"signature" binding:"required"`
|
||||
}
|
||||
|
||||
// HoldersSnapshot represents the holders_snapshots table
|
||||
// 每小时快照:记录用户持有 YT/LP/Lending 代币的余额及积分计算结果
|
||||
type HoldersSnapshot struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
WalletAddress string `gorm:"size:42;not null;index" json:"wallet_address"`
|
||||
TokenType string `gorm:"size:20;not null" json:"token_type"`
|
||||
TokenAddress string `gorm:"size:42;not null" json:"token_address"`
|
||||
ChainID int `gorm:"not null" json:"chain_id"`
|
||||
Balance float64 `gorm:"type:decimal(30,18);not null" json:"balance"`
|
||||
BalanceUSD float64 `gorm:"type:decimal(30,2)" json:"balance_usd"`
|
||||
HoldingDurationHours int `json:"holding_duration_hours"`
|
||||
PointsMultiplier float64 `gorm:"type:decimal(10,4);default:1.0000" json:"points_multiplier"`
|
||||
EarnedPoints int `json:"earned_points"`
|
||||
SnapshotTime time.Time `gorm:"not null;index" json:"snapshot_time"`
|
||||
SeasonID *uint `gorm:"index" json:"season_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (HoldersSnapshot) TableName() string {
|
||||
return "holders_snapshots"
|
||||
}
|
||||
20
webapp-back/models/system_contract.go
Normal file
20
webapp-back/models/system_contract.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// SystemContract is the central registry for all infrastructure contract addresses.
|
||||
// One row per (name, chain_id) pair.
|
||||
// Replaces the former alp_pools and lending_markets tables (which had only one row each).
|
||||
type SystemContract struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Name string `gorm:"size:100;not null;uniqueIndex:uk_name_chain" json:"name"`
|
||||
ChainID int `gorm:"not null;uniqueIndex:uk_name_chain" json:"chain_id"`
|
||||
Address string `gorm:"size:42" json:"address"`
|
||||
DeployBlock *uint64 `json:"deploy_block"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (SystemContract) TableName() string { return "system_contracts" }
|
||||
27
webapp-back/models/user.go
Normal file
27
webapp-back/models/user.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// User represents the users table
|
||||
// Web3 native: wallet_address is the primary key (no numeric id, no auth_user_id)
|
||||
type User struct {
|
||||
WalletAddress string `gorm:"primaryKey;size:42" json:"wallet_address"`
|
||||
Nickname string `gorm:"size:100" json:"nickname"`
|
||||
Avatar string `gorm:"type:text" json:"avatar"`
|
||||
Bio string `gorm:"type:text" json:"bio"`
|
||||
ReferrerWallet *string `gorm:"size:42;index" json:"referrer_wallet,omitempty"`
|
||||
InviteCode string `gorm:"size:20;unique;index" json:"invite_code"`
|
||||
DirectInvitesCount int `gorm:"default:0" json:"direct_invites_count"`
|
||||
MemberTier string `gorm:"size:50;default:'Bronze'" json:"member_tier"`
|
||||
VIPLevel int `gorm:"default:1" json:"vip_level"`
|
||||
TotalPoints int64 `gorm:"default:0" json:"total_points"`
|
||||
GlobalRank *int `gorm:"index" json:"global_rank,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (User) TableName() string {
|
||||
return "users"
|
||||
}
|
||||
24
webapp-back/models/yt_swap.go
Normal file
24
webapp-back/models/yt_swap.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// YTSwapRecord records each Swap event emitted by YT Vault contracts.
|
||||
// Swap(address account, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 feeBasisPoints)
|
||||
// account/tokenIn/tokenOut are indexed (topics), amountIn/amountOut are in data.
|
||||
type YTSwapRecord struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
TxHash string `gorm:"size:66;uniqueIndex:uk_tx_log" json:"tx_hash"`
|
||||
LogIndex uint `gorm:"uniqueIndex:uk_tx_log" json:"log_index"`
|
||||
ChainID int `gorm:"index" json:"chain_id"`
|
||||
BlockNumber uint64 `json:"block_number"`
|
||||
BlockTime time.Time `gorm:"index" json:"block_time"`
|
||||
VaultAddr string `gorm:"size:42;index" json:"vault_addr"`
|
||||
Account string `gorm:"size:42;index" json:"account"`
|
||||
TokenIn string `gorm:"size:42" json:"token_in"`
|
||||
TokenOut string `gorm:"size:42" json:"token_out"`
|
||||
AmountIn string `gorm:"size:78" json:"amount_in"` // wei string, base units
|
||||
AmountOut string `gorm:"size:78" json:"amount_out"` // wei string, base units
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (YTSwapRecord) TableName() string { return "yt_swap_records" }
|
||||
Reference in New Issue
Block a user