Skip to content

Commit

Permalink
Merge pull request #83 from decert-me/feature/solana
Browse files Browse the repository at this point in the history
Add 添加 Solana 登陆、空投功能
  • Loading branch information
0xdwong authored Oct 9, 2023
2 parents c7e5660 + f439f08 commit fe4c7e9
Show file tree
Hide file tree
Showing 21 changed files with 440 additions and 43 deletions.
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/dghubble/oauth1 v0.7.2
github.com/ethereum/go-ethereum v1.13.1
github.com/fsnotify/fsnotify v1.6.0
github.com/gagliardetto/solana-go v1.8.4
github.com/getsentry/sentry-go v0.24.1
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.8.2
Expand All @@ -34,10 +35,13 @@ require (
)

require (
contrib.go.opencensus.io/exporter/stackdriver v0.13.4 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/bits-and-blooms/bitset v1.5.0 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/btcsuite/btcd v0.20.1-beta // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
Expand All @@ -50,9 +54,13 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79 // indirect
github.com/dghubble/sling v1.4.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/ethereum/c-kzg-4844 v0.3.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/gagliardetto/binary v0.7.7 // indirect
github.com/gagliardetto/treeout v0.1.4 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-playground/locales v0.14.1 // indirect
Expand All @@ -65,6 +73,7 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
Expand All @@ -83,16 +92,21 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
Expand All @@ -114,21 +128,26 @@ require (
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/wealdtech/go-multicodec v1.4.0 // indirect
go.mongodb.org/mongo-driver v1.11.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
187 changes: 187 additions & 0 deletions go.sum

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions internal/app/api/v1/badge.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package v1
import (
"backend-go/internal/app/model/request"
"github.com/gin-gonic/gin"
"strconv"
)

// PermitClaimBadge claim Badge NFT
Expand Down Expand Up @@ -64,3 +65,18 @@ func SubmitClaimShare(c *gin.Context) {
OkWithData(res, c)
}
}

func HasClaimed(c *gin.Context) {
address := c.GetString("address")
tokenId := c.Param("tokenID")
_tokenId, err := strconv.Atoi(tokenId)
if err != nil {
FailWithMessage(GetMessage(c, "ParameterError"), c)
return
}
if res, err := srv.HasClaimed(address, int64(_tokenId)); err != nil {
FailWithMessage(GetMessage(c, err.Error()), c)
} else {
OkWithData(map[string]uint8{"status": res}, c)
}
}
13 changes: 8 additions & 5 deletions internal/app/api/v1/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ func GetUserChallengeList(c *gin.Context) {
func GetLoginMessage(c *gin.Context) {
var request request.GetLoginMessageRequest
_ = c.ShouldBindQuery(&request)
if !utils.IsValidAddress(request.Address) {
FailWithMessage(GetMessage(c, "AddressError"), c)
return
}
if loginMessage, err := srv.GetLoginMessage(request.Address); err != nil {
FailWithMessage(GetMessage(c, "FetchFailed"), c)
} else {
Expand All @@ -156,7 +152,14 @@ func AuthLoginSign(c *gin.Context) {
FailWithMessage(GetMessage(c, "ParameterError"), c)
return
}
if token, err := srv.AuthLoginSignRequest(request); err != nil {
var token string
var err error
if utils.IsValidAddress(request.Address) {
token, err = srv.AuthLoginSignRequest(request)
} else {
token, err = srv.AuthLoginSignRequestSolana(request)
}
if err != nil {
FailWithMessage(GetMessage(c, err.Error()), c)
} else {
OkWithDetailed(map[string]string{"token": token}, GetMessage(c, "FetchSuccess"), c)
Expand Down
15 changes: 10 additions & 5 deletions internal/app/dao/claim_badge_tweet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package dao

import (
"backend-go/internal/app/model"
"backend-go/pkg/log"
"github.com/ethereum/go-ethereum/common"
"go.uber.org/zap"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
Expand Down Expand Up @@ -70,12 +68,19 @@ func (d *Dao) UpdateAirdroppedOne(tokenId int64, receivers string, hash string)
}

func (d *Dao) HasAirdrop(address string, tokenId int64) bool {
//var total int64
//err := d.db.Model(&model.ClaimBadgeTweet{}).
// Where("address = ? AND token_id = ? AND status=1", address, tokenId).
// Count(&total).Error
//if err != nil {
// log.Errorv("HasAirdrop error", zap.Error(err))
// return false
//}
var total int64
err := d.db.Model(&model.ClaimBadgeTweet{}).
Where("address = ? AND token_id = ? AND status=1", address, tokenId).
err := d.db.Model(&model.UserChallenges{}).
Where("address = ? AND token_id = ?", address, tokenId).
Count(&total).Error
if err != nil {
log.Errorv("HasAirdrop error", zap.Error(err))
return false
}
return total != 0
Expand Down
4 changes: 2 additions & 2 deletions internal/app/dao/quest.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (d *Dao) GetQuestByUUID(uuid string) (quest model.Quest, err error) {

func (d *Dao) GetQuestWithClaimStatusByTokenID(id int64, address string) (quest response.GetQuestRes, err error) {
err = d.db.Model(&model.Quest{}).
Select("quest.*,b.claimed").
Select("quest.*,b.claimed,b.user_score,b.nft_address").
Joins("left join user_challenges b ON quest.token_id=b.token_id AND b.address= ?", address).
Where("quest.token_id", id).
First(&quest).Error
Expand All @@ -157,7 +157,7 @@ func (d *Dao) GetQuestWithClaimStatusByTokenID(id int64, address string) (quest

func (d *Dao) GetQuestWithClaimStatusByUUID(uuid string, address string) (quest response.GetQuestRes, err error) {
err = d.db.Model(&model.Quest{}).
Select("quest.*,b.claimed").
Select("quest.*,b.claimed,b.user_score,b.nft_address").
Joins("left join user_challenges b ON quest.token_id=b.token_id AND b.address= ?", address).
Where("quest.uuid", uuid).
First(&quest).Error
Expand Down
26 changes: 26 additions & 0 deletions internal/app/dao/user_challenge_claim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dao

import (
"backend-go/internal/app/model"
"gorm.io/gorm"
)

// CreateUserChallengeClaim 创建记录
func (d *Dao) CreateUserChallengeClaim(claim *model.UserChallengeClaim) (err error) {
err = d.db.Create(&claim).Error
return
}

// HasClaimed 查询是否claim
func (d *Dao) HasClaimed(address string, tokenID int64) (status uint8, err error) {
var claim model.UserChallengeClaim
err = d.db.Model(&model.UserChallengeClaim{}).Where("address = ? AND token_id = ?", address, tokenID).First(&claim).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return 0, nil
} else {
return 0, err
}
}
return claim.Status, nil
}
26 changes: 14 additions & 12 deletions internal/app/dao/user_challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ func (d *Dao) CreateChallengesList(tokenId int64, receivers []common.Address) (e
return
}

func (d *Dao) CreateChallengesOne(tokenId int64, receiver string) (err error) {
func (d *Dao) CreateChallengesOne(tokenId int64, receiver string, uerScore int64, nftAddress string) (err error) {
challenge := model.UserChallenges{
Address: receiver,
TokenId: tokenId,
Claimed: true,
Status: 2,
Address: receiver,
TokenId: tokenId,
Claimed: true,
Status: 2,
UserScore: uerScore,
NFTAddress: nftAddress,
}
err = d.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "address"}, {Name: "token_id"}},
Expand Down Expand Up @@ -103,20 +105,20 @@ func (d *Dao) GetOwnerChallengeList(req *request.GetChallengeListRequest) (res [
}
}

err = db.Raw("SELECT count(1) FROM (SELECT a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? "+
err = db.Raw("SELECT count(1) FROM (SELECT a.nft_address,a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? "+
" UNION "+
"SELECT 'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM claim_badge_tweet a JOIN quest b ON a.token_id=b.token_id WHERE a.address = ? AND a.status=0"+
"SELECT '' as nft_address,'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM claim_badge_tweet a JOIN quest b ON a.token_id=b.token_id WHERE a.address = ? AND a.status=0"+
" UNION "+
fmt.Sprintf("SELECT 'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM %s a JOIN quest b ON a.token_id=b.token_id", tempDB)+
fmt.Sprintf("SELECT '' as nft_address,'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM %s a JOIN quest b ON a.token_id=b.token_id", tempDB)+
") a1", req.Address, req.Address).Scan(&total).Error
if err != nil {
return res, total, err
}
err = db.Raw("SELECT * FROM ((SELECT a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? ORDER BY a.add_ts DESC"+
err = db.Raw("SELECT * FROM ((SELECT a.nft_address,a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? ORDER BY a.add_ts DESC"+
") UNION ("+
"SELECT 'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM claim_badge_tweet a JOIN quest b ON a.token_id=b.token_id WHERE a.address = ? AND a.status=0 ORDER BY a.add_ts DESC"+
"SELECT '' as nft_address,'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM claim_badge_tweet a JOIN quest b ON a.token_id=b.token_id WHERE a.address = ? AND a.status=0 ORDER BY a.add_ts DESC"+
") UNION ("+
fmt.Sprintf("SELECT 'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM %s a JOIN quest b ON a.token_id=b.token_id", tempDB)+
fmt.Sprintf("SELECT '' as nft_address,'f' as claimed,a.add_ts as complete_ts,b.* as claimed FROM %s a JOIN quest b ON a.token_id=b.token_id", tempDB)+
")) a1 ORDER BY complete_ts DESC LIMIT ? OFFSET ? ",
req.Address, req.Address, limit, offset).Scan(&res).Error
if err != nil {
Expand All @@ -135,7 +137,7 @@ func (d *Dao) GetChallengeList(req *request.GetChallengeListRequest) (res []resp
if err != nil {
return res, total, err
}
err = db.Raw("SELECT a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? ORDER BY a.add_ts DESC LIMIT ? OFFSET ?",
err = db.Raw("SELECT a.nft_address,a.claimed,a.add_ts as complete_ts,b.* FROM user_challenges a JOIN quest b ON a.token_id=b.token_id WHERE address = ? ORDER BY a.add_ts DESC LIMIT ? OFFSET ?",
req.Address, limit, offset).Scan(&res).Error
if err != nil {
return res, total, err
Expand Down
1 change: 1 addition & 0 deletions internal/app/initialize/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func RegisterTables(db *gorm.DB) {
model.Upload{},
model.UserChallengeLog{},
model.ReadProgress{},
model.UserChallengeClaim{},
)
if err != nil {
panic("register table failed")
Expand Down
2 changes: 1 addition & 1 deletion internal/app/model/claim_badge_tweet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package model

type ClaimBadgeTweet struct {
ID uint `gorm:"primarykey"`
Address string `gorm:"column:address;type:char(42);index:address_tokenId,UNIQUE;comment:钱包地址" json:"address" form:"address"`
Address string `gorm:"column:address;type:char(44);index:address_tokenId,UNIQUE;comment:钱包地址" json:"address" form:"address"`
TokenId int64 `gorm:"column:token_id;index:address_tokenId,UNIQUE" json:"tokenId"` // badgeNFT tokenId
Score int64 `gorm:"column:score" form:"score" json:"score"` // badgeNFT score
Url string `gorm:"column:url;type:varchar" json:"url"` // 推文链接地址
Expand Down
5 changes: 3 additions & 2 deletions internal/app/model/response/challenge.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "backend-go/internal/app/model"

type GetChallengeListRes struct {
model.Quest
CompleteTs int64 `json:"complete_ts"`
Claimed bool `json:"claimed"`
CompleteTs int64 `json:"complete_ts"`
Claimed bool `json:"claimed"`
NFTAddress string `json:"nft_address"`
}
4 changes: 3 additions & 1 deletion internal/app/model/response/quest.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ type GetQuestChallengeUserRes struct {

type GetQuestRes struct {
model.Quest
Claimed bool `gorm:"claimed" json:"claimed"`
Claimed bool `gorm:"claimed" json:"claimed"`
UserScore int64 `gorm:"user_score" json:"user_score"`
NFTAddress string `gorm:"column:nft_address" json:"nft_address"`
}
10 changes: 10 additions & 0 deletions internal/app/model/user_challenge_claim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package model

import "gorm.io/gorm"

type UserChallengeClaim struct {
gorm.Model
Address string `gorm:"column:address;type:char(44);comment:钱包地址" json:"address" form:"address"`
TokenId int64 `gorm:"column:token_id" json:"token_id"`
Status uint8 `gorm:"column:status;default:1" json:"status"` // 状态 1: 待空投 2: 成功空投
}
2 changes: 1 addition & 1 deletion internal/app/model/user_challenge_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import "gorm.io/datatypes"

type UserChallengeLog struct {
ID uint `gorm:"primarykey"`
Address string `gorm:"column:address;type:char(42);comment:钱包地址" json:"address" form:"address"`
Address string `gorm:"column:address;type:char(44);comment:钱包地址" json:"address" form:"address"`
TokenId int64 `gorm:"column:token_id" json:"token_id"`
Answer datatypes.JSON `gorm:"column:answer" json:"answer"`
AddTs int64 `gorm:"column:add_ts;autoCreateTime" json:"add_ts"`
Expand Down
21 changes: 11 additions & 10 deletions internal/app/model/user_challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
)

type UserChallenges struct {
ID uint `gorm:"primarykey"`
Address string `gorm:"column:address;type:char(42);index:,unique,composite:challenges_address_tokenId;comment:钱包地址" json:"address" form:"address"`
TokenId int64 `gorm:"column:token_id;index:,unique,composite:challenges_address_tokenId;" json:"tokenId"`
Status uint8 `gorm:"column:status;default:0;size:30;comment:0 进行中 1 等待验证 2 成功;" json:"status" form:"status"` // 0:进行中;1:等待验证;2:成功;
Content datatypes.JSON `gorm:"column:content" json:"content"`
AddTs int64 `gorm:"column:add_ts;autoCreateTime" json:"addTs"`
Claimed bool `gorm:"column:claimed;default:false" json:"claimed"`
UpdateTs int64 `gorm:"column:update_ts;autoUpdateTime" json:"updateTs"`
UserScore int64 `gorm:"column:user_score" form:"user_score" json:"user_score"` // 分数
ClaimTs int64 `gorm:"column:claim_ts;" json:"claimTs"`
ID uint `gorm:"primarykey"`
Address string `gorm:"column:address;type:char(44);index:,unique,composite:challenges_address_tokenId;comment:钱包地址" json:"address" form:"address"`
TokenId int64 `gorm:"column:token_id;index:,unique,composite:challenges_address_tokenId;" json:"tokenId"`
Status uint8 `gorm:"column:status;default:0;size:30;comment:0 进行中 1 等待验证 2 成功;" json:"status" form:"status"` // 0:进行中;1:等待验证;2:成功;
Content datatypes.JSON `gorm:"column:content" json:"content"`
AddTs int64 `gorm:"column:add_ts;autoCreateTime" json:"addTs"`
Claimed bool `gorm:"column:claimed;default:false" json:"claimed"`
UpdateTs int64 `gorm:"column:update_ts;autoUpdateTime" json:"updateTs"`
UserScore int64 `gorm:"column:user_score" form:"user_score" json:"user_score"` // 分数
ClaimTs int64 `gorm:"column:claim_ts;" json:"claimTs"`
NFTAddress string `gorm:"column:nft_address" json:"nft_address" form:"nft_address"`
}
2 changes: 1 addition & 1 deletion internal/app/model/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

type Users struct {
ID uint `gorm:"primarykey" json:"-"`
Address string `gorm:"column:address;type:char(42);UNIQUE;comment:钱包地址" json:"address" form:"address"`
Address string `gorm:"column:address;type:char(44);UNIQUE;comment:钱包地址" json:"address" form:"address"`
NickName *string `gorm:"column:nickname;type:varchar(200);default:''" json:"nickname" form:"nickname"`
Avatar *string `gorm:"column:avatar;type:varchar(200);comment:用户头像;default:''" json:"avatar" form:"avatar"`
Description *string `gorm:"column:description;type:varchar(100);comment:自我介绍;default:''" json:"description" form:"description"`
Expand Down
4 changes: 4 additions & 0 deletions internal/app/router/badge.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import (

func InitBadgeRouter(Router *gin.RouterGroup) {
badgeRouter := Router.Group("badge").Use(middleware.Auth())
badgeAddrRouter := Router.Group("badge").Use(middleware.Addr())
{
badgeRouter.POST("submitClaimTweet", v1.SubmitClaimTweet)
badgeRouter.POST("submitClaimShare", v1.SubmitClaimShare)
badgeRouter.POST("claim", v1.PermitClaimBadge)
badgeRouter.PUT("uri", v1.UpdateBadgeURI)
}
{
badgeAddrRouter.GET("hasClaimed/:tokenID", v1.HasClaimed)
}
}
Loading

0 comments on commit fe4c7e9

Please sign in to comment.