code.vegaprotocol.io/vega@v0.79.0/core/collateral/transfer_funds_test.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 collateral_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  
    25  	"github.com/golang/mock/gomock"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func TestCollateralTransferFunds(t *testing.T) {
    31  	t.Run("invalid number of parameters", testInvalidNumberOfParameters)
    32  	t.Run("general to general", testTransferFundsFromGeneralToGeneral)
    33  	t.Run("general to reward pool", testTransferFundsFromGeneralToRewardPool)
    34  	t.Run("take from general do not distribute", testTakeFromGeneralDoNotDistribute)
    35  	t.Run("distribute only from pending transfer", testDistributeScheduleFunds)
    36  }
    37  
    38  func testDistributeScheduleFunds(t *testing.T) {
    39  	e := getTestEngine(t)
    40  	defer e.Finish()
    41  
    42  	party1 := "party1"
    43  	initialBalance := num.NewUint(90)
    44  
    45  	e.broker.EXPECT().Send(gomock.Any()).Times(1)
    46  	pendingTransfersAcc := e.GetPendingTransfersAccount(testMarketAsset)
    47  	assert.Equal(t, pendingTransfersAcc.Balance, num.UintZero())
    48  
    49  	err := e.UpdateBalance(context.Background(), pendingTransfersAcc.ID, initialBalance)
    50  	assert.Nil(t, err)
    51  
    52  	e.broker.EXPECT().Send(gomock.Any()).Times(4)
    53  
    54  	// now we create the transfers:
    55  	resps, err := e.TransferFunds(
    56  		context.Background(),
    57  		[]*types.Transfer{
    58  			{
    59  				Owner: party1,
    60  				Amount: &types.FinancialAmount{
    61  					Asset:  testMarketAsset,
    62  					Amount: num.NewUint(90), // we assume the transfer to the other party is 90
    63  				},
    64  				Type:      types.TransferTypeTransferFundsDistribute,
    65  				MinAmount: num.NewUint(90),
    66  			},
    67  		},
    68  		// 1 general accounts
    69  		[]types.AccountType{
    70  			types.AccountTypeGeneral,
    71  		},
    72  		[]string{
    73  			"pending-transfer-account-to-party1",
    74  		},
    75  		// no fees, they are paid before
    76  		[]*types.Transfer{},
    77  		[]types.AccountType{},
    78  	)
    79  
    80  	assert.NoError(t, err)
    81  	assert.Len(t, resps, 1)
    82  
    83  	// ensure balances now
    84  	acc1, err := e.GetPartyGeneralAccount(party1, testMarketAsset)
    85  	assert.NoError(t, err)
    86  	assert.Equal(t, acc1.Balance, num.NewUint(90))
    87  
    88  	pendingTransfersAcc = e.GetPendingTransfersAccount(testMarketAsset)
    89  	assert.NoError(t, err)
    90  	assert.Equal(t, pendingTransfersAcc.Balance, num.UintZero())
    91  }
    92  
    93  func testTakeFromGeneralDoNotDistribute(t *testing.T) {
    94  	e := getTestEngine(t)
    95  	defer e.Finish()
    96  
    97  	party1 := "party1"
    98  	initialBalance := num.NewUint(100)
    99  
   100  	// create party1 account + top up
   101  	// no need to create party2 account, this account
   102  	// should be created on the go
   103  	e.broker.EXPECT().Send(gomock.Any()).Times(3)
   104  
   105  	p1AccID, err := e.CreatePartyGeneralAccount(
   106  		context.Background(), party1, testMarketAsset)
   107  	require.NoError(t, err)
   108  
   109  	err = e.UpdateBalance(context.Background(), p1AccID, initialBalance)
   110  	assert.Nil(t, err)
   111  
   112  	e.broker.EXPECT().Send(gomock.Any()).Times(4)
   113  
   114  	// now we create the transfers:
   115  	resps, err := e.TransferFunds(
   116  		context.Background(),
   117  		[]*types.Transfer{
   118  			{
   119  				Owner: party1,
   120  				Amount: &types.FinancialAmount{
   121  					Asset:  testMarketAsset,
   122  					Amount: num.NewUint(90), // we assume the transfer to the other party is 90
   123  				},
   124  				Type:      types.TransferTypeTransferFundsSend,
   125  				MinAmount: num.NewUint(90),
   126  			},
   127  		},
   128  		// 1 general accounts
   129  		[]types.AccountType{
   130  			types.AccountTypeGeneral,
   131  		},
   132  		[]string{
   133  			"party1-to-party2",
   134  		},
   135  		// fee transfer
   136  		[]*types.Transfer{
   137  			{
   138  				Owner: party1,
   139  				Amount: &types.FinancialAmount{
   140  					Asset:  testMarketAsset,
   141  					Amount: num.NewUint(10), // we should have just enough to pay the fee
   142  				},
   143  				Type:      types.TransferTypeInfrastructureFeePay,
   144  				MinAmount: num.NewUint(10),
   145  			},
   146  		},
   147  		[]types.AccountType{
   148  			types.AccountTypeGeneral, // only one account, the general account of party
   149  		},
   150  	)
   151  
   152  	assert.NoError(t, err)
   153  	assert.Len(t, resps, 2)
   154  
   155  	// ensure balances now
   156  	acc1, err := e.GetPartyGeneralAccount(party1, testMarketAsset)
   157  	assert.NoError(t, err)
   158  	assert.Equal(t, acc1.Balance, num.UintZero())
   159  
   160  	pendingTransfersAcc := e.GetPendingTransfersAccount(testMarketAsset)
   161  	assert.NoError(t, err)
   162  	assert.Equal(t, pendingTransfersAcc.Balance, num.NewUint(90))
   163  }
   164  
   165  func testTransferFundsFromGeneralToGeneral(t *testing.T) {
   166  	e := getTestEngine(t)
   167  	defer e.Finish()
   168  
   169  	party1 := "party1"
   170  	party2 := "party2"
   171  	initialBalance := num.NewUint(100)
   172  
   173  	// create party1 account + top up
   174  	// no need to create party2 account, this account
   175  	// should be created on the go
   176  	e.broker.EXPECT().Send(gomock.Any()).Times(3)
   177  
   178  	p1AccID, err := e.CreatePartyGeneralAccount(
   179  		context.Background(), party1, testMarketAsset)
   180  	require.NoError(t, err)
   181  
   182  	err = e.UpdateBalance(context.Background(), p1AccID, initialBalance)
   183  	assert.Nil(t, err)
   184  
   185  	e.broker.EXPECT().Send(gomock.Any()).Times(8)
   186  
   187  	// now we create the transfers:
   188  	resps, err := e.TransferFunds(
   189  		context.Background(),
   190  		[]*types.Transfer{
   191  			{
   192  				Owner: party1,
   193  				Amount: &types.FinancialAmount{
   194  					Asset:  testMarketAsset,
   195  					Amount: num.NewUint(90), // we assume the transfer to the other party is 90
   196  				},
   197  				Type:      types.TransferTypeTransferFundsSend,
   198  				MinAmount: num.NewUint(90),
   199  			},
   200  			{
   201  				Owner: party2,
   202  				Amount: &types.FinancialAmount{
   203  					Asset:  testMarketAsset,
   204  					Amount: num.NewUint(90),
   205  				},
   206  				Type:      types.TransferTypeTransferFundsDistribute,
   207  				MinAmount: num.NewUint(90),
   208  			},
   209  		},
   210  		// 2 general accounts
   211  		[]types.AccountType{
   212  			types.AccountTypeGeneral,
   213  			types.AccountTypeGeneral,
   214  		},
   215  		[]string{
   216  			"party1-to-party2",
   217  			"party1-to-party2",
   218  		},
   219  		// fee transfer
   220  		[]*types.Transfer{
   221  			{
   222  				Owner: party1,
   223  				Amount: &types.FinancialAmount{
   224  					Asset:  testMarketAsset,
   225  					Amount: num.NewUint(10), // we should have just enough to pay the fee
   226  				},
   227  				Type:      types.TransferTypeInfrastructureFeePay,
   228  				MinAmount: num.NewUint(10),
   229  			},
   230  		},
   231  		[]types.AccountType{
   232  			types.AccountTypeGeneral, // only one account, the general account of party
   233  		},
   234  	)
   235  
   236  	assert.NoError(t, err)
   237  	assert.Len(t, resps, 3)
   238  
   239  	// ensure balances now
   240  	acc1, err := e.GetPartyGeneralAccount(party1, testMarketAsset)
   241  	assert.NoError(t, err)
   242  	assert.Equal(t, acc1.Balance, num.UintZero())
   243  
   244  	acc2, err := e.GetPartyGeneralAccount(party2, testMarketAsset)
   245  	assert.NoError(t, err)
   246  	assert.Equal(t, acc2.Balance, num.NewUint(90))
   247  
   248  	pendingTransfersAcc := e.GetPendingTransfersAccount(testMarketAsset)
   249  	assert.NoError(t, err)
   250  	assert.Equal(t, pendingTransfersAcc.Balance, num.UintZero())
   251  }
   252  
   253  func testTransferFundsFromGeneralToRewardPool(t *testing.T) {
   254  	e := getTestEngine(t)
   255  	defer e.Finish()
   256  
   257  	party1 := "party1"
   258  	initialBalance := num.NewUint(100)
   259  
   260  	// create party1 account + top up
   261  	// no need to create party2 account, this account
   262  	// should be created on the go
   263  	e.broker.EXPECT().Send(gomock.Any()).Times(3)
   264  
   265  	p1AccID, err := e.CreatePartyGeneralAccount(
   266  		context.Background(), party1, testMarketAsset)
   267  	require.NoError(t, err)
   268  
   269  	err = e.UpdateBalance(context.Background(), p1AccID, initialBalance)
   270  	assert.Nil(t, err)
   271  
   272  	e.broker.EXPECT().Send(gomock.Any()).Times(6)
   273  
   274  	// now we create the transfers:
   275  	resps, err := e.TransferFunds(
   276  		context.Background(),
   277  		[]*types.Transfer{
   278  			{
   279  				Owner: party1,
   280  				Amount: &types.FinancialAmount{
   281  					Asset:  testMarketAsset,
   282  					Amount: num.NewUint(90), // we assume the transfer to the other party is 90
   283  				},
   284  				Type:      types.TransferTypeTransferFundsSend,
   285  				MinAmount: num.NewUint(90),
   286  			},
   287  			{
   288  				Owner: "",
   289  				Amount: &types.FinancialAmount{
   290  					Asset:  testMarketAsset,
   291  					Amount: num.NewUint(90),
   292  				},
   293  				Type:      types.TransferTypeTransferFundsDistribute,
   294  				MinAmount: num.NewUint(90),
   295  			},
   296  		},
   297  		// 2 general accounts
   298  		[]types.AccountType{
   299  			types.AccountTypeGeneral,
   300  			types.AccountTypeGlobalReward,
   301  		},
   302  		[]string{
   303  			"party1-to-reward",
   304  			"party1-to-reward",
   305  		},
   306  		// fee transfer
   307  		[]*types.Transfer{
   308  			{
   309  				Owner: party1,
   310  				Amount: &types.FinancialAmount{
   311  					Asset:  testMarketAsset,
   312  					Amount: num.NewUint(10), // we should have just enough to pay the fee
   313  				},
   314  				Type:      types.TransferTypeInfrastructureFeePay,
   315  				MinAmount: num.NewUint(10),
   316  			},
   317  		},
   318  		[]types.AccountType{
   319  			types.AccountTypeGeneral, // only one account, the general account of party
   320  		},
   321  	)
   322  
   323  	assert.NoError(t, err)
   324  	assert.Len(t, resps, 3)
   325  
   326  	// ensure balances now
   327  	acc1, err := e.GetPartyGeneralAccount(party1, testMarketAsset)
   328  	assert.NoError(t, err)
   329  	assert.Equal(t, acc1.Balance, num.UintZero())
   330  
   331  	rewardAcc, err := e.GetGlobalRewardAccount(testMarketAsset)
   332  	assert.NoError(t, err)
   333  	assert.Equal(t, rewardAcc.Balance, num.NewUint(90))
   334  
   335  	pendingTransfersAcc := e.GetPendingTransfersAccount(testMarketAsset)
   336  	assert.NoError(t, err)
   337  	assert.Equal(t, pendingTransfersAcc.Balance, num.UintZero())
   338  }
   339  
   340  func testInvalidNumberOfParameters(t *testing.T) {
   341  	e := getTestEngine(t)
   342  	defer e.Finish()
   343  
   344  	assert.Panics(t, func() {
   345  		e.TransferFunds(
   346  			context.Background(),
   347  			make([]*types.Transfer, 3),
   348  			make([]types.AccountType, 2),
   349  			make([]string, 3),
   350  			make([]*types.Transfer, 1),
   351  			make([]types.AccountType, 1),
   352  		)
   353  	})
   354  	assert.Panics(t, func() {
   355  		e.TransferFunds(
   356  			context.Background(),
   357  			make([]*types.Transfer, 3),
   358  			make([]types.AccountType, 3),
   359  			make([]string, 1),
   360  			make([]*types.Transfer, 1),
   361  			make([]types.AccountType, 1),
   362  		)
   363  	})
   364  	assert.Panics(t, func() {
   365  		e.TransferFunds(
   366  			context.Background(),
   367  			make([]*types.Transfer, 3),
   368  			make([]types.AccountType, 3),
   369  			make([]string, 3),
   370  			make([]*types.Transfer, 2),
   371  			make([]types.AccountType, 1),
   372  		)
   373  	})
   374  }