From 996fefa0f3f70dbd8bc208d1df863ea5b6b19528 Mon Sep 17 00:00:00 2001 From: phucledien Date: Wed, 23 Aug 2023 16:28:26 +0700 Subject: [PATCH 1/4] feat: add onboarding start notification --- docs/docs.go | 114 ++++++++++++++++++----- docs/swagger.json | 114 ++++++++++++++++++----- docs/swagger.yaml | 76 +++++++++++---- go.mod | 2 +- go.sum | 4 +- pkg/config/config.go | 4 + pkg/entities/onboarding.go | 110 ++++++++++++++++++++++ pkg/handler/handler.go | 3 + pkg/handler/onboarding/interface.go | 7 ++ pkg/handler/onboarding/onboarding.go | 49 ++++++++++ pkg/kafka/message/onboarding.go | 15 +++ pkg/request/onboarding.go | 6 ++ pkg/response/onboarding.go | 15 +++ pkg/routes/v1.go | 5 + pkg/service/mochipay/mochipay.go | 28 ++++++ pkg/service/mochipay/request.go | 21 +++++ pkg/service/mochipay/response.go | 4 + pkg/service/mochipay/service.go | 1 + pkg/service/mochiprofile/mochiprofile.go | 37 ++++++++ pkg/service/mochiprofile/model.go | 4 + pkg/service/mochiprofile/service.go | 2 + 21 files changed, 554 insertions(+), 67 deletions(-) create mode 100644 pkg/entities/onboarding.go create mode 100644 pkg/handler/onboarding/interface.go create mode 100644 pkg/handler/onboarding/onboarding.go create mode 100644 pkg/kafka/message/onboarding.go create mode 100644 pkg/request/onboarding.go create mode 100644 pkg/response/onboarding.go diff --git a/docs/docs.go b/docs/docs.go index 892e8db5f..77a245c49 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4479,6 +4479,40 @@ const docTemplate = `{ } } }, + "/onboarding/start": { + "post": { + "description": "User did start onboarding", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Defi" + ], + "summary": "User did start onboarding", + "parameters": [ + { + "description": "onboarding start request", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.OnboardingStartRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.OnboardingStartResponse" + } + } + } + } + }, "/onchain/invest-stake-data": { "get": { "description": "Get onchain invest stake data", @@ -5693,7 +5727,7 @@ const docTemplate = `{ }, "/vault": { "get": { - "description": "Get vaults", + "description": "Get vault", "consumes": [ "application/json" ], @@ -5703,18 +5737,8 @@ const docTemplate = `{ "tags": [ "Vault" ], - "summary": "Get vaults", + "summary": "Get vault", "parameters": [ - { - "type": "string", - "name": "evmAddress", - "in": "query" - }, - { - "type": "string", - "name": "guildID", - "in": "query" - }, { "type": "string", "default": "false", @@ -5723,17 +5747,7 @@ const docTemplate = `{ }, { "type": "string", - "name": "profileID", - "in": "query" - }, - { - "type": "string", - "name": "solanaAddress", - "in": "query" - }, - { - "type": "string", - "name": "threshold", + "name": "vaultId", "in": "query" } ], @@ -5741,7 +5755,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.GetVaultsResponse" + "$ref": "#/definitions/response.GetVaultResponse" } } } @@ -6804,6 +6818,9 @@ const docTemplate = `{ "description": { "type": "string" }, + "discord_alias": { + "type": "string" + }, "discord_command": { "type": "string" }, @@ -6813,6 +6830,9 @@ const docTemplate = `{ "scope": { "type": "integer" }, + "telegram_alias": { + "type": "string" + }, "telegram_command": { "type": "string" }, @@ -7910,6 +7930,25 @@ const docTemplate = `{ } } }, + "request.OnboardingStartRequest": { + "type": "object", + "required": [ + "platform", + "profile_id" + ], + "properties": { + "platform": { + "type": "string", + "enum": [ + "discord", + "telegram" + ] + }, + "profile_id": { + "type": "string" + } + } + }, "request.RoleReactionRequest": { "type": "object", "properties": { @@ -9890,6 +9929,14 @@ const docTemplate = `{ } } }, + "response.GetVaultResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Vault" + } + } + }, "response.GetVaultsResponse": { "type": "object", "properties": { @@ -11171,6 +11218,25 @@ const docTemplate = `{ } } }, + "response.OnboardingStartData": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "userDidStartOnboarding": { + "type": "boolean" + } + } + }, + "response.OnboardingStartResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.OnboardingStartData" + } + } + }, "response.OnchainInvestData": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 026afb1e9..7b740d6c1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4471,6 +4471,40 @@ } } }, + "/onboarding/start": { + "post": { + "description": "User did start onboarding", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Defi" + ], + "summary": "User did start onboarding", + "parameters": [ + { + "description": "onboarding start request", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.OnboardingStartRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.OnboardingStartResponse" + } + } + } + } + }, "/onchain/invest-stake-data": { "get": { "description": "Get onchain invest stake data", @@ -5685,7 +5719,7 @@ }, "/vault": { "get": { - "description": "Get vaults", + "description": "Get vault", "consumes": [ "application/json" ], @@ -5695,18 +5729,8 @@ "tags": [ "Vault" ], - "summary": "Get vaults", + "summary": "Get vault", "parameters": [ - { - "type": "string", - "name": "evmAddress", - "in": "query" - }, - { - "type": "string", - "name": "guildID", - "in": "query" - }, { "type": "string", "default": "false", @@ -5715,17 +5739,7 @@ }, { "type": "string", - "name": "profileID", - "in": "query" - }, - { - "type": "string", - "name": "solanaAddress", - "in": "query" - }, - { - "type": "string", - "name": "threshold", + "name": "vaultId", "in": "query" } ], @@ -5733,7 +5747,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.GetVaultsResponse" + "$ref": "#/definitions/response.GetVaultResponse" } } } @@ -6796,6 +6810,9 @@ "description": { "type": "string" }, + "discord_alias": { + "type": "string" + }, "discord_command": { "type": "string" }, @@ -6805,6 +6822,9 @@ "scope": { "type": "integer" }, + "telegram_alias": { + "type": "string" + }, "telegram_command": { "type": "string" }, @@ -7902,6 +7922,25 @@ } } }, + "request.OnboardingStartRequest": { + "type": "object", + "required": [ + "platform", + "profile_id" + ], + "properties": { + "platform": { + "type": "string", + "enum": [ + "discord", + "telegram" + ] + }, + "profile_id": { + "type": "string" + } + } + }, "request.RoleReactionRequest": { "type": "object", "properties": { @@ -9882,6 +9921,14 @@ } } }, + "response.GetVaultResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Vault" + } + } + }, "response.GetVaultsResponse": { "type": "object", "properties": { @@ -11163,6 +11210,25 @@ } } }, + "response.OnboardingStartData": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "userDidStartOnboarding": { + "type": "boolean" + } + } + }, + "response.OnboardingStartResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.OnboardingStartData" + } + } + }, "response.OnchainInvestData": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1b408e188..934d0d7ed 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -560,12 +560,16 @@ definitions: type: string description: type: string + discord_alias: + type: string discord_command: type: string id: type: integer scope: type: integer + telegram_alias: + type: string telegram_command: type: string updated_at: @@ -1288,6 +1292,19 @@ definitions: transfer_type: type: string type: object + request.OnboardingStartRequest: + properties: + platform: + enum: + - discord + - telegram + type: string + profile_id: + type: string + required: + - platform + - profile_id + type: object request.RoleReactionRequest: properties: guild_id: @@ -2580,6 +2597,11 @@ definitions: data: $ref: '#/definitions/response.User' type: object + response.GetVaultResponse: + properties: + data: + $ref: '#/definitions/model.Vault' + type: object response.GetVaultsResponse: properties: data: @@ -3416,6 +3438,18 @@ definitions: $ref: '#/definitions/response.OffchainTipBotTransferToken' type: array type: object + response.OnboardingStartData: + properties: + message: + type: string + userDidStartOnboarding: + type: boolean + type: object + response.OnboardingStartResponse: + properties: + data: + $ref: '#/definitions/response.OnboardingStartData' + type: object response.OnchainInvestData: properties: tx_object: @@ -6777,6 +6811,28 @@ paths: summary: Get NFT trading volume tags: - NFT + /onboarding/start: + post: + consumes: + - application/json + description: User did start onboarding + parameters: + - description: onboarding start request + in: body + name: req + required: true + schema: + $ref: '#/definitions/request.OnboardingStartRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.OnboardingStartResponse' + summary: User did start onboarding + tags: + - Defi /onchain/invest-stake-data: get: consumes: @@ -7576,26 +7632,14 @@ paths: get: consumes: - application/json - description: Get vaults + description: Get vault parameters: - - in: query - name: evmAddress - type: string - - in: query - name: guildID - type: string - default: "false" in: query name: noFetchAmount type: string - in: query - name: profileID - type: string - - in: query - name: solanaAddress - type: string - - in: query - name: threshold + name: vaultId type: string produces: - application/json @@ -7603,8 +7647,8 @@ paths: "200": description: OK schema: - $ref: '#/definitions/response.GetVaultsResponse' - summary: Get vaults + $ref: '#/definitions/response.GetVaultResponse' + summary: Get vault tags: - Vault /verify/assign-role: diff --git a/go.mod b/go.mod index 74055febf..203c858ce 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce github.com/bwmarrin/discordgo v0.26.1 github.com/confluentinc/confluent-kafka-go v1.9.2 - github.com/consolelabs/mochi-typeset v0.0.0-20230814034025-6e2f5371a41f + github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573 github.com/ethereum/go-ethereum v1.12.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-contrib/pprof v1.4.0 diff --git a/go.sum b/go.sum index 81e2c532b..fb05888f7 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/consolelabs/mochi-toolkit v0.0.0-20230713093321-b3c70e7b2905 h1:n5JZF1xv7w+UoOjtx2VrROuqUYAFm9uDRwPeSgmxV+M= github.com/consolelabs/mochi-toolkit v0.0.0-20230713093321-b3c70e7b2905/go.mod h1:ZShtpSO6HNmj+G2W/vFDi28BneoLis6AWYnRIAnfIxU= -github.com/consolelabs/mochi-typeset v0.0.0-20230814034025-6e2f5371a41f h1:OKUmIuggUW1en8smCz6wchpeNR+SNnkppsoYibRlmu0= -github.com/consolelabs/mochi-typeset v0.0.0-20230814034025-6e2f5371a41f/go.mod h1:HSKMB2HqQKHgeVpG/QZAs2nHulZbLA8PreLeujm2Ups= +github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573 h1:lDzeYUew4MNfFXwpEJeF6q5tN5fVm5G2Dhnkp6ie3mk= +github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573/go.mod h1:HSKMB2HqQKHgeVpG/QZAs2nHulZbLA8PreLeujm2Ups= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= diff --git a/pkg/config/config.go b/pkg/config/config.go index dad1bfa5d..09414f906 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -130,6 +130,8 @@ type Config struct { KrystalBaseUrl string KrystalApiKey string + + MochiAppPrivateKey string } type MarketplaceBaseUrl struct { @@ -351,6 +353,8 @@ func generateConfigFromViper(v *viper.Viper) Config { KrystalBaseUrl: v.GetString("KRYSTAL_BASE_URL"), KrystalApiKey: v.GetString("KRYSTAL_API_KEY"), + + MochiAppPrivateKey: v.GetString("MOCHI_APP_PRIVATE_KEY"), } } diff --git a/pkg/entities/onboarding.go b/pkg/entities/onboarding.go new file mode 100644 index 000000000..031760abc --- /dev/null +++ b/pkg/entities/onboarding.go @@ -0,0 +1,110 @@ +package entities + +import ( + "crypto/ed25519" + "encoding/hex" + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/math" + + "github.com/defipod/mochi/pkg/logger" + "github.com/defipod/mochi/pkg/request" + "github.com/defipod/mochi/pkg/service/mochipay" +) + +func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { + // Check onboarding status + onboardingStatus, err := e.svc.MochiProfile.GetOnboardingStatus(req.ProfileId) + if err != nil { + e.log.Fields(logger.Fields{"profileId": req.ProfileId}).Error(err, "[Entity.OnboardingStart] svc.MochiProfile.GetOnboardingStatus() failed") + return err + } + if onboardingStatus.DidOnboarding { + // if user already start onboarding, just return + return nil + } + + // Get reward token info + var ( + symbol = "KEKK" + chainId = "1" + ) + kekkToken, err := e.svc.MochiPay.GetToken(symbol, chainId) + if err != nil { + e.log. + Fields(logger.Fields{"symbol": symbol, "chainId": chainId}). + Error(err, "[Entity.OnboardingStart] svc.MochiPay.GetToken() failed") + return err + } + decimal := math.BigPow(10, kekkToken.Decimal) + rewardAmount := 10 + amount := new(big.Int).Mul(big.NewInt(int64(rewardAmount)), decimal).String() + + // Prepare application auth + privateKey, err := hex.DecodeString(e.cfg.MochiAppPrivateKey) + if err != nil { + e.log.Error(err, "[Entity.OnboardingStart] hex.DecodeString() failed") + return err + } + message := "ApplicationTransfer" + signature := ed25519.Sign(privateKey, []byte(message)) + sigStr := hex.EncodeToString(signature) + if err != nil { + e.log.Error(err, "[Entity.OnboardingStart] hex.EncodeString() failed") + return err + } + + // Transfer reward token + appTransferReq := mochipay.ApplicationTransferRequest{ + AppId: "35", + Header: mochipay.ApplicationBaseHeaderRequest{ + Application: "Mochi", + Message: message, + Signature: sigStr, + }, + Metadata: mochipay.ApplicationTransferMetadata{ + RecipientIds: []string{req.ProfileId}, + Amounts: []string{amount}, + TokenId: kekkToken.Id, + References: "", + Description: "User onboarding reward", + Platform: req.Platform, + }, + } + _, err = e.svc.MochiPay.ApplicationTransfer(appTransferReq) + if err != nil { + e.log. + Fields(logger.Fields{"appTransferRequest": appTransferReq}). + Error(err, "[Entity.OnboardingStart] svc.MochiPay.ApplicationTransfer() failed") + return err + } + + // Mark user already started onboarding + if err := e.svc.MochiProfile.MarkUserDidOnboarding(req.ProfileId); err != nil { + e.log. + Fields(logger.Fields{"profileId": req.ProfileId}). + Error(err, "[Entity.OnboardingStart] svc.MochiProfile.MarkUserDidOnboarding() failed") + return err + } + + // Send notification to user + if err := e.sendOnboardingStartNotification(); err != nil { + e.log. + Fields(logger.Fields{"profileId": req.ProfileId}). + Error(err, "[Entity.OnboardingStart] e.sendOnboardingStartNotification() failed") + return nil + } + + return nil +} + +func (e *Entity) sendOnboardingStartNotification() error { + msg := struct{ Message string }{Message: "Hello"} + byteNotification, _ := json.Marshal(msg) + if err := e.kafka.ProduceNotification(e.cfg.Kafka.NotificationTopic, byteNotification); err != nil { + e.log.Fields(logger.Fields{"req": ""}).Error(err, "[entity.sendOnboardingStartNotification] - e.kafka.Produce failed") + return err + } + return nil +} diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go index ef039601b..205b8354d 100644 --- a/pkg/handler/handler.go +++ b/pkg/handler/handler.go @@ -19,6 +19,7 @@ import ( "github.com/defipod/mochi/pkg/handler/healthz" "github.com/defipod/mochi/pkg/handler/invest" "github.com/defipod/mochi/pkg/handler/nft" + "github.com/defipod/mochi/pkg/handler/onboarding" pkpass "github.com/defipod/mochi/pkg/handler/pk-pass" productdata "github.com/defipod/mochi/pkg/handler/product-data" "github.com/defipod/mochi/pkg/handler/swap" @@ -60,6 +61,7 @@ type Handler struct { Invest invest.IHandler ProductData productdata.IHandler Dexes dexes.IHandler + Onboarding onboarding.IHandler } func New(entities *entities.Entity, logger logger.Logger) *Handler { @@ -91,5 +93,6 @@ func New(entities *entities.Entity, logger logger.Logger) *Handler { DaoVoting: daovoting.New(entities, logger), ProductData: productdata.New(entities, logger), Dexes: dexes.New(entities, logger), + Onboarding: onboarding.New(entities, logger), } } diff --git a/pkg/handler/onboarding/interface.go b/pkg/handler/onboarding/interface.go new file mode 100644 index 000000000..27a5e5c13 --- /dev/null +++ b/pkg/handler/onboarding/interface.go @@ -0,0 +1,7 @@ +package onboarding + +import "github.com/gin-gonic/gin" + +type IHandler interface { + Start(c *gin.Context) +} diff --git a/pkg/handler/onboarding/onboarding.go b/pkg/handler/onboarding/onboarding.go new file mode 100644 index 000000000..adea8c570 --- /dev/null +++ b/pkg/handler/onboarding/onboarding.go @@ -0,0 +1,49 @@ +package onboarding + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/defipod/mochi/pkg/entities" + "github.com/defipod/mochi/pkg/logger" + baseerrs "github.com/defipod/mochi/pkg/model/errors" + "github.com/defipod/mochi/pkg/request" + "github.com/defipod/mochi/pkg/response" +) + +type Handler struct { + entities *entities.Entity + log logger.Logger +} + +func New(entities *entities.Entity, logger logger.Logger) IHandler { + return &Handler{ + entities: entities, + log: logger, + } +} + +// Start godoc +// @Summary User did start onboarding +// @Description User did start onboarding +// @Tags Defi +// @Accept json +// @Produce json +// @Param req body request.OnboardingStartRequest true "onboarding start request" +// @Success 200 {object} response.ResponseDataMessage +// @Router /onboarding/start [post] +func (h *Handler) Start(c *gin.Context) { + var req request.OnboardingStartRequest + if err := c.ShouldBindJSON(&req); err != nil { + h.log.Error(err, "[handler.Start] BindJSON() failed") + c.JSON(http.StatusBadRequest, response.CreateResponse[any](nil, nil, err, nil)) + return + } + if err := h.entities.OnboardingStart(req); err != nil { + h.log.Error(err, "[handler.Start] entity.OnboardingStart() failed") + c.JSON(baseerrs.GetStatusCode(err), response.CreateResponse[any](nil, nil, err, nil)) + return + } + c.JSON(http.StatusOK, response.CreateResponse[any](response.ResponseMessage{Message: "OK"}, nil, nil, nil)) +} diff --git a/pkg/kafka/message/onboarding.go b/pkg/kafka/message/onboarding.go new file mode 100644 index 000000000..a59f97f47 --- /dev/null +++ b/pkg/kafka/message/onboarding.go @@ -0,0 +1,15 @@ +package message + +import "github.com/consolelabs/mochi-typeset/typeset" + +type OnboardingStart struct { + Type typeset.NotificationType `json:"type"` + Metadata OnboardingStartMetadata `json:"metadata"` +} + +type OnboardingStartMetadata struct { + Token string `json:"token"` + TokenAmount string `json:"token_amount"` + TokenDecimal int64 `json:"token_decimal"` + RecipientProfileId string `json:"recipient_profile_id"` +} diff --git a/pkg/request/onboarding.go b/pkg/request/onboarding.go new file mode 100644 index 000000000..09b2cb5b8 --- /dev/null +++ b/pkg/request/onboarding.go @@ -0,0 +1,6 @@ +package request + +type OnboardingStartRequest struct { + ProfileId string `json:"profile_id" binding:"required"` + Platform string `json:"platform" binding:"required,oneof=discord telegram"` +} diff --git a/pkg/response/onboarding.go b/pkg/response/onboarding.go new file mode 100644 index 000000000..6c53659cb --- /dev/null +++ b/pkg/response/onboarding.go @@ -0,0 +1,15 @@ +package response + +type OnboardingStartResponse struct { + Data OnboardingStartData `json:"data"` +} + +type OnboardingReward struct { + TokenSymbol string `json:"token_symbol"` + Amount int `json:"amount"` +} + +type OnboardingStartData struct { + DidOnboarding bool `json:"did_onboarding"` + Reward OnboardingReward `json:"reward"` +} diff --git a/pkg/routes/v1.go b/pkg/routes/v1.go index 5d6c6688e..26aec624a 100644 --- a/pkg/routes/v1.go +++ b/pkg/routes/v1.go @@ -462,4 +462,9 @@ func NewRoutes(r *gin.Engine, h *handler.Handler, cfg config.Config) { { dexesGroup.GET("/search", h.Dexes.SearchDexPair) } + + onboardingGroup := v1.Group("/onboarding") + { + onboardingGroup.POST("/start", h.Onboarding.Start) + } } diff --git a/pkg/service/mochipay/mochipay.go b/pkg/service/mochipay/mochipay.go index 3af23e8f5..184afa929 100644 --- a/pkg/service/mochipay/mochipay.go +++ b/pkg/service/mochipay/mochipay.go @@ -497,3 +497,31 @@ func (m *MochiPay) TransferV2(req TransferV2Request) (*TransferV2Response, error return res, nil } + +func (m *MochiPay) ApplicationTransfer(req ApplicationTransferRequest) (*ApplicationTransferResponse, error) { + payload, err := json.Marshal(req.Metadata) + if err != nil { + return nil, err + } + + res := &ApplicationTransferResponse{} + status, err := util.SendRequest(util.SendRequestQuery{ + URL: fmt.Sprintf("%s/api/v2/applications/%s/transfer", m.config.MochiPayServerHost, req.AppId), + Body: bytes.NewBuffer(payload), + Method: "POST", + ParseForm: res, + Headers: map[string]string{ + "x-application": req.Header.Application, + "x-message": req.Header.Message, + "x-signature": req.Header.Signature, + }, + }) + if err != nil { + return nil, err + } + if status != http.StatusOK { + return nil, fmt.Errorf("transfer failed with status %d", status) + } + + return res, nil +} diff --git a/pkg/service/mochipay/request.go b/pkg/service/mochipay/request.go index 11b20e411..595757790 100644 --- a/pkg/service/mochipay/request.go +++ b/pkg/service/mochipay/request.go @@ -39,3 +39,24 @@ type TransferV2Request struct { Action string `json:"action" binding:"required"` Metadata map[string]interface{} `json:"metadata"` } + +type ApplicationBaseHeaderRequest struct { + Application string `header:"x-application"` + Message string `header:"x-message"` + Signature string `header:"x-signature"` +} + +type ApplicationTransferRequest struct { + AppId string `json:"appId"` + Metadata ApplicationTransferMetadata `json:"metadata"` + Header ApplicationBaseHeaderRequest `json:"header"` +} + +type ApplicationTransferMetadata struct { + RecipientIds []string `json:"recipient_ids"` + Amounts []string `json:"amounts"` + TokenId string `json:"token_id" ` + References string `json:"references"` + Description string `json:"description"` + Platform string `json:"platform"` +} diff --git a/pkg/service/mochipay/response.go b/pkg/service/mochipay/response.go index 221b9801b..3dc1f5635 100644 --- a/pkg/service/mochipay/response.go +++ b/pkg/service/mochipay/response.go @@ -136,3 +136,7 @@ type TransferV2TransactionData struct { ExpiredAt *time.Time `json:"expired_at"` Token *Token `json:"token"` } + +type ApplicationTransferResponse struct { + Data []TransferV2TransactionData `json:"data"` +} diff --git a/pkg/service/mochipay/service.go b/pkg/service/mochipay/service.go index 41ee6608a..5e89089e4 100644 --- a/pkg/service/mochipay/service.go +++ b/pkg/service/mochipay/service.go @@ -19,4 +19,5 @@ type Service interface { // TransferV2 TransferV2(req TransferV2Request) (*TransferV2Response, error) + ApplicationTransfer(req ApplicationTransferRequest) (*ApplicationTransferResponse, error) } diff --git a/pkg/service/mochiprofile/mochiprofile.go b/pkg/service/mochiprofile/mochiprofile.go index e2f54c3d9..b74bb04e2 100644 --- a/pkg/service/mochiprofile/mochiprofile.go +++ b/pkg/service/mochiprofile/mochiprofile.go @@ -259,3 +259,40 @@ func (m *MochiProfile) UnlinkDex(profileId, platform string) error { return nil } + +func (m *MochiProfile) GetOnboardingStatus(profileId string) (res *OnboardingStatusResponse, err error) { + url := fmt.Sprintf("%s/api/v1/profiles/%s/onboarding-status", m.config.MochiProfileServerHost, profileId) + req := util.SendRequestQuery{ + URL: url, + ParseForm: &res, + Headers: map[string]string{"Content-Type": "application/json"}, + } + statusCode, err := util.SendRequest(req) + if err != nil || statusCode != http.StatusOK { + return nil, fmt.Errorf("[mochiprofile.GetOnboardingStatus] util.SendRequest() failed: %v", err) + } + return res, nil +} + +func (m *MochiProfile) MarkUserDidOnboarding(profileId string) error { + url := fmt.Sprintf("%s/api/v1/profiles/%s/onboarding-status", m.config.MochiProfileServerHost, profileId) + request, err := http.NewRequest("POST", url, nil) + if err != nil { + return err + } + request.Header.Add("Content-Type", "application/json") + + client := &http.Client{} + response, err := client.Do(request) + if err != nil { + return err + } + + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.ErrProfile + } + + return nil +} diff --git a/pkg/service/mochiprofile/model.go b/pkg/service/mochiprofile/model.go index 7497ea826..748a11433 100644 --- a/pkg/service/mochiprofile/model.go +++ b/pkg/service/mochiprofile/model.go @@ -58,3 +58,7 @@ type EvmAssociatedAccount struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } + +type OnboardingStatusResponse struct { + DidOnboarding bool `json:"did_onboarding"` +} diff --git a/pkg/service/mochiprofile/service.go b/pkg/service/mochiprofile/service.go index f187fe552..53914901b 100644 --- a/pkg/service/mochiprofile/service.go +++ b/pkg/service/mochiprofile/service.go @@ -8,4 +8,6 @@ type Service interface { GetAllEvmAccount() ([]*EvmAssociatedAccount, error) AssociateDex(profileId, platform, apiKey, apiSecret string) error UnlinkDex(profileId, platform string) error + GetOnboardingStatus(profileId string) (res *OnboardingStatusResponse, err error) + MarkUserDidOnboarding(profileId string) error } From d1e5993d3536e7819cd8475f72d7ecd65bf260d5 Mon Sep 17 00:00:00 2001 From: phucledien Date: Wed, 23 Aug 2023 16:43:54 +0700 Subject: [PATCH 2/4] feat: onboarding start --- docs/docs.go | 98 ++++++++++++++++++++++------ docs/swagger.json | 98 ++++++++++++++++++++++------ docs/swagger.yaml | 80 ++++++++++++++++------- go.mod | 2 +- go.sum | 4 +- pkg/entities/onboarding.go | 19 ++++-- pkg/handler/onboarding/onboarding.go | 2 +- pkg/kafka/message/onboarding.go | 12 ++-- 8 files changed, 237 insertions(+), 78 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 77a245c49..14f169a4f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4489,7 +4489,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "Defi" + "Onboarding" ], "summary": "User did start onboarding", "parameters": [ @@ -4507,7 +4507,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.OnboardingStartResponse" + "$ref": "#/definitions/response.ResponseDataMessage" } } } @@ -4647,6 +4647,41 @@ const docTemplate = `{ } } }, + "/product-metadata/changelogs": { + "get": { + "description": "Get product changelogs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ProductMetadata" + ], + "summary": "Get product changelogs", + "parameters": [ + { + "type": "string", + "name": "product", + "in": "query" + }, + { + "type": "string", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.ProductChangelogs" + } + } + } + } + }, "/product-metadata/commands": { "get": { "description": "Get product bot commands", @@ -6841,6 +6876,35 @@ const docTemplate = `{ } } }, + "model.ProductChangelogs": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "github_url": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "product": { + "type": "integer" + }, + "thumbnail_url": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.ProductMetadataEmojis": { "type": "object", "properties": { @@ -11218,25 +11282,6 @@ const docTemplate = `{ } } }, - "response.OnboardingStartData": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "userDidStartOnboarding": { - "type": "boolean" - } - } - }, - "response.OnboardingStartResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/response.OnboardingStartData" - } - } - }, "response.OnchainInvestData": { "type": "object", "properties": { @@ -11280,6 +11325,17 @@ const docTemplate = `{ } } }, + "response.ProductChangelogs": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ProductChangelogs" + } + } + } + }, "response.ProfileAirdropCampaignResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 7b740d6c1..3598f1fec 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4481,7 +4481,7 @@ "application/json" ], "tags": [ - "Defi" + "Onboarding" ], "summary": "User did start onboarding", "parameters": [ @@ -4499,7 +4499,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.OnboardingStartResponse" + "$ref": "#/definitions/response.ResponseDataMessage" } } } @@ -4639,6 +4639,41 @@ } } }, + "/product-metadata/changelogs": { + "get": { + "description": "Get product changelogs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ProductMetadata" + ], + "summary": "Get product changelogs", + "parameters": [ + { + "type": "string", + "name": "product", + "in": "query" + }, + { + "type": "string", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.ProductChangelogs" + } + } + } + } + }, "/product-metadata/commands": { "get": { "description": "Get product bot commands", @@ -6833,6 +6868,35 @@ } } }, + "model.ProductChangelogs": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "github_url": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "product": { + "type": "integer" + }, + "thumbnail_url": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.ProductMetadataEmojis": { "type": "object", "properties": { @@ -11210,25 +11274,6 @@ } } }, - "response.OnboardingStartData": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "userDidStartOnboarding": { - "type": "boolean" - } - } - }, - "response.OnboardingStartResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/response.OnboardingStartData" - } - } - }, "response.OnchainInvestData": { "type": "object", "properties": { @@ -11272,6 +11317,17 @@ } } }, + "response.ProductChangelogs": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ProductChangelogs" + } + } + } + }, "response.ProfileAirdropCampaignResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 934d0d7ed..2480637a7 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -575,6 +575,25 @@ definitions: updated_at: type: string type: object + model.ProductChangelogs: + properties: + content: + type: string + created_at: + type: string + github_url: + type: string + id: + type: integer + product: + type: integer + thumbnail_url: + type: string + title: + type: string + updated_at: + type: string + type: object model.ProductMetadataEmojis: properties: code: @@ -2527,14 +2546,14 @@ definitions: type: string usd: type: number + usd_7d_change: + type: number usd_14d_change: type: number usd_1h_change: type: number usd_1y_change: type: number - usd_7d_change: - type: number usd_24h_change: type: number usd_24h_vol: @@ -3155,6 +3174,12 @@ definitions: additionalProperties: type: number type: object + price_change_percentage_7d: + type: number + price_change_percentage_7d_in_currency: + additionalProperties: + type: number + type: object price_change_percentage_14d: type: number price_change_percentage_14d_in_currency: @@ -3173,12 +3198,6 @@ definitions: additionalProperties: type: number type: object - price_change_percentage_7d: - type: number - price_change_percentage_7d_in_currency: - additionalProperties: - type: number - type: object price_change_percentage_24h: type: number price_change_percentage_24h_in_currency: @@ -3438,18 +3457,6 @@ definitions: $ref: '#/definitions/response.OffchainTipBotTransferToken' type: array type: object - response.OnboardingStartData: - properties: - message: - type: string - userDidStartOnboarding: - type: boolean - type: object - response.OnboardingStartResponse: - properties: - data: - $ref: '#/definitions/response.OnboardingStartData' - type: object response.OnchainInvestData: properties: tx_object: @@ -3478,6 +3485,13 @@ definitions: $ref: '#/definitions/model.ProductBotCommand' type: array type: object + response.ProductChangelogs: + properties: + data: + items: + $ref: '#/definitions/model.ProductChangelogs' + type: array + type: object response.ProfileAirdropCampaignResponse: properties: data: @@ -6829,10 +6843,10 @@ paths: "200": description: OK schema: - $ref: '#/definitions/response.OnboardingStartResponse' + $ref: '#/definitions/response.ResponseDataMessage' summary: User did start onboarding tags: - - Defi + - Onboarding /onchain/invest-stake-data: get: consumes: @@ -6925,6 +6939,28 @@ paths: summary: Get onchain invest unstake data tags: - Invest + /product-metadata/changelogs: + get: + consumes: + - application/json + description: Get product changelogs + parameters: + - in: query + name: product + type: string + - in: query + name: size + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.ProductChangelogs' + summary: Get product changelogs + tags: + - ProductMetadata /product-metadata/commands: get: consumes: diff --git a/go.mod b/go.mod index 203c858ce..a1c2d60f1 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce github.com/bwmarrin/discordgo v0.26.1 github.com/confluentinc/confluent-kafka-go v1.9.2 - github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573 + github.com/consolelabs/mochi-typeset v0.0.0-20230823081345-e192d01ca34f github.com/ethereum/go-ethereum v1.12.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-contrib/pprof v1.4.0 diff --git a/go.sum b/go.sum index fb05888f7..0a12cd1c4 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/consolelabs/mochi-toolkit v0.0.0-20230713093321-b3c70e7b2905 h1:n5JZF1xv7w+UoOjtx2VrROuqUYAFm9uDRwPeSgmxV+M= github.com/consolelabs/mochi-toolkit v0.0.0-20230713093321-b3c70e7b2905/go.mod h1:ZShtpSO6HNmj+G2W/vFDi28BneoLis6AWYnRIAnfIxU= -github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573 h1:lDzeYUew4MNfFXwpEJeF6q5tN5fVm5G2Dhnkp6ie3mk= -github.com/consolelabs/mochi-typeset v0.0.0-20230823042741-8cdc64c01573/go.mod h1:HSKMB2HqQKHgeVpG/QZAs2nHulZbLA8PreLeujm2Ups= +github.com/consolelabs/mochi-typeset v0.0.0-20230823081345-e192d01ca34f h1:eJ+39cmbuqCY7eI8TF1LgAtjTjuOBY/LhOmsTHSVKw4= +github.com/consolelabs/mochi-typeset v0.0.0-20230823081345-e192d01ca34f/go.mod h1:HSKMB2HqQKHgeVpG/QZAs2nHulZbLA8PreLeujm2Ups= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= diff --git a/pkg/entities/onboarding.go b/pkg/entities/onboarding.go index 031760abc..34171b108 100644 --- a/pkg/entities/onboarding.go +++ b/pkg/entities/onboarding.go @@ -6,8 +6,10 @@ import ( "encoding/json" "math/big" + "github.com/consolelabs/mochi-typeset/typeset" "github.com/ethereum/go-ethereum/common/math" + "github.com/defipod/mochi/pkg/kafka/message" "github.com/defipod/mochi/pkg/logger" "github.com/defipod/mochi/pkg/request" "github.com/defipod/mochi/pkg/service/mochipay" @@ -89,7 +91,8 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { } // Send notification to user - if err := e.sendOnboardingStartNotification(); err != nil { + if err := e.sendOnboardingStartNotification(req.ProfileId, symbol, amount, kekkToken.Decimal); err != nil { + // just log if send notification failed e.log. Fields(logger.Fields{"profileId": req.ProfileId}). Error(err, "[Entity.OnboardingStart] e.sendOnboardingStartNotification() failed") @@ -99,11 +102,19 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { return nil } -func (e *Entity) sendOnboardingStartNotification() error { - msg := struct{ Message string }{Message: "Hello"} +func (e *Entity) sendOnboardingStartNotification(profileId, tokenSymbol, tokenAmount string, tokenDecimal int64) error { + msg := message.OnboardingStart{ + Type: typeset.NOTIFICATION_ONBOARDING_START, + OnboardingStartMetadata: message.OnboardingStartMetadata{ + UserProfileID: profileId, + Token: tokenSymbol, + Amount: tokenAmount, + Decimal: tokenDecimal, + }, + } byteNotification, _ := json.Marshal(msg) if err := e.kafka.ProduceNotification(e.cfg.Kafka.NotificationTopic, byteNotification); err != nil { - e.log.Fields(logger.Fields{"req": ""}).Error(err, "[entity.sendOnboardingStartNotification] - e.kafka.Produce failed") + e.log.Fields(logger.Fields{"msg": msg}).Error(err, "[entity.sendOnboardingStartNotification] - e.kafka.Produce failed") return err } return nil diff --git a/pkg/handler/onboarding/onboarding.go b/pkg/handler/onboarding/onboarding.go index adea8c570..900e4a2b8 100644 --- a/pkg/handler/onboarding/onboarding.go +++ b/pkg/handler/onboarding/onboarding.go @@ -27,7 +27,7 @@ func New(entities *entities.Entity, logger logger.Logger) IHandler { // Start godoc // @Summary User did start onboarding // @Description User did start onboarding -// @Tags Defi +// @Tags Onboarding // @Accept json // @Produce json // @Param req body request.OnboardingStartRequest true "onboarding start request" diff --git a/pkg/kafka/message/onboarding.go b/pkg/kafka/message/onboarding.go index a59f97f47..936074bd1 100644 --- a/pkg/kafka/message/onboarding.go +++ b/pkg/kafka/message/onboarding.go @@ -3,13 +3,13 @@ package message import "github.com/consolelabs/mochi-typeset/typeset" type OnboardingStart struct { - Type typeset.NotificationType `json:"type"` - Metadata OnboardingStartMetadata `json:"metadata"` + Type typeset.NotificationType `json:"type"` + OnboardingStartMetadata OnboardingStartMetadata `json:"onboarding_start_metadata"` } type OnboardingStartMetadata struct { - Token string `json:"token"` - TokenAmount string `json:"token_amount"` - TokenDecimal int64 `json:"token_decimal"` - RecipientProfileId string `json:"recipient_profile_id"` + UserProfileID string `json:"user_profile_id"` + Token string `json:"token"` + Amount string `json:"amount"` + Decimal int64 `json:"decimal"` } From 3bfa20ef69466fcef24acc809618ee126852d3e0 Mon Sep 17 00:00:00 2001 From: phucledien Date: Wed, 23 Aug 2023 16:48:05 +0700 Subject: [PATCH 3/4] chore: remove unused file --- pkg/response/onboarding.go | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 pkg/response/onboarding.go diff --git a/pkg/response/onboarding.go b/pkg/response/onboarding.go deleted file mode 100644 index 6c53659cb..000000000 --- a/pkg/response/onboarding.go +++ /dev/null @@ -1,15 +0,0 @@ -package response - -type OnboardingStartResponse struct { - Data OnboardingStartData `json:"data"` -} - -type OnboardingReward struct { - TokenSymbol string `json:"token_symbol"` - Amount int `json:"amount"` -} - -type OnboardingStartData struct { - DidOnboarding bool `json:"did_onboarding"` - Reward OnboardingReward `json:"reward"` -} From a7ec82dc6ba73a48559e09183ef31589303b5f85 Mon Sep 17 00:00:00 2001 From: phucledien Date: Thu, 24 Aug 2023 16:42:20 +0700 Subject: [PATCH 4/4] fix: update response and clear notification --- docs/docs.go | 32 ++++++++++++- docs/swagger.json | 32 ++++++++++++- docs/swagger.yaml | 37 +++++++++++---- pkg/entities/onboarding.go | 70 +++++++++------------------- pkg/handler/onboarding/onboarding.go | 7 +-- pkg/response/onboarding.go | 15 ++++++ pkg/service/mochipay/mochipay.go | 2 +- 7 files changed, 133 insertions(+), 62 deletions(-) create mode 100644 pkg/response/onboarding.go diff --git a/docs/docs.go b/docs/docs.go index 14f169a4f..49c1dccbf 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4507,7 +4507,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.ResponseDataMessage" + "$ref": "#/definitions/response.OnboardingStartResponse" } } } @@ -11282,6 +11282,36 @@ const docTemplate = `{ } } }, + "response.OnboardingStartData": { + "type": "object", + "properties": { + "reward": { + "$ref": "#/definitions/response.OnboardingStartReward" + }, + "user_already_started": { + "type": "boolean" + } + } + }, + "response.OnboardingStartResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.OnboardingStartData" + } + } + }, + "response.OnboardingStartReward": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, "response.OnchainInvestData": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 3598f1fec..d94bfbf9d 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4499,7 +4499,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/response.ResponseDataMessage" + "$ref": "#/definitions/response.OnboardingStartResponse" } } } @@ -11274,6 +11274,36 @@ } } }, + "response.OnboardingStartData": { + "type": "object", + "properties": { + "reward": { + "$ref": "#/definitions/response.OnboardingStartReward" + }, + "user_already_started": { + "type": "boolean" + } + } + }, + "response.OnboardingStartResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.OnboardingStartData" + } + } + }, + "response.OnboardingStartReward": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, "response.OnchainInvestData": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 2480637a7..6a16b3ade 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2546,12 +2546,12 @@ definitions: type: string usd: type: number + usd_1h_change: + type: number usd_7d_change: type: number usd_14d_change: type: number - usd_1h_change: - type: number usd_1y_change: type: number usd_24h_change: @@ -3174,12 +3174,6 @@ definitions: additionalProperties: type: number type: object - price_change_percentage_7d: - type: number - price_change_percentage_7d_in_currency: - additionalProperties: - type: number - type: object price_change_percentage_14d: type: number price_change_percentage_14d_in_currency: @@ -3198,6 +3192,12 @@ definitions: additionalProperties: type: number type: object + price_change_percentage_7d: + type: number + price_change_percentage_7d_in_currency: + additionalProperties: + type: number + type: object price_change_percentage_24h: type: number price_change_percentage_24h_in_currency: @@ -3457,6 +3457,25 @@ definitions: $ref: '#/definitions/response.OffchainTipBotTransferToken' type: array type: object + response.OnboardingStartData: + properties: + reward: + $ref: '#/definitions/response.OnboardingStartReward' + user_already_started: + type: boolean + type: object + response.OnboardingStartResponse: + properties: + data: + $ref: '#/definitions/response.OnboardingStartData' + type: object + response.OnboardingStartReward: + properties: + amount: + type: string + token: + type: string + type: object response.OnchainInvestData: properties: tx_object: @@ -6843,7 +6862,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/response.ResponseDataMessage' + $ref: '#/definitions/response.OnboardingStartResponse' summary: User did start onboarding tags: - Onboarding diff --git a/pkg/entities/onboarding.go b/pkg/entities/onboarding.go index 34171b108..0980cd68c 100644 --- a/pkg/entities/onboarding.go +++ b/pkg/entities/onboarding.go @@ -3,28 +3,27 @@ package entities import ( "crypto/ed25519" "encoding/hex" - "encoding/json" - "math/big" + "strconv" + "time" - "github.com/consolelabs/mochi-typeset/typeset" - "github.com/ethereum/go-ethereum/common/math" - - "github.com/defipod/mochi/pkg/kafka/message" "github.com/defipod/mochi/pkg/logger" "github.com/defipod/mochi/pkg/request" + "github.com/defipod/mochi/pkg/response" "github.com/defipod/mochi/pkg/service/mochipay" ) -func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { +func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) (*response.OnboardingStartData, error) { // Check onboarding status onboardingStatus, err := e.svc.MochiProfile.GetOnboardingStatus(req.ProfileId) if err != nil { e.log.Fields(logger.Fields{"profileId": req.ProfileId}).Error(err, "[Entity.OnboardingStart] svc.MochiProfile.GetOnboardingStatus() failed") - return err + return nil, err } if onboardingStatus.DidOnboarding { - // if user already start onboarding, just return - return nil + return &response.OnboardingStartData{ + UserAlreadyStarted: true, + Reward: nil, + }, nil } // Get reward token info @@ -37,27 +36,25 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { e.log. Fields(logger.Fields{"symbol": symbol, "chainId": chainId}). Error(err, "[Entity.OnboardingStart] svc.MochiPay.GetToken() failed") - return err + return nil, err } - decimal := math.BigPow(10, kekkToken.Decimal) - rewardAmount := 10 - amount := new(big.Int).Mul(big.NewInt(int64(rewardAmount)), decimal).String() // Prepare application auth privateKey, err := hex.DecodeString(e.cfg.MochiAppPrivateKey) if err != nil { e.log.Error(err, "[Entity.OnboardingStart] hex.DecodeString() failed") - return err + return nil, err } - message := "ApplicationTransfer" + message := strconv.FormatInt(time.Now().Unix(), 10) signature := ed25519.Sign(privateKey, []byte(message)) sigStr := hex.EncodeToString(signature) if err != nil { e.log.Error(err, "[Entity.OnboardingStart] hex.EncodeString() failed") - return err + return nil, err } // Transfer reward token + rewardAmount := "10" appTransferReq := mochipay.ApplicationTransferRequest{ AppId: "35", Header: mochipay.ApplicationBaseHeaderRequest{ @@ -67,7 +64,7 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { }, Metadata: mochipay.ApplicationTransferMetadata{ RecipientIds: []string{req.ProfileId}, - Amounts: []string{amount}, + Amounts: []string{rewardAmount}, TokenId: kekkToken.Id, References: "", Description: "User onboarding reward", @@ -79,7 +76,7 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { e.log. Fields(logger.Fields{"appTransferRequest": appTransferReq}). Error(err, "[Entity.OnboardingStart] svc.MochiPay.ApplicationTransfer() failed") - return err + return nil, err } // Mark user already started onboarding @@ -87,35 +84,14 @@ func (e *Entity) OnboardingStart(req request.OnboardingStartRequest) error { e.log. Fields(logger.Fields{"profileId": req.ProfileId}). Error(err, "[Entity.OnboardingStart] svc.MochiProfile.MarkUserDidOnboarding() failed") - return err - } - - // Send notification to user - if err := e.sendOnboardingStartNotification(req.ProfileId, symbol, amount, kekkToken.Decimal); err != nil { - // just log if send notification failed - e.log. - Fields(logger.Fields{"profileId": req.ProfileId}). - Error(err, "[Entity.OnboardingStart] e.sendOnboardingStartNotification() failed") - return nil + return nil, err } - return nil -} - -func (e *Entity) sendOnboardingStartNotification(profileId, tokenSymbol, tokenAmount string, tokenDecimal int64) error { - msg := message.OnboardingStart{ - Type: typeset.NOTIFICATION_ONBOARDING_START, - OnboardingStartMetadata: message.OnboardingStartMetadata{ - UserProfileID: profileId, - Token: tokenSymbol, - Amount: tokenAmount, - Decimal: tokenDecimal, + return &response.OnboardingStartData{ + UserAlreadyStarted: false, + Reward: &response.OnboardingStartReward{ + Token: kekkToken.Symbol, + Amount: rewardAmount, }, - } - byteNotification, _ := json.Marshal(msg) - if err := e.kafka.ProduceNotification(e.cfg.Kafka.NotificationTopic, byteNotification); err != nil { - e.log.Fields(logger.Fields{"msg": msg}).Error(err, "[entity.sendOnboardingStartNotification] - e.kafka.Produce failed") - return err - } - return nil + }, nil } diff --git a/pkg/handler/onboarding/onboarding.go b/pkg/handler/onboarding/onboarding.go index 900e4a2b8..02bd337a7 100644 --- a/pkg/handler/onboarding/onboarding.go +++ b/pkg/handler/onboarding/onboarding.go @@ -31,7 +31,7 @@ func New(entities *entities.Entity, logger logger.Logger) IHandler { // @Accept json // @Produce json // @Param req body request.OnboardingStartRequest true "onboarding start request" -// @Success 200 {object} response.ResponseDataMessage +// @Success 200 {object} response.OnboardingStartResponse // @Router /onboarding/start [post] func (h *Handler) Start(c *gin.Context) { var req request.OnboardingStartRequest @@ -40,10 +40,11 @@ func (h *Handler) Start(c *gin.Context) { c.JSON(http.StatusBadRequest, response.CreateResponse[any](nil, nil, err, nil)) return } - if err := h.entities.OnboardingStart(req); err != nil { + data, err := h.entities.OnboardingStart(req) + if err != nil { h.log.Error(err, "[handler.Start] entity.OnboardingStart() failed") c.JSON(baseerrs.GetStatusCode(err), response.CreateResponse[any](nil, nil, err, nil)) return } - c.JSON(http.StatusOK, response.CreateResponse[any](response.ResponseMessage{Message: "OK"}, nil, nil, nil)) + c.JSON(http.StatusOK, response.CreateResponse[any](data, nil, nil, nil)) } diff --git a/pkg/response/onboarding.go b/pkg/response/onboarding.go new file mode 100644 index 000000000..1cc39d6c0 --- /dev/null +++ b/pkg/response/onboarding.go @@ -0,0 +1,15 @@ +package response + +type OnboardingStartResponse struct { + Data OnboardingStartData `json:"data"` +} + +type OnboardingStartData struct { + UserAlreadyStarted bool `json:"user_already_started"` + Reward *OnboardingStartReward `json:"reward"` +} + +type OnboardingStartReward struct { + Token string `json:"token"` + Amount string `json:"amount"` +} diff --git a/pkg/service/mochipay/mochipay.go b/pkg/service/mochipay/mochipay.go index 184afa929..9c2a19d36 100644 --- a/pkg/service/mochipay/mochipay.go +++ b/pkg/service/mochipay/mochipay.go @@ -506,7 +506,7 @@ func (m *MochiPay) ApplicationTransfer(req ApplicationTransferRequest) (*Applica res := &ApplicationTransferResponse{} status, err := util.SendRequest(util.SendRequestQuery{ - URL: fmt.Sprintf("%s/api/v2/applications/%s/transfer", m.config.MochiPayServerHost, req.AppId), + URL: fmt.Sprintf("%s/api/v1/applications/%s/transfer", m.config.MochiPayServerHost, req.AppId), Body: bytes.NewBuffer(payload), Method: "POST", ParseForm: res,