package keeper_test import ( "testing" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/kava-labs/kava/x/earn/testutil" "github.com/kava-labs/kava/x/earn/types" ) type vaultShareTestSuite struct { testutil.Suite } func (suite *vaultShareTestSuite) SetupTest() { suite.Suite.SetupTest() suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) } func TestVaultShareTestSuite(t *testing.T) { suite.Run(t, new(vaultShareTestSuite)) } func (suite *vaultShareTestSuite) TestConvertToShares() { vaultDenom := "usdx" tests := []struct { name string beforeConvert func() giveAmount sdk.Coin wantShares types.VaultShare }{ { name: "initial 1:1", beforeConvert: func() {}, giveAmount: sdk.NewCoin(vaultDenom, sdkmath.NewInt(100)), wantShares: types.NewVaultShare(vaultDenom, sdk.NewDec(100)), }, { name: "value doubled", beforeConvert: func() { // set total shares set total value for hard // value is double than shares // shares is 2x price now suite.addTotalShareAndValue(vaultDenom, sdk.NewDec(100), sdkmath.NewInt(200)) }, giveAmount: sdk.NewCoin(vaultDenom, sdkmath.NewInt(100)), wantShares: types.NewVaultShare(vaultDenom, sdk.NewDec(50)), }, { name: "truncate", beforeConvert: func() { suite.addTotalShareAndValue(vaultDenom, sdk.NewDec(1000), sdkmath.NewInt(1001)) }, giveAmount: sdk.NewCoin(vaultDenom, sdkmath.NewInt(100)), // 100 * 100 / 101 = 99.0099something wantShares: types.NewVaultShare(vaultDenom, sdk.NewDec(100).MulInt64(1000).QuoInt64(1001)), }, } for _, tt := range tests { suite.Run(tt.name, func() { // Reset state suite.Suite.SetupTest() suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil) err := suite.App.FundModuleAccount( suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 10000)), ) suite.Require().NoError(err) // Run any deposits or any other setup tt.beforeConvert() issuedShares, err := suite.Keeper.ConvertToShares(suite.Ctx, tt.giveAmount) suite.Require().NoError(err) suite.Equal(tt.wantShares, issuedShares) }) } } func (suite *vaultShareTestSuite) addTotalShareAndValue( vaultDenom string, vaultShares sdk.Dec, hardDeposit sdkmath.Int, ) { macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName) vaultRecord, found := suite.Keeper.GetVaultRecord(suite.Ctx, vaultDenom) if !found { vaultRecord = types.NewVaultRecord(vaultDenom, sdk.ZeroDec()) } // Add to vault record vaultRecord.TotalShares.Amount = vaultRecord.TotalShares.Amount.Add(vaultShares) // set total shares suite.Keeper.UpdateVaultRecord( suite.Ctx, vaultRecord, ) // add value for hard -- this does not set err := suite.HardKeeper.Deposit( suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewCoin(vaultDenom, hardDeposit)), ) suite.Require().NoError(err) } func TestPrecisionMulQuoOrder(t *testing.T) { assetAmount := sdk.NewDec(100) totalShares := sdk.NewDec(100) totalValue := sdk.NewDec(105) // issuedShares = assetAmount * (totalValue / totalShares) // = (assetAmount * totalShares) / totalValue mulFirst := assetAmount.Mul(totalShares).QuoTruncate(totalValue) quoFirst := assetAmount.Mul(totalShares.QuoTruncate(totalValue)) assert.Equal(t, sdk.MustNewDecFromStr("95.238095238095238095"), mulFirst) assert.Equal(t, sdk.MustNewDecFromStr("95.238095238095238000"), quoFirst) assert.NotEqual(t, mulFirst, quoFirst) }