code.vegaprotocol.io/vega@v0.79.0/core/banking/cancel_transfer_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 banking_test 17 18 import ( 19 "context" 20 "testing" 21 22 "code.vegaprotocol.io/vega/core/assets" 23 "code.vegaprotocol.io/vega/core/assets/common" 24 "code.vegaprotocol.io/vega/core/banking" 25 "code.vegaprotocol.io/vega/core/events" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/protos/vega" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 func TestCancelTransfer(t *testing.T) { 36 e := getTestEngine(t) 37 38 // let's do a massive fee, easy to test 39 e.OnTransferFeeFactorUpdate(context.Background(), num.NewDecimalFromFloat(0.5)) 40 e.OnEpoch(context.Background(), types.Epoch{Seq: 7, Action: vega.EpochAction_EPOCH_ACTION_START}) 41 e.OnEpoch(context.Background(), types.Epoch{Seq: 7, Action: vega.EpochAction_EPOCH_ACTION_END}) 42 43 var endEpoch13 uint64 = 11 44 transferID := "TRANSFERID" 45 partyID := "03ae90688632c649c4beab6040ff5bd04dbde8efbf737d8673bbda792a110301" 46 ctx := context.Background() 47 transfer := &types.TransferFunds{ 48 Kind: types.TransferCommandKindRecurring, 49 Recurring: &types.RecurringTransfer{ 50 TransferBase: &types.TransferBase{ 51 ID: transferID, 52 From: partyID, 53 54 FromAccountType: types.AccountTypeGeneral, 55 To: "0000000000000000000000000000000000000000000000000000000000000000", 56 ToAccountType: types.AccountTypeGlobalReward, 57 Asset: "eth", 58 Amount: num.NewUint(100), 59 Reference: "someref", 60 }, 61 StartEpoch: 10, 62 EndEpoch: &endEpoch13, 63 Factor: num.MustDecimalFromString("0.9"), 64 }, 65 } 66 67 asset := "ETH" 68 69 e.assets.EXPECT().Get(gomock.Any()).Times(2).Return( 70 assets.NewAsset(&mockAsset{quantum: num.DecimalFromFloat(100), name: asset}), nil) 71 e.broker.EXPECT().Send(gomock.Any()).Times(2) 72 assert.NoError(t, e.TransferFunds(ctx, transfer)) 73 74 // now we try to cancel an non-existing transfer 75 assert.EqualError(t, 76 e.CancelTransferFunds(ctx, &types.CancelTransferFunds{TransferID: "NOPE"}), 77 banking.ErrRecurringTransferDoesNotExists.Error(), 78 ) 79 80 // now we try to cancel the right transfer, but with the wrong party 81 assert.EqualError(t, 82 e.CancelTransferFunds(ctx, &types.CancelTransferFunds{ 83 TransferID: transferID, 84 Party: "NOPE", 85 }), 86 banking.ErrCannotCancelOtherPartiesRecurringTransfers.Error(), 87 ) 88 89 // now we move in time just a bit so we get some transfer processed, but then cancel before 90 // then end of the transfer 91 fromAcc := types.Account{ 92 Balance: num.NewUint(1000), 93 Asset: asset, 94 } 95 96 // asset exists 97 e.col.EXPECT().GetPartyGeneralAccount(gomock.Any(), gomock.Any()).Times(1).Return(&fromAcc, nil) 98 99 // assert the calculation of fees and transfer request are correct 100 e.col.EXPECT().TransferFunds(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn( 101 func(ctx context.Context, 102 transfers []*types.Transfer, 103 accountTypes []types.AccountType, 104 references []string, 105 feeTransfers []*types.Transfer, 106 feeTransfersAccountTypes []types.AccountType, 107 ) ([]*types.LedgerMovement, error, 108 ) { 109 t.Run("ensure transfers are correct", func(t *testing.T) { 110 // transfer is done fully instantly, we should have 2 transfer 111 assert.Len(t, transfers, 2) 112 assert.Equal(t, transfers[0].Owner, "03ae90688632c649c4beab6040ff5bd04dbde8efbf737d8673bbda792a110301") 113 assert.Equal(t, transfers[0].Amount.Amount, num.NewUint(100)) 114 assert.Equal(t, transfers[0].Amount.Asset, asset) 115 116 // 1 account types too 117 assert.Len(t, accountTypes, 2) 118 assert.Equal(t, accountTypes[0], types.AccountTypeGeneral) 119 }) 120 121 t.Run("ensure fee transfers are correct", func(t *testing.T) { 122 assert.Len(t, feeTransfers, 1) 123 assert.Equal(t, feeTransfers[0].Owner, "03ae90688632c649c4beab6040ff5bd04dbde8efbf737d8673bbda792a110301") 124 assert.Equal(t, feeTransfers[0].Amount.Amount, num.NewUint(50)) 125 assert.Equal(t, feeTransfers[0].Amount.Asset, asset) 126 127 // then the fees account types 128 assert.Len(t, feeTransfersAccountTypes, 1) 129 assert.Equal(t, accountTypes[0], types.AccountTypeGeneral) 130 }) 131 132 return nil, nil 133 }) 134 135 e.OnEpoch(context.Background(), types.Epoch{Seq: 10, Action: vega.EpochAction_EPOCH_ACTION_START}) 136 e.OnEpoch(context.Background(), types.Epoch{Seq: 10, Action: vega.EpochAction_EPOCH_ACTION_END}) 137 138 // now we cancel it, we should get no error and and event 139 e.broker.EXPECT().Send(gomock.Any()).DoAndReturn(func(evt events.Event) { 140 t.Run("ensure transfer is done", func(t *testing.T) { 141 e, ok := evt.(*events.TransferFunds) 142 assert.True(t, ok, "unexpected event from the bus") 143 assert.Equal(t, e.Proto().Status, types.TransferStatusCancelled) 144 assert.Equal(t, "transfer cancelled", *e.Proto().Reason) 145 }) 146 }) 147 148 key := (&types.PayloadBankingRecurringTransfers{}).Key() 149 _, _, err := e.GetState(key) 150 require.NoError(t, err) 151 152 assert.NoError(t, 153 e.CancelTransferFunds(ctx, &types.CancelTransferFunds{ 154 TransferID: transferID, 155 Party: partyID, 156 }), 157 ) 158 // now we move in time, the recurring transfer was suppose to go 159 // 'til epoch 11, but it's not cancelled, and nothing should happen 160 e.OnEpoch(context.Background(), types.Epoch{Seq: 11, Action: vega.EpochAction_EPOCH_ACTION_START}) 161 e.OnEpoch(context.Background(), types.Epoch{Seq: 11, Action: vega.EpochAction_EPOCH_ACTION_END}) 162 } 163 164 type mockAsset struct { 165 quantum num.Decimal 166 name string 167 } 168 169 func (m *mockAsset) Type() *types.Asset { 170 return &types.Asset{ 171 ID: m.name, 172 Details: &types.AssetDetails{ 173 Name: m.name, 174 Symbol: m.name, 175 Quantum: m.quantum, 176 }, 177 } 178 } 179 180 func (m *mockAsset) SetPendingListing() {} 181 func (m *mockAsset) SetRejected() {} 182 func (m *mockAsset) SetEnabled() {} 183 184 func (m *mockAsset) GetAssetClass() common.AssetClass { return common.ERC20 } 185 func (m *mockAsset) IsValid() bool { return true } 186 func (m *mockAsset) SetValid() {} 187 func (m *mockAsset) String() string { return "" }