Skip to content

Commit

Permalink
Add self custody available field to get wallet endpoint (#2287)
Browse files Browse the repository at this point in the history
* feat: add self custody available field v4 get wallet

* feat: add self custody available field v4 get wallet
  • Loading branch information
clD11 committed Jan 10, 2024
1 parent 45f5c27 commit 875466d
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 6 deletions.
46 changes: 41 additions & 5 deletions services/wallet/controllers_v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
errorutils "github.com/brave-intl/bat-go/libs/errors"
"github.com/brave-intl/bat-go/libs/handlers"
"github.com/brave-intl/bat-go/libs/httpsignature"
"github.com/brave-intl/bat-go/libs/inputs"
"github.com/brave-intl/bat-go/libs/logging"
"github.com/brave-intl/bat-go/libs/middleware"
"github.com/brave-intl/bat-go/services/wallet/model"
"github.com/go-chi/chi"
)

Expand Down Expand Up @@ -167,12 +169,46 @@ func UpdateWalletV4(s *Service) func(w http.ResponseWriter, r *http.Request) *ha
}
}

// GetWalletV4 is the same as get wallet v3, but we are now requiring http signatures for get wallet requests
func GetWalletV4(w http.ResponseWriter, r *http.Request) *handlers.AppError {
return GetWalletV3(w, r)
}

// GetUpholdWalletBalanceV4 produces an http handler for the service s which handles balance inquiries of uphold wallets
func GetUpholdWalletBalanceV4(w http.ResponseWriter, r *http.Request) *handlers.AppError {
return GetUpholdWalletBalanceV3(w, r)
}

func GetWalletV4(s *Service) func(w http.ResponseWriter, r *http.Request) *handlers.AppError {
return func(w http.ResponseWriter, r *http.Request) *handlers.AppError {
var ctx = r.Context()

l := logging.Logger(ctx, "wallet")

var id inputs.ID
if err := inputs.DecodeAndValidateString(ctx, &id, chi.URLParam(r, "paymentID")); err != nil {
l.Warn().Err(err).Str("paymentID", id.String()).Msg("failed to decode and validate paymentID from url")
return handlers.ValidationError("Error validating paymentID url parameter", map[string]interface{}{
"paymentId": err.Error(),
})
}

paymentID := *id.UUID()

info, err := s.Datastore.GetWallet(ctx, paymentID)
if err != nil {
l.Error().Err(err).Str("paymentID", id.String()).Msg("error getting wallet")
return handlers.WrapError(err, "error getting wallet from storage", http.StatusInternalServerError)
}

if info == nil {
l.Info().Interface("paymentID", paymentID).Msg("wallet not found")
return handlers.WrapError(err, "no such wallet", http.StatusNotFound)
}

if _, err := s.allowListRepo.GetAllowListEntry(ctx, s.Datastore.RawDB(), paymentID); err != nil && !errors.Is(err, model.ErrNotFound) {
return handlers.WrapError(err, "error getting allow list entry from storage", http.StatusInternalServerError)
}

solSelfCustody := !errors.Is(err, model.ErrNotFound)

resp := infoToResponseV4(info, solSelfCustody)

return handlers.RenderContent(ctx, resp, w, http.StatusOK)
}
}
48 changes: 48 additions & 0 deletions services/wallet/controllers_v4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import (
"context"
"crypto"
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"

appctx "github.com/brave-intl/bat-go/libs/context"
errorutils "github.com/brave-intl/bat-go/libs/errors"
"github.com/brave-intl/bat-go/libs/middleware"
"github.com/brave-intl/bat-go/services/wallet/storage"

"github.com/brave-intl/bat-go/libs/clients"

Expand Down Expand Up @@ -558,6 +561,51 @@ func (suite *WalletControllersV4TestSuite) TestUpdateBraveWalletV4_ReputationCal
suite.Require().Equal(http.StatusInternalServerError, rw.Code)
}

func (suite *WalletControllersTestSuite) TestGetWalletV4() {
pg, _, err := wallet.NewPostgres()
suite.Require().NoError(err)

pub, _, err := ed25519.GenerateKey(nil)
suite.Require().NoError(err)

paymentID := uuid.NewV4()
w := &walletutils.Info{
ID: paymentID.String(),
Provider: "brave",
PublicKey: hex.EncodeToString(pub),
AltCurrency: ptrTo(altcurrency.BAT),
}
err = pg.InsertWallet(context.TODO(), w)
suite.Require().NoError(err)

whitelistWallet(suite.T(), pg, w.ID)

allowList := storage.NewAllowList()

service, _ := wallet.InitService(pg, nil, nil, allowList, nil, nil, nil, nil, nil, nil, wallet.DAppConfig{})

handler := handlers.AppHandler(wallet.GetWalletV4(service))

req, err := http.NewRequest("GET", "/v4/wallets/"+paymentID.String(), nil)
suite.Require().NoError(err, "a request should be created")

req = req.WithContext(context.WithValue(req.Context(), appctx.NoUnlinkPriorToDurationCTXKey, "-P1D"))
rctx := chi.NewRouteContext()
rctx.URLParams.Add("paymentID", paymentID.String())
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))

rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)

suite.Assert().Equal(http.StatusOK, rr.Code)

var resp wallet.ResponseV4
err = json.Unmarshal(rr.Body.Bytes(), &resp)
suite.Require().NoError(err)

suite.Assert().Equal(true, resp.SelfCustodyAvailable["solana"])
}

func signUpdateRequest(req *http.Request, paymentID string, privateKey ed25519.PrivateKey) error {
var s httpsignature.SignatureParams
s.Algorithm = httpsignature.ED25519
Expand Down
68 changes: 68 additions & 0 deletions services/wallet/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,74 @@ func infoToResponseV3(info *walletutils.Info) ResponseV3 {
return resp
}

// ResponseV4 - wallet creation response
type ResponseV4 struct {
PaymentID string `json:"paymentId"`
DepositAccountProvider *DepositAccountProviderDetailsV3 `json:"depositAccountProvider,omitempty"`
WalletProvider *ProviderDetailsV3 `json:"walletProvider,omitempty"`
AltCurrency string `json:"altcurrency"`
PublicKey string `json:"publicKey"`
SelfCustodyAvailable map[string]bool `json:"selfCustodyAvailable"`
}

func infoToResponseV4(info *walletutils.Info, selfCustody bool) ResponseV4 {
var (
linkingID string
anonymousAddress string
)
if info == nil {
return ResponseV4{}
}

var altCurrency = convertAltCurrency(info.AltCurrency)

if info.ProviderLinkingID == nil {
linkingID = ""
} else {
linkingID = info.ProviderLinkingID.String()
}

if info.AnonymousAddress == nil {
anonymousAddress = ""
} else {
anonymousAddress = info.AnonymousAddress.String()
}

// common to all wallets
resp := ResponseV4{
PaymentID: info.ID,
AltCurrency: altCurrency,
PublicKey: info.PublicKey,
WalletProvider: &ProviderDetailsV3{
Name: info.Provider,
},
SelfCustodyAvailable: map[string]bool{
"solana": selfCustody,
},
}

// setup the wallet provider (anon card uphold)
if info.Provider == "uphold" {
// this is a uphold provided wallet (anon card based)
resp.WalletProvider.ID = info.ProviderID
resp.WalletProvider.AnonymousAddress = anonymousAddress
resp.WalletProvider.LinkingID = linkingID
}

// now setup user deposit account
if info.UserDepositAccountProvider != nil {
// this brave wallet has a linked deposit account
resp.DepositAccountProvider = &DepositAccountProviderDetailsV3{
Name: info.UserDepositAccountProvider,
ID: &info.UserDepositDestination,
LinkingID: linkingID,
AnonymousAddress: anonymousAddress,
}
}

return resp
}

// BalanceResponseV3 - wallet creation response
type BalanceResponseV3 struct {
Total float64 `json:"total"`
Expand Down
2 changes: 1 addition & 1 deletion services/wallet/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ func RegisterRoutes(ctx context.Context, s *Service, r *chi.Mux, metricsMw middl
"UpdateWalletV4", UpdateWalletV4(s))).ServeHTTP)
r.Get("/{paymentID}",
middleware.HTTPSignedOnly(s)(middleware.InstrumentHandlerFunc(
"GetWalletV4", GetWalletV4)).ServeHTTP)
"GetWalletV4", GetWalletV4(s))).ServeHTTP)
// get wallet balance routes
r.Get("/uphold/{paymentID}",
middleware.HTTPSignedOnly(s)(middleware.InstrumentHandlerFunc(
Expand Down

0 comments on commit 875466d

Please sign in to comment.