code.vegaprotocol.io/vega@v0.79.0/core/vesting/helper_for_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 vesting_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/assets/common"
    24  	bmocks "code.vegaprotocol.io/vega/core/broker/mocks"
    25  	"code.vegaprotocol.io/vega/core/integration/stubs"
    26  	"code.vegaprotocol.io/vega/core/snapshot"
    27  	"code.vegaprotocol.io/vega/core/stats"
    28  	"code.vegaprotocol.io/vega/core/types"
    29  	"code.vegaprotocol.io/vega/core/vesting"
    30  	"code.vegaprotocol.io/vega/core/vesting/mocks"
    31  	"code.vegaprotocol.io/vega/libs/num"
    32  	"code.vegaprotocol.io/vega/logging"
    33  	"code.vegaprotocol.io/vega/paths"
    34  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    35  
    36  	"github.com/golang/mock/gomock"
    37  	"github.com/stretchr/testify/require"
    38  )
    39  
    40  type testEngine struct {
    41  	*vesting.Engine
    42  
    43  	ctrl            *gomock.Controller
    44  	col             *collateralMock
    45  	asvm            *mocks.MockActivityStreakVestingMultiplier
    46  	broker          *bmocks.MockBroker
    47  	assets          *mocks.MockAssets
    48  	parties         *mocks.MockParties
    49  	t               *mocks.MockTime
    50  	stakeAccounting *mocks.MockStakeAccounting
    51  }
    52  
    53  func getTestEngine(t *testing.T) *testEngine {
    54  	t.Helper()
    55  	ctrl := gomock.NewController(t)
    56  	logger := logging.NewTestLogger()
    57  	col := newCollateralMock(t)
    58  	broker := bmocks.NewMockBroker(ctrl)
    59  	asvm := mocks.NewMockActivityStreakVestingMultiplier(ctrl)
    60  	assets := mocks.NewMockAssets(ctrl)
    61  	parties := mocks.NewMockParties(ctrl)
    62  	tim := mocks.NewMockTime(ctrl)
    63  	stakeAccounting := mocks.NewMockStakeAccounting(ctrl)
    64  
    65  	return &testEngine{
    66  		Engine: vesting.New(
    67  			logger, col, asvm, broker, assets, parties, tim, stakeAccounting,
    68  		),
    69  		ctrl:            ctrl,
    70  		broker:          broker,
    71  		col:             col,
    72  		asvm:            asvm,
    73  		assets:          assets,
    74  		parties:         parties,
    75  		t:               tim,
    76  		stakeAccounting: stakeAccounting,
    77  	}
    78  }
    79  
    80  type testSnapshotEngine struct {
    81  	engine *vesting.SnapshotEngine
    82  
    83  	ctrl            *gomock.Controller
    84  	col             *collateralMock
    85  	asvm            *mocks.MockActivityStreakVestingMultiplier
    86  	broker          *bmocks.MockBroker
    87  	assets          *mocks.MockAssets
    88  	parties         *mocks.MockParties
    89  	t               *mocks.MockTime
    90  	stakeAccounting *mocks.MockStakeAccounting
    91  
    92  	currentEpoch uint64
    93  }
    94  
    95  func newEngine(t *testing.T) *testSnapshotEngine {
    96  	t.Helper()
    97  	ctrl := gomock.NewController(t)
    98  	col := newCollateralMock(t)
    99  	asvm := mocks.NewMockActivityStreakVestingMultiplier(ctrl)
   100  	broker := bmocks.NewMockBroker(ctrl)
   101  	assets := mocks.NewMockAssets(ctrl)
   102  	parties := mocks.NewMockParties(ctrl)
   103  	tim := mocks.NewMockTime(ctrl)
   104  	stakeAccounting := mocks.NewMockStakeAccounting(ctrl)
   105  
   106  	return &testSnapshotEngine{
   107  		engine: vesting.NewSnapshotEngine(
   108  			logging.NewTestLogger(), col, asvm, broker, assets, parties, tim, stakeAccounting,
   109  		),
   110  		ctrl:            ctrl,
   111  		col:             col,
   112  		asvm:            asvm,
   113  		broker:          broker,
   114  		assets:          assets,
   115  		parties:         parties,
   116  		currentEpoch:    10,
   117  		t:               tim,
   118  		stakeAccounting: stakeAccounting,
   119  	}
   120  }
   121  
   122  type collateralMock struct {
   123  	vestedAccountAmount            map[string]map[string]*num.Uint
   124  	vestingQuantumBalanceCallCount int
   125  }
   126  
   127  func (c *collateralMock) InitVestedBalance(party, asset string, balance *num.Uint) {
   128  	c.vestedAccountAmount[party] = map[string]*num.Uint{
   129  		asset: balance,
   130  	}
   131  }
   132  
   133  func (c *collateralMock) TransferVestedRewards(_ context.Context, transfers []*types.Transfer) ([]*types.LedgerMovement, error) {
   134  	for _, transfer := range transfers {
   135  		vestedAccount, ok := c.vestedAccountAmount[transfer.Owner]
   136  		if !ok {
   137  			vestedAccount = map[string]*num.Uint{}
   138  			c.vestedAccountAmount[transfer.Owner] = map[string]*num.Uint{}
   139  		}
   140  
   141  		amount, ok := vestedAccount[transfer.Amount.Asset]
   142  		if !ok {
   143  			amount = num.UintZero()
   144  			vestedAccount[transfer.Amount.Asset] = amount
   145  		}
   146  
   147  		amount.AddSum(transfer.Amount.Amount)
   148  	}
   149  	return []*types.LedgerMovement{}, nil
   150  }
   151  
   152  func (c *collateralMock) GetVestingRecovery() map[string]map[string]*num.Uint {
   153  	// Only used for checkpoint.
   154  	return nil
   155  }
   156  
   157  // GetAllVestingQuantumBalance is a custom implementation used to ensure
   158  // the vesting engine account for benefit tiers during computation.
   159  // Using this implementation saves us from mocking this at every call to
   160  // `OnEpochEvent()` with consistent results.
   161  func (c *collateralMock) GetAllVestingQuantumBalance(party string) num.Decimal {
   162  	vestedAccount, ok := c.vestedAccountAmount[party]
   163  	if !ok {
   164  		return num.DecimalZero()
   165  	}
   166  
   167  	balance := num.DecimalZero()
   168  	for _, n := range vestedAccount {
   169  		balance = balance.Add(num.DecimalFromUint(n))
   170  	}
   171  
   172  	c.vestingQuantumBalanceCallCount += 1
   173  
   174  	return balance
   175  }
   176  
   177  func (c *collateralMock) ResetVestingQuantumBalanceCallCount() {
   178  	c.vestingQuantumBalanceCallCount = 0
   179  }
   180  
   181  func (c *collateralMock) GetVestingQuantumBalanceCallCount() int {
   182  	return c.vestingQuantumBalanceCallCount
   183  }
   184  
   185  func (c *collateralMock) GetAllVestingAndVestedAccountForAsset(asset string) []*types.Account {
   186  	return nil
   187  }
   188  
   189  func newCollateralMock(t *testing.T) *collateralMock {
   190  	t.Helper()
   191  
   192  	return &collateralMock{
   193  		vestedAccountAmount: make(map[string]map[string]*num.Uint),
   194  	}
   195  }
   196  
   197  type dummyAsset struct {
   198  	quantum uint64
   199  }
   200  
   201  func (d dummyAsset) Type() *types.Asset {
   202  	return &types.Asset{
   203  		Details: &types.AssetDetails{
   204  			Quantum: num.DecimalFromInt64(int64(d.quantum)),
   205  		},
   206  	}
   207  }
   208  
   209  func (dummyAsset) GetAssetClass() common.AssetClass { return common.ERC20 }
   210  func (dummyAsset) IsValid() bool                    { return true }
   211  func (dummyAsset) SetPendingListing()               {}
   212  func (dummyAsset) SetRejected()                     {}
   213  func (dummyAsset) SetEnabled()                      {}
   214  func (dummyAsset) SetValid()                        {}
   215  func (dummyAsset) String() string                   { return "" }
   216  
   217  func newSnapshotEngine(t *testing.T, vegaPath paths.Paths, now time.Time, engine *vesting.SnapshotEngine) *snapshot.Engine {
   218  	t.Helper()
   219  
   220  	log := logging.NewTestLogger()
   221  	timeService := stubs.NewTimeStub()
   222  	timeService.SetTime(now)
   223  	statsData := stats.New(log, stats.NewDefaultConfig())
   224  	config := snapshot.DefaultConfig()
   225  
   226  	snapshotEngine, err := snapshot.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain)
   227  	require.NoError(t, err)
   228  
   229  	snapshotEngine.AddProviders(engine)
   230  
   231  	return snapshotEngine
   232  }
   233  
   234  func nextEpoch(ctx context.Context, t *testing.T, te *testSnapshotEngine, startEpochTime time.Time) {
   235  	t.Helper()
   236  
   237  	te.engine.OnEpochEvent(ctx, types.Epoch{
   238  		Seq:     te.currentEpoch,
   239  		Action:  vegapb.EpochAction_EPOCH_ACTION_END,
   240  		EndTime: startEpochTime.Add(-1 * time.Second),
   241  	})
   242  
   243  	te.currentEpoch += 1
   244  	te.engine.OnEpochEvent(ctx, types.Epoch{
   245  		Seq:       te.currentEpoch,
   246  		Action:    vegapb.EpochAction_EPOCH_ACTION_START,
   247  		StartTime: startEpochTime,
   248  	})
   249  }