satellite/{payments, console}: added functionality to get wallet's transactions (including pending)
Added new functionality to query storjscan for all wallet transactions (including pending). Added new endpoint to query all wallet transactions. Issue: https://github.com/storj/storj/issues/5978 Change-Id: Id15fddfc9c95efcaa32aa21403cb177f9297e1ab
This commit is contained in:
parent
2ee0195eba
commit
583ad54d86
@ -547,7 +547,9 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
peer.Payments.StorjscanService = storjscan.NewService(log.Named("storjscan-service"),
|
||||
peer.DB.Wallets(),
|
||||
peer.DB.StorjscanPayments(),
|
||||
peer.Payments.StorjscanClient)
|
||||
peer.Payments.StorjscanClient,
|
||||
pc.Storjscan.Confirmations,
|
||||
pc.BonusRate)
|
||||
if err != nil {
|
||||
return nil, errs.Combine(err, peer.Close())
|
||||
}
|
||||
@ -610,6 +612,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
accountFreezeService,
|
||||
peer.Console.Listener,
|
||||
config.Payments.StripeCoinPayments.StripePublicKey,
|
||||
config.Payments.Storjscan.Confirmations,
|
||||
peer.URL(),
|
||||
config.Payments.PackagePlans,
|
||||
)
|
||||
|
@ -48,6 +48,7 @@ type FrontendConfig struct {
|
||||
PricingPackagesEnabled bool `json:"pricingPackagesEnabled"`
|
||||
NewUploadModalEnabled bool `json:"newUploadModalEnabled"`
|
||||
GalleryViewEnabled bool `json:"galleryViewEnabled"`
|
||||
NeededTransactionConfirmations int `json:"neededTransactionConfirmations"`
|
||||
}
|
||||
|
||||
// Satellites is a configuration value that contains a list of satellite names and addresses.
|
||||
|
@ -466,6 +466,30 @@ func (p *Payments) WalletPayments(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// WalletPaymentsWithConfirmations returns with the list of storjscan transactions (including confirmations count) for user`s wallet.
|
||||
func (p *Payments) WalletPaymentsWithConfirmations(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var err error
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
walletPayments, err := p.service.Payments().WalletPaymentsWithConfirmations(ctx)
|
||||
if err != nil {
|
||||
if console.ErrUnauthorized.Has(err) {
|
||||
p.serveJSONError(ctx, w, http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = json.NewEncoder(w).Encode(walletPayments); err != nil {
|
||||
p.log.Error("failed to encode wallet payments with confirmations", zap.Error(ErrPaymentsAPI.Wrap(err)))
|
||||
}
|
||||
}
|
||||
|
||||
// GetProjectUsagePriceModel returns the project usage price model for the user.
|
||||
func (p *Payments) GetProjectUsagePriceModel(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
@ -144,7 +144,8 @@ type Server struct {
|
||||
userIDRateLimiter *web.RateLimiter
|
||||
nodeURL storj.NodeURL
|
||||
|
||||
stripePublicKey string
|
||||
stripePublicKey string
|
||||
neededTokenPaymentConfirmations int
|
||||
|
||||
packagePlans paymentsconfig.PackagePlans
|
||||
|
||||
@ -210,20 +211,21 @@ func (a *apiAuth) RemoveAuthCookie(w http.ResponseWriter) {
|
||||
}
|
||||
|
||||
// NewServer creates new instance of console server.
|
||||
func NewServer(logger *zap.Logger, config Config, service *console.Service, oidcService *oidc.Service, mailService *mailservice.Service, analytics *analytics.Service, abTesting *abtesting.Service, accountFreezeService *console.AccountFreezeService, listener net.Listener, stripePublicKey string, nodeURL storj.NodeURL, packagePlans paymentsconfig.PackagePlans) *Server {
|
||||
func NewServer(logger *zap.Logger, config Config, service *console.Service, oidcService *oidc.Service, mailService *mailservice.Service, analytics *analytics.Service, abTesting *abtesting.Service, accountFreezeService *console.AccountFreezeService, listener net.Listener, stripePublicKey string, neededTokenPaymentConfirmations int, nodeURL storj.NodeURL, packagePlans paymentsconfig.PackagePlans) *Server {
|
||||
server := Server{
|
||||
log: logger,
|
||||
config: config,
|
||||
listener: listener,
|
||||
service: service,
|
||||
mailService: mailService,
|
||||
analytics: analytics,
|
||||
abTesting: abTesting,
|
||||
stripePublicKey: stripePublicKey,
|
||||
ipRateLimiter: web.NewIPRateLimiter(config.RateLimit, logger),
|
||||
userIDRateLimiter: NewUserIDRateLimiter(config.RateLimit, logger),
|
||||
nodeURL: nodeURL,
|
||||
packagePlans: packagePlans,
|
||||
log: logger,
|
||||
config: config,
|
||||
listener: listener,
|
||||
service: service,
|
||||
mailService: mailService,
|
||||
analytics: analytics,
|
||||
abTesting: abTesting,
|
||||
stripePublicKey: stripePublicKey,
|
||||
neededTokenPaymentConfirmations: neededTokenPaymentConfirmations,
|
||||
ipRateLimiter: web.NewIPRateLimiter(config.RateLimit, logger),
|
||||
userIDRateLimiter: NewUserIDRateLimiter(config.RateLimit, logger),
|
||||
nodeURL: nodeURL,
|
||||
packagePlans: packagePlans,
|
||||
}
|
||||
|
||||
logger.Debug("Starting Satellite Console server.", zap.Stringer("Address", server.listener.Addr()))
|
||||
@ -332,6 +334,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
|
||||
paymentsRouter.HandleFunc("/wallet", paymentController.GetWallet).Methods(http.MethodGet, http.MethodOptions)
|
||||
paymentsRouter.HandleFunc("/wallet", paymentController.ClaimWallet).Methods(http.MethodPost, http.MethodOptions)
|
||||
paymentsRouter.HandleFunc("/wallet/payments", paymentController.WalletPayments).Methods(http.MethodGet, http.MethodOptions)
|
||||
paymentsRouter.HandleFunc("/wallet/payments-with-confirmations", paymentController.WalletPaymentsWithConfirmations).Methods(http.MethodGet, http.MethodOptions)
|
||||
paymentsRouter.HandleFunc("/billing-history", paymentController.BillingHistory).Methods(http.MethodGet, http.MethodOptions)
|
||||
paymentsRouter.Handle("/coupon/apply", server.userIDRateLimiter.Limit(http.HandlerFunc(paymentController.ApplyCouponCode))).Methods(http.MethodPatch, http.MethodOptions)
|
||||
paymentsRouter.HandleFunc("/coupon", paymentController.GetCoupon).Methods(http.MethodGet, http.MethodOptions)
|
||||
@ -718,6 +721,7 @@ func (server *Server) frontendConfigHandler(w http.ResponseWriter, r *http.Reque
|
||||
PricingPackagesEnabled: server.config.PricingPackagesEnabled,
|
||||
NewUploadModalEnabled: server.config.NewUploadModalEnabled,
|
||||
GalleryViewEnabled: server.config.GalleryViewEnabled,
|
||||
NeededTransactionConfirmations: server.neededTokenPaymentConfirmations,
|
||||
}
|
||||
|
||||
err := json.NewEncoder(w).Encode(&cfg)
|
||||
|
@ -3091,6 +3091,12 @@ func EtherscanURL(tx string) string {
|
||||
// ErrWalletNotClaimed shows that no address is claimed by the user.
|
||||
var ErrWalletNotClaimed = errs.Class("wallet is not claimed")
|
||||
|
||||
// TestSwapDepositWallets replaces the existing handler for deposit wallets with
|
||||
// the one specified for use in testing.
|
||||
func (payment Payments) TestSwapDepositWallets(dw payments.DepositWallets) {
|
||||
payment.service.depositWallets = dw
|
||||
}
|
||||
|
||||
// ClaimWallet requests a new wallet for the users to be used for payments. If wallet is already claimed,
|
||||
// it will return with the info without error.
|
||||
func (payment Payments) ClaimWallet(ctx context.Context) (_ WalletInfo, err error) {
|
||||
@ -3211,6 +3217,27 @@ func (payment Payments) WalletPayments(ctx context.Context) (_ WalletPayments, e
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WalletPaymentsWithConfirmations returns with all the native blockchain payments (including pending) for a user's wallet.
|
||||
func (payment Payments) WalletPaymentsWithConfirmations(ctx context.Context) (paymentsWithConfirmations []payments.WalletPaymentWithConfirmations, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
user, err := GetUser(ctx)
|
||||
if err != nil {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
address, err := payment.service.depositWallets.Get(ctx, user.ID)
|
||||
if err != nil {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
|
||||
paymentsWithConfirmations, err = payment.service.depositWallets.PaymentsWithConfirmations(ctx, address)
|
||||
if err != nil {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Purchase makes a purchase of `price` amount with description of `desc` and payment method with id of `paymentMethodID`.
|
||||
// If a paid invoice with the same description exists, then we assume this is a retried request and don't create and pay
|
||||
// another invoice.
|
||||
|
@ -1702,6 +1702,86 @@ func TestPaymentsWalletPayments(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
type mockDepositWallets struct {
|
||||
address blockchain.Address
|
||||
payments []payments.WalletPaymentWithConfirmations
|
||||
}
|
||||
|
||||
func (dw mockDepositWallets) Claim(_ context.Context, _ uuid.UUID) (blockchain.Address, error) {
|
||||
return dw.address, nil
|
||||
}
|
||||
|
||||
func (dw mockDepositWallets) Get(_ context.Context, _ uuid.UUID) (blockchain.Address, error) {
|
||||
return dw.address, nil
|
||||
}
|
||||
|
||||
func (dw mockDepositWallets) Payments(_ context.Context, _ blockchain.Address, _ int, _ int64) (p []payments.WalletPayment, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (dw mockDepositWallets) PaymentsWithConfirmations(_ context.Context, _ blockchain.Address) ([]payments.WalletPaymentWithConfirmations, error) {
|
||||
return dw.payments, nil
|
||||
}
|
||||
|
||||
func TestWalletPaymentsWithConfirmations(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
sat := planet.Satellites[0]
|
||||
service := sat.API.Console.Service
|
||||
paymentsService := service.Payments()
|
||||
|
||||
user, err := sat.AddUser(ctx, console.CreateUser{
|
||||
FullName: "Test User",
|
||||
Email: "test@mail.test",
|
||||
Password: "example",
|
||||
}, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
now := time.Now()
|
||||
wallet := blockchaintest.NewAddress()
|
||||
|
||||
var expected []payments.WalletPaymentWithConfirmations
|
||||
for i := 0; i < 3; i++ {
|
||||
expected = append(expected, payments.WalletPaymentWithConfirmations{
|
||||
From: blockchaintest.NewAddress().Hex(),
|
||||
To: wallet.Hex(),
|
||||
TokenValue: currency.AmountFromBaseUnits(int64(i), currency.StorjToken).AsDecimal(),
|
||||
USDValue: currency.AmountFromBaseUnits(int64(i), currency.USDollarsMicro).AsDecimal(),
|
||||
Status: payments.PaymentStatusConfirmed,
|
||||
BlockHash: blockchaintest.NewHash().Hex(),
|
||||
BlockNumber: int64(i),
|
||||
Transaction: blockchaintest.NewHash().Hex(),
|
||||
LogIndex: i,
|
||||
Timestamp: now,
|
||||
Confirmations: int64(i),
|
||||
BonusTokens: decimal.NewFromInt(int64(i)),
|
||||
})
|
||||
}
|
||||
|
||||
paymentsService.TestSwapDepositWallets(mockDepositWallets{address: wallet, payments: expected})
|
||||
|
||||
reqCtx := console.WithUser(ctx, user)
|
||||
|
||||
walletPayments, err := paymentsService.WalletPaymentsWithConfirmations(reqCtx)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, len(walletPayments))
|
||||
|
||||
for i, wp := range walletPayments {
|
||||
require.Equal(t, expected[i].From, wp.From)
|
||||
require.Equal(t, expected[i].To, wp.To)
|
||||
require.Equal(t, expected[i].TokenValue, wp.TokenValue)
|
||||
require.Equal(t, expected[i].USDValue, wp.USDValue)
|
||||
require.Equal(t, expected[i].Status, wp.Status)
|
||||
require.Equal(t, expected[i].BlockHash, wp.BlockHash)
|
||||
require.Equal(t, expected[i].BlockNumber, wp.BlockNumber)
|
||||
require.Equal(t, expected[i].Transaction, wp.Transaction)
|
||||
require.Equal(t, expected[i].LogIndex, wp.LogIndex)
|
||||
require.Equal(t, expected[i].Timestamp, wp.Timestamp)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaymentsPurchase(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
||||
|
@ -496,7 +496,9 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
peer.Payments.StorjscanService = storjscan.NewService(log.Named("storjscan-service"),
|
||||
peer.DB.Wallets(),
|
||||
peer.DB.StorjscanPayments(),
|
||||
peer.Payments.StorjscanClient)
|
||||
peer.Payments.StorjscanClient,
|
||||
pc.Storjscan.Confirmations,
|
||||
pc.BonusRate)
|
||||
if err != nil {
|
||||
return nil, errs.Combine(err, peer.Close())
|
||||
}
|
||||
|
@ -105,6 +105,12 @@ type Transaction struct {
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// CalculateBonusAmount calculates bonus for given currency amount and bonus rate.
|
||||
func CalculateBonusAmount(amount currency.Amount, bonusRate int64) currency.Amount {
|
||||
bonusUnits := amount.BaseUnits() * bonusRate / 100
|
||||
return currency.AmountFromBaseUnits(bonusUnits, amount.Currency())
|
||||
}
|
||||
|
||||
func prepareBonusTransaction(bonusRate int64, source string, transaction Transaction) (Transaction, bool) {
|
||||
// Bonus transactions only apply when enabled (i.e. positive rate) and
|
||||
// for StorjScan transactions.
|
||||
@ -120,7 +126,7 @@ func prepareBonusTransaction(bonusRate int64, source string, transaction Transac
|
||||
|
||||
return Transaction{
|
||||
UserID: transaction.UserID,
|
||||
Amount: calculateBonusAmount(transaction.Amount, bonusRate),
|
||||
Amount: CalculateBonusAmount(transaction.Amount, bonusRate),
|
||||
Description: fmt.Sprintf("STORJ Token Bonus (%d%%)", bonusRate),
|
||||
Source: StorjScanBonusSource,
|
||||
Status: TransactionStatusCompleted,
|
||||
@ -129,8 +135,3 @@ func prepareBonusTransaction(bonusRate int64, source string, transaction Transac
|
||||
Metadata: append([]byte(nil), transaction.Metadata...),
|
||||
}, true
|
||||
}
|
||||
|
||||
func calculateBonusAmount(amount currency.Amount, bonusRate int64) currency.Amount {
|
||||
bonusUnits := amount.BaseUnits() * bonusRate / 100
|
||||
return currency.AmountFromBaseUnits(bonusUnits, amount.Currency())
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ func (chore *Chore) Run(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
latestPayments, err := chore.client.Payments(ctx, from)
|
||||
latestPayments, err := chore.client.AllPayments(ctx, from)
|
||||
if err != nil {
|
||||
chore.log.Error("error retrieving payments", zap.Error(ChoreErr.Wrap(err)))
|
||||
return nil
|
||||
|
@ -67,13 +67,30 @@ func NewClient(endpoint, identifier, secret string) *Client {
|
||||
}
|
||||
}
|
||||
|
||||
// Payments retrieves all payments after specified block for wallets associated with particular API key.
|
||||
func (client *Client) Payments(ctx context.Context, from int64) (_ LatestPayments, err error) {
|
||||
// AllPayments retrieves all payments after specified block for wallets associated with particular API key.
|
||||
func (client *Client) AllPayments(ctx context.Context, from int64) (payments LatestPayments, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
p := client.endpoint + "/api/v0/tokens/payments"
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p, nil)
|
||||
payments, err = client.getPayments(ctx, p, from)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Payments retrieves payments after specified block for given address associated with particular API key.
|
||||
func (client *Client) Payments(ctx context.Context, from int64, address string) (payments LatestPayments, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
p := client.endpoint + "/api/v0/tokens/payments/" + address
|
||||
|
||||
payments, err = client.getPayments(ctx, p, from)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) getPayments(ctx context.Context, path string, from int64) (_ LatestPayments, err error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return LatestPayments{}, ClientErr.Wrap(err)
|
||||
}
|
||||
|
@ -69,17 +69,17 @@ func TestClientMocked(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := storjscan.NewClient(server.URL, "eu", "secret")
|
||||
client := storjscan.NewClient(server.URL, identifier, secret)
|
||||
|
||||
t.Run("all payments from 0", func(t *testing.T) {
|
||||
actual, err := client.Payments(ctx, 0)
|
||||
actual, err := client.AllPayments(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, latestBlock, actual.LatestBlock)
|
||||
require.Equal(t, len(payments), len(actual.Payments))
|
||||
require.Equal(t, payments, actual.Payments)
|
||||
})
|
||||
t.Run("payments from 50", func(t *testing.T) {
|
||||
actual, err := client.Payments(ctx, 50)
|
||||
t.Run("all payments from 50", func(t *testing.T) {
|
||||
actual, err := client.AllPayments(ctx, 50)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, latestBlock, actual.LatestBlock)
|
||||
require.Equal(t, 50, len(actual.Payments))
|
||||
@ -104,7 +104,7 @@ func TestClientMockedUnauthorized(t *testing.T) {
|
||||
|
||||
t.Run("empty credentials", func(t *testing.T) {
|
||||
client := storjscan.NewClient(server.URL, "", "")
|
||||
_, err := client.Payments(ctx, 0)
|
||||
_, err := client.AllPayments(ctx, 0)
|
||||
require.Error(t, err)
|
||||
require.True(t, storjscan.ClientErrUnauthorized.Has(err))
|
||||
require.Equal(t, "identifier is invalid", errs.Unwrap(err).Error())
|
||||
@ -112,7 +112,7 @@ func TestClientMockedUnauthorized(t *testing.T) {
|
||||
|
||||
t.Run("invalid identifier", func(t *testing.T) {
|
||||
client := storjscan.NewClient(server.URL, "invalid", "secret")
|
||||
_, err := client.Payments(ctx, 0)
|
||||
_, err := client.AllPayments(ctx, 0)
|
||||
require.Error(t, err)
|
||||
require.True(t, storjscan.ClientErrUnauthorized.Has(err))
|
||||
require.Equal(t, "identifier is invalid", errs.Unwrap(err).Error())
|
||||
@ -120,7 +120,7 @@ func TestClientMockedUnauthorized(t *testing.T) {
|
||||
|
||||
t.Run("invalid secret", func(t *testing.T) {
|
||||
client := storjscan.NewClient(server.URL, "eu", "invalid")
|
||||
_, err := client.Payments(ctx, 0)
|
||||
_, err := client.AllPayments(ctx, 0)
|
||||
require.Error(t, err)
|
||||
require.True(t, storjscan.ClientErrUnauthorized.Has(err))
|
||||
require.Equal(t, "secret is invalid", errs.Unwrap(err).Error())
|
||||
|
@ -35,19 +35,23 @@ var _ billing.PaymentType = (*Service)(nil)
|
||||
|
||||
// Service exposes API to interact with storjscan payments provider.
|
||||
type Service struct {
|
||||
log *zap.Logger
|
||||
walletsDB WalletsDB
|
||||
paymentsDB PaymentsDB
|
||||
client *Client
|
||||
log *zap.Logger
|
||||
walletsDB WalletsDB
|
||||
paymentsDB PaymentsDB
|
||||
client *Client
|
||||
neededConfirmations int
|
||||
bonusRate int64
|
||||
}
|
||||
|
||||
// NewService creates new storjscan service instance.
|
||||
func NewService(log *zap.Logger, walletsDB WalletsDB, paymentsDB PaymentsDB, client *Client) *Service {
|
||||
func NewService(log *zap.Logger, walletsDB WalletsDB, paymentsDB PaymentsDB, client *Client, neededConfirmations int, bonusRate int64) *Service {
|
||||
return &Service{
|
||||
log: log,
|
||||
walletsDB: walletsDB,
|
||||
paymentsDB: paymentsDB,
|
||||
client: client,
|
||||
log: log,
|
||||
walletsDB: walletsDB,
|
||||
paymentsDB: paymentsDB,
|
||||
client: client,
|
||||
neededConfirmations: neededConfirmations,
|
||||
bonusRate: bonusRate,
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +120,45 @@ func (service *Service) Payments(ctx context.Context, wallet blockchain.Address,
|
||||
return walletPayments, nil
|
||||
}
|
||||
|
||||
// PaymentsWithConfirmations returns payments with confirmations count for a particular wallet.
|
||||
func (service *Service) PaymentsWithConfirmations(ctx context.Context, wallet blockchain.Address) (_ []payments.WalletPaymentWithConfirmations, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
latestPayments, err := service.client.Payments(ctx, 0, wallet.Hex())
|
||||
if err != nil {
|
||||
return nil, ErrService.Wrap(err)
|
||||
}
|
||||
|
||||
var walletPayments []payments.WalletPaymentWithConfirmations
|
||||
for _, pmnt := range latestPayments.Payments {
|
||||
confirmations := latestPayments.LatestBlock.Number - pmnt.BlockNumber
|
||||
|
||||
var status payments.PaymentStatus
|
||||
if confirmations >= int64(service.neededConfirmations) {
|
||||
status = payments.PaymentStatusConfirmed
|
||||
} else {
|
||||
status = payments.PaymentStatusPending
|
||||
}
|
||||
|
||||
walletPayments = append(walletPayments, payments.WalletPaymentWithConfirmations{
|
||||
From: pmnt.From.Hex(),
|
||||
To: pmnt.To.Hex(),
|
||||
TokenValue: pmnt.TokenValue.AsDecimal(),
|
||||
USDValue: pmnt.USDValue.AsDecimal(),
|
||||
Status: status,
|
||||
BlockHash: pmnt.BlockHash.Hex(),
|
||||
BlockNumber: pmnt.BlockNumber,
|
||||
Transaction: pmnt.Transaction.Hex(),
|
||||
LogIndex: pmnt.LogIndex,
|
||||
Timestamp: pmnt.Timestamp,
|
||||
Confirmations: confirmations,
|
||||
BonusTokens: billing.CalculateBonusAmount(pmnt.TokenValue, service.bonusRate).AsDecimal(),
|
||||
})
|
||||
}
|
||||
|
||||
return walletPayments, nil
|
||||
}
|
||||
|
||||
// Source defines the billing transaction source for storjscan payments.
|
||||
func (service *Service) Source() string {
|
||||
return billing.StorjScanSource
|
||||
|
@ -99,7 +99,7 @@ func TestServicePayments(t *testing.T) {
|
||||
err := paymentsDB.InsertBatch(ctx, cachedPayments)
|
||||
require.NoError(t, err)
|
||||
|
||||
service := storjscan.NewService(zaptest.NewLogger(t), db.Wallets(), paymentsDB, nil)
|
||||
service := storjscan.NewService(zaptest.NewLogger(t), db.Wallets(), paymentsDB, nil, 15, 10)
|
||||
|
||||
t.Run("wallet 1", func(t *testing.T) {
|
||||
expected := []payments.WalletPayment{walletPayments[3], walletPayments[1], walletPayments[0]}
|
||||
@ -151,7 +151,7 @@ func TestServiceWallets(t *testing.T) {
|
||||
err = db.Wallets().Add(ctx, userID3, walletAddress3)
|
||||
require.NoError(t, err)
|
||||
|
||||
service := storjscan.NewService(zaptest.NewLogger(t), db.Wallets(), db.StorjscanPayments(), nil)
|
||||
service := storjscan.NewService(zaptest.NewLogger(t), db.Wallets(), db.StorjscanPayments(), nil, 15, 10)
|
||||
|
||||
t.Run("get Wallet", func(t *testing.T) {
|
||||
actual, err := service.Get(ctx, userID1)
|
||||
|
@ -34,6 +34,8 @@ type DepositWallets interface {
|
||||
Get(ctx context.Context, userID uuid.UUID) (blockchain.Address, error)
|
||||
// Payments returns payments for a particular wallet.
|
||||
Payments(ctx context.Context, wallet blockchain.Address, limit int, offset int64) ([]WalletPayment, error)
|
||||
// PaymentsWithConfirmations returns payments with confirmations count for a particular wallet.
|
||||
PaymentsWithConfirmations(ctx context.Context, wallet blockchain.Address) ([]WalletPaymentWithConfirmations, error)
|
||||
}
|
||||
|
||||
// TransactionStatus defines allowed statuses
|
||||
@ -121,3 +123,19 @@ type WalletPayment struct {
|
||||
LogIndex int `json:"logIndex"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// WalletPaymentWithConfirmations holds storj token payment data with confirmations count.
|
||||
type WalletPaymentWithConfirmations struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
TokenValue decimal.Decimal `json:"tokenValue"`
|
||||
USDValue decimal.Decimal `json:"usdValue"`
|
||||
Status PaymentStatus `json:"status"`
|
||||
BlockHash string `json:"blockHash"`
|
||||
BlockNumber int64 `json:"blockNumber"`
|
||||
Transaction string `json:"transaction"`
|
||||
LogIndex int `json:"logIndex"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Confirmations int64 `json:"confirmations"`
|
||||
BonusTokens decimal.Decimal `json:"bonusTokens"`
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func TestClientPayments(t *testing.T) {
|
||||
err = stack.App.TokenPrice.Service.SavePrice(ctx, blockTime.Add(-30*time.Second), price)
|
||||
require.NoError(t, err)
|
||||
|
||||
pmnts, err := planet.Satellites[0].API.Payments.StorjscanClient.Payments(ctx, 0)
|
||||
pmnts, err := planet.Satellites[0].API.Payments.StorjscanClient.AllPayments(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, block.Number().Int64(), pmnts.LatestBlock.Number)
|
||||
require.Len(t, pmnts.Payments, 1)
|
||||
|
Loading…
Reference in New Issue
Block a user