From 31a674080da69fb826ebacb64b63188e8820f411 Mon Sep 17 00:00:00 2001 From: lianghuanjie Date: Fri, 27 Dec 2024 18:06:13 +0800 Subject: [PATCH] =?UTF-8?q?nft=E8=B4=A8=E6=8A=BC=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/api/nova-task.api | 48 ++++ doc/sql/novatask.sql | 89 +++++--- doc/swagger/nova-task.json | 216 ++++++++++++++++++ etc/novatask.example.yaml | 53 +++++ etc/novatask.yaml | 14 +- internal/config/config.go | 16 +- internal/consts/consts.go | 3 + internal/handler/routes.go | 24 ++ internal/handler/task/get_nft_list_handler.go | 22 ++ .../task/get_stake_task_detail_handler.go | 22 ++ internal/handler/task/stake_nft_handler.go | 28 +++ internal/handler/task/un_stake_nft_handler.go | 29 +++ internal/job/earn/{earn.go => cron.go} | 41 ++-- .../job/{pledge/pledge.go => holder/cron.go} | 33 +-- internal/job/{pledge => holder}/nft.go | 2 +- internal/job/job.go | 20 +- internal/job/stake_settle/cron.go | 41 ++++ internal/logic/task/get_nft_list_logic.go | 68 ++++++ .../logic/task/get_stake_task_detail_logic.go | 64 ++++++ internal/logic/task/stake_nft_logic.go | 36 +++ internal/logic/task/un_stake_nft_logic.go | 37 +++ .../logic/task/verify_task_result_logic.go | 22 +- internal/model/nh_game_pit_model.go | 44 ++++ internal/model/nh_game_pit_model_gen.go | 89 ++++++++ .../nh_nft_holder_change_log_model_gen.go | 10 +- internal/model/nh_nft_holder_model.go | 11 + internal/model/nh_nft_holder_model_gen.go | 10 +- internal/model/nh_system_config_model.go | 44 ++++ internal/model/nh_task_nft_stake_log_model.go | 29 +++ .../model/nh_task_nft_stake_log_model_gen.go | 93 ++++++++ internal/model/nh_task_nft_stake_model.go | 52 +++++ internal/model/nh_task_nft_stake_model_gen.go | 105 +++++++++ .../model/nh_task_nft_stake_reward_model.go | 29 +++ .../nh_task_nft_stake_reward_model_gen.go | 95 ++++++++ internal/model/nh_wallet_model.go | 19 +- internal/pkg/errs/reason.go | 11 +- internal/pkg/utils/utils.go | 24 ++ internal/svc/service_context.go | 11 + internal/types/types.go | 27 +++ 39 files changed, 1532 insertions(+), 99 deletions(-) create mode 100644 etc/novatask.example.yaml create mode 100644 internal/handler/task/get_nft_list_handler.go create mode 100644 internal/handler/task/get_stake_task_detail_handler.go create mode 100644 internal/handler/task/stake_nft_handler.go create mode 100644 internal/handler/task/un_stake_nft_handler.go rename internal/job/earn/{earn.go => cron.go} (63%) rename internal/job/{pledge/pledge.go => holder/cron.go} (76%) rename internal/job/{pledge => holder}/nft.go (98%) create mode 100644 internal/job/stake_settle/cron.go create mode 100644 internal/logic/task/get_nft_list_logic.go create mode 100644 internal/logic/task/get_stake_task_detail_logic.go create mode 100644 internal/logic/task/stake_nft_logic.go create mode 100644 internal/logic/task/un_stake_nft_logic.go create mode 100755 internal/model/nh_game_pit_model.go create mode 100755 internal/model/nh_game_pit_model_gen.go create mode 100755 internal/model/nh_task_nft_stake_log_model.go create mode 100755 internal/model/nh_task_nft_stake_log_model_gen.go create mode 100755 internal/model/nh_task_nft_stake_model.go create mode 100755 internal/model/nh_task_nft_stake_model_gen.go create mode 100755 internal/model/nh_task_nft_stake_reward_model.go create mode 100755 internal/model/nh_task_nft_stake_reward_model_gen.go create mode 100644 internal/pkg/utils/utils.go diff --git a/doc/api/nova-task.api b/doc/api/nova-task.api index d1e806e..985fd97 100644 --- a/doc/api/nova-task.api +++ b/doc/api/nova-task.api @@ -27,6 +27,22 @@ service novatask { @doc "领取任务奖励" @handler GetTaskReward get /reward/:id (TaskIdPath) returns (GetTaskRewardResp) + + @doc "拉取玩家持有的nft列表" + @handler GetNftList + get /nfts returns (UserNftList) + + @doc "质押任务详情" + @handler GetStakeTaskDetail + get /task/stake returns (StakeTaskDetail) + + @doc "质押NFT" + @handler StakeNft + post /nft/stake (StakeNftList) + + @doc "取消质押NFT" + @handler UnStakeNft + post /nft/unstake (UnStakeNftReq) } type GetTaskListReq { @@ -86,3 +102,35 @@ type GetCommunityListResp { CommunityList []Community `json:"community_list"` // 社区列表 } +// StakeTaskDetail 质押任务详情 +type StakeTaskDetail { + StartDate string `json:"start_date"` // 开始日期 + EndDate string `json:"end_date"` // 结束日期 + CountDown int `json:"count_down"` // 剩余结算时间 + ProduceTokensToday float64 `json:"produce_token_today"` // 今日产出代币 + GameBonus int `json:"game_bonus"` // 游戏加成比率 + CanReceiveTokens float64 `json:"can_receive_tokens"` // 可领取代币数量 +} + +// UserNft 用户NFT +type UserNft { + TokenId string `json:"token_id"` // nftID + HasStake bool `json:"has_stake"` // 是否已质押 + StakeAt string `json:"stake_at"` // 质押时间 +} + +// UserNftList 用户NFT列表 +type UserNftList { + NftList []UserNft `json:"nft_list"` +} + +// StakeNftList 质押请求参数NFT列表 +type StakeNftList { + TokenIds []string `json:"token_ids"` // nft列表 +} + +// UnStakeNftReq 取消质押请求参数 +type UnStakeNftReq { + TokenId string `json:"token_id"` // nftID +} + diff --git a/doc/sql/novatask.sql b/doc/sql/novatask.sql index 8a6d189..ffd0524 100644 --- a/doc/sql/novatask.sql +++ b/doc/sql/novatask.sql @@ -1,41 +1,78 @@ -#DROP TABLE IF EXISTS `nh_task_progress`; CREATE TABLE `nh_task_progress` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `uid` int(11) NOT NULL, - `task_id` int(11) unsigned NOT NULL COMMENT '任务id', - `task_seq` int(11) NOT NULL COMMENT '用于可重复任务的序列号', - `stage` tinyint NOT NULL DEFAULT 0 COMMENT '任务的阶段, 0:未完成 1:待校验 2:已完成未领取 3:已领取', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `uid` int(11) unsigned NOT NULL, + `task_id` int(11) unsigned NOT NULL COMMENT '任务id', + `task_seq` int(11) NOT NULL COMMENT '用于可重复任务的序列号', + `stage` tinyint NOT NULL DEFAULT 0 COMMENT '任务的阶段, 0:未完成 1:待校验 2:已完成未领取 3:已领取', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uid_task_id_seq` (`uid`, `task_id`, `task_seq`) -) COMMENT='用户任务节点'; +) COMMENT ='用户任务节点'; -#DROP TABLE IF EXISTS `nh_nft_holder`; CREATE TABLE `nh_nft_holder` ( - `id` int NOT NULL AUTO_INCREMENT, - `address` varchar(80) NOT NULL COMMENT '钱包地址', - `token_id` varchar(80) NOT NULL COMMENT 'token id', - `balance` int(11) NOT NULL DEFAULT 0 COMMENT '余额', - `update_seq` int NOT NULL COMMENT '更新序列号', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `id` int unsigned NOT NULL AUTO_INCREMENT, + `address` varchar(80) NOT NULL COMMENT '钱包地址', + `token_id` varchar(32) NOT NULL COMMENT 'token id', + `balance` int(11) NOT NULL DEFAULT 0 COMMENT '余额', + `update_seq` int NOT NULL COMMENT '更新序列号', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY (`address`, `token_id`), INDEX (`update_seq`) ) COMMENT ='nft 持有表'; -#DROP TABLE IF EXISTS `nh_nft_holder_change_log`; CREATE TABLE `nh_nft_holder_change_log` ( - `id` int NOT NULL AUTO_INCREMENT, - `address` varchar(80) NOT NULL COMMENT '钱包地址', - `token_id` varchar(80) NOT NULL COMMENT 'token id', - `value` int(11) NOT NULL COMMENT '变化数量', - `balance` int(11) NOT NULL COMMENT '余额', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `id` int unsigned NOT NULL AUTO_INCREMENT, + `address` varchar(80) NOT NULL COMMENT '钱包地址', + `token_id` varchar(32) NOT NULL COMMENT 'token id', + `value` int(11) NOT NULL COMMENT '变化数量', + `balance` int(11) NOT NULL COMMENT '余额', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`) -) COMMENT ='nft 持有表变化日志'; \ No newline at end of file +) COMMENT ='nft 持有表变化日志'; + +CREATE TABLE `nh_task_nft_stake` +( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `uid` int unsigned NOT NULL COMMENT '用户钱包', + `token_id` varchar(32) NOT NULL COMMENT 'token id', + `state` tinyint NOT NULL DEFAULT 0 COMMENT '状态:1质押中, 0已取消质押', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY (`uid`, `token_id`) +) COMMENT ='nft质押表'; + +CREATE TABLE `nh_task_nft_stake_log` +( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `uid` int unsigned NOT NULL COMMENT '用户钱包', + `address` varchar(80) NOT NULL COMMENT '钱包地址', + `token_id` varchar(32) NOT NULL COMMENT 'token id', + `award_seq` int NOT NULL COMMENT '派奖序列号', + `balance` int(11) NOT NULL COMMENT '余额', + `stake` tinyint NOT NULL DEFAULT 0 COMMENT '状态:1质押中, 0未质押', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) +) COMMENT ='派奖时nft质押日志表'; + +CREATE TABLE `nh_task_nft_stake_reward` +( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `uid` int unsigned NOT NULL COMMENT '用户钱包', + `award_seq` int NOT NULL COMMENT '派奖序列号', + `pledge_output` decimal(40, 8) DEFAULT NULL COMMENT '质押产出代币', + `random_coefficient` float NOT NULL COMMENT '随机系数', + `occupy_percent` int NOT NULL DEFAULT 100 COMMENT '占领百分比', + `reward` decimal(40, 8) DEFAULT NULL COMMENT '奖励金额', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) +) COMMENT ='nft质押派奖表'; \ No newline at end of file diff --git a/doc/swagger/nova-task.json b/doc/swagger/nova-task.json index 73aef71..77bd0b3 100644 --- a/doc/swagger/nova-task.json +++ b/doc/swagger/nova-task.json @@ -32,6 +32,90 @@ ] } }, + "/gapi/task/v1/nft/stake": { + "post": { + "summary": "质押NFT", + "operationId": "StakeNft", + "responses": { + "200": { + "description": "A successful response.", + "schema": {} + } + }, + "parameters": [ + { + "name": "body", + "description": " StakeNftList 质押请求参数NFT列表", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/StakeNftList" + } + } + ], + "tags": [ + "task" + ], + "security": [ + { + "apiKey": [] + } + ] + } + }, + "/gapi/task/v1/nft/unstake": { + "post": { + "summary": "取消质押NFT", + "operationId": "UnStakeNft", + "responses": { + "200": { + "description": "A successful response.", + "schema": {} + } + }, + "parameters": [ + { + "name": "body", + "description": " UnStakeNftReq 取消质押请求参数", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UnStakeNftReq" + } + } + ], + "tags": [ + "task" + ], + "security": [ + { + "apiKey": [] + } + ] + } + }, + "/gapi/task/v1/nfts": { + "get": { + "summary": "拉取玩家持有的nft列表", + "operationId": "GetNftList", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/UserNftList" + } + } + }, + "tags": [ + "task" + ], + "security": [ + { + "apiKey": [] + } + ] + } + }, "/gapi/task/v1/reward/{id}": { "get": { "summary": "领取任务奖励", @@ -104,6 +188,28 @@ ] } }, + "/gapi/task/v1/task/stake": { + "get": { + "summary": "质押任务详情", + "operationId": "GetStakeTaskDetail", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/StakeTaskDetail" + } + } + }, + "tags": [ + "task" + ], + "security": [ + { + "apiKey": [] + } + ] + } + }, "/gapi/task/v1/tasks": { "get": { "summary": "获取任务列表", @@ -233,6 +339,64 @@ "points" ] }, + "StakeNftList": { + "type": "object", + "properties": { + "token_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": " nft列表" + } + }, + "title": "StakeNftList", + "required": [ + "token_ids" + ] + }, + "StakeTaskDetail": { + "type": "object", + "properties": { + "start_date": { + "type": "string", + "description": " 开始日期" + }, + "end_date": { + "type": "string", + "description": " 结束日期" + }, + "count_down": { + "type": "integer", + "format": "int32", + "description": " 剩余结算时间" + }, + "produce_token_today": { + "type": "number", + "format": "double", + "description": " 今日产出代币" + }, + "game_bonus": { + "type": "integer", + "format": "int32", + "description": " 游戏加成比率" + }, + "can_receive_tokens": { + "type": "number", + "format": "double", + "description": " 可领取代币数量" + } + }, + "title": "StakeTaskDetail", + "required": [ + "start_date", + "end_date", + "count_down", + "produce_token_today", + "game_bonus", + "can_receive_tokens" + ] + }, "Task": { "type": "object", "properties": { @@ -333,6 +497,58 @@ "type": "object", "title": "TaskIdPath" }, + "UnStakeNftReq": { + "type": "object", + "properties": { + "token_id": { + "type": "string", + "description": " nftID" + } + }, + "title": "UnStakeNftReq", + "required": [ + "token_id" + ] + }, + "UserNft": { + "type": "object", + "properties": { + "token_id": { + "type": "string", + "description": " nftID" + }, + "has_stake": { + "type": "boolean", + "format": "boolean", + "description": " 是否已质押" + }, + "stake_at": { + "type": "string", + "description": " 质押时间" + } + }, + "title": "UserNft", + "required": [ + "token_id", + "has_stake", + "stake_at" + ] + }, + "UserNftList": { + "type": "object", + "properties": { + "nft_list": { + "type": "array", + "items": { + "$ref": "#/definitions/UserNft" + } + } + }, + "title": "UserNftList", + "required": [ + "nft_list" + ] + }, "VerifyTaskResultReq": { "type": "object", "properties": { diff --git a/etc/novatask.example.yaml b/etc/novatask.example.yaml new file mode 100644 index 0000000..fdce005 --- /dev/null +++ b/etc/novatask.example.yaml @@ -0,0 +1,53 @@ +Name: novatask # 服务名称 +Host: 0.0.0.0 # 服务监听地址 +Port: 8888 # 服务监听端口 + +# 日志配置 +Log: + Mode: "file" + Encoding: "json" + Path: "logs" + Level: "info" + Compress: true + KeepDays: 7 + MaxBackups: 3 + MaxSize: 100 + +# 鉴权密钥配置 +Auth: + AccessSecret: "Mj2G%szYe&$MP@ytNv8JktQN1n5^cPq%" # 鉴权token密钥 + +# mysql相关配置 +MySql: + Addr: "127.0.0.1:3306" # mysql地址 + User: "root" # mysql用户 + Password: "123456" # mysql密码 + Database: "nova_home" # 数据库名 + +# redis配置 +Redis: + Host: "127.0.0.1:6379" + Pass: "xxx" + +# redis缓存相关配置 +Cache: + - Host: "127.0.0.1:6379" + Pass: "xxx" + +# earn平台配置 +Earn: + ClientId: "4d6269e3-8aac-4550-acf9-dc891caf20a8" + ClientSecret: "GJpQ4TmX4p2VMY7U3XtExZQKYfibMv24" + GameId: "c0deda99-bb15-47a2-a3be-f1fe2983cde2" + + +# earn 数据上报 定时任务配置 +EarnCorn: + Spec: "@every 5m" + RunOnStart : true # 是否在启动时执行一次 + +# nft质押查询定时任务配置 +NftTaskCron: + HolderSpec: "@every 30m" + SettleSpec: "5 0 0 * * ?" # 每天凌晨0点5秒执行质押结算 + HolderCheckRunOnStart : false \ No newline at end of file diff --git a/etc/novatask.yaml b/etc/novatask.yaml index 417c495..a4033ad 100644 --- a/etc/novatask.yaml +++ b/etc/novatask.yaml @@ -23,6 +23,9 @@ MySql: # mysql相关配置 Password: "jMDqPQM^a6hsAR" # mysql密码 Database: "nova_home" # 数据库名 +Redis: + Host: "127.0.0.1:6379" + Cache: - Host: "127.0.0.1:6379" @@ -31,14 +34,11 @@ Earn: ClientSecret: "GJpQ4TmX4p2VMY7U3XtExZQKYfibMv24" GameId: "c0deda99-bb15-47a2-a3be-f1fe2983cde2" -DailyPay: - Contract: "0xf5b1c3f66c418071b025e3fa63e0f0100240951477fa45c760de80e3232b95bf::my_counter" - Network: "testnet" - EarnCorn: Spec: "@every 5m" RunOnStart : true -PledgeCron: - Spec: "@every 30m" - RunOnStart : true \ No newline at end of file +NftTaskCron: + HolderSpec: "@every 30m" + SettleSpec: "5 0 0 * * ?" # 每天凌晨0点5秒执行质押结算 + HolderCheckRunOnStart : false \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 80abdfd..f14109a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,6 +3,7 @@ package config import ( "fmt" "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/rest" "net/url" @@ -13,15 +14,22 @@ import ( type Config struct { rest.RestConf MySql MySqlConf + Redis redis.RedisConf Cache cache.CacheConf Auth struct { AccessSecret string AccessExpire time.Duration `json:",default=168h"` } - Earn earn.Config - DailyPay DailyPay - EarnCorn Cron `json:",optional"` - PledgeCron Cron `json:",optional"` + Earn earn.Config + EarnCorn struct { + Spec string + RunOnStart bool `json:",optional"` + } `json:",optional"` + NftTaskCron struct { + HolderSpec string + SettleSpec string + HolderCheckRunOnStart bool `json:",optional"` + } `json:",optional"` } type Cron struct { diff --git a/internal/consts/consts.go b/internal/consts/consts.go index f6b1665..cc652f7 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -2,4 +2,7 @@ package consts const ( EarnAllianceInviterId = "earn_alliance_inviter_id" + DailyPayConf = "daily_pay_conf" + NftStakeTaskDate = "nft_stake_task_date" + NftStakeTaskConf = "nft_stake_task_conf" ) diff --git a/internal/handler/routes.go b/internal/handler/routes.go index e3ef417..8a4c404 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -33,6 +33,24 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ + { + // 质押NFT + Method: http.MethodPost, + Path: "/nft/stake", + Handler: task.StakeNftHandler(serverCtx), + }, + { + // 取消质押NFT + Method: http.MethodPost, + Path: "/nft/unstake", + Handler: task.UnStakeNftHandler(serverCtx), + }, + { + // 拉取玩家持有的nft列表 + Method: http.MethodGet, + Path: "/nfts", + Handler: task.GetNftListHandler(serverCtx), + }, { // 领取任务奖励 Method: http.MethodGet, @@ -45,6 +63,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/task", Handler: task.VerifyTaskResultHandler(serverCtx), }, + { + // 质押任务详情 + Method: http.MethodGet, + Path: "/task/stake", + Handler: task.GetStakeTaskDetailHandler(serverCtx), + }, }, rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/gapi/task/v1"), diff --git a/internal/handler/task/get_nft_list_handler.go b/internal/handler/task/get_nft_list_handler.go new file mode 100644 index 0000000..93833cb --- /dev/null +++ b/internal/handler/task/get_nft_list_handler.go @@ -0,0 +1,22 @@ +package task + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/task" + "nova_task/internal/svc" +) + +// 拉取玩家持有的nft列表 +func GetNftListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + l := task.NewGetNftListLogic(r.Context(), svcCtx) + resp, err := l.GetNftList() + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/task/get_stake_task_detail_handler.go b/internal/handler/task/get_stake_task_detail_handler.go new file mode 100644 index 0000000..636ebbb --- /dev/null +++ b/internal/handler/task/get_stake_task_detail_handler.go @@ -0,0 +1,22 @@ +package task + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/task" + "nova_task/internal/svc" +) + +// 质押任务详情 +func GetStakeTaskDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + l := task.NewGetStakeTaskDetailLogic(r.Context(), svcCtx) + resp, err := l.GetStakeTaskDetail() + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/task/stake_nft_handler.go b/internal/handler/task/stake_nft_handler.go new file mode 100644 index 0000000..130dcdf --- /dev/null +++ b/internal/handler/task/stake_nft_handler.go @@ -0,0 +1,28 @@ +package task + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/task" + "nova_task/internal/svc" + "nova_task/internal/types" +) + +func StakeNftHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.StakeNftList + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := task.NewStakeNftLogic(r.Context(), svcCtx) + err := l.StakeNft(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.Ok(w) + } + } +} diff --git a/internal/handler/task/un_stake_nft_handler.go b/internal/handler/task/un_stake_nft_handler.go new file mode 100644 index 0000000..dffbac1 --- /dev/null +++ b/internal/handler/task/un_stake_nft_handler.go @@ -0,0 +1,29 @@ +package task + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/task" + "nova_task/internal/svc" + "nova_task/internal/types" +) + +// 取消质押NFT +func UnStakeNftHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.UnStakeNftReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := task.NewUnStakeNftLogic(r.Context(), svcCtx) + err := l.UnStakeNft(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.Ok(w) + } + } +} diff --git a/internal/job/earn/earn.go b/internal/job/earn/cron.go similarity index 63% rename from internal/job/earn/earn.go rename to internal/job/earn/cron.go index aed8e1e..3f2a133 100644 --- a/internal/job/earn/earn.go +++ b/internal/job/earn/cron.go @@ -3,65 +3,66 @@ package earn import ( "context" ea "github.com/earn-alliance/earnalliance-go" + "github.com/robfig/cron/v3" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" "nova_task/internal/consts" "nova_task/internal/svc" ) -// Earn 用户数据上报earn平台定时任务 -type Earn struct { +// Cron 用户数据上报earn平台定时任务 +type Cron struct { ctx context.Context svcCtx *svc.ServiceContext } -func NewEarn(ctx context.Context, svcCtx *svc.ServiceContext) *Earn { - e := &Earn{ctx: ctx, svcCtx: svcCtx} +func NewCron(ctx context.Context, svcCtx *svc.ServiceContext) cron.Job { + e := &Cron{ctx: ctx, svcCtx: svcCtx} if e.svcCtx.Config.EarnCorn.RunOnStart { e.Run() } return e } -func (e *Earn) Spec() string { - return e.svcCtx.Config.EarnCorn.Spec +func (c *Cron) Spec() string { + return c.svcCtx.Config.EarnCorn.Spec } -func (e *Earn) Run() { +func (c *Cron) Run() { logx.Debugw("run earn cron task") - c, err := e.svcCtx.ConfigModel.FindOneByName(e.ctx, consts.EarnAllianceInviterId) + conf, err := c.svcCtx.ConfigModel.FindOneByName(c.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)) + c.pushUserInfo(cast.ToUint(conf.Value)) + c.pushUserBind(cast.ToUint(conf.Value)) } -func (e *Earn) pushUserInfo(shareId uint) { - us, err := e.svcCtx.PromoteBindModel.FindRequirePushUser(e.ctx, shareId) +func (c *Cron) pushUserInfo(shareId uint) { + us, err := c.svcCtx.PromoteBindModel.FindRequirePushUser(c.ctx, shareId) if err != nil { logx.Errorw("find require push user failed", logx.Field("err", err), logx.Field("share_id", shareId)) return } logx.Debugw("find require push user", logx.Field("count", len(us))) for _, u := range us { - ui, err := e.svcCtx.UserModel.FindOne(e.ctx, u.InvitedUid) + ui, err := c.svcCtx.UserModel.FindOne(c.ctx, u.InvitedUid) if err != nil { logx.Errorw("find user failed", logx.Field("err", err), logx.Field("uid", u.InvitedUid)) continue } var twitterId string - ut, err := e.svcCtx.TwitterModel.FindOne(e.ctx, u.InvitedUid) + ut, err := c.svcCtx.TwitterModel.FindOne(c.ctx, u.InvitedUid) if err == nil { twitterId = ut.TwitterId } - err = e.svcCtx.PromoteBindModel.UpdatePushUser(e.ctx, u.Id) + err = c.svcCtx.PromoteBindModel.UpdatePushUser(c.ctx, u.Id) if err != nil { logx.Errorw("update push user failed", logx.Field("err", err), logx.Field("uid", u.InvitedUid), logx.Field("twitter_id", twitterId), logx.Field("email", ui.Email)) } else { - e.svcCtx.Earn.SetIdentifiers(cast.ToString(ui.Id), &ea.Identifiers{ + c.svcCtx.Earn.SetIdentifiers(cast.ToString(ui.Id), &ea.Identifiers{ Email: ea.IdentifierFrom(ui.Email), TwitterId: ea.IdentifierFrom(twitterId), }) @@ -70,19 +71,19 @@ func (e *Earn) pushUserInfo(shareId uint) { } } -func (e *Earn) pushUserBind(shareId uint) { - us, err := e.svcCtx.TouristBindModel.FindRequirePushUser(e.ctx, shareId) +func (c *Cron) pushUserBind(shareId uint) { + us, err := c.svcCtx.TouristBindModel.FindRequirePushUser(c.ctx, shareId) if err != nil { logx.Errorw("find require push bind role user failed", logx.Field("err", err), logx.Field("share_id", shareId)) return } logx.Debugw("find require push bind role user", logx.Field("count", len(us))) for _, u := range us { - err = e.svcCtx.PromoteBindModel.UpdatePushRole(e.ctx, u.Id) + err = c.svcCtx.PromoteBindModel.UpdatePushRole(c.ctx, u.Id) if err != nil { logx.Errorw("update push user failed", logx.Field("err", err), logx.Field("uid", u.Uid)) } else { - e.svcCtx.Earn.Track(cast.ToString(u.Uid), "BIND_ROLE", nil, nil) + c.svcCtx.Earn.Track(cast.ToString(u.Uid), "BIND_ROLE", nil, nil) logx.Infow("push user info success", logx.Field("uid", u.Uid)) } } diff --git a/internal/job/pledge/pledge.go b/internal/job/holder/cron.go similarity index 76% rename from internal/job/pledge/pledge.go rename to internal/job/holder/cron.go index 06add91..ac1bb06 100644 --- a/internal/job/pledge/pledge.go +++ b/internal/job/holder/cron.go @@ -1,8 +1,9 @@ -package pledge +package holder import ( "context" "errors" + "github.com/robfig/cron/v3" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" "nova_task/internal/model" @@ -10,28 +11,28 @@ import ( "time" ) -type Pledge struct { +type Cron struct { ctx context.Context svcCtx *svc.ServiceContext } -func NewPledge(ctx context.Context, svcCtx *svc.ServiceContext) *Pledge { - pg := &Pledge{ +func NewCron(ctx context.Context, svcCtx *svc.ServiceContext) cron.Job { + pg := &Cron{ ctx: ctx, svcCtx: svcCtx, } - if svcCtx.Config.PledgeCron.RunOnStart { + if svcCtx.Config.NftTaskCron.HolderCheckRunOnStart { pg.Run() } return pg } -func (p *Pledge) Spec() string { - return p.svcCtx.Config.PledgeCron.Spec +func (c *Cron) Spec() string { + return c.svcCtx.Config.NftTaskCron.HolderSpec } -func (p *Pledge) Run() { - logx.Debugw("run pledge cron task") +func (c *Cron) Run() { + logx.Debugw("run Cron cron task") ols, err := GetOwnerList() if err != nil { logx.Errorw("get owner list error", logx.Field("error", err)) @@ -42,7 +43,7 @@ func (p *Pledge) Run() { for _, tk := range o.TokenBalances { balance := cast.ToInt(tk.Balance) logx.Debugw("owner token", logx.Field("address", o.OwnerAddress), logx.Field("token", tk.TokenID), logx.Field("balance", tk.Balance)) - nft, err := p.svcCtx.NftHolderModel.FindOneByAddressTokenId(p.ctx, o.OwnerAddress, tk.TokenID) + nft, err := c.svcCtx.NftHolderModel.FindOneByAddressTokenId(c.ctx, o.OwnerAddress, tk.TokenID) if err != nil { if errors.Is(err, model.ErrNotFound) { nft = &model.NhNftHolder{ @@ -60,7 +61,7 @@ func (p *Pledge) Run() { var value int if nft.Id == 0 { // 新增 - _, err = p.svcCtx.NftHolderModel.Insert(p.ctx, nft) + _, err = c.svcCtx.NftHolderModel.Insert(c.ctx, nft) value = balance } else { // 持有数量变化 @@ -68,7 +69,7 @@ func (p *Pledge) Run() { if value != 0 { nft.Balance = balance nft.UpdateSeq = updateSeq - err = p.svcCtx.NftHolderModel.Update(p.ctx, nft) + err = c.svcCtx.NftHolderModel.Update(c.ctx, nft) } } @@ -78,7 +79,7 @@ func (p *Pledge) Run() { // 余额有变化,记录变化日志 if value != 0 { - _, err = p.svcCtx.NftHolderChangeLogModel.Insert(p.ctx, &model.NhNftHolderChangeLog{ + _, err = c.svcCtx.NftHolderChangeLogModel.Insert(c.ctx, &model.NhNftHolderChangeLog{ Address: o.OwnerAddress, TokenId: tk.TokenID, Value: balance, @@ -92,13 +93,13 @@ func (p *Pledge) Run() { } // 删除已经不持有的地址,且添加变化日志 - nfts, err := p.svcCtx.NftHolderModel.FindOtherUpdateSeq(p.ctx, updateSeq) + nfts, err := c.svcCtx.NftHolderModel.FindOtherUpdateSeq(c.ctx, updateSeq) if err != nil { logx.Errorw("find other update seq error", logx.Field("error", err)) return } for _, nft := range nfts { - _, err = p.svcCtx.NftHolderChangeLogModel.Insert(p.ctx, &model.NhNftHolderChangeLog{ + _, err = c.svcCtx.NftHolderChangeLogModel.Insert(c.ctx, &model.NhNftHolderChangeLog{ Address: nft.Address, TokenId: nft.TokenId, Value: -nft.Balance, @@ -108,7 +109,7 @@ func (p *Pledge) Run() { logx.Errorw("delete nft holder error", logx.Field("error", err), logx.Field("address", nft.Address), logx.Field("token", nft.TokenId)) } } - err = p.svcCtx.NftHolderModel.DeleteOtherUpdateSeq(p.ctx, updateSeq) + err = c.svcCtx.NftHolderModel.DeleteOtherUpdateSeq(c.ctx, updateSeq) if err != nil { logx.Errorw("delete other update seq error", logx.Field("error", err), logx.Field("update_seq", updateSeq)) } diff --git a/internal/job/pledge/nft.go b/internal/job/holder/nft.go similarity index 98% rename from internal/job/pledge/nft.go rename to internal/job/holder/nft.go index 99260ea..62edc9a 100644 --- a/internal/job/pledge/nft.go +++ b/internal/job/holder/nft.go @@ -1,4 +1,4 @@ -package pledge +package holder import ( "encoding/json" diff --git a/internal/job/job.go b/internal/job/job.go index bb5f5ad..aff1437 100644 --- a/internal/job/job.go +++ b/internal/job/job.go @@ -6,10 +6,18 @@ import ( "github.com/robfig/cron/v3" "github.com/zeromicro/go-zero/core/logx" "nova_task/internal/job/earn" - "nova_task/internal/job/pledge" + "nova_task/internal/job/holder" + "nova_task/internal/job/stake_settle" "nova_task/internal/svc" ) +// cronList 定时器Builder列表 +var cronList = []func(context.Context, *svc.ServiceContext) cron.Job{ + earn.NewCron, + holder.NewCron, + stake_settle.NewCron, +} + type Job struct { ctx context.Context cancel context.CancelFunc @@ -21,15 +29,13 @@ type Spec interface { Spec() string } +// NewJob 创建定时器服务 func NewJob(svcCtx *svc.ServiceContext) *Job { ctx, cancel := context.WithCancel(context.Background()) - var cronList = []cron.Job{ - earn.NewEarn(ctx, svcCtx), - pledge.NewPledge(ctx, svcCtx), - } var err error - c := cron.New() - for _, cr := range cronList { + c := cron.New(cron.WithSeconds()) + for _, cf := range cronList { + cr := cf(ctx, svcCtx) if cs, ok := cr.(Spec); ok { spec := cs.Spec() if spec == "" { diff --git a/internal/job/stake_settle/cron.go b/internal/job/stake_settle/cron.go new file mode 100644 index 0000000..109ce37 --- /dev/null +++ b/internal/job/stake_settle/cron.go @@ -0,0 +1,41 @@ +package stake_settle + +import ( + "context" + "github.com/robfig/cron/v3" + "github.com/zeromicro/go-zero/core/logx" + "nova_task/internal/svc" + "time" +) + +type Cron struct { + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCron(ctx context.Context, svcCtx *svc.ServiceContext) cron.Job { + return &Cron{ + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (c *Cron) Spec() string { + return c.svcCtx.Config.NftTaskCron.SettleSpec +} + +func (c *Cron) Run() { + start, end, err := c.svcCtx.ConfigModel.GetNftStakeTaskOpenDate(c.ctx) + if err != nil { + logx.Errorw("get nft stake task open date failed", logx.Field("err", err)) + return + } + end = end.AddDate(0, 0, 1).Add(-time.Second) + now := time.Now() + if now.Before(start) || now.After(end) { + logx.Debugw("now is not in the date range", logx.Field("now", now), logx.Field("start", start), logx.Field("end", end)) + return + } + + logx.Debugw("run settle cron task") +} diff --git a/internal/logic/task/get_nft_list_logic.go b/internal/logic/task/get_nft_list_logic.go new file mode 100644 index 0000000..8279453 --- /dev/null +++ b/internal/logic/task/get_nft_list_logic.go @@ -0,0 +1,68 @@ +package task + +import ( + "context" + "errors" + "nova_task/internal/model" + "nova_task/internal/pkg/errs" + "nova_task/internal/pkg/utils" + "time" + + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetNftListLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// 拉取玩家持有的nft列表 +func NewGetNftListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNftListLogic { + return &GetNftListLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetNftListLogic) GetNftList() (*types.UserNftList, error) { + uid := utils.GetUidUint(l.ctx) + address, err := l.svcCtx.WalletModel.FindAddressByUid(l.ctx, uid) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, errs.New(errs.ErrNotBindWallet, "") + } + l.Errorw("find address by uid failed", logx.Field("err", err), logx.Field("uid", uid)) + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + + tokens, err := l.svcCtx.NftHolderModel.FindTokensByAddress(l.ctx, address) + if err != nil { + l.Errorw("find tokens by address failed", logx.Field("err", err), logx.Field("address", address), logx.Field("uid", uid)) + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + + var nftList []types.UserNft + for _, token := range tokens { + var hasStake bool + var stakeAt string + nft, err := l.svcCtx.StakeNftModel.FindOneByUidTokenId(l.ctx, uid, token) + if err == nil { + hasStake = nft.State == 1 + stakeAt = nft.UpdatedAt.Format(time.DateOnly) + } + nftList = append(nftList, types.UserNft{ + TokenId: token, + HasStake: hasStake, + StakeAt: stakeAt, + }) + } + + return &types.UserNftList{ + NftList: nftList, + }, nil +} diff --git a/internal/logic/task/get_stake_task_detail_logic.go b/internal/logic/task/get_stake_task_detail_logic.go new file mode 100644 index 0000000..eefa9d0 --- /dev/null +++ b/internal/logic/task/get_stake_task_detail_logic.go @@ -0,0 +1,64 @@ +package task + +import ( + "context" + "errors" + "nova_task/internal/model" + "nova_task/internal/pkg/errs" + "nova_task/internal/pkg/utils" + "time" + + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetStakeTaskDetailLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewGetStakeTaskDetailLogic 质押任务详情 +func NewGetStakeTaskDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetStakeTaskDetailLogic { + return &GetStakeTaskDetailLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetStakeTaskDetailLogic) GetStakeTaskDetail() (*types.StakeTaskDetail, error) { + uid := utils.GetUidUint(l.ctx) + start, end, err := l.svcCtx.ConfigModel.GetNftStakeTaskOpenDate(l.ctx) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, errs.New(errs.ErrTaskOpenDateNotSet, "task open date not set") + } + l.Errorw("get nft stake task open date failed", logx.Field("err", err)) + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + + taskConf, err := l.svcCtx.ConfigModel.GetNftStakeTaskConf(l.ctx) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, errs.New(errs.ErrTaskConfNotSet, "task config not set") + } + l.Errorw("get nft stake task conf failed", logx.Field("err", err)) + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + var gameBonus int + if l.svcCtx.GamePitModel.UserExist(l.ctx, uid) { + gameBonus = taskConf.OccupyPercent + } + + return &types.StakeTaskDetail{ + StartDate: start.Format(time.DateOnly), + EndDate: end.Format(time.DateOnly), + CountDown: utils.TodayRemainSeconds(), + ProduceTokensToday: 0, + GameBonus: gameBonus, + CanReceiveTokens: 0, + }, nil +} diff --git a/internal/logic/task/stake_nft_logic.go b/internal/logic/task/stake_nft_logic.go new file mode 100644 index 0000000..c0cc35f --- /dev/null +++ b/internal/logic/task/stake_nft_logic.go @@ -0,0 +1,36 @@ +package task + +import ( + "context" + "nova_task/internal/pkg/errs" + "nova_task/internal/pkg/utils" + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type StakeNftLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewStakeNftLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StakeNftLogic { + return &StakeNftLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *StakeNftLogic) StakeNft(req *types.StakeNftList) error { + uid := utils.GetUidUint(l.ctx) + err := l.svcCtx.StakeNftModel.StakeNft(l.ctx, uid, req.TokenIds) + if err != nil { + l.Errorw("stake nft failed", logx.Field("err", err), logx.Field("uid", uid), logx.Field("tokenIds", req.TokenIds)) + return errs.New(errs.ErrDatabaseOperate, err) + } + + return errs.Success() +} diff --git a/internal/logic/task/un_stake_nft_logic.go b/internal/logic/task/un_stake_nft_logic.go new file mode 100644 index 0000000..34ef892 --- /dev/null +++ b/internal/logic/task/un_stake_nft_logic.go @@ -0,0 +1,37 @@ +package task + +import ( + "context" + "nova_task/internal/pkg/errs" + "nova_task/internal/pkg/utils" + + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UnStakeNftLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUnStakeNftLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UnStakeNftLogic { + return &UnStakeNftLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UnStakeNftLogic) UnStakeNft(req *types.UnStakeNftReq) error { + uid := utils.GetUidUint(l.ctx) + err := l.svcCtx.StakeNftModel.UnStakeNft(l.ctx, uid, req.TokenId) + if err != nil { + l.Errorw("unstake nft failed", logx.Field("err", err), logx.Field("uid", uid), logx.Field("tokenIds", req.TokenId)) + return errs.New(errs.ErrDatabaseOperate, err) + } + + return errs.Success() +} diff --git a/internal/logic/task/verify_task_result_logic.go b/internal/logic/task/verify_task_result_logic.go index 4bbb3f1..20ad829 100644 --- a/internal/logic/task/verify_task_result_logic.go +++ b/internal/logic/task/verify_task_result_logic.go @@ -2,9 +2,11 @@ package task import ( "context" + "encoding/json" "errors" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/aptos" "nova_task/internal/pkg/errs" @@ -99,12 +101,28 @@ func (l *VerifyTaskResultLogic) VerifyTaskResult(req *types.VerifyTaskResultReq) } func (l *VerifyTaskResultLogic) checkoutTranscation(uid int, txHash string) bool { - address, err := aptos.GetTransactionOwnerAddress(l.svcCtx.Config.DailyPay.Contract, txHash, l.svcCtx.Config.DailyPay.Network) + conf := struct { + Contract string `json:"contract"` + Network string `json:"network"` + }{} + cf, err := l.svcCtx.ConfigModel.FindOneByName(l.ctx, consts.DailyPayConf) + if err != nil { + if !errors.Is(err, model.ErrNotFound) { + l.Errorw("find daily pay conf error", logx.Field("err", err)) + } + return false + } + err = json.Unmarshal([]byte(cf.Value), &conf) + if err != nil { + l.Errorw("unmarshal daily pay conf error", logx.Field("err", err), logx.Field("value", cf.Value)) + return false + } + address, err := aptos.GetTransactionOwnerAddress(conf.Contract, txHash, conf.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) + targetUid, err := l.svcCtx.WalletModel.FindUidByAddress(l.ctx, 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 diff --git a/internal/model/nh_game_pit_model.go b/internal/model/nh_game_pit_model.go new file mode 100755 index 0000000..efae8e1 --- /dev/null +++ b/internal/model/nh_game_pit_model.go @@ -0,0 +1,44 @@ +package model + +import ( + "context" + "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ NhGamePitModel = (*customNhGamePitModel)(nil) + +type ( + // NhGamePitModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhGamePitModel. + NhGamePitModel interface { + nhGamePitModel + withSession(session sqlx.Session) NhGamePitModel + UserExist(ctx context.Context, uid uint) bool + } + + customNhGamePitModel struct { + *defaultNhGamePitModel + } +) + +func (m *customNhGamePitModel) UserExist(ctx context.Context, uid uint) bool { + query := fmt.Sprintf("SELECT `id` FROM %s WHERE `uid` = ? LIMIT 1", m.table) + var id int + err := m.conn.QueryRowCtx(ctx, &id, query, uid) + if err != nil { + return false + } + return id > 0 +} + +// NewNhGamePitModel returns a model for the database table. +func NewNhGamePitModel(conn sqlx.SqlConn) NhGamePitModel { + return &customNhGamePitModel{ + defaultNhGamePitModel: newNhGamePitModel(conn), + } +} + +func (m *customNhGamePitModel) withSession(session sqlx.Session) NhGamePitModel { + return NewNhGamePitModel(sqlx.NewSqlConnFromSession(session)) +} diff --git a/internal/model/nh_game_pit_model_gen.go b/internal/model/nh_game_pit_model_gen.go new file mode 100755 index 0000000..b7c9ebd --- /dev/null +++ b/internal/model/nh_game_pit_model_gen.go @@ -0,0 +1,89 @@ +// 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/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + nhGamePitFieldNames = builder.RawFieldNames(&NhGamePit{}) + nhGamePitRows = strings.Join(nhGamePitFieldNames, ",") + nhGamePitRowsExpectAutoSet = strings.Join(stringx.Remove(nhGamePitFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhGamePitRowsWithPlaceHolder = strings.Join(stringx.Remove(nhGamePitFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + nhGamePitModel interface { + Insert(ctx context.Context, data *NhGamePit) (sql.Result, error) + FindOne(ctx context.Context, id uint) (*NhGamePit, error) + Update(ctx context.Context, data *NhGamePit) error + Delete(ctx context.Context, id uint) error + } + + defaultNhGamePitModel struct { + conn sqlx.SqlConn + table string + } + + NhGamePit struct { + Id uint `db:"id"` + Uid uint `db:"uid"` // 用户ID + RoleId int64 `db:"role_id"` // 角色id + CreatedAt time.Time `db:"created_at"` // 创建时间 + UpdatedAt time.Time `db:"updated_at"` // 修改时间 + } +) + +func newNhGamePitModel(conn sqlx.SqlConn) *defaultNhGamePitModel { + return &defaultNhGamePitModel{ + conn: conn, + table: "`nh_game_pit`", + } +} + +func (m *defaultNhGamePitModel) Delete(ctx context.Context, id uint) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultNhGamePitModel) FindOne(ctx context.Context, id uint) (*NhGamePit, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhGamePitRows, m.table) + var resp NhGamePit + 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 *defaultNhGamePitModel) Insert(ctx context.Context, data *NhGamePit) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, nhGamePitRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.RoleId) + return ret, err +} + +func (m *defaultNhGamePitModel) Update(ctx context.Context, data *NhGamePit) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhGamePitRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.Uid, data.RoleId, data.Id) + return err +} + +func (m *defaultNhGamePitModel) tableName() string { + return m.table +} diff --git a/internal/model/nh_nft_holder_change_log_model_gen.go b/internal/model/nh_nft_holder_change_log_model_gen.go index f647c35..8483e06 100755 --- a/internal/model/nh_nft_holder_change_log_model_gen.go +++ b/internal/model/nh_nft_holder_change_log_model_gen.go @@ -26,9 +26,9 @@ var ( type ( nhNftHolderChangeLogModel interface { Insert(ctx context.Context, data *NhNftHolderChangeLog) (sql.Result, error) - FindOne(ctx context.Context, id int) (*NhNftHolderChangeLog, error) + FindOne(ctx context.Context, id uint) (*NhNftHolderChangeLog, error) Update(ctx context.Context, data *NhNftHolderChangeLog) error - Delete(ctx context.Context, id int) error + Delete(ctx context.Context, id uint) error } defaultNhNftHolderChangeLogModel struct { @@ -37,7 +37,7 @@ type ( } NhNftHolderChangeLog struct { - Id int `db:"id"` + Id uint `db:"id"` Address string `db:"address"` // 钱包地址 TokenId string `db:"token_id"` // token id Value int `db:"value"` // 变化数量 @@ -54,13 +54,13 @@ func newNhNftHolderChangeLogModel(conn sqlx.SqlConn) *defaultNhNftHolderChangeLo } } -func (m *defaultNhNftHolderChangeLogModel) Delete(ctx context.Context, id int) error { +func (m *defaultNhNftHolderChangeLogModel) Delete(ctx context.Context, id uint) error { query := fmt.Sprintf("delete from %s where `id` = ?", m.table) _, err := m.conn.ExecCtx(ctx, query, id) return err } -func (m *defaultNhNftHolderChangeLogModel) FindOne(ctx context.Context, id int) (*NhNftHolderChangeLog, error) { +func (m *defaultNhNftHolderChangeLogModel) FindOne(ctx context.Context, id uint) (*NhNftHolderChangeLog, error) { query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhNftHolderChangeLogRows, m.table) var resp NhNftHolderChangeLog err := m.conn.QueryRowCtx(ctx, &resp, query, id) diff --git a/internal/model/nh_nft_holder_model.go b/internal/model/nh_nft_holder_model.go index 6b4e19e..b943563 100755 --- a/internal/model/nh_nft_holder_model.go +++ b/internal/model/nh_nft_holder_model.go @@ -17,6 +17,7 @@ type ( withSession(session sqlx.Session) NhNftHolderModel FindOtherUpdateSeq(ctx context.Context, updateSeq int) ([]*NhNftHolder, error) DeleteOtherUpdateSeq(ctx context.Context, updateSeq int) error + FindTokensByAddress(ctx context.Context, address string) ([]string, error) } customNhNftHolderModel struct { @@ -24,6 +25,16 @@ type ( } ) +func (m *customNhNftHolderModel) FindTokensByAddress(ctx context.Context, address string) ([]string, error) { + query := fmt.Sprintf("select `token_id` from %s where `address` = ?", m.table) + var tokens []string + err := m.conn.QueryRowsCtx(ctx, &tokens, query, address) + if err != nil && !errors.Is(err, sqlx.ErrNotFound) { + return nil, err + } + return tokens, nil +} + func (m *customNhNftHolderModel) DeleteOtherUpdateSeq(ctx context.Context, updateSeq int) error { delSql := fmt.Sprintf("delete from %s where `update_seq` != ?", m.table) _, err := m.conn.ExecCtx(ctx, delSql, updateSeq) diff --git a/internal/model/nh_nft_holder_model_gen.go b/internal/model/nh_nft_holder_model_gen.go index dbcee2f..05bf4d7 100755 --- a/internal/model/nh_nft_holder_model_gen.go +++ b/internal/model/nh_nft_holder_model_gen.go @@ -26,10 +26,10 @@ var ( type ( nhNftHolderModel interface { Insert(ctx context.Context, data *NhNftHolder) (sql.Result, error) - FindOne(ctx context.Context, id int) (*NhNftHolder, error) + FindOne(ctx context.Context, id uint) (*NhNftHolder, error) FindOneByAddressTokenId(ctx context.Context, address string, tokenId string) (*NhNftHolder, error) Update(ctx context.Context, data *NhNftHolder) error - Delete(ctx context.Context, id int) error + Delete(ctx context.Context, id uint) error } defaultNhNftHolderModel struct { @@ -38,7 +38,7 @@ type ( } NhNftHolder struct { - Id int `db:"id"` + Id uint `db:"id"` Address string `db:"address"` // 钱包地址 TokenId string `db:"token_id"` // token id Balance int `db:"balance"` // 余额 @@ -55,13 +55,13 @@ func newNhNftHolderModel(conn sqlx.SqlConn) *defaultNhNftHolderModel { } } -func (m *defaultNhNftHolderModel) Delete(ctx context.Context, id int) error { +func (m *defaultNhNftHolderModel) Delete(ctx context.Context, id uint) error { query := fmt.Sprintf("delete from %s where `id` = ?", m.table) _, err := m.conn.ExecCtx(ctx, query, id) return err } -func (m *defaultNhNftHolderModel) FindOne(ctx context.Context, id int) (*NhNftHolder, error) { +func (m *defaultNhNftHolderModel) FindOne(ctx context.Context, id uint) (*NhNftHolder, error) { query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhNftHolderRows, m.table) var resp NhNftHolder err := m.conn.QueryRowCtx(ctx, &resp, query, id) diff --git a/internal/model/nh_system_config_model.go b/internal/model/nh_system_config_model.go index 5aa72f1..8510976 100755 --- a/internal/model/nh_system_config_model.go +++ b/internal/model/nh_system_config_model.go @@ -1,8 +1,12 @@ package model import ( + "context" + "encoding/json" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlx" + "nova_task/internal/consts" + "time" ) var _ NhSystemConfigModel = (*customNhSystemConfigModel)(nil) @@ -12,6 +16,8 @@ type ( // and implement the added methods in customNhSystemConfigModel. NhSystemConfigModel interface { nhSystemConfigModel + GetNftStakeTaskOpenDate(ctx context.Context) (start, end time.Time, err error) + GetNftStakeTaskConf(ctx context.Context) (conf NftStakeTaskConf, err error) } customNhSystemConfigModel struct { @@ -25,3 +31,41 @@ func NewNhSystemConfigModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache. defaultNhSystemConfigModel: newNhSystemConfigModel(conn, c, opts...), } } + +func (m *customNhSystemConfigModel) GetNftStakeTaskOpenDate(ctx context.Context) (start, end time.Time, err error) { + cf, err := m.FindOneByName(ctx, consts.NftStakeTaskDate) + if err != nil { + return + } + dateConf := struct { + Start string `json:"start"` + End string `json:"end"` + }{} + err = json.Unmarshal([]byte(cf.Value), &dateConf) + if err != nil { + return + } + start, err = time.ParseInLocation(time.DateOnly, dateConf.Start, time.Local) + if err != nil { + return + } + end, err = time.ParseInLocation(time.DateOnly, dateConf.End, time.Local) + return +} + +type NftStakeTaskConf struct { + OccupyPercent int `json:"occupy_percent"` + LittleTarot int `json:"little_tarot"` + GreatTarot int `json:"great_tarot"` + MinCoefficient float64 `json:"min_coefficient"` + MaxCoefficient float64 `json:"max_coefficient"` +} + +func (m *customNhSystemConfigModel) GetNftStakeTaskConf(ctx context.Context) (conf NftStakeTaskConf, err error) { + cf, err := m.FindOneByName(ctx, consts.NftStakeTaskConf) + if err != nil { + return + } + err = json.Unmarshal([]byte(cf.Value), &conf) + return +} diff --git a/internal/model/nh_task_nft_stake_log_model.go b/internal/model/nh_task_nft_stake_log_model.go new file mode 100755 index 0000000..d885aba --- /dev/null +++ b/internal/model/nh_task_nft_stake_log_model.go @@ -0,0 +1,29 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ NhTaskNftStakeLogModel = (*customNhTaskNftStakeLogModel)(nil) + +type ( + // NhTaskNftStakeLogModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhTaskNftStakeLogModel. + NhTaskNftStakeLogModel interface { + nhTaskNftStakeLogModel + withSession(session sqlx.Session) NhTaskNftStakeLogModel + } + + customNhTaskNftStakeLogModel struct { + *defaultNhTaskNftStakeLogModel + } +) + +// NewNhTaskNftStakeLogModel returns a model for the database table. +func NewNhTaskNftStakeLogModel(conn sqlx.SqlConn) NhTaskNftStakeLogModel { + return &customNhTaskNftStakeLogModel{ + defaultNhTaskNftStakeLogModel: newNhTaskNftStakeLogModel(conn), + } +} + +func (m *customNhTaskNftStakeLogModel) withSession(session sqlx.Session) NhTaskNftStakeLogModel { + return NewNhTaskNftStakeLogModel(sqlx.NewSqlConnFromSession(session)) +} diff --git a/internal/model/nh_task_nft_stake_log_model_gen.go b/internal/model/nh_task_nft_stake_log_model_gen.go new file mode 100755 index 0000000..02f6c44 --- /dev/null +++ b/internal/model/nh_task_nft_stake_log_model_gen.go @@ -0,0 +1,93 @@ +// 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/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + nhTaskNftStakeLogFieldNames = builder.RawFieldNames(&NhTaskNftStakeLog{}) + nhTaskNftStakeLogRows = strings.Join(nhTaskNftStakeLogFieldNames, ",") + nhTaskNftStakeLogRowsExpectAutoSet = strings.Join(stringx.Remove(nhTaskNftStakeLogFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhTaskNftStakeLogRowsWithPlaceHolder = strings.Join(stringx.Remove(nhTaskNftStakeLogFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + nhTaskNftStakeLogModel interface { + Insert(ctx context.Context, data *NhTaskNftStakeLog) (sql.Result, error) + FindOne(ctx context.Context, id uint) (*NhTaskNftStakeLog, error) + Update(ctx context.Context, data *NhTaskNftStakeLog) error + Delete(ctx context.Context, id uint) error + } + + defaultNhTaskNftStakeLogModel struct { + conn sqlx.SqlConn + table string + } + + NhTaskNftStakeLog struct { + Id uint `db:"id"` + Uid uint `db:"uid"` // 用户钱包 + Address string `db:"address"` // 钱包地址 + TokenId string `db:"token_id"` // token id + AwardSeq int `db:"award_seq"` // 派奖序列号 + Balance int `db:"balance"` // 余额 + Stake int8 `db:"stake"` // 状态:1质押中, 0未质押 + CreatedAt time.Time `db:"created_at"` // 创建时间 + UpdatedAt time.Time `db:"updated_at"` // 修改时间 + } +) + +func newNhTaskNftStakeLogModel(conn sqlx.SqlConn) *defaultNhTaskNftStakeLogModel { + return &defaultNhTaskNftStakeLogModel{ + conn: conn, + table: "`nh_task_nft_stake_log`", + } +} + +func (m *defaultNhTaskNftStakeLogModel) Delete(ctx context.Context, id uint) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultNhTaskNftStakeLogModel) FindOne(ctx context.Context, id uint) (*NhTaskNftStakeLog, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhTaskNftStakeLogRows, m.table) + var resp NhTaskNftStakeLog + 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 *defaultNhTaskNftStakeLogModel) Insert(ctx context.Context, data *NhTaskNftStakeLog) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, nhTaskNftStakeLogRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.Address, data.TokenId, data.AwardSeq, data.Balance, data.Stake) + return ret, err +} + +func (m *defaultNhTaskNftStakeLogModel) Update(ctx context.Context, data *NhTaskNftStakeLog) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhTaskNftStakeLogRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.Uid, data.Address, data.TokenId, data.AwardSeq, data.Balance, data.Stake, data.Id) + return err +} + +func (m *defaultNhTaskNftStakeLogModel) tableName() string { + return m.table +} diff --git a/internal/model/nh_task_nft_stake_model.go b/internal/model/nh_task_nft_stake_model.go new file mode 100755 index 0000000..9bcfa94 --- /dev/null +++ b/internal/model/nh_task_nft_stake_model.go @@ -0,0 +1,52 @@ +package model + +import ( + "context" + "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ NhTaskNftStakeModel = (*customNhTaskNftStakeModel)(nil) + +type ( + // NhTaskNftStakeModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhTaskNftStakeModel. + NhTaskNftStakeModel interface { + nhTaskNftStakeModel + withSession(session sqlx.Session) NhTaskNftStakeModel + StakeNft(ctx context.Context, uid uint, tokens []string) error + UnStakeNft(ctx context.Context, uid uint, token string) error + } + + customNhTaskNftStakeModel struct { + *defaultNhTaskNftStakeModel + } +) + +func (m *customNhTaskNftStakeModel) UnStakeNft(ctx context.Context, uid uint, token string) error { + update := fmt.Sprintf("UPDATE %s SET `state` = 0 WHERE `uid` = ? AND `token_id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, update, uid, token) + return err +} + +func (m *customNhTaskNftStakeModel) StakeNft(ctx context.Context, uid uint, tokens []string) error { + insertOrUpdate := fmt.Sprintf("INSERT INTO %s (`uid`, `token_id`, `state`) VALUES (?, ?, 1) ON DUPLICATE KEY UPDATE `state` = 1", m.table) + for _, token := range tokens { + _, err := m.conn.ExecCtx(ctx, insertOrUpdate, uid, token) + if err != nil { + return err + } + } + return nil +} + +// NewNhTaskNftStakeModel returns a model for the database table. +func NewNhTaskNftStakeModel(conn sqlx.SqlConn) NhTaskNftStakeModel { + return &customNhTaskNftStakeModel{ + defaultNhTaskNftStakeModel: newNhTaskNftStakeModel(conn), + } +} + +func (m *customNhTaskNftStakeModel) withSession(session sqlx.Session) NhTaskNftStakeModel { + return NewNhTaskNftStakeModel(sqlx.NewSqlConnFromSession(session)) +} diff --git a/internal/model/nh_task_nft_stake_model_gen.go b/internal/model/nh_task_nft_stake_model_gen.go new file mode 100755 index 0000000..f3042a9 --- /dev/null +++ b/internal/model/nh_task_nft_stake_model_gen.go @@ -0,0 +1,105 @@ +// 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/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + nhTaskNftStakeFieldNames = builder.RawFieldNames(&NhTaskNftStake{}) + nhTaskNftStakeRows = strings.Join(nhTaskNftStakeFieldNames, ",") + nhTaskNftStakeRowsExpectAutoSet = strings.Join(stringx.Remove(nhTaskNftStakeFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhTaskNftStakeRowsWithPlaceHolder = strings.Join(stringx.Remove(nhTaskNftStakeFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + nhTaskNftStakeModel interface { + Insert(ctx context.Context, data *NhTaskNftStake) (sql.Result, error) + FindOne(ctx context.Context, id uint) (*NhTaskNftStake, error) + FindOneByUidTokenId(ctx context.Context, uid uint, tokenId string) (*NhTaskNftStake, error) + Update(ctx context.Context, data *NhTaskNftStake) error + Delete(ctx context.Context, id uint) error + } + + defaultNhTaskNftStakeModel struct { + conn sqlx.SqlConn + table string + } + + NhTaskNftStake struct { + Id uint `db:"id"` + Uid uint `db:"uid"` // 用户钱包 + TokenId string `db:"token_id"` // token id + State int8 `db:"state"` // 状态:1质押中, 0已取消质押 + CreatedAt time.Time `db:"created_at"` // 创建时间 + UpdatedAt time.Time `db:"updated_at"` // 修改时间 + } +) + +func newNhTaskNftStakeModel(conn sqlx.SqlConn) *defaultNhTaskNftStakeModel { + return &defaultNhTaskNftStakeModel{ + conn: conn, + table: "`nh_task_nft_stake`", + } +} + +func (m *defaultNhTaskNftStakeModel) Delete(ctx context.Context, id uint) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultNhTaskNftStakeModel) FindOne(ctx context.Context, id uint) (*NhTaskNftStake, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhTaskNftStakeRows, m.table) + var resp NhTaskNftStake + 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 *defaultNhTaskNftStakeModel) FindOneByUidTokenId(ctx context.Context, uid uint, tokenId string) (*NhTaskNftStake, error) { + var resp NhTaskNftStake + query := fmt.Sprintf("select %s from %s where `uid` = ? and `token_id` = ? limit 1", nhTaskNftStakeRows, m.table) + err := m.conn.QueryRowCtx(ctx, &resp, query, uid, tokenId) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultNhTaskNftStakeModel) Insert(ctx context.Context, data *NhTaskNftStake) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, nhTaskNftStakeRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.TokenId, data.State) + return ret, err +} + +func (m *defaultNhTaskNftStakeModel) Update(ctx context.Context, newData *NhTaskNftStake) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhTaskNftStakeRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, newData.Uid, newData.TokenId, newData.State, newData.Id) + return err +} + +func (m *defaultNhTaskNftStakeModel) tableName() string { + return m.table +} diff --git a/internal/model/nh_task_nft_stake_reward_model.go b/internal/model/nh_task_nft_stake_reward_model.go new file mode 100755 index 0000000..bab07e7 --- /dev/null +++ b/internal/model/nh_task_nft_stake_reward_model.go @@ -0,0 +1,29 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ NhTaskNftStakeRewardModel = (*customNhTaskNftStakeRewardModel)(nil) + +type ( + // NhTaskNftStakeRewardModel is an interface to be customized, add more methods here, + // and implement the added methods in customNhTaskNftStakeRewardModel. + NhTaskNftStakeRewardModel interface { + nhTaskNftStakeRewardModel + withSession(session sqlx.Session) NhTaskNftStakeRewardModel + } + + customNhTaskNftStakeRewardModel struct { + *defaultNhTaskNftStakeRewardModel + } +) + +// NewNhTaskNftStakeRewardModel returns a model for the database table. +func NewNhTaskNftStakeRewardModel(conn sqlx.SqlConn) NhTaskNftStakeRewardModel { + return &customNhTaskNftStakeRewardModel{ + defaultNhTaskNftStakeRewardModel: newNhTaskNftStakeRewardModel(conn), + } +} + +func (m *customNhTaskNftStakeRewardModel) withSession(session sqlx.Session) NhTaskNftStakeRewardModel { + return NewNhTaskNftStakeRewardModel(sqlx.NewSqlConnFromSession(session)) +} diff --git a/internal/model/nh_task_nft_stake_reward_model_gen.go b/internal/model/nh_task_nft_stake_reward_model_gen.go new file mode 100755 index 0000000..b6ddf75 --- /dev/null +++ b/internal/model/nh_task_nft_stake_reward_model_gen.go @@ -0,0 +1,95 @@ +// 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/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + + "github.com/shopspring/decimal" +) + +var ( + nhTaskNftStakeRewardFieldNames = builder.RawFieldNames(&NhTaskNftStakeReward{}) + nhTaskNftStakeRewardRows = strings.Join(nhTaskNftStakeRewardFieldNames, ",") + nhTaskNftStakeRewardRowsExpectAutoSet = strings.Join(stringx.Remove(nhTaskNftStakeRewardFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + nhTaskNftStakeRewardRowsWithPlaceHolder = strings.Join(stringx.Remove(nhTaskNftStakeRewardFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + nhTaskNftStakeRewardModel interface { + Insert(ctx context.Context, data *NhTaskNftStakeReward) (sql.Result, error) + FindOne(ctx context.Context, id uint) (*NhTaskNftStakeReward, error) + Update(ctx context.Context, data *NhTaskNftStakeReward) error + Delete(ctx context.Context, id uint) error + } + + defaultNhTaskNftStakeRewardModel struct { + conn sqlx.SqlConn + table string + } + + NhTaskNftStakeReward struct { + Id uint `db:"id"` + Uid uint `db:"uid"` // 用户钱包 + AwardSeq int `db:"award_seq"` // 派奖序列号 + PledgeOutput decimal.NullDecimal `db:"pledge_output"` // 质押产出代币 + RandomCoefficient float64 `db:"random_coefficient"` // 随机系数 + OccupyPercent int `db:"occupy_percent"` // 占领百分比 + Reward decimal.NullDecimal `db:"reward"` // 奖励金额 + CreatedAt time.Time `db:"created_at"` // 创建时间 + UpdatedAt time.Time `db:"updated_at"` // 修改时间 + } +) + +func newNhTaskNftStakeRewardModel(conn sqlx.SqlConn) *defaultNhTaskNftStakeRewardModel { + return &defaultNhTaskNftStakeRewardModel{ + conn: conn, + table: "`nh_task_nft_stake_reward`", + } +} + +func (m *defaultNhTaskNftStakeRewardModel) Delete(ctx context.Context, id uint) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultNhTaskNftStakeRewardModel) FindOne(ctx context.Context, id uint) (*NhTaskNftStakeReward, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhTaskNftStakeRewardRows, m.table) + var resp NhTaskNftStakeReward + 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 *defaultNhTaskNftStakeRewardModel) Insert(ctx context.Context, data *NhTaskNftStakeReward) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, nhTaskNftStakeRewardRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.AwardSeq, data.PledgeOutput, data.RandomCoefficient, data.OccupyPercent, data.Reward) + return ret, err +} + +func (m *defaultNhTaskNftStakeRewardModel) Update(ctx context.Context, data *NhTaskNftStakeReward) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhTaskNftStakeRewardRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.Uid, data.AwardSeq, data.PledgeOutput, data.RandomCoefficient, data.OccupyPercent, data.Reward, data.Id) + return err +} + +func (m *defaultNhTaskNftStakeRewardModel) tableName() string { + return m.table +} diff --git a/internal/model/nh_wallet_model.go b/internal/model/nh_wallet_model.go index 060a3ab..13ebcf9 100755 --- a/internal/model/nh_wallet_model.go +++ b/internal/model/nh_wallet_model.go @@ -2,6 +2,7 @@ package model import ( "context" + "errors" "fmt" "github.com/zeromicro/go-zero/core/stores/sqlx" "nova_task/internal/pkg/aptos" @@ -15,7 +16,8 @@ type ( NhWalletModel interface { nhWalletModel withSession(session sqlx.Session) NhWalletModel - FindWalletByAddress(ctx context.Context, address string) (uint, error) + FindUidByAddress(ctx context.Context, address string) (uint, error) + FindAddressByUid(ctx context.Context, uid uint) (string, error) } customNhWalletModel struct { @@ -23,10 +25,23 @@ type ( } ) -func (m *customNhWalletModel) FindWalletByAddress(ctx context.Context, address string) (uint, error) { +func (m *customNhWalletModel) FindAddressByUid(ctx context.Context, uid uint) (string, error) { + query := fmt.Sprintf("select `address` from %s where `uid` = ? and `status` = 0 limit 1", m.table) + var address string + err := m.conn.QueryRowCtx(ctx, &address, query, uid) + if errors.Is(err, sqlx.ErrNotFound) { + return "", ErrNotFound + } + return address, err +} + +func (m *customNhWalletModel) FindUidByAddress(ctx context.Context, address string) (uint, error) { query := fmt.Sprintf("select `uid` from %s where `address` = ? or `address` = ? limit 1", m.table) var uid uint err := m.conn.QueryRowCtx(ctx, &uid, query, address, aptos.StrPadAptosAddress(address)) + if errors.Is(err, sqlx.ErrNotFound) { + return 0, ErrNotFound + } return uid, err } diff --git a/internal/pkg/errs/reason.go b/internal/pkg/errs/reason.go index 06ca23d..01a982d 100644 --- a/internal/pkg/errs/reason.go +++ b/internal/pkg/errs/reason.go @@ -18,8 +18,11 @@ const ( ErrGenerateToken Reason = 1005 // 生成token错误 // ======= 业务层错误:20000~29999 ======= - ErrUnknownLogicError Reason = 20000 // 未知的业务错误 - ErrTaskNotFound Reason = 20001 // 任务不存在 - ErrTaskAlreadyReward Reason = 20002 // 任务已领取 - ErrTaskNotFinished Reason = 20003 // 任务未完成 + ErrUnknownLogicError Reason = 20000 // 未知的业务错误 + ErrTaskNotFound Reason = 20001 // 任务不存在 + ErrTaskAlreadyReward Reason = 20002 // 任务已领取 + ErrTaskNotFinished Reason = 20003 // 任务未完成 + ErrNotBindWallet Reason = 20004 // 未绑定钱包 + ErrTaskOpenDateNotSet Reason = 20005 // 任务开放时间未设置 + ErrTaskConfNotSet Reason = 20006 // 任务配置未设置 ) diff --git a/internal/pkg/utils/utils.go b/internal/pkg/utils/utils.go new file mode 100644 index 0000000..5767478 --- /dev/null +++ b/internal/pkg/utils/utils.go @@ -0,0 +1,24 @@ +package utils + +import ( + "context" + "github.com/spf13/cast" + "time" +) + +func GetUidUint(ctx context.Context) uint { + uid, _ := cast.ToStringMapInt(ctx.Value("data"))["id"] + return uint(uid) +} + +func GetUid(ctx context.Context) int { + uid, _ := cast.ToStringMapInt(ctx.Value("data"))["id"] + return uid +} + +func TodayRemainSeconds() int { + now := time.Now() + end, _ := time.ParseInLocation(time.DateOnly, now.Format(time.DateOnly), time.Local) + end = end.AddDate(0, 0, 1) + return int(end.Sub(now).Seconds()) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 40f6081..0196c52 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -3,6 +3,7 @@ package svc import ( ea "github.com/earn-alliance/earnalliance-go" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlx" "nova_task/internal/config" "nova_task/internal/model" @@ -24,9 +25,14 @@ type ServiceContext struct { ConfigModel model.NhSystemConfigModel NftHolderModel model.NhNftHolderModel NftHolderChangeLogModel model.NhNftHolderChangeLogModel + StakeNftModel model.NhTaskNftStakeModel + StakeNftLogModel model.NhTaskNftStakeLogModel + StakeRewardModel model.NhTaskNftStakeRewardModel + GamePitModel model.NhGamePitModel Earn *ea.Client DBConn sqlx.SqlConn + Redis *redis.Redis } func NewServiceContext(c config.Config) *ServiceContext { @@ -47,9 +53,14 @@ func NewServiceContext(c config.Config) *ServiceContext { ConfigModel: model.NewNhSystemConfigModel(dbConn, c.Cache), NftHolderModel: model.NewNhNftHolderModel(dbConn), NftHolderChangeLogModel: model.NewNhNftHolderChangeLogModel(dbConn), + StakeNftModel: model.NewNhTaskNftStakeModel(dbConn), + StakeNftLogModel: model.NewNhTaskNftStakeLogModel(dbConn), + StakeRewardModel: model.NewNhTaskNftStakeRewardModel(dbConn), + GamePitModel: model.NewNhGamePitModel(dbConn), Earn: c.Earn.BuildEarnClient(), DBConn: dbConn, + Redis: redis.MustNewRedis(c.Redis), } } diff --git a/internal/types/types.go b/internal/types/types.go index b0ebded..d8fb043 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -28,6 +28,19 @@ type GetTaskRewardResp struct { Points int `json:"points"` // 积分 } +type StakeNftList struct { + TokenIds []string `json:"token_ids"` // nft列表 +} + +type StakeTaskDetail struct { + StartDate string `json:"start_date"` // 开始日期 + EndDate string `json:"end_date"` // 结束日期 + CountDown int `json:"count_down"` // 剩余结算时间 + ProduceTokensToday float64 `json:"produce_token_today"` // 今日产出代币 + GameBonus int `json:"game_bonus"` // 游戏加成比率 + CanReceiveTokens float64 `json:"can_receive_tokens"` // 可领取代币数量 +} + type Task struct { Id uint `json:"id"` // 任务ID CommunityId uint `json:"community_id"` // 所属社区ID @@ -51,6 +64,20 @@ type TaskIdPath struct { ID uint `path:"id"` // 任务ID } +type UnStakeNftReq struct { + TokenId string `json:"token_id"` // nftID +} + +type UserNft struct { + TokenId string `json:"token_id"` // nftID + HasStake bool `json:"has_stake"` // 是否已质押 + StakeAt string `json:"stake_at"` // 质押时间 +} + +type UserNftList struct { + NftList []UserNft `json:"nft_list"` +} + type VerifyTaskResultReq struct { ID uint `form:"id"` // 任务ID Params string `form:"params,optional"` // 额外的参数