Skip to content

Commit

Permalink
add: 添加Solana collection接口
Browse files Browse the repository at this point in the history
  • Loading branch information
liangjies committed Oct 9, 2023
1 parent 09cb552 commit 1237a1f
Show file tree
Hide file tree
Showing 18 changed files with 470 additions and 85 deletions.
8 changes: 2 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ module nft-collect
go 1.19

require (
github.com/allegro/bigcache/v3 v3.1.0
github.com/chenyahui/gin-cache v1.8.0
github.com/blocto/solana-go-sdk v1.26.0
github.com/ethereum/go-ethereum v1.10.26
github.com/fsnotify/fsnotify v1.6.0
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
Expand All @@ -25,18 +24,17 @@ require (
)

require (
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/goccy/go-json v0.10.0 // indirect
Expand All @@ -51,7 +49,6 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.2.0 // indirect
github.com/jellydator/ttlcache/v2 v2.11.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand Down Expand Up @@ -95,7 +92,6 @@ require (
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/mod v0.6.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.2.0 // indirect
Expand Down
62 changes: 4 additions & 58 deletions go.sum

Large diffs are not rendered by default.

26 changes: 18 additions & 8 deletions internal/app/api/v1/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,27 @@ func GetCollection(c *gin.Context) {
}

func GetContract(c *gin.Context) {
address := strings.ToLower(c.Param("address"))
address := c.Param("address")
account := c.GetString("address")
if !utils.IsValidAddress(address) {
response.FailWithMessage("Param Error", c)
if utils.IsValidSolanaAddress(address) {
response.OkWithDetailed(nil, "Success", c)
return
}
if list, err := service.GetContract(address, account); err != nil {
global.LOG.Error("Error!", zap.Error(err))
response.FailWithMessage("Error", c)
if list, err := service.GetSolanaContract(address, account); err != nil {
global.LOG.Error("Error!", zap.Error(err))
response.FailWithMessage("Error", c)
} else {
response.OkWithDetailed(list, "Success", c)
}
} else if utils.IsValidAddress(address) {
address = strings.ToLower(address)
if list, err := service.GetContract(address, account); err != nil {
global.LOG.Error("Error!", zap.Error(err))
response.FailWithMessage("Error", c)
} else {
response.OkWithDetailed(list, "Success", c)
}
} else {
response.OkWithDetailed(list, "Success", c)
response.FailWithMessage("地址错误", c)
}
}

Expand Down
2 changes: 2 additions & 0 deletions internal/app/initialize/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func RegisterTables(db *gorm.DB) {
model.Account{},
model.ContractDefault{},
model.Ens{},
model.CollectionSolana{},
model.ContractSolana{},
)
if err != nil {
global.LOG.Error("register table failed", zap.Error(err))
Expand Down
5 changes: 3 additions & 2 deletions internal/app/model/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (

type Account struct {
global.MODEL
Address string `gorm:"type:char(42);index:account_address,unique;not null;" json:"address" form:"address"`
Address string `gorm:"type:char(44);index:account_address,unique;not null;" json:"address" form:"address"`
ContractIDs pq.StringArray `gorm:"type:uuid[]" json:"contract_ids" form:"contract_ids"` // 合约ID
Counts pq.Int64Array `gorm:"type:integer[]" json:"counts" form:"counts"` // 数量
CountsShow pq.Int64Array `gorm:"type:integer[]" json:"counts_show" form:"counts_show"` // 显示数量
//CountsDefault pq.Int64Array `gorm:"type:integer[]" json:"counts_default" form:"counts_default"` // 默认合约数量
Total int `gorm:"column:total;default:0"` // NFT总数
Total int `gorm:"column:total;default:0"` // NFT总数
Type uint8 `gorm:"column:type;default:1"` // 类型(1:eth 2:solana)
}
4 changes: 2 additions & 2 deletions internal/app/model/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import (
type Collection struct {
global.MODEL
Chain string `gorm:"column:chain;index:chain_address_contract_token,unique" json:"chain" form:"chain"` // 区块链的简称(eth, bnb, polygon, moonbeam, arbitrum, optimism, platon, avalanche, cronos)
AccountAddress string `gorm:"column:account_address;type:char(42);index:chain_address_contract_token,unique" json:"account_address" form:"account_address"` // 资产持有者的地址
AccountAddress string `gorm:"column:account_address;type:char(44);index:chain_address_contract_token,unique" json:"account_address" form:"account_address"` // 资产持有者的地址
Status uint8 `gorm:"default:0;" json:"status" form:"status"` // 显示状态(0:初始状态 1:隐藏 2:显示)
NFTScanOwn
}

type CollectionUpdate struct {
global.MODEL
Chain string `gorm:"column:chain;index:chain_address_contract_token,unique" json:"chain" form:"chain"` // 区块链的简称(eth, bnb, polygon, moonbeam, arbitrum, optimism, platon, avalanche, cronos)
AccountAddress string `gorm:"column:account_address;type:char(42);index:chain_address_contract_token,unique" json:"account_address" form:"account_address"` // 资产持有者的地址
AccountAddress string `gorm:"column:account_address;type:char(44);index:chain_address_contract_token,unique" json:"account_address" form:"account_address"` // 资产持有者的地址
Status uint8 `gorm:"-" json:"status" form:"status"` // 显示状态(1:隐藏 2:显示)
NFTScanOwn
}
Expand Down
27 changes: 27 additions & 0 deletions internal/app/model/collection_solana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package model

import (
"nft-collect/internal/app/global"
)

type CollectionSolana struct {
global.MODEL
Status uint8 `gorm:"default:0;" json:"status" form:"status"` // 显示状态(0:初始状态 1:隐藏 2:显示)
NFTScanSolana
}

type NFTScanSolana struct {
Collection string `gorm:"column:collection" json:"collection" form:"collection"` // Collection 地址
TokenAddress string `gorm:"column:token_address;unique" json:"token_address" form:"token_address"` // Token 地址
Minter string `json:"minter" form:"minter"`
Owner string `json:"owner" form:"owner"`
MintTimestamp int64 `json:"mint_timestamp"`
MintTransactionHash string `json:"mint_transaction_hash"`
TokenURI string `json:"token_uri"`
MetadataJSON string `json:"metadata_json"`
Name string `json:"name"`
ContentType string `json:"content_type"`
ContentURI string `json:"content_uri"`
ImageURI string `json:"image_uri"`
ExternalLink string `json:"external_link"`
}
18 changes: 18 additions & 0 deletions internal/app/model/contract_solana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package model

import (
"nft-collect/internal/app/global"
)

type ContractSolana struct {
global.MODEL
Chain string `gorm:"default:'solana'" json:"chain" form:"chain"` // 区块链的简称
ContractAddress string `gorm:"default:''" json:"contract_address" form:"contract_address"` // 合约地址
ContractName string `gorm:"default:'';not null" json:"contract_name" form:"contract_name"` // 合约名称
ContractLogo string `gorm:"default:''" json:"contract_logo" form:"contract_logo"` // 合约Logo
ContractBanner string `gorm:"default:''" json:"contract_banner" form:"contract_banner"` // 合约Banner
ContractDescription string `gorm:"default:''" json:"contract_description" form:"contract_description"` // 合约Description
ContractWebsite string `gorm:"default:''" json:"contract_website" form:"contract_website"` // 合约Website
ContractOwner string `gorm:"default:''" json:"contract_owner" form:"contract_owner"` // 合约Owner
Status uint8 `gorm:"default:1;" json:"-" form:"-"` // 显示状态(1:未获取 2:已获取)
}
31 changes: 31 additions & 0 deletions internal/app/model/receive/solana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package receive

type SolanaCollection struct {
Code int `json:"code"`
Msg interface{} `json:"msg"`
Data struct {
Total int `json:"total"`
Next interface{} `json:"next"`
Content []struct {
BlockNumber int `json:"block_number"`
InteractProgram string `json:"interact_program"`
Collection string `json:"collection"`
TokenAddress string `json:"token_address"`
Minter string `json:"minter"`
Owner string `json:"owner"`
MintTimestamp int64 `json:"mint_timestamp"`
MintTransactionHash string `json:"mint_transaction_hash"`
MintPrice int `json:"mint_price"`
TokenURI string `json:"token_uri"`
MetadataJSON string `json:"metadata_json"`
Name string `json:"name"`
ContentType string `json:"content_type"`
ContentURI string `json:"content_uri"`
ImageURI string `json:"image_uri"`
ExternalLink string `json:"external_link"`
LatestTradePrice interface{} `json:"latest_trade_price"`
LatestTradeTimestamp interface{} `json:"latest_trade_timestamp"`
LatestTradeTransactionHash interface{} `json:"latest_trade_transaction_hash"`
} `json:"content"`
} `json:"data"`
}
5 changes: 5 additions & 0 deletions internal/app/model/response/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import (
"nft-collect/internal/app/model"
)

type GetSolanaContractRes struct {
model.ContractSolana
Count int64 `gorm:"-" json:"count" form:"count"`
}

type GetContractRes struct {
model.Contract
Count int64 `gorm:"-" json:"count" form:"count"`
Expand Down
136 changes: 136 additions & 0 deletions internal/app/service/account_solana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package service

import (
"gorm.io/gorm"
"nft-collect/internal/app/global"
"nft-collect/internal/app/model"
"nft-collect/internal/app/model/response"
)

// GetSolanaContract 获取 Solana 合约
func GetSolanaContract(address, account string) (res []response.GetSolanaContractRes, err error) {
db := global.DB
var user model.Account

errFirst := db.Model(&model.Account{}).Where("address = ?", address).First(&user).Error
if errFirst != nil && errFirst != gorm.ErrRecordNotFound {
return res, errFirst
}
// 初始化账户
if errFirst == gorm.ErrRecordNotFound {
initSolanaAccount(address)
if err = db.Model(&model.Account{}).Where("address = ?", address).First(&user).Error; err != nil {
return
}
}

//if len(user.ContractIDs) != len(user.Counts) {
// updateSolanaContractCount(address)
//}
// TODO 查询默认合约
dealList := []string{"Decert Badge"}
contractMap := make(map[string]int64)
for _, name := range dealList {
// TODO 优化
var count int64
err = db.Model(&model.Collection{}).
Raw("SElECT COUNT(1) FROM collection_solana a JOIN contract_solana b ON a.collection=b.contract_name WHERE b.contract_name = ? AND minter= ?", name, address).
Scan(&count).Error
contractMap[name] = count
}
// show different counts
if address == account {
for i, _ := range user.ContractIDs {
contractMap[user.ContractIDs[i]] = user.Counts[i]
}
} else {
for i, _ := range user.ContractIDs {
contractMap[user.ContractIDs[i]] = user.CountsShow[i]
}
}
// slice as query
var contractIDs []string
for _, c := range dealList {
contractIDs = append(contractIDs, c)
}
for _, c := range user.ContractIDs {
contractIDs = append(contractIDs, c)
}
// get contract detail
var contract []model.ContractSolana
err = db.Model(&model.ContractSolana{}).Where("contract_name", contractIDs).Find(&contract).Error
if err != nil {
return res, err
}
res = append(res, response.GetSolanaContractRes{ContractSolana: contract[0], Count: contractMap[contract[0].ContractName]})
return res, err
}

// initSolanaAccount
func initSolanaAccount(address string) (err error) {
var uuidList []string
// 创建
var id string
db := global.DB.Model(&model.ContractSolana{}).Select("id")
errFirst := db.First(&id).Error
if errFirst != nil {
if errFirst != gorm.ErrRecordNotFound {
return errFirst
}
return errFirst
}
uuidList = append(uuidList, id)

user := &model.Account{Address: address}
err = global.DB.Model(&model.Account{}).Create(&user).Error
if err != nil {
return err
}
//updateSolanaAllCollection(address, uuidList, true, false)
return err
}

/*
// updateSolanaContractCount
func updateSolanaContractCount(address string) (err error) {
db := global.DB
var user model.Account
if err = db.Model(&model.Account{}).Select("contract_ids").Where("address", address).First(&user).Error; err != nil {
return err
}
var counts []int64
var countsShow []int64
var contractIDs []string
for _, v := range user.ContractIDs {
var nftContract model.ContractSolana
if errErrFind := db.Model(&model.ContractSolana{}).Where("id", v).First(&nftContract).Error; errErrFind != nil {
continue
}
var count int64
var countShow int64
// TODO: 添加状态 需要确定是否过滤
err = db.Model(&model.CollectionSolana{}).
Where("collection", nftContract.ContractName).Where("minter", address).
Count(&count).Error
if err != nil {
return err
}
err = db.Model(&model.CollectionSolana{}).
Where("collection", nftContract.ContractName).Where("minter", address).Where("status", 2).
Count(&countShow).Error
if err != nil {
return err
}
contractIDs = append(contractIDs, v)
counts = append(counts, count)
countsShow = append(countsShow, countShow)
}
if err = db.Model(&model.Account{}).Where("address", address).Updates(model.Account{ContractIDs: contractIDs, Counts: counts, CountsShow: countsShow}).Error; err != nil {
return err
}
// TODO: 清除零数量的合约
return nil
}
*/
Loading

0 comments on commit 1237a1f

Please sign in to comment.