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 }