code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/withdrawals.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package sqlstore
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  
    22  	"code.vegaprotocol.io/vega/datanode/entities"
    23  	"code.vegaprotocol.io/vega/datanode/metrics"
    24  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    25  
    26  	"github.com/georgysavva/scany/pgxscan"
    27  )
    28  
    29  type Withdrawals struct {
    30  	*ConnectionSource
    31  }
    32  
    33  const withdrawalsFilterDateColumn = "vega_time"
    34  
    35  func NewWithdrawals(connectionSource *ConnectionSource) *Withdrawals {
    36  	return &Withdrawals{
    37  		ConnectionSource: connectionSource,
    38  	}
    39  }
    40  
    41  var withdrawalsOrdering = TableOrdering{
    42  	ColumnOrdering{Name: "vega_time", Sorting: ASC},
    43  	ColumnOrdering{Name: "id", Sorting: ASC},
    44  }
    45  
    46  func (w *Withdrawals) Upsert(ctx context.Context, withdrawal *entities.Withdrawal) error {
    47  	defer metrics.StartSQLQuery("Withdrawals", "Upsert")()
    48  	query := `insert into withdrawals(
    49  		id, party_id, amount, asset, status, ref, foreign_tx_hash,
    50  		created_timestamp, withdrawn_timestamp, ext, tx_hash, vega_time
    51  	)
    52  		values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
    53  		on conflict (id, party_id, vega_time) do update
    54  		set
    55  			amount=EXCLUDED.amount,
    56  			asset=EXCLUDED.asset,
    57  			status=EXCLUDED.status,
    58  			ref=EXCLUDED.ref,
    59  			foreign_tx_hash=EXCLUDED.foreign_tx_hash,
    60  			created_timestamp=EXCLUDED.created_timestamp,
    61  			withdrawn_timestamp=EXCLUDED.withdrawn_timestamp,
    62  			ext=EXCLUDED.ext,
    63  			tx_hash=EXCLUDED.tx_hash`
    64  
    65  	if _, err := w.Exec(ctx, query,
    66  		withdrawal.ID,
    67  		withdrawal.PartyID,
    68  		withdrawal.Amount,
    69  		withdrawal.Asset,
    70  		withdrawal.Status,
    71  		withdrawal.Ref,
    72  		withdrawal.ForeignTxHash,
    73  		withdrawal.CreatedTimestamp,
    74  		withdrawal.WithdrawnTimestamp,
    75  		withdrawal.Ext,
    76  		withdrawal.TxHash,
    77  		withdrawal.VegaTime); err != nil {
    78  		err = fmt.Errorf("could not insert withdrawal into database: %w", err)
    79  		return err
    80  	}
    81  
    82  	return nil
    83  }
    84  
    85  func (w *Withdrawals) GetByID(ctx context.Context, withdrawalID string) (entities.Withdrawal, error) {
    86  	defer metrics.StartSQLQuery("Withdrawals", "GetByID")()
    87  	var withdrawal entities.Withdrawal
    88  	query := `select distinct on (id) id, party_id, amount, asset, status, ref,
    89  									  foreign_tx_hash, created_timestamp, withdrawn_timestamp,
    90  									  ext, tx_hash, vega_time
    91  		from withdrawals
    92  		where id = $1
    93  		order by id, vega_time desc`
    94  
    95  	return withdrawal, w.wrapE(pgxscan.Get(ctx, w.ConnectionSource, &withdrawal, query, entities.WithdrawalID(withdrawalID)))
    96  }
    97  
    98  func (w *Withdrawals) GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]entities.Withdrawal, error) {
    99  	defer metrics.StartSQLQuery("Withdrawals", "GetByTxHash")()
   100  
   101  	var withdrawals []entities.Withdrawal
   102  	query := `SELECT id, party_id, amount, asset, status, ref,
   103  				foreign_tx_hash, created_timestamp, withdrawn_timestamp,
   104  				ext, tx_hash, vega_time
   105  		FROM withdrawals WHERE tx_hash = $1`
   106  
   107  	err := pgxscan.Select(ctx, w.ConnectionSource, &withdrawals, query, txHash)
   108  	if err != nil {
   109  		return nil, w.wrapE(err)
   110  	}
   111  
   112  	return withdrawals, nil
   113  }
   114  
   115  func (w *Withdrawals) GetByParty(ctx context.Context, partyID string, openOnly bool, pagination entities.Pagination, dateRange entities.DateRange) (
   116  	[]entities.Withdrawal, entities.PageInfo, error,
   117  ) {
   118  	switch p := pagination.(type) {
   119  	case entities.CursorPagination:
   120  		return w.getByPartyCursor(ctx, partyID, p, dateRange)
   121  	default:
   122  		panic("unsupported pagination")
   123  	}
   124  }
   125  
   126  func (w *Withdrawals) getByPartyCursor(ctx context.Context, partyID string, pagination entities.CursorPagination, dateRange entities.DateRange) ([]entities.Withdrawal, entities.PageInfo, error) {
   127  	var (
   128  		withdrawals []entities.Withdrawal
   129  		pageInfo    entities.PageInfo
   130  		err         error
   131  	)
   132  
   133  	query, args := getWithdrawalsByPartyQuery(partyID, dateRange)
   134  	query, args, err = PaginateQuery[entities.WithdrawalCursor](query, args, withdrawalsOrdering, pagination)
   135  	if err != nil {
   136  		return withdrawals, pageInfo, err
   137  	}
   138  
   139  	defer metrics.StartSQLQuery("Withdrawals", "GetByParty")()
   140  	if err = pgxscan.Select(ctx, w.ConnectionSource, &withdrawals, query, args...); err != nil {
   141  		return nil, pageInfo, fmt.Errorf("could not get withdrawals by party: %w", err)
   142  	}
   143  
   144  	withdrawals, pageInfo = entities.PageEntities[*v2.WithdrawalEdge](withdrawals, pagination)
   145  
   146  	return withdrawals, pageInfo, nil
   147  }
   148  
   149  func getWithdrawalsByPartyQuery(partyID string, dateRange entities.DateRange) (string, []interface{}) {
   150  	var args []interface{}
   151  
   152  	query := `SELECT
   153  		id, party_id, amount, asset, status, ref, foreign_tx_hash,
   154  		created_timestamp, withdrawn_timestamp, ext, tx_hash, vega_time
   155  		FROM withdrawals_current`
   156  
   157  	first := true
   158  	if partyID != "" {
   159  		query = fmt.Sprintf("%s WHERE party_id = %s", query, nextBindVar(&args, entities.PartyID(partyID)))
   160  		first = false
   161  	}
   162  
   163  	return filterDateRange(query, withdrawalsFilterDateColumn, dateRange, first, args...)
   164  }