code.vegaprotocol.io/vega@v0.79.0/core/execution/spot/holding_account_tracker_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 spot_test
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"fmt"
    22  	"testing"
    23  
    24  	bmocks "code.vegaprotocol.io/vega/core/broker/mocks"
    25  	"code.vegaprotocol.io/vega/core/collateral"
    26  	"code.vegaprotocol.io/vega/core/execution/common/mocks"
    27  	"code.vegaprotocol.io/vega/core/execution/spot"
    28  	"code.vegaprotocol.io/vega/core/types"
    29  	"code.vegaprotocol.io/vega/libs/num"
    30  	"code.vegaprotocol.io/vega/libs/proto"
    31  	"code.vegaprotocol.io/vega/logging"
    32  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    33  
    34  	"github.com/golang/mock/gomock"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  type testHat struct {
    39  	*spot.HoldingAccountTracker
    40  	collat *collateral.Engine
    41  }
    42  
    43  func getTestHat(t *testing.T) *testHat {
    44  	t.Helper()
    45  	log := logging.NewTestLogger()
    46  	ctrl := gomock.NewController(t)
    47  	timeService := mocks.NewMockTimeService(ctrl)
    48  	timeService.EXPECT().GetTimeNow().AnyTimes()
    49  
    50  	broker := bmocks.NewMockBroker(ctrl)
    51  	collat := collateral.New(log, collateral.NewDefaultConfig(), timeService, broker)
    52  	asset := types.Asset{
    53  		ID: "BTC",
    54  		Details: &types.AssetDetails{
    55  			Symbol:   "BTC",
    56  			Name:     "BTC",
    57  			Decimals: 0,
    58  			Quantum:  num.DecimalZero(),
    59  			Source: &types.AssetDetailsBuiltinAsset{
    60  				BuiltinAsset: &types.BuiltinAsset{
    61  					MaxFaucetAmountMint: num.UintZero(),
    62  				},
    63  			},
    64  		},
    65  	}
    66  	broker.EXPECT().Send(gomock.Any()).AnyTimes()
    67  	err := collat.EnableAsset(context.Background(), asset)
    68  	require.NoError(t, err)
    69  	id, err := collat.CreatePartyGeneralAccount(context.Background(), "zohar", "BTC")
    70  	require.NoError(t, err)
    71  	require.NoError(t, collat.IncrementBalance(context.Background(), id, num.NewUint(1500)))
    72  
    73  	return &testHat{
    74  		HoldingAccountTracker: spot.NewHoldingAccountTracker("market1", log, collat),
    75  		collat:                collat,
    76  	}
    77  }
    78  
    79  func TestReleaseAllFromHoldingAccount(t *testing.T) {
    80  	hat := getTestHat(t)
    81  
    82  	generalAccount, err := hat.collat.GetPartyGeneralAccount("zohar", "BTC")
    83  	require.NoError(t, err)
    84  	require.Equal(t, num.NewUint(1500), generalAccount.Balance)
    85  
    86  	_, err = hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(1000), num.NewUint(2), types.AccountTypeGeneral)
    87  	require.NoError(t, err)
    88  
    89  	_, err = hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(200), num.NewUint(3), types.AccountTypeGeneral)
    90  	require.Error(t, fmt.Errorf("funds for the order have already been transferred to the holding account"), err)
    91  
    92  	holdingQty, holdingFee := hat.GetCurrentHolding("1")
    93  	require.Equal(t, num.NewUint(1000), holdingQty)
    94  	require.Equal(t, num.NewUint(2), holdingFee)
    95  
    96  	generalAccount, err = hat.collat.GetPartyGeneralAccount("zohar", "BTC")
    97  	require.NoError(t, err)
    98  	require.Equal(t, num.NewUint(498), generalAccount.Balance)
    99  
   100  	_, err = hat.ReleaseAllFromHoldingAccount(context.Background(), "1", "zohar", "BTC", types.AccountTypeGeneral)
   101  	require.NoError(t, err)
   102  
   103  	holdingQty, holdingFee = hat.GetCurrentHolding("1")
   104  	require.Equal(t, num.UintZero(), holdingQty)
   105  	require.Equal(t, num.UintZero(), holdingFee)
   106  
   107  	generalAccount, err = hat.collat.GetPartyGeneralAccount("zohar", "BTC")
   108  	require.NoError(t, err)
   109  	require.Equal(t, num.NewUint(1500), generalAccount.Balance)
   110  }
   111  
   112  func TestReleaseQuantityHoldingAccount(t *testing.T) {
   113  	hat := getTestHat(t)
   114  
   115  	generalAccount, err := hat.collat.GetPartyGeneralAccount("zohar", "BTC")
   116  	require.NoError(t, err)
   117  	require.Equal(t, num.NewUint(1500), generalAccount.Balance)
   118  
   119  	_, err = hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(1000), num.NewUint(2), types.AccountTypeGeneral)
   120  	require.NoError(t, err)
   121  	holdingQty, holdingFee := hat.GetCurrentHolding("1")
   122  	require.Equal(t, num.NewUint(1000), holdingQty)
   123  	require.Equal(t, num.NewUint(2), holdingFee)
   124  
   125  	generalAccount, err = hat.collat.GetPartyGeneralAccount("zohar", "BTC")
   126  	require.NoError(t, err)
   127  	require.Equal(t, num.NewUint(498), generalAccount.Balance)
   128  
   129  	_, err = hat.ReleaseQuantityHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(500), num.NewUint(1), types.AccountTypeGeneral)
   130  	require.NoError(t, err)
   131  	holdingQty, holdingFee = hat.GetCurrentHolding("1")
   132  	require.Equal(t, num.NewUint(500), holdingQty)
   133  	require.Equal(t, num.NewUint(1), holdingFee)
   134  
   135  	generalAccount, err = hat.collat.GetPartyGeneralAccount("zohar", "BTC")
   136  	require.NoError(t, err)
   137  	require.Equal(t, num.NewUint(999), generalAccount.Balance)
   138  }
   139  
   140  func TestReleaseFeeFromHoldingAccount(t *testing.T) {
   141  	hat := getTestHat(t)
   142  
   143  	_, err := hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(1000), num.NewUint(2), types.AccountTypeGeneral)
   144  	require.NoError(t, err)
   145  
   146  	holdingQty, holdingFee := hat.GetCurrentHolding("1")
   147  	require.Equal(t, num.NewUint(1000), holdingQty)
   148  	require.Equal(t, num.NewUint(2), holdingFee)
   149  
   150  	le, err := hat.ReleaseFeeFromHoldingAccount(context.Background(), "1", "zohar", "BTC", types.AccountTypeGeneral)
   151  	require.NoError(t, err)
   152  
   153  	_, holdingFee = hat.GetCurrentHolding("1")
   154  	require.Equal(t, num.UintZero(), holdingFee)
   155  	require.Equal(t, num.NewUint(2), le.Balances[0].Balance)
   156  }
   157  
   158  func TestTransferFeeToHoldingAccount(t *testing.T) {
   159  	hat := getTestHat(t)
   160  	_, err := hat.TransferFeeToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(2), types.AccountTypeGeneral)
   161  	require.NoError(t, err)
   162  
   163  	holdingQty, holdingFee := hat.GetCurrentHolding("1")
   164  	require.Equal(t, num.UintZero(), holdingQty)
   165  	require.Equal(t, num.NewUint(2), holdingFee)
   166  }
   167  
   168  func TestSnapshot(t *testing.T) {
   169  	hat := getTestHat(t)
   170  	_, err := hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(1000), num.NewUint(2), types.AccountTypeGeneral)
   171  	require.NoError(t, err)
   172  
   173  	state, _, err := hat.GetState("market1")
   174  	require.NoError(t, err)
   175  	var active snapshot.Payload
   176  	require.NoError(t, proto.Unmarshal(state, &active))
   177  	payload := types.PayloadFromProto(&active)
   178  
   179  	hat2 := getTestHat(t)
   180  	hat2.LoadState(context.Background(), payload)
   181  	state2, _, err := hat2.GetState("market1")
   182  	require.NoError(t, err)
   183  
   184  	require.True(t, bytes.Equal(state, state2))
   185  }
   186  
   187  func TestTransferToHoldingAccount(t *testing.T) {
   188  	hat := getTestHat(t)
   189  
   190  	_, err := hat.TransferToHoldingAccount(context.Background(), "1", "zohar", "BTC", num.NewUint(1000), num.NewUint(2), types.AccountTypeGeneral)
   191  	require.NoError(t, err)
   192  
   193  	holdingQty, holdingFee := hat.GetCurrentHolding("1")
   194  	require.Equal(t, num.NewUint(1000), holdingQty)
   195  	require.Equal(t, num.NewUint(2), holdingFee)
   196  }