From b28c8aec41fd6243277392795a03abe0e3873fa7 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 13 Feb 2025 03:20:16 +0400 Subject: [PATCH 1/5] Backporting T&C endpoint into phase-2 codebase --- internal/shared/api/handlers/handler/terms.go | 56 +++++++++++++++++++ internal/shared/api/routes.go | 4 ++ internal/shared/config/config.go | 17 +++--- internal/shared/config/terms.go | 5 ++ internal/shared/db/model/terms.go | 9 +++ internal/shared/services/service/interface.go | 1 + internal/shared/services/service/terms.go | 15 +++++ 7 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 internal/shared/api/handlers/handler/terms.go create mode 100644 internal/shared/config/terms.go create mode 100644 internal/shared/db/model/terms.go create mode 100644 internal/shared/services/service/terms.go diff --git a/internal/shared/api/handlers/handler/terms.go b/internal/shared/api/handlers/handler/terms.go new file mode 100644 index 00000000..ff1d83e1 --- /dev/null +++ b/internal/shared/api/handlers/handler/terms.go @@ -0,0 +1,56 @@ +package handler + +import ( + "net/http" + + "github.com/babylonlabs-io/staking-api-service/internal/shared/types" + "github.com/btcsuite/btcd/chaincfg" + "github.com/babylonlabs-io/staking-api-service/internal/shared/utils" + "encoding/json" +) + +type TermsAcceptanceLoggingRequest struct { + Address string `json:"address"` + PublicKey string `json:"public_key"` +} + +type TermsAcceptancePublic struct { + Status bool `json:"status"` +} + +func (h *Handler) LogTermsAcceptance(request *http.Request) (*Result, *types.Error) { + address, publicKey, err := parseTermsAcceptanceLoggingRequest(request, h.Config.Server.BTCNetParam) + if err != nil { + return nil, err + } + + if err := h.Service.AcceptTerms(request.Context(), address, publicKey); err != nil { + return nil, types.NewInternalServiceError(err) + } + + return NewResult(TermsAcceptancePublic{Status: true}), nil +} + +// parseTermsAcceptanceLoggingRequest parses the terms acceptance request bdoy and returns the address and public key +func parseTermsAcceptanceLoggingRequest(request *http.Request, btcNetParam *chaincfg.Params) (string, string, *types.Error) { + var req TermsAcceptanceLoggingRequest + if err := json.NewDecoder(request.Body).Decode(&req); err != nil { + return "", "", types.NewErrorWithMsg(http.StatusBadRequest, types.BadRequest, "Invalid request payload") + } + + // Validate the Bitcoin address + if _, err := utils.CheckBtcAddressType(req.Address, btcNetParam); err != nil { + return "", "", types.NewErrorWithMsg(http.StatusBadRequest, types.BadRequest, "Invalid Bitcoin address") + } + + // Validate the public key + if _, err := utils.GetSchnorrPkFromHex(req.PublicKey); err != nil { + return "", "", types.NewErrorWithMsg(http.StatusBadRequest, types.BadRequest, "Invalid public key") + } + + if req.Address == "" || req.PublicKey == "" { + return "", "", types.NewErrorWithMsg(http.StatusBadRequest, types.BadRequest, "Address and public key are required") + } + + return req.Address, req.PublicKey, nil +} diff --git a/internal/shared/api/routes.go b/internal/shared/api/routes.go index 5ded6b71..6f0c8413 100644 --- a/internal/shared/api/routes.go +++ b/internal/shared/api/routes.go @@ -21,6 +21,10 @@ func (a *Server) SetupRoutes(r *chi.Mux) { r.Post("/v1/ordinals/verify-utxos", registerHandler(handlers.SharedHandler.VerifyUTXOs)) } + if a.cfg.TermsAcceptanceLogging.Enabled { + r.Post("/log-terms-acceptance", registerHandler(handlers.SharedHandler.LogTermsAcceptance)) + } + // V2 API r.Get("/v2/network-info", registerHandler(handlers.V2Handler.GetNetworkInfo)) r.Get("/v2/finality-providers", registerHandler(handlers.V2Handler.GetFinalityProviders)) diff --git a/internal/shared/config/config.go b/internal/shared/config/config.go index f2668a73..b1b2b21b 100644 --- a/internal/shared/config/config.go +++ b/internal/shared/config/config.go @@ -10,14 +10,15 @@ import ( ) type Config struct { - Server *ServerConfig `mapstructure:"server"` - StakingDb *DbConfig `mapstructure:"staking-db"` - IndexerDb *DbConfig `mapstructure:"indexer-db"` - Queue *queue.QueueConfig `mapstructure:"queue"` - Metrics *MetricsConfig `mapstructure:"metrics"` - Assets *AssetsConfig `mapstructure:"assets"` - DelegationTransition *DelegationTransitionConfig `mapstructure:"delegation-transition"` - ExternalAPIs *ExternalAPIsConfig `mapstructure:"external_apis"` + Server *ServerConfig `mapstructure:"server"` + StakingDb *DbConfig `mapstructure:"staking-db"` + IndexerDb *DbConfig `mapstructure:"indexer-db"` + Queue *queue.QueueConfig `mapstructure:"queue"` + Metrics *MetricsConfig `mapstructure:"metrics"` + Assets *AssetsConfig `mapstructure:"assets"` + DelegationTransition *DelegationTransitionConfig `mapstructure:"delegation-transition"` + ExternalAPIs *ExternalAPIsConfig `mapstructure:"external_apis"` + TermsAcceptanceLogging *TermsAcceptanceConfig `mapstructure:"terms_acceptance_logging"` } func (cfg *Config) Validate() error { diff --git a/internal/shared/config/terms.go b/internal/shared/config/terms.go new file mode 100644 index 00000000..04d94c2c --- /dev/null +++ b/internal/shared/config/terms.go @@ -0,0 +1,5 @@ +package config + +type TermsAcceptanceConfig struct { + Enabled bool `mapstructure:"enabled"` +} diff --git a/internal/shared/db/model/terms.go b/internal/shared/db/model/terms.go new file mode 100644 index 00000000..933cd3ce --- /dev/null +++ b/internal/shared/db/model/terms.go @@ -0,0 +1,9 @@ +package dbmodel + +import "go.mongodb.org/mongo-driver/bson/primitive" + +type TermsAcceptance struct { + Id primitive.ObjectID `bson:"_id,omitempty"` + Address string `bson:"address"` + PublicKey string `bson:"public_key"` +} diff --git a/internal/shared/services/service/interface.go b/internal/shared/services/service/interface.go index 92ef661a..282f5c92 100644 --- a/internal/shared/services/service/interface.go +++ b/internal/shared/services/service/interface.go @@ -10,4 +10,5 @@ type SharedServiceProvider interface { DoHealthCheck(ctx context.Context) error VerifyUTXOs(ctx context.Context, utxos []types.UTXOIdentifier, address string) ([]*SafeUTXOPublic, *types.Error) SaveUnprocessableMessages(ctx context.Context, messages string, receipt string) *types.Error + AcceptTerms(ctx context.Context, address, publicKey string) error } diff --git a/internal/shared/services/service/terms.go b/internal/shared/services/service/terms.go new file mode 100644 index 00000000..0f79859e --- /dev/null +++ b/internal/shared/services/service/terms.go @@ -0,0 +1,15 @@ +package service + +import ( + "context" + model "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" +) + +func (s *Service) AcceptTerms(ctx context.Context, address, publicKey string) error { + termsAcceptance := &model.TermsAcceptance{ + Address: address, + PublicKey: publicKey, + } + + return s.DbClients.SaveTermsAcceptance(ctx, termsAcceptance) +} From 9959252f485b0fd88248654024365f3ab503357c Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 17 Feb 2025 03:07:35 +0400 Subject: [PATCH 2/5] Add db implementation --- internal/shared/api/routes.go | 2 +- internal/shared/db/client/interface.go | 1 + internal/shared/db/client/terms.go | 13 +++++++++++++ internal/shared/db/model/setup.go | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 internal/shared/db/client/terms.go diff --git a/internal/shared/api/routes.go b/internal/shared/api/routes.go index 6f0c8413..02799b81 100644 --- a/internal/shared/api/routes.go +++ b/internal/shared/api/routes.go @@ -21,7 +21,7 @@ func (a *Server) SetupRoutes(r *chi.Mux) { r.Post("/v1/ordinals/verify-utxos", registerHandler(handlers.SharedHandler.VerifyUTXOs)) } - if a.cfg.TermsAcceptanceLogging.Enabled { + if a.cfg.TermsAcceptanceLogging != nil && a.cfg.TermsAcceptanceLogging.Enabled { r.Post("/log-terms-acceptance", registerHandler(handlers.SharedHandler.LogTermsAcceptance)) } diff --git a/internal/shared/db/client/interface.go b/internal/shared/db/client/interface.go index d9b3750a..31f5f422 100644 --- a/internal/shared/db/client/interface.go +++ b/internal/shared/db/client/interface.go @@ -37,4 +37,5 @@ type DBClient interface { GetLatestPrice(ctx context.Context, symbol string) (float64, error) // SetLatestPrice sets the latest symbol price in the database SetLatestPrice(ctx context.Context, symbol string, price float64) error + SaveTermsAcceptance(ctx context.Context, termsAcceptance *dbmodel.TermsAcceptance) error } diff --git a/internal/shared/db/client/terms.go b/internal/shared/db/client/terms.go new file mode 100644 index 00000000..8d50502c --- /dev/null +++ b/internal/shared/db/client/terms.go @@ -0,0 +1,13 @@ +package dbclient + +import ( + "context" + model "github.com/babylonlabs-io/staking-api-service/internal/shared/db/model" +) + +func (db *Database) SaveTermsAcceptance(ctx context.Context, termsAcceptance *model.TermsAcceptance) error { + collection := db.Client.Database(db.DbName).Collection(model.TermsAcceptanceCollection) + + _, err := collection.InsertOne(ctx, termsAcceptance) + return err +} diff --git a/internal/shared/db/model/setup.go b/internal/shared/db/model/setup.go index e642ad0e..76b689a1 100644 --- a/internal/shared/db/model/setup.go +++ b/internal/shared/db/model/setup.go @@ -17,6 +17,7 @@ import ( const ( // Shared PkAddressMappingsCollection = "pk_address_mappings" + TermsAcceptanceCollection = "terms_acceptance" // V1 V1StatsLockCollection = "stats_lock" V1OverallStatsCollection = "overall_stats" @@ -47,6 +48,7 @@ var collections = map[string][]index{ {Indexes: map[string]int{"native_segwit_odd": 1}, Unique: true}, {Indexes: map[string]int{"native_segwit_even": 1}, Unique: true}, }, + TermsAcceptanceCollection: {{Indexes: map[string]int{}}}, // V1 V1StatsLockCollection: {{Indexes: map[string]int{}}}, V1OverallStatsCollection: {{Indexes: map[string]int{}}}, From fc4844d0b306d949f02392ccbf40d9b3435dba27 Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 17 Feb 2025 03:11:43 +0400 Subject: [PATCH 3/5] fix build --- internal/shared/services/service/terms.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/shared/services/service/terms.go b/internal/shared/services/service/terms.go index 0f79859e..d68da3b8 100644 --- a/internal/shared/services/service/terms.go +++ b/internal/shared/services/service/terms.go @@ -11,5 +11,5 @@ func (s *Service) AcceptTerms(ctx context.Context, address, publicKey string) er PublicKey: publicKey, } - return s.DbClients.SaveTermsAcceptance(ctx, termsAcceptance) + return s.DbClients.SharedDBClient.SaveTermsAcceptance(ctx, termsAcceptance) } From fa059c817aa8bfdeaa4aa78c6cd1a2b11728a00f Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 17 Feb 2025 12:34:16 +0400 Subject: [PATCH 4/5] Modify config --- config/config-docker.yml | 2 ++ config/config-local.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/config/config-docker.yml b/config/config-docker.yml index f2395c90..c0a9d5dc 100644 --- a/config/config-docker.yml +++ b/config/config-docker.yml @@ -42,6 +42,8 @@ assets: host: "http://ord-poc.devnet.babylonchain.io" port: 8888 timeout: 1000 +terms_acceptance_logging: + enabled: true external_apis: coinmarketcap: api_key: ${COINMARKETCAP_API_KEY} diff --git a/config/config-local.yml b/config/config-local.yml index 90fbcdc5..a27c8b2d 100644 --- a/config/config-local.yml +++ b/config/config-local.yml @@ -39,6 +39,8 @@ assets: host: "http://ord-poc.devnet.babylonchain.io" port: 8888 timeout: 5000 +terms_acceptance_logging: + enabled: true external_apis: coinmarketcap: api_key: ${COINMARKETCAP_API_KEY} From 7ac59975f3ef647d9dee5d2be133658a1ee1aa6c Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 17 Feb 2025 12:41:35 +0400 Subject: [PATCH 5/5] Rewrite config with using env variable --- config/config-local.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config-local.yml b/config/config-local.yml index a27c8b2d..f039dcf8 100644 --- a/config/config-local.yml +++ b/config/config-local.yml @@ -40,7 +40,7 @@ assets: port: 8888 timeout: 5000 terms_acceptance_logging: - enabled: true + enabled: ${TERMS_ACCEPTANCE_LOGGING_ENABLED} external_apis: coinmarketcap: api_key: ${COINMARKETCAP_API_KEY}