diff --git a/Makefile b/Makefile index 15795af..7a4d97a 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ api: .PHONY: build # 编译二进制可执行文件 build: - mkdir -p bin/ && go build -ldflags="-s -w" -o ./bin/ ./... + mkdir -p bin/ && go build -ldflags="-s -w" -tags no_k8s -o ./bin/ ./... .PHONY: img # 构建Docker镜像 diff --git a/etc/novatask.yaml b/etc/novatask.yaml index 0372d2e..2880908 100644 --- a/etc/novatask.yaml +++ b/etc/novatask.yaml @@ -6,7 +6,6 @@ KeyFile: "etc/cert/saas.key" Auth: # js-sdk鉴权相关配置 AccessSecret: "Mj2G%szYe&$MP@ytNv8JktQN1n5^cPq%" # 鉴权token密钥 - AccessExpire: 168h # 鉴权token过期时间 MySql: # mysql相关配置 Addr: "192.168.2.108:3306" # mysql地址 @@ -14,7 +13,13 @@ MySql: # mysql相关配置 Password: "jMDqPQM^a6hsAR" # mysql密码 Database: "nova_home" # 数据库名 +Cache: + - Host: "127.0.0.1:6379" + Earn: ClientId: "4d6269e3-8aac-4550-acf9-dc891caf20a8" ClientSecret: "GJpQ4TmX4p2VMY7U3XtExZQKYfibMv24" GameId: "c0deda99-bb15-47a2-a3be-f1fe2983cde2" + +DailyPay: + Contract: "xxx" \ No newline at end of file diff --git a/go.mod b/go.mod index a4f7ed1..d486ecc 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.23.4 require ( github.com/earn-alliance/earnalliance-go v0.0.2 github.com/golang-jwt/jwt/v4 v4.5.1 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v1.4.0 github.com/spf13/cast v1.7.0 github.com/stretchr/testify v1.9.0 @@ -17,6 +19,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.18.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -30,14 +33,13 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.3 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/redis/go-redis/v9 v9.7.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect diff --git a/go.sum b/go.sum index 4514aef..990732c 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,16 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= +github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -11,6 +19,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/earn-alliance/earnalliance-go v0.0.2 h1:cKxc+lEn6vj+qgoIkwUjeW3nLmghb86ZGtBs5Saokwc= github.com/earn-alliance/earnalliance-go v0.0.2/go.mod h1:mN3wHms0bjW4SQ15smJoXbwCc2Aj/Yeij+Bma7LgvMQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -73,6 +83,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -94,6 +106,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zeromicro/go-zero v1.7.4 h1:lyIUsqbpVRzM4NmXu5pRM3XrdRdUuWOkQmHiNmJF0VU= github.com/zeromicro/go-zero v1.7.4/go.mod h1:jmv4hTdUBkDn6kxgI+WrKQw0q6LKxDElGPMfCLOeeEY= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= diff --git a/internal/config/config.go b/internal/config/config.go index 352377f..fc6ea94 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/rest" "net/url" @@ -12,11 +13,18 @@ import ( type Config struct { rest.RestConf MySql MySqlConf + Cache cache.CacheConf Auth struct { AccessSecret string - AccessExpire time.Duration + AccessExpire time.Duration `json:",default=168h"` } - Earn earn.Config + Earn earn.Config + DailyPay DailyPay +} + +type DailyPay struct { + Contract string + Network string `json:",default=mainnet"` } // MySqlConf mysql配置 diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 0000000..f6b1665 --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1,5 @@ +package consts + +const ( + EarnAllianceInviterId = "earn_alliance_inviter_id" +) diff --git a/internal/job/earn/earn.go b/internal/job/earn/earn.go index daf1812..2c61b4f 100644 --- a/internal/job/earn/earn.go +++ b/internal/job/earn/earn.go @@ -5,6 +5,7 @@ import ( ea "github.com/earn-alliance/earnalliance-go" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" + "nova_task/internal/consts" "nova_task/internal/svc" ) @@ -25,8 +26,13 @@ func (e *Earn) Spec() string { } func (e *Earn) Run() { - e.pushUserInfo(666) - e.pushUserBind() + c, err := e.svcCtx.ConfigModel.FindOneByName(e.ctx, consts.EarnAllianceInviterId) + if err != nil { + logx.Errorw("find earn alliance inviter id failed", logx.Field("err", err)) + return + } + e.pushUserInfo(cast.ToUint(c.Value)) + e.pushUserBind(cast.ToUint(c.Value)) } func (e *Earn) pushUserInfo(shareId uint) { @@ -54,8 +60,25 @@ func (e *Earn) pushUserInfo(shareId uint) { err = e.svcCtx.PromoteBindModel.UpdatePushUser(e.ctx, u.Id) if err != nil { logx.Errorw("update push user failed", logx.Field("err", err), logx.Field("uid", u.InvitedUid)) + } else { + logx.Infow("push user info success", logx.Field("uid", u.InvitedUid)) } } } -func (e *Earn) pushUserBind() {} +func (e *Earn) pushUserBind(shareId uint) { + us, err := e.svcCtx.TouristBindModel.FindRequirePushUser(e.ctx, shareId) + if err != nil { + logx.Errorw("find require push bind role user failed", logx.Field("err", err), logx.Field("share_id", shareId)) + return + } + for _, u := range us { + e.svcCtx.Earn.Track(cast.ToString(u.Uid), "BIND_ROLE", nil, nil) + err = e.svcCtx.PromoteBindModel.UpdatePushRole(e.ctx, u.Id) + if err != nil { + logx.Errorw("update push user failed", logx.Field("err", err), logx.Field("uid", u.Uid)) + } else { + logx.Infow("push user info success", logx.Field("uid", u.Uid)) + } + } +} diff --git a/internal/logic/task/verify_task_result_logic.go b/internal/logic/task/verify_task_result_logic.go index 52c8690..1c0e627 100644 --- a/internal/logic/task/verify_task_result_logic.go +++ b/internal/logic/task/verify_task_result_logic.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" "nova_task/internal/model" + "nova_task/internal/pkg/aptos" "nova_task/internal/pkg/errs" "nova_task/internal/svc" "nova_task/internal/types" @@ -74,6 +75,10 @@ func (l *VerifyTaskResultLogic) VerifyTaskResult(req *types.VerifyTaskResultReq) case model.TASKTYPE_DAILY_PAY: if req.Params == "" { return &types.VerifyTaskResultResp{Finish: false}, nil + } else { + if !l.checkoutTranscation(uid, req.Params) { + return &types.VerifyTaskResultResp{Finish: false}, nil + } } default: } @@ -92,3 +97,17 @@ func (l *VerifyTaskResultLogic) VerifyTaskResult(req *types.VerifyTaskResultReq) return &types.VerifyTaskResultResp{Finish: true}, nil } + +func (l *VerifyTaskResultLogic) checkoutTranscation(uid int, txHash string) bool { + address, err := aptos.GetTransactionOwnerAddress(l.svcCtx.Config.DailyPay.Contract, txHash, l.svcCtx.Config.DailyPay.Network) + if err != nil { + l.Errorw("get transaction owner address error", logx.Field("err", err)) + return false + } + targetUid, err := l.svcCtx.WalletModel.FindWalletByAddress(l.ctx, address, aptos.StrPadAptosAddress(address)) + if err != nil { + l.Errorw("find wallet by address error", logx.Field("err", err), logx.Field("address", address), logx.Field("target_uid", targetUid)) + return false + } + return targetUid == uint(uid) +} diff --git a/internal/model/nh_system_config_model.go b/internal/model/nh_system_config_model.go new file mode 100755 index 0000000..5aa72f1 --- /dev/null +++ b/internal/model/nh_system_config_model.go @@ -0,0 +1,27 @@ +package model + +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ NhSystemConfigModel = (*customNhSystemConfigModel)(nil) + +type ( + // NhSystemConfigModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhSystemConfigModel. + NhSystemConfigModel interface { + nhSystemConfigModel + } + + customNhSystemConfigModel struct { + *defaultNhSystemConfigModel + } +) + +// NewNhSystemConfigModel returns a model for the database table. +func NewNhSystemConfigModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) NhSystemConfigModel { + return &customNhSystemConfigModel{ + defaultNhSystemConfigModel: newNhSystemConfigModel(conn, c, opts...), + } +} diff --git a/internal/model/nh_system_config_model_gen.go b/internal/model/nh_system_config_model_gen.go new file mode 100755 index 0000000..88e5812 --- /dev/null +++ b/internal/model/nh_system_config_model_gen.go @@ -0,0 +1,155 @@ +// Code generated by goctl. DO NOT EDIT. +// versions: +// goctl version: 1.7.3 + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + "time" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + nhSystemConfigFieldNames = builder.RawFieldNames(&NhSystemConfig{}) + nhSystemConfigRows = strings.Join(nhSystemConfigFieldNames, ",") + nhSystemConfigRowsExpectAutoSet = strings.Join(stringx.Remove(nhSystemConfigFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhSystemConfigRowsWithPlaceHolder = strings.Join(stringx.Remove(nhSystemConfigFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" + + cacheNovaHomeNhSystemConfigIdPrefix = "cache:novaHome:nhSystemConfig:id:" + cacheNovaHomeNhSystemConfigNamePrefix = "cache:novaHome:nhSystemConfig:name:" +) + +type ( + nhSystemConfigModel interface { + Insert(ctx context.Context, data *NhSystemConfig) (sql.Result, error) + FindOne(ctx context.Context, id uint64) (*NhSystemConfig, error) + FindOneByName(ctx context.Context, name string) (*NhSystemConfig, error) + Update(ctx context.Context, data *NhSystemConfig) error + Delete(ctx context.Context, id uint64) error + } + + defaultNhSystemConfigModel struct { + sqlc.CachedConn + table string + } + + NhSystemConfig struct { + Id uint64 `db:"id"` + Module string `db:"module"` // 模块 + Name string `db:"name"` // 变量名 + Type string `db:"type"` // 类型text,radio,checkbox,select,input,array等等 + Value string `db:"value"` // 变量值 + Remark string `db:"remark"` // 变量注释 + Sort uint64 `db:"sort"` // 排序 + CreatedId uint `db:"created_id"` // 创建人ID + UpdatedId uint `db:"updated_id"` // 修改人ID + CreatedAt time.Time `db:"created_at"` // 创建时间 + UpdatedAt time.Time `db:"updated_at"` // 修改时间 + } +) + +func newNhSystemConfigModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultNhSystemConfigModel { + return &defaultNhSystemConfigModel{ + CachedConn: sqlc.NewConn(conn, c, opts...), + table: "`nh_system_config`", + } +} + +func (m *defaultNhSystemConfigModel) Delete(ctx context.Context, id uint64) error { + data, err := m.FindOne(ctx, id) + if err != nil { + return err + } + + novaHomeNhSystemConfigIdKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigIdPrefix, id) + novaHomeNhSystemConfigNameKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigNamePrefix, data.Name) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + return conn.ExecCtx(ctx, query, id) + }, novaHomeNhSystemConfigIdKey, novaHomeNhSystemConfigNameKey) + return err +} + +func (m *defaultNhSystemConfigModel) FindOne(ctx context.Context, id uint64) (*NhSystemConfig, error) { + novaHomeNhSystemConfigIdKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigIdPrefix, id) + var resp NhSystemConfig + err := m.QueryRowCtx(ctx, &resp, novaHomeNhSystemConfigIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhSystemConfigRows, m.table) + return conn.QueryRowCtx(ctx, v, query, id) + }) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultNhSystemConfigModel) FindOneByName(ctx context.Context, name string) (*NhSystemConfig, error) { + novaHomeNhSystemConfigNameKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigNamePrefix, name) + var resp NhSystemConfig + err := m.QueryRowIndexCtx(ctx, &resp, novaHomeNhSystemConfigNameKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) { + query := fmt.Sprintf("select %s from %s where `name` = ? limit 1", nhSystemConfigRows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, name); err != nil { + return nil, err + } + return resp.Id, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultNhSystemConfigModel) Insert(ctx context.Context, data *NhSystemConfig) (sql.Result, error) { + novaHomeNhSystemConfigIdKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigIdPrefix, data.Id) + novaHomeNhSystemConfigNameKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigNamePrefix, data.Name) + ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, nhSystemConfigRowsExpectAutoSet) + return conn.ExecCtx(ctx, query, data.Module, data.Name, data.Type, data.Value, data.Remark, data.Sort, data.CreatedId, data.UpdatedId) + }, novaHomeNhSystemConfigIdKey, novaHomeNhSystemConfigNameKey) + return ret, err +} + +func (m *defaultNhSystemConfigModel) Update(ctx context.Context, newData *NhSystemConfig) error { + data, err := m.FindOne(ctx, newData.Id) + if err != nil { + return err + } + + novaHomeNhSystemConfigIdKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigIdPrefix, data.Id) + novaHomeNhSystemConfigNameKey := fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigNamePrefix, data.Name) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhSystemConfigRowsWithPlaceHolder) + return conn.ExecCtx(ctx, query, newData.Module, newData.Name, newData.Type, newData.Value, newData.Remark, newData.Sort, newData.CreatedId, newData.UpdatedId, newData.Id) + }, novaHomeNhSystemConfigIdKey, novaHomeNhSystemConfigNameKey) + return err +} + +func (m *defaultNhSystemConfigModel) formatPrimary(primary any) string { + return fmt.Sprintf("%s%v", cacheNovaHomeNhSystemConfigIdPrefix, primary) +} + +func (m *defaultNhSystemConfigModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhSystemConfigRows, m.table) + return conn.QueryRowCtx(ctx, v, query, primary) +} + +func (m *defaultNhSystemConfigModel) tableName() string { + return m.table +} diff --git a/internal/model/nh_tourist_bind_model.go b/internal/model/nh_tourist_bind_model.go index ca4a563..358bebc 100755 --- a/internal/model/nh_tourist_bind_model.go +++ b/internal/model/nh_tourist_bind_model.go @@ -1,6 +1,11 @@ package model -import "github.com/zeromicro/go-zero/core/stores/sqlx" +import ( + "context" + "errors" + "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) var _ NhTouristBindModel = (*customNhTouristBindModel)(nil) @@ -10,13 +15,29 @@ type ( NhTouristBindModel interface { nhTouristBindModel withSession(session sqlx.Session) NhTouristBindModel + FindRequirePushUser(ctx context.Context, shareUid uint) ([]NhTouristBindUser, error) } customNhTouristBindModel struct { *defaultNhTouristBindModel } + + NhTouristBindUser struct { + Id uint `db:"id"` + Uid uint `db:"uid"` + } ) +func (m *customNhTouristBindModel) FindRequirePushUser(ctx context.Context, shareUid uint) ([]NhTouristBindUser, error) { + query := fmt.Sprintf("SELECT t2.id, t1.uid FROM nh_tourist_bind t1 JOIN nh_promote_bind t2 ON t1.uid = t2.invited_uid WHERE t2.share_uid = ? AND t2.is_push_role = 0;") + var resp []NhTouristBindUser + err := m.conn.QueryRowsCtx(ctx, &resp, query, shareUid) + if err != nil && !errors.Is(err, sqlx.ErrNotFound) { + return nil, err + } + return resp, nil +} + // NewNhTouristBindModel returns a model for the database table. func NewNhTouristBindModel(conn sqlx.SqlConn) NhTouristBindModel { return &customNhTouristBindModel{ diff --git a/internal/model/nh_tourist_bind_model_gen.go b/internal/model/nh_tourist_bind_model_gen.go index c280671..dca5da1 100755 --- a/internal/model/nh_tourist_bind_model_gen.go +++ b/internal/model/nh_tourist_bind_model_gen.go @@ -40,6 +40,7 @@ type ( TouristAccount string `db:"tourist_account"` // 游客账号 FormalAccount string `db:"formal_account"` // 正式账号 CreateTime int `db:"create_time"` // 创建时间 + Uid uint `db:"uid"` // 用户ID } ) @@ -71,14 +72,14 @@ func (m *defaultNhTouristBindModel) FindOne(ctx context.Context, id int) (*NhTou } func (m *defaultNhTouristBindModel) Insert(ctx context.Context, data *NhTouristBind) (sql.Result, error) { - query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, nhTouristBindRowsExpectAutoSet) - ret, err := m.conn.ExecCtx(ctx, query, data.TouristAccount, data.FormalAccount) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, nhTouristBindRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.TouristAccount, data.FormalAccount, data.Uid) return ret, err } func (m *defaultNhTouristBindModel) Update(ctx context.Context, data *NhTouristBind) error { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhTouristBindRowsWithPlaceHolder) - _, err := m.conn.ExecCtx(ctx, query, data.TouristAccount, data.FormalAccount, data.Id) + _, err := m.conn.ExecCtx(ctx, query, data.TouristAccount, data.FormalAccount, data.Uid, data.Id) return err } diff --git a/internal/model/nh_wallet_model.go b/internal/model/nh_wallet_model.go new file mode 100755 index 0000000..22fbd4a --- /dev/null +++ b/internal/model/nh_wallet_model.go @@ -0,0 +1,41 @@ +package model + +import ( + "context" + "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ NhWalletModel = (*customNhWalletModel)(nil) + +type ( + // NhWalletModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhWalletModel. + NhWalletModel interface { + nhWalletModel + withSession(session sqlx.Session) NhWalletModel + FindWalletByAddress(ctx context.Context, address ...string) (uint, error) + } + + customNhWalletModel struct { + *defaultNhWalletModel + } +) + +func (m *customNhWalletModel) FindWalletByAddress(ctx context.Context, address ...string) (uint, error) { + query := fmt.Sprintf("select `uid` from %s where `address` in ? limit 1", m.table) + var uid uint + err := m.conn.QueryRowCtx(ctx, &uid, query, address) + return uid, err +} + +// NewNhWalletModel returns a model for the database table. +func NewNhWalletModel(conn sqlx.SqlConn) NhWalletModel { + return &customNhWalletModel{ + defaultNhWalletModel: newNhWalletModel(conn), + } +} + +func (m *customNhWalletModel) withSession(session sqlx.Session) NhWalletModel { + return NewNhWalletModel(sqlx.NewSqlConnFromSession(session)) +} diff --git a/internal/model/nh_wallet_model_gen.go b/internal/model/nh_wallet_model_gen.go new file mode 100755 index 0000000..1cc4a88 --- /dev/null +++ b/internal/model/nh_wallet_model_gen.go @@ -0,0 +1,90 @@ +// Code generated by goctl. DO NOT EDIT. +// versions: +// goctl version: 1.7.3 + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + nhWalletFieldNames = builder.RawFieldNames(&NhWallet{}) + nhWalletRows = strings.Join(nhWalletFieldNames, ",") + nhWalletRowsExpectAutoSet = strings.Join(stringx.Remove(nhWalletFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhWalletRowsWithPlaceHolder = strings.Join(stringx.Remove(nhWalletFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + nhWalletModel interface { + Insert(ctx context.Context, data *NhWallet) (sql.Result, error) + FindOne(ctx context.Context, id int) (*NhWallet, error) + Update(ctx context.Context, data *NhWallet) error + Delete(ctx context.Context, id int) error + } + + defaultNhWalletModel struct { + conn sqlx.SqlConn + table string + } + + NhWallet struct { + Id int `db:"id"` + Uid sql.NullInt64 `db:"uid"` + Address sql.NullString `db:"address"` + Type string `db:"type"` // 区块连钱包类型 + Iid sql.NullInt64 `db:"iid"` // nh_invite_code表的ID,钱包在检查持有NFT的情况下会分配一个邀请码/测试码给它 + CreateTime sql.NullInt64 `db:"create_time"` + Status int8 `db:"status"` // 0:正常;1:删除 + } +) + +func newNhWalletModel(conn sqlx.SqlConn) *defaultNhWalletModel { + return &defaultNhWalletModel{ + conn: conn, + table: "`nh_wallet`", + } +} + +func (m *defaultNhWalletModel) Delete(ctx context.Context, id int) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultNhWalletModel) FindOne(ctx context.Context, id int) (*NhWallet, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhWalletRows, m.table) + var resp NhWallet + err := m.conn.QueryRowCtx(ctx, &resp, query, id) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultNhWalletModel) Insert(ctx context.Context, data *NhWallet) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, nhWalletRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.Address, data.Type, data.Iid, data.Status) + return ret, err +} + +func (m *defaultNhWalletModel) Update(ctx context.Context, data *NhWallet) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhWalletRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.Uid, data.Address, data.Type, data.Iid, data.Status, data.Id) + return err +} + +func (m *defaultNhWalletModel) tableName() string { + return m.table +} diff --git a/internal/pkg/aptos/aptos.go b/internal/pkg/aptos/aptos.go new file mode 100644 index 0000000..a929241 --- /dev/null +++ b/internal/pkg/aptos/aptos.go @@ -0,0 +1,59 @@ +package aptos + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" +) + +// GetTransactionOwnerAddress get Aptos transaction address +func GetTransactionOwnerAddress(contract, txHash, aptosNet string) (string, error) { + if aptosNet == "" { + aptosNet = "mainnet" + } + url := fmt.Sprintf("https://fullnode.%s.aptoslabs.com/v1/transactions/by_hash/%s", aptosNet, txHash) + + // Make a GET request to fetch transaction details + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", err + } + + payload, exists := result["payload"].(map[string]interface{}) + if !exists || payload["function"] == nil || payload["arguments"] == nil { + return "", errors.New("invalid transaction format") + } + + // Validate contract address + function := payload["function"].(string) + parts := strings.Split(function, "::") + fmt.Println(parts[0] + "::" + parts[1]) + if len(parts) < 2 || parts[0]+"::"+parts[1] != contract { + return "", errors.New("invalid contract address") + } + + // Check if address exists + address, ok := payload["arguments"].([]interface{})[0].(string) + if !ok { + return "", errors.New("invalid address format") + } + return address, nil +} + +// StrPadAptosAddress aptos 地址补全 +func StrPadAptosAddress(address string) string { + if len(address) >= 66 { + return address + } + perfix := "0000000000000000000000000000000000000000000000000000000000000000" + address = address[2:] + return "0x" + perfix[:64-len(address)] + address +} diff --git a/internal/pkg/aptos/aptos_test.go b/internal/pkg/aptos/aptos_test.go new file mode 100644 index 0000000..83d6a0b --- /dev/null +++ b/internal/pkg/aptos/aptos_test.go @@ -0,0 +1,17 @@ +package aptos + +import ( + "fmt" + "github.com/stretchr/testify/require" + "testing" +) + +func TestGetTransactionOwnerAddress(t *testing.T) { + addr, err := GetTransactionOwnerAddress("0x5a0ad9e31a2f452504429b6f7073cb325994c2c66204f5deb8e0561a9e950c3c::TeviStar", "0xaa42ec3ca61f398e52ed05fe12daee7df768468e77079184665846a1a1891217", "") + require.Nil(t, err) + fmt.Println(addr) +} + +func TestStrPadAptosAddress(t *testing.T) { + fmt.Println(StrPadAptosAddress("0x69d09434572ff312fcd4dc805318c29acf8e5daa2938cd38e674b7eb446063")) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 59881c4..48f2dda 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -20,6 +20,8 @@ type ServiceContext struct { TouristBindModel model.NhTouristBindModel CommunityModel model.NhTaskCommunityModel UserModel model.NhUserModel + WalletModel model.NhWalletModel + ConfigModel model.NhSystemConfigModel Earn *ea.Client DBConn sqlx.SqlConn @@ -38,6 +40,9 @@ func NewServiceContext(c config.Config) *ServiceContext { PromoteBindModel: model.NewNhPromoteBindModel(dbConn), CommunityModel: model.NewNhTaskCommunityModel(dbConn), UserModel: model.NewNhUserModel(dbConn), + TouristBindModel: model.NewNhTouristBindModel(dbConn), + WalletModel: model.NewNhWalletModel(dbConn), + ConfigModel: model.NewNhSystemConfigModel(dbConn, c.Cache), Earn: c.Earn.BuildEarnClient(), DBConn: dbConn,