satellite/console: add STORJ bonus to transactions

This change includes STORJ bonuses to the list of transactions returned
by the /wallet/payments endpoint.

Issue: https://github.com/storj/storj/issues/5755

Change-Id: Icc95c2cb9dd9fc5ee7a373e68c1cf8a991e1aa58
This commit is contained in:
Wilfred Asomani 2023-05-15 15:14:30 +00:00 committed by Storj Robot
parent c48bd81e5f
commit 4791a6422d
6 changed files with 200 additions and 0 deletions

View File

@ -4,8 +4,10 @@
package console
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"math"
@ -3082,6 +3084,10 @@ func (payment Payments) WalletPayments(ctx context.Context) (_ WalletPayments, e
if err != nil {
return WalletPayments{}, Error.Wrap(err)
}
txns, err := payment.service.billing.ListSource(ctx, user.ID, billing.StorjScanBonusSource)
if err != nil {
return WalletPayments{}, Error.Wrap(err)
}
var paymentInfos []PaymentInfo
for _, walletPayment := range walletPayments {
@ -3107,6 +3113,25 @@ func (payment Payments) WalletPayments(ctx context.Context) (_ WalletPayments, e
Timestamp: txInfo.CreatedAt.UTC(),
})
}
for _, txn := range txns {
var meta struct {
ReferenceID string
LogIndex int
}
err = json.NewDecoder(bytes.NewReader(txn.Metadata)).Decode(&meta)
if err != nil {
return WalletPayments{}, Error.Wrap(err)
}
paymentInfos = append(paymentInfos, PaymentInfo{
ID: fmt.Sprintf("%s#%d", meta.ReferenceID, meta.LogIndex),
Type: txn.Source,
Wallet: address.Hex(),
Amount: txn.Amount,
Status: string(txn.Status),
Link: EtherscanURL(meta.ReferenceID),
Timestamp: txn.Timestamp,
})
}
return WalletPayments{
Payments: paymentInfos,

View File

@ -4,6 +4,7 @@
package console_test
import (
"bytes"
"context"
"database/sql"
"encoding/json"
@ -30,6 +31,7 @@ import (
"storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/billing"
"storj.io/storj/satellite/payments/coinpayments"
"storj.io/storj/satellite/payments/storjscan"
"storj.io/storj/satellite/payments/storjscan/blockchaintest"
@ -1485,6 +1487,12 @@ func TestDeleteAllSessionsByUserIDExcept(t *testing.T) {
func TestPaymentsWalletPayments(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.Payments.BillingConfig.DisableLoop = false
config.Payments.BonusRate = 10
},
},
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
sat := planet.Satellites[0]
now := time.Now().Truncate(time.Second).UTC()
@ -1574,6 +1582,37 @@ func TestPaymentsWalletPayments(t *testing.T) {
})
}
// get billing chore to insert bonuses for transactions.
sat.Core.Payments.BillingChore.TransactionCycle.TriggerWait()
txns, err := sat.DB.Billing().ListSource(ctx, user.ID, billing.StorjScanBonusSource)
require.NoError(t, err)
require.NotEmpty(t, txns)
for _, txn := range txns {
if txn.Source != billing.StorjScanBonusSource {
continue
}
var meta struct {
ReferenceID string
Wallet string
LogIndex int
}
err = json.NewDecoder(bytes.NewReader(txn.Metadata)).Decode(&meta)
if err != nil {
continue
}
expected = append(expected, console.PaymentInfo{
ID: fmt.Sprintf("%s#%d", meta.ReferenceID, meta.LogIndex),
Type: txn.Source,
Wallet: meta.Wallet,
Amount: txn.Amount,
Status: string(txn.Status),
Link: console.EtherscanURL(meta.ReferenceID),
Timestamp: txn.Timestamp,
})
}
walletPayments, err := sat.API.Console.Service.Payments().WalletPayments(reqCtx)
require.NoError(t, err)
require.Equal(t, expected, walletPayments.Payments)

View File

@ -65,6 +65,8 @@ type TransactionsDB interface {
LastTransaction(ctx context.Context, txSource string, txType TransactionType) (time.Time, []byte, error)
// List returns all transactions for the specified user.
List(ctx context.Context, userID uuid.UUID) ([]Transaction, error)
// ListSource returns all transactions for the specified user and source.
ListSource(ctx context.Context, userID uuid.UUID, txSource string) ([]Transaction, error)
// GetBalance returns the current usable balance for the specified user.
GetBalance(ctx context.Context, userID uuid.UUID) (currency.Amount, error)
}

View File

@ -235,6 +235,25 @@ func (db billingDB) List(ctx context.Context, userID uuid.UUID) (txs []billing.T
return txs, nil
}
func (db billingDB) ListSource(ctx context.Context, userID uuid.UUID, txSource string) (txs []billing.Transaction, err error) {
defer mon.Task()(&ctx)(&err)
dbxTXs, err := db.db.All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx,
dbx.BillingTransaction_UserId(userID[:]), dbx.BillingTransaction_Source(txSource))
if err != nil {
return nil, Error.Wrap(err)
}
for _, dbxTX := range dbxTXs {
tx, err := fromDBXBillingTransaction(dbxTX)
if err != nil {
return nil, Error.Wrap(err)
}
txs = append(txs, *tx)
}
return txs, nil
}
func (db billingDB) GetBalance(ctx context.Context, userID uuid.UUID) (_ currency.Amount, err error) {
defer mon.Task()(&ctx)(&err)
dbxBilling, err := db.db.Get_BillingBalance_Balance_By_UserId(ctx,

View File

@ -110,6 +110,13 @@ read all (
orderby desc billing_transaction.timestamp
)
read all (
select billing_transaction
where billing_transaction.user_id = ?
where billing_transaction.source = ?
orderby desc billing_transaction.timestamp
)
read first (
select billing_transaction
where billing_transaction.source = ?

View File

@ -14005,6 +14005,52 @@ func (obj *pgxImpl) All_BillingTransaction_By_UserId_OrderBy_Desc_Timestamp(ctx
}
func (obj *pgxImpl) All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field,
billing_transaction_source BillingTransaction_Source_Field) (
rows []*BillingTransaction, err error) {
defer mon.Task()(&ctx)(&err)
var __embed_stmt = __sqlbundle_Literal("SELECT billing_transactions.id, billing_transactions.user_id, billing_transactions.amount, billing_transactions.currency, billing_transactions.description, billing_transactions.source, billing_transactions.status, billing_transactions.type, billing_transactions.metadata, billing_transactions.timestamp, billing_transactions.created_at FROM billing_transactions WHERE billing_transactions.user_id = ? AND billing_transactions.source = ? ORDER BY billing_transactions.timestamp DESC")
var __values []interface{}
__values = append(__values, billing_transaction_user_id.value(), billing_transaction_source.value())
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
for {
rows, err = func() (rows []*BillingTransaction, err error) {
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
if err != nil {
return nil, err
}
defer __rows.Close()
for __rows.Next() {
billing_transaction := &BillingTransaction{}
err = __rows.Scan(&billing_transaction.Id, &billing_transaction.UserId, &billing_transaction.Amount, &billing_transaction.Currency, &billing_transaction.Description, &billing_transaction.Source, &billing_transaction.Status, &billing_transaction.Type, &billing_transaction.Metadata, &billing_transaction.Timestamp, &billing_transaction.CreatedAt)
if err != nil {
return nil, err
}
rows = append(rows, billing_transaction)
}
if err := __rows.Err(); err != nil {
return nil, err
}
return rows, nil
}()
if err != nil {
if obj.shouldRetry(err) {
continue
}
return nil, obj.makeErr(err)
}
return rows, nil
}
}
func (obj *pgxImpl) First_BillingTransaction_By_Source_And_Type_OrderBy_Desc_CreatedAt(ctx context.Context,
billing_transaction_source BillingTransaction_Source_Field,
billing_transaction_type BillingTransaction_Type_Field) (
@ -21818,6 +21864,52 @@ func (obj *pgxcockroachImpl) All_BillingTransaction_By_UserId_OrderBy_Desc_Times
}
func (obj *pgxcockroachImpl) All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field,
billing_transaction_source BillingTransaction_Source_Field) (
rows []*BillingTransaction, err error) {
defer mon.Task()(&ctx)(&err)
var __embed_stmt = __sqlbundle_Literal("SELECT billing_transactions.id, billing_transactions.user_id, billing_transactions.amount, billing_transactions.currency, billing_transactions.description, billing_transactions.source, billing_transactions.status, billing_transactions.type, billing_transactions.metadata, billing_transactions.timestamp, billing_transactions.created_at FROM billing_transactions WHERE billing_transactions.user_id = ? AND billing_transactions.source = ? ORDER BY billing_transactions.timestamp DESC")
var __values []interface{}
__values = append(__values, billing_transaction_user_id.value(), billing_transaction_source.value())
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
for {
rows, err = func() (rows []*BillingTransaction, err error) {
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
if err != nil {
return nil, err
}
defer __rows.Close()
for __rows.Next() {
billing_transaction := &BillingTransaction{}
err = __rows.Scan(&billing_transaction.Id, &billing_transaction.UserId, &billing_transaction.Amount, &billing_transaction.Currency, &billing_transaction.Description, &billing_transaction.Source, &billing_transaction.Status, &billing_transaction.Type, &billing_transaction.Metadata, &billing_transaction.Timestamp, &billing_transaction.CreatedAt)
if err != nil {
return nil, err
}
rows = append(rows, billing_transaction)
}
if err := __rows.Err(); err != nil {
return nil, err
}
return rows, nil
}()
if err != nil {
if obj.shouldRetry(err) {
continue
}
return nil, obj.makeErr(err)
}
return rows, nil
}
}
func (obj *pgxcockroachImpl) First_BillingTransaction_By_Source_And_Type_OrderBy_Desc_CreatedAt(ctx context.Context,
billing_transaction_source BillingTransaction_Source_Field,
billing_transaction_type BillingTransaction_Type_Field) (
@ -27473,6 +27565,17 @@ func (rx *Rx) All_AccountFreezeEvent_By_UserId(ctx context.Context,
return tx.All_AccountFreezeEvent_By_UserId(ctx, account_freeze_event_user_id)
}
func (rx *Rx) All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field,
billing_transaction_source BillingTransaction_Source_Field) (
rows []*BillingTransaction, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx, billing_transaction_user_id, billing_transaction_source)
}
func (rx *Rx) All_BillingTransaction_By_UserId_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field) (
rows []*BillingTransaction, err error) {
@ -29467,6 +29570,11 @@ type Methods interface {
account_freeze_event_user_id AccountFreezeEvent_UserId_Field) (
rows []*AccountFreezeEvent, err error)
All_BillingTransaction_By_UserId_And_Source_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field,
billing_transaction_source BillingTransaction_Source_Field) (
rows []*BillingTransaction, err error)
All_BillingTransaction_By_UserId_OrderBy_Desc_Timestamp(ctx context.Context,
billing_transaction_user_id BillingTransaction_UserId_Field) (
rows []*BillingTransaction, err error)