diff --git a/cmd/service/api.go b/cmd/service/api.go index 10b7d58..3689ccc 100644 --- a/cmd/service/api.go +++ b/cmd/service/api.go @@ -29,12 +29,6 @@ func initApiServer(custodialContainer *custodial.Custodial) *echo.Echo { } server.HTTPErrorHandler = customHTTPErrorHandler - server.Use(func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - c.Set("cu", custodialContainer) - return next(c) - } - }) server.Use(middleware.Recover()) server.Use(middleware.BodyLimit("1M")) server.Use(middleware.ContextTimeout(contextTimeout)) @@ -48,10 +42,10 @@ func initApiServer(custodialContainer *custodial.Custodial) *echo.Echo { apiRoute := server.Group("/api", systemGlobalLock) - apiRoute.POST("/account/create", api.HandleAccountCreate) - apiRoute.GET("/account/status/:address", api.HandleNetworkAccountStatus) - apiRoute.POST("/sign/transfer", api.HandleSignTransfer) - apiRoute.GET("/track/:trackingId", api.HandleTrackTx) + apiRoute.POST("/account/create", api.HandleAccountCreate(custodialContainer)) + apiRoute.GET("/account/status/:address", api.HandleNetworkAccountStatus(custodialContainer)) + apiRoute.POST("/sign/transfer", api.HandleSignTransfer(custodialContainer)) + apiRoute.GET("/track/:trackingId", api.HandleTrackTx(custodialContainer)) return server } diff --git a/internal/api/account.go b/internal/api/account.go index c57f446..3bbe99d 100644 --- a/internal/api/account.go +++ b/internal/api/account.go @@ -15,49 +15,47 @@ import ( // CreateAccountHandler route. // POST: /api/account/create // Returns the public key. -func HandleAccountCreate(c echo.Context) error { - var ( - cu = c.Get("cu").(*custodial.Custodial) - ) +func HandleAccountCreate(cu *custodial.Custodial) func(echo.Context) error { + return func(c echo.Context) error { + generatedKeyPair, err := keypair.Generate() + if err != nil { + return err + } - generatedKeyPair, err := keypair.Generate() - if err != nil { - return err + id, err := cu.Keystore.WriteKeyPair(c.Request().Context(), generatedKeyPair) + if err != nil { + return err + } + + trackingId := uuid.NewString() + taskPayload, err := json.Marshal(task.AccountPayload{ + PublicKey: generatedKeyPair.Public, + TrackingId: trackingId, + }) + if err != nil { + return err + } + + _, err = cu.TaskerClient.CreateTask( + c.Request().Context(), + tasker.AccountPrepareTask, + tasker.DefaultPriority, + &tasker.Task{ + Id: trackingId, + Payload: taskPayload, + }, + ) + if err != nil { + return err + } + + return c.JSON(http.StatusOK, OkResp{ + Ok: true, + Result: H{ + "publicKey": generatedKeyPair.Public, + "custodialId": id, + "trackingId": trackingId, + }, + }) } - - id, err := cu.Keystore.WriteKeyPair(c.Request().Context(), generatedKeyPair) - if err != nil { - return err - } - - trackingId := uuid.NewString() - taskPayload, err := json.Marshal(task.AccountPayload{ - PublicKey: generatedKeyPair.Public, - TrackingId: trackingId, - }) - if err != nil { - return err - } - - _, err = cu.TaskerClient.CreateTask( - c.Request().Context(), - tasker.AccountPrepareTask, - tasker.DefaultPriority, - &tasker.Task{ - Id: trackingId, - Payload: taskPayload, - }, - ) - if err != nil { - return err - } - - return c.JSON(http.StatusOK, OkResp{ - Ok: true, - Result: H{ - "publicKey": generatedKeyPair.Public, - "custodialId": id, - "trackingId": trackingId, - }, - }) } diff --git a/internal/api/network.go b/internal/api/network.go index efe8e0a..cb020a2 100644 --- a/internal/api/network.go +++ b/internal/api/network.go @@ -11,41 +11,42 @@ import ( "github.com/labstack/echo/v4" ) -func HandleNetworkAccountStatus(c echo.Context) error { - var ( - cu = c.Get("cu").(*custodial.Custodial) - accountStatusRequest struct { - Address string `param:"address" validate:"required,eth_addr_checksum"` +func HandleNetworkAccountStatus(cu *custodial.Custodial) func(echo.Context) error { + return func(c echo.Context) error { + var ( + accountStatusRequest struct { + Address string `param:"address" validate:"required,eth_addr_checksum"` + } + networkBalance big.Int + networkNonce uint64 + ) + + if err := c.Bind(&accountStatusRequest); err != nil { + return NewBadRequestError(ErrInvalidJSON) } - networkBalance big.Int - networkNonce uint64 - ) - if err := c.Bind(&accountStatusRequest); err != nil { - return NewBadRequestError(ErrInvalidJSON) + if err := c.Validate(accountStatusRequest); err != nil { + return err + } + + if err := cu.CeloProvider.Client.CallCtx( + c.Request().Context(), + eth.Nonce(w3.A(accountStatusRequest.Address), nil).Returns(&networkNonce), + eth.Balance(w3.A(accountStatusRequest.Address), nil).Returns(&networkBalance), + ); err != nil { + return err + } + + if networkNonce > 0 { + networkNonce-- + } + + return c.JSON(http.StatusOK, OkResp{ + Ok: true, + Result: H{ + "balance": fmt.Sprintf("%s CELO", w3.FromWei(&networkBalance, 18)), + "nonce": networkNonce, + }, + }) } - - if err := c.Validate(accountStatusRequest); err != nil { - return err - } - - if err := cu.CeloProvider.Client.CallCtx( - c.Request().Context(), - eth.Nonce(w3.A(accountStatusRequest.Address), nil).Returns(&networkNonce), - eth.Balance(w3.A(accountStatusRequest.Address), nil).Returns(&networkBalance), - ); err != nil { - return err - } - - if networkNonce > 0 { - networkNonce-- - } - - return c.JSON(http.StatusOK, OkResp{ - Ok: true, - Result: H{ - "balance": fmt.Sprintf("%s CELO", w3.FromWei(&networkBalance, 18)), - "nonce": networkNonce, - }, - }) } diff --git a/internal/api/sign.go b/internal/api/sign.go index d45c1c4..ea3fbba 100644 --- a/internal/api/sign.go +++ b/internal/api/sign.go @@ -21,78 +21,79 @@ import ( // amount -> int (6 d.p. precision) // e.g. 1000000 = 1 VOUCHER // Returns the task id. -func HandleSignTransfer(c echo.Context) error { - var ( - cu = c.Get("cu").(*custodial.Custodial) - req struct { - From string `json:"from" validate:"required,eth_addr_checksum"` - To string `json:"to" validate:"required,eth_addr_checksum"` - VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr_checksum"` - Amount uint64 `json:"amount" validate:"required"` +func HandleSignTransfer(cu *custodial.Custodial) func(echo.Context) error { + return func(c echo.Context) error { + var ( + req struct { + From string `json:"from" validate:"required,eth_addr_checksum"` + To string `json:"to" validate:"required,eth_addr_checksum"` + VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr_checksum"` + Amount uint64 `json:"amount" validate:"required"` + } + ) + + if err := c.Bind(&req); err != nil { + return NewBadRequestError(ErrInvalidJSON) } - ) - if err := c.Bind(&req); err != nil { - return NewBadRequestError(ErrInvalidJSON) - } + if err := c.Validate(req); err != nil { + return err + } - if err := c.Validate(req); err != nil { - return err - } + accountActive, gasQuota, err := cu.PgStore.GetAccountStatusByAddress(c.Request().Context(), req.From) + if err != nil { + return err + } - accountActive, gasQuota, err := cu.PgStore.GetAccountStatusByAddress(c.Request().Context(), req.From) - if err != nil { - return err - } + if !accountActive { + return c.JSON(http.StatusForbidden, ErrResp{ + Ok: false, + Message: "Account pending activation. Try again later.", + }) + } - if !accountActive { - return c.JSON(http.StatusForbidden, ErrResp{ - Ok: false, - Message: "Account pending activation. Try again later.", + if gasQuota < 1 { + return c.JSON(http.StatusForbidden, ErrResp{ + Ok: false, + Message: "Out of gas, refill pending. Try again later.", + }) + } + + trackingId := uuid.NewString() + taskPayload, err := json.Marshal(task.TransferPayload{ + TrackingId: trackingId, + From: req.From, + To: req.To, + VoucherAddress: req.VoucherAddress, + Amount: req.Amount, + }) + if err != nil { + return err + } + + _, err = cu.TaskerClient.CreateTask( + c.Request().Context(), + tasker.SignTransferTask, + tasker.HighPriority, + &tasker.Task{ + Id: trackingId, + Payload: taskPayload, + }, + ) + if err != nil { + return err + } + + err = cu.PgStore.DecrGasQuota(c.Request().Context(), req.From) + if err != nil { + return err + } + + return c.JSON(http.StatusOK, OkResp{ + Ok: true, + Result: H{ + "trackingId": trackingId, + }, }) } - - if gasQuota < 1 { - return c.JSON(http.StatusForbidden, ErrResp{ - Ok: false, - Message: "Out of gas, refill pending. Try again later.", - }) - } - - trackingId := uuid.NewString() - taskPayload, err := json.Marshal(task.TransferPayload{ - TrackingId: trackingId, - From: req.From, - To: req.To, - VoucherAddress: req.VoucherAddress, - Amount: req.Amount, - }) - if err != nil { - return err - } - - _, err = cu.TaskerClient.CreateTask( - c.Request().Context(), - tasker.SignTransferTask, - tasker.HighPriority, - &tasker.Task{ - Id: trackingId, - Payload: taskPayload, - }, - ) - if err != nil { - return err - } - - err = cu.PgStore.DecrGasQuota(c.Request().Context(), req.From) - if err != nil { - return err - } - - return c.JSON(http.StatusOK, OkResp{ - Ok: true, - Result: H{ - "trackingId": trackingId, - }, - }) } diff --git a/internal/api/track.go b/internal/api/track.go index 26f8adb..6bff890 100644 --- a/internal/api/track.go +++ b/internal/api/track.go @@ -12,31 +12,32 @@ import ( // Route param: // trackingId -> tracking UUID // Returns array of tx status. -func HandleTrackTx(c echo.Context) error { - var ( - cu = c.Get("cu").(*custodial.Custodial) - txStatusRequest struct { - TrackingId string `param:"trackingId" validate:"required,uuid"` +func HandleTrackTx(cu *custodial.Custodial) func(echo.Context) error { + return func(c echo.Context) error { + var ( + txStatusRequest struct { + TrackingId string `param:"trackingId" validate:"required,uuid"` + } + ) + + if err := c.Bind(&txStatusRequest); err != nil { + return NewBadRequestError(err) } - ) - if err := c.Bind(&txStatusRequest); err != nil { - return NewBadRequestError(err) + if err := c.Validate(txStatusRequest); err != nil { + return err + } + + txs, err := cu.PgStore.GetTxStatusByTrackingId(c.Request().Context(), txStatusRequest.TrackingId) + if err != nil { + return err + } + + return c.JSON(http.StatusOK, OkResp{ + Ok: true, + Result: H{ + "transactions": txs, + }, + }) } - - if err := c.Validate(txStatusRequest); err != nil { - return err - } - - txs, err := cu.PgStore.GetTxStatusByTrackingId(c.Request().Context(), txStatusRequest.TrackingId) - if err != nil { - return err - } - - return c.JSON(http.StatusOK, OkResp{ - Ok: true, - Result: H{ - "transactions": txs, - }, - }) }