init: 初始化 AssetX 项目仓库
包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、 antdesign(管理后台)、landingpage(营销落地页)、 数据库 SQL 和配置文件。
This commit is contained in:
200
webapp-back/main.go
Normal file
200
webapp-back/main.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/admin"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/alp"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/articles"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/common"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/config"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/fundmarket"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/holders"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/lending"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/middleware"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/models"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/points"
|
||||
"github.com/gothinkster/golang-gin-realworld-example-app/users"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Migrate(db *gorm.DB) {
|
||||
// Original tables
|
||||
users.AutoMigrate()
|
||||
db.AutoMigrate(&articles.ArticleModel{})
|
||||
db.AutoMigrate(&articles.TagModel{})
|
||||
db.AutoMigrate(&articles.FavoriteModel{})
|
||||
db.AutoMigrate(&articles.ArticleUserModel{})
|
||||
db.AutoMigrate(&articles.CommentModel{})
|
||||
|
||||
// AssetX core tables
|
||||
db.AutoMigrate(&models.User{})
|
||||
db.AutoMigrate(&models.HolderSnapshot{})
|
||||
db.AutoMigrate(&models.Asset{})
|
||||
db.AutoMigrate(&models.AssetPerformance{})
|
||||
db.AutoMigrate(&models.APYSnapshot{})
|
||||
db.AutoMigrate(&models.AssetCustody{})
|
||||
db.AutoMigrate(&models.AssetAuditReport{})
|
||||
|
||||
// Config / content tables
|
||||
db.AutoMigrate(&models.SystemContract{})
|
||||
db.AutoMigrate(&models.ProductLink{})
|
||||
|
||||
// Points system tables
|
||||
db.AutoMigrate(&models.PointsRule{})
|
||||
db.AutoMigrate(&models.Season{})
|
||||
db.AutoMigrate(&models.VIPTier{})
|
||||
db.AutoMigrate(&models.InviteCode{})
|
||||
db.AutoMigrate(&models.Invitation{})
|
||||
db.AutoMigrate(&models.UserPointsSummary{})
|
||||
db.AutoMigrate(&models.UserPointsRecord{})
|
||||
db.AutoMigrate(&models.UserTeam{})
|
||||
|
||||
// ALP pool snapshots
|
||||
db.AutoMigrate(&models.ALPSnapshot{})
|
||||
|
||||
// Liquidation bot records
|
||||
db.AutoMigrate(&models.LiquidationRecord{})
|
||||
db.AutoMigrate(&models.KnownBorrower{})
|
||||
|
||||
// Collateral buyer bot records
|
||||
db.AutoMigrate(&models.CollateralBuyRecord{})
|
||||
|
||||
// Scanner state: drop old single-column unique index, then migrate with composite index
|
||||
db.Exec("ALTER TABLE scanner_state DROP INDEX `uni_chain_id`") // ignore error if not exists
|
||||
db.AutoMigrate(&models.ScannerState{})
|
||||
|
||||
// YT Swap event records (for "Your Total Earning" calculation)
|
||||
db.AutoMigrate(&models.YTSwapRecord{})
|
||||
|
||||
// Audit / ops
|
||||
db.AutoMigrate(&models.OperationLog{})
|
||||
|
||||
log.Println("✓ Database migration completed")
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
log.Println("✓ Configuration loaded")
|
||||
|
||||
var db *gorm.DB
|
||||
if cfg.DBType == "mysql" {
|
||||
db = common.InitMySQL()
|
||||
} else {
|
||||
db = common.Init()
|
||||
}
|
||||
|
||||
Migrate(db)
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
log.Println("failed to get sql.DB:", err)
|
||||
} else {
|
||||
defer sqlDB.Close()
|
||||
}
|
||||
|
||||
common.InitRedis()
|
||||
|
||||
// Start holder scanner (continuous block scanning)
|
||||
go holders.StartAllScanners()
|
||||
|
||||
// Start background snapshot services (run every hour)
|
||||
go fundmarket.StartPriceSnapshot(cfg)
|
||||
go alp.StartALPSnapshot(cfg)
|
||||
go lending.StartLendingAPYSnapshot(cfg)
|
||||
|
||||
// Start liquidation bot (requires LIQUIDATOR_PRIVATE_KEY)
|
||||
go lending.StartLiquidationBot(cfg)
|
||||
|
||||
// Start collateral buyer bot (requires COLLATERAL_BUYER_PRIVATE_KEY)
|
||||
go lending.StartCollateralBuyerBot(cfg)
|
||||
|
||||
if cfg.GinMode == "release" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
r := gin.Default()
|
||||
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowAllOrigins: true,
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: false,
|
||||
}))
|
||||
|
||||
r.RedirectTrailingSlash = false
|
||||
|
||||
// Serve uploaded files
|
||||
r.Static("/uploads", "./uploads")
|
||||
|
||||
v1 := r.Group("/api")
|
||||
|
||||
// Public routes
|
||||
users.UsersRegister(v1.Group("/users"))
|
||||
articles.ArticlesAnonymousRegister(v1.Group("/articles"))
|
||||
articles.TagsAnonymousRegister(v1.Group("/tags"))
|
||||
users.ProfileRetrieveRegister(v1.Group("/profiles"))
|
||||
|
||||
v1.GET("/holders/stats", holders.GetStats)
|
||||
v1.GET("/holders/:tokenType", holders.GetHoldersByType)
|
||||
|
||||
v1.GET("/contracts", admin.GetContracts)
|
||||
|
||||
v1.GET("/fundmarket/products", fundmarket.GetProducts)
|
||||
v1.GET("/fundmarket/stats", fundmarket.GetStats)
|
||||
v1.GET("/fundmarket/products/:id", fundmarket.GetProductByID)
|
||||
v1.GET("/fundmarket/products/:id/history", fundmarket.GetProductHistory)
|
||||
v1.GET("/fundmarket/products/:id/daily-returns", fundmarket.GetDailyReturns)
|
||||
v1.GET("/fundmarket/net-deposited", fundmarket.GetNetDeposited)
|
||||
|
||||
v1.GET("/alp/stats", alp.GetALPStats)
|
||||
v1.GET("/alp/history", alp.GetALPHistory)
|
||||
|
||||
v1.GET("/lending/position/:address", lending.GetUserPosition)
|
||||
v1.GET("/lending/stats", lending.GetLendingStats)
|
||||
v1.GET("/lending/markets", lending.GetLendingMarkets)
|
||||
v1.GET("/lending/apy-history", lending.GetLendingAPYHistory)
|
||||
v1.GET("/lending/tokens", lending.GetTokensInfo)
|
||||
v1.GET("/lending/tokens/:assetCode", lending.GetTokenInfo)
|
||||
v1.POST("/lending/supply", lending.SupplyUSDC)
|
||||
v1.POST("/lending/withdraw", lending.WithdrawUSDC)
|
||||
v1.POST("/lending/supply-collateral", lending.SupplyCollateral)
|
||||
v1.POST("/lending/withdraw-collateral", lending.WithdrawCollateral)
|
||||
v1.POST("/lending/borrow", lending.BorrowUSDC)
|
||||
v1.POST("/lending/repay", lending.RepayUSDC)
|
||||
|
||||
v1.POST("/points/wallet-register", points.WalletRegister)
|
||||
v1.GET("/points/dashboard", points.GetDashboard)
|
||||
v1.GET("/points/leaderboard", points.GetLeaderboard)
|
||||
v1.GET("/points/invite-code", points.GetInviteCode)
|
||||
v1.POST("/points/bind-invite", points.BindInvite)
|
||||
v1.GET("/points/team", points.GetTeamTVL)
|
||||
v1.GET("/points/activities", points.GetActivities)
|
||||
|
||||
// Admin API (has its own auth + RequireAdmin middleware internally)
|
||||
admin.RegisterRoutes(v1)
|
||||
|
||||
// Protected routes
|
||||
v1.Use(middleware.AuthMiddleware(true))
|
||||
{
|
||||
users.UserRegister(v1.Group("/user"))
|
||||
users.ProfileRegister(v1.Group("/profiles"))
|
||||
articles.ArticlesRegister(v1.Group("/articles"))
|
||||
|
||||
holdersGroup := v1.Group("/holders")
|
||||
holdersGroup.POST("/update", middleware.RequireAdmin(), holders.UpdateHolders)
|
||||
}
|
||||
|
||||
r.GET("/api/ping", func(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "pong", "version": "1.0.0-assetx"})
|
||||
})
|
||||
|
||||
port := ":" + cfg.Port
|
||||
log.Printf("✓ Server starting on port %s\n", cfg.Port)
|
||||
if err := r.Run(port); err != nil {
|
||||
log.Fatal("failed to start server:", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user