code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/the_following_transfers_should_happen.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 steps
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  	"code.vegaprotocol.io/vega/core/integration/stubs"
    23  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    24  
    25  	"github.com/cucumber/godog"
    26  )
    27  
    28  func TheFollowingTransfersShouldHappen(
    29  	broker *stubs.BrokerStub,
    30  	exec Execution,
    31  	table *godog.Table,
    32  ) error {
    33  	transfers := broker.GetTransfers(true)
    34  
    35  	for _, r := range parseTransferTable(table) {
    36  		row := transferRow{row: r}
    37  		if row.IsAMM() {
    38  			found := false
    39  			if id, ok := exec.GetAMMSubAccountID(row.From()); ok {
    40  				row.row.values["from"] = id
    41  				found = true
    42  			}
    43  			if id, ok := exec.GetAMMSubAccountID(row.To()); ok {
    44  				row.row.values["to"] = id
    45  				found = true
    46  			}
    47  			if !found {
    48  				return fmt.Errorf("no AMM aliases found for from (%s) or to (%s)", row.From(), row.To())
    49  			}
    50  		}
    51  
    52  		matched, divergingAmounts := matchTransfers(transfers, row)
    53  
    54  		if matched {
    55  			continue
    56  		}
    57  
    58  		if len(divergingAmounts) == 0 {
    59  			return errMissingTransfer(row)
    60  		}
    61  		return errTransferFoundButNotRightAmount(row, divergingAmounts)
    62  	}
    63  
    64  	broker.ResetType(events.LedgerMovementsEvent)
    65  
    66  	return nil
    67  }
    68  
    69  func errTransferFoundButNotRightAmount(row transferRow, divergingAmounts []uint64) error {
    70  	return formatDiff(
    71  		fmt.Sprintf("invalid amount for transfer from %s to %s", row.FromAccountID(), row.ToAccountID()),
    72  		map[string]string{
    73  			"amount": u64ToS(row.Amount()),
    74  		},
    75  		map[string]string{
    76  			"amount": u64SToS(divergingAmounts),
    77  		},
    78  	)
    79  }
    80  
    81  func errMissingTransfer(row transferRow) error {
    82  	return fmt.Errorf("missing transfers between %v and %v for amount %v",
    83  		row.FromAccountID(), row.ToAccountID(), row.Amount(),
    84  	)
    85  }
    86  
    87  func matchTransfers(ledgerEntries []*vegapb.LedgerEntry, row transferRow) (bool, []uint64) {
    88  	divergingAmounts := []uint64{}
    89  	for _, transfer := range ledgerEntries {
    90  		if transfer.FromAccount.ID() == row.FromAccountID() && transfer.ToAccount.ID() == row.ToAccountID() {
    91  			if row.Type() != "" && transfer.Type != vegapb.TransferType(vegapb.TransferType_value[row.Type()]) {
    92  				continue
    93  			}
    94  			if stringToU64(transfer.Amount) == row.Amount() {
    95  				return true, nil
    96  			}
    97  			divergingAmounts = append(divergingAmounts, stringToU64(transfer.Amount))
    98  		}
    99  	}
   100  	return false, divergingAmounts
   101  }
   102  
   103  func parseTransferTable(table *godog.Table) []RowWrapper {
   104  	return StrictParseTable(table, []string{
   105  		"from",
   106  		"from account",
   107  		"to",
   108  		"to account",
   109  		"market id",
   110  		"amount",
   111  		"asset",
   112  	}, []string{
   113  		"type",
   114  		"is amm",
   115  	})
   116  }
   117  
   118  type transferRow struct {
   119  	row RowWrapper
   120  }
   121  
   122  func (r transferRow) From() string {
   123  	return r.row.MustStr("from")
   124  }
   125  
   126  func (r transferRow) FromAccount() vegapb.AccountType {
   127  	return r.row.MustAccount("from account")
   128  }
   129  
   130  func (r transferRow) FromAccountID() string {
   131  	return AccountID(r.MarketID(), r.From(), r.Asset(), r.FromAccount())
   132  }
   133  
   134  func (r transferRow) To() string {
   135  	return r.row.MustStr("to")
   136  }
   137  
   138  func (r transferRow) Type() string {
   139  	return r.row.Str("type")
   140  }
   141  
   142  func (r transferRow) ToAccount() vegapb.AccountType {
   143  	return r.row.MustAccount("to account")
   144  }
   145  
   146  func (r transferRow) ToAccountID() string {
   147  	mID := r.MarketID()
   148  	ta := r.ToAccount()
   149  	if ta == vegapb.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY {
   150  		mID = ""
   151  	}
   152  	return AccountID(mID, r.To(), r.Asset(), ta)
   153  }
   154  
   155  func (r transferRow) MarketID() string {
   156  	return r.row.MustStr("market id")
   157  }
   158  
   159  func (r transferRow) Amount() uint64 {
   160  	return r.row.MustU64("amount")
   161  }
   162  
   163  func (r transferRow) Asset() string {
   164  	return r.row.MustStr("asset")
   165  }
   166  
   167  func (r transferRow) IsAMM() bool {
   168  	if !r.row.HasColumn("is amm") {
   169  		return false
   170  	}
   171  	return r.row.MustBool("is amm")
   172  }