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 }