-
Nicolas Lara authored9ffdc37c
package keeper_test
import (
"time"
abci "github.com/tendermint/tendermint/abci/types"
lockuptypes "github.com/osmosis-labs/osmosis/v10/x/lockup/types"
"github.com/osmosis-labs/osmosis/v10/x/superfluid/keeper"
"github.com/osmosis-labs/osmosis/v10/x/superfluid/types"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
type superfluidDelegation struct {
delIndex int64
valIndex int64
lpIndex int64
lpAmount int64
}
func (suite *KeeperTestSuite) TestSuperfluidDelegate() {
testCases := []struct {
name string
validatorStats []stakingtypes.BondStatus
superDelegations []superfluidDelegation
expInterDelegation []sdk.Dec
}{
{
"with single validator and single superfluid delegation",
[]stakingtypes.BondStatus{stakingtypes.Bonded},
[]superfluidDelegation{{0, 0, 0, 1000000}},
[]sdk.Dec{sdk.NewDec(10000000)}, // 50% x 20 x 1000000
},
{
"with single validator and additional superfluid delegations",
[]stakingtypes.BondStatus{stakingtypes.Bonded},
[]superfluidDelegation{{0, 0, 0, 1000000}, {0, 0, 0, 1000000}},
[]sdk.Dec{sdk.NewDec(20000000)}, // 50% x 20 x 1000000 x 2
},
{
"with multiple validators and multiple superfluid delegations",
[]stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded},
[]superfluidDelegation{{0, 0, 0, 1000000}, {1, 1, 0, 1000000}},
[]sdk.Dec{sdk.NewDec(10000000), sdk.NewDec(10000000)}, // 50% x 20 x 1000000
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest()
bondDenom := suite.App.StakingKeeper.BondDenom(suite.Ctx)
// setup validators
valAddrs := suite.SetupValidators(tc.validatorStats)
denoms, _ := suite.SetupGammPoolsAndSuperfluidAssets([]sdk.Dec{sdk.NewDec(20), sdk.NewDec(20)})
// get pre-superfluid delgations osmo supply and supplyWithOffset
presupply := suite.App.BankKeeper.GetSupply(suite.Ctx, bondDenom)
presupplyWithOffset := suite.App.BankKeeper.GetSupplyWithOffset(suite.Ctx, bondDenom)
// setup superfluid delegations
_, intermediaryAccs, locks := suite.setupSuperfluidDelegations(valAddrs, tc.superDelegations, denoms)
// ensure post-superfluid delegations osmo supplywithoffset is the same while supply is not
postsupply := suite.App.BankKeeper.GetSupply(suite.Ctx, bondDenom)
postsupplyWithOffset := suite.App.BankKeeper.GetSupplyWithOffset(suite.Ctx, bondDenom)
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
suite.Require().False(postsupply.IsEqual(presupply), "presupply: %s postsupply: %s", presupply, postsupply)
suite.Require().Equal(postsupplyWithOffset.String(), presupplyWithOffset.String())
unbondingDuration := suite.App.StakingKeeper.GetParams(suite.Ctx).UnbondingTime
for index, del := range tc.superDelegations {
lock := locks[index]
valAddr := valAddrs[del.valIndex]
// check synthetic lockup creation
synthLock, err := suite.App.LockupKeeper.GetSyntheticLockup(suite.Ctx, lock.ID, keeper.StakingSyntheticDenom(lock.Coins[0].Denom, valAddr.String()))
suite.Require().NoError(err)
suite.Require().Equal(synthLock.UnderlyingLockId, lock.ID)
suite.Require().Equal(synthLock.SynthDenom, keeper.StakingSyntheticDenom(lock.Coins[0].Denom, valAddr.String()))
suite.Require().Equal(synthLock.EndTime, time.Time{})
expAcc := types.NewSuperfluidIntermediaryAccount(lock.Coins[0].Denom, valAddr.String(), 0)
// Check lockID connection with intermediary account
intAcc := suite.App.SuperfluidKeeper.GetLockIdIntermediaryAccountConnection(suite.Ctx, lock.ID)
suite.Require().Equal(intAcc.String(), expAcc.GetAccAddress().String())
}
for index, expAcc := range intermediaryAccs {
// check intermediary account creation
gotAcc := suite.App.SuperfluidKeeper.GetIntermediaryAccount(suite.Ctx, expAcc.GetAccAddress())
suite.Require().Equal(gotAcc.Denom, expAcc.Denom)
suite.Require().Equal(gotAcc.ValAddr, expAcc.ValAddr)
suite.Require().GreaterOrEqual(gotAcc.GaugeId, uint64(1))
valAddr, err := sdk.ValAddressFromBech32(expAcc.ValAddr)
suite.Require().NoError(err)
// check gauge creation
gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gotAcc.GaugeId)
suite.Require().NoError(err)
suite.Require().Equal(gauge.Id, gotAcc.GaugeId)
suite.Require().Equal(gauge.IsPerpetual, true)
suite.Require().Equal(gauge.DistributeTo, lockuptypes.QueryCondition{
LockQueryType: lockuptypes.ByDuration,
Denom: keeper.StakingSyntheticDenom(expAcc.Denom, valAddr.String()),
Duration: unbondingDuration,
})
suite.Require().Equal(gauge.Coins, sdk.Coins(nil))
suite.Require().Equal(gauge.StartTime, suite.Ctx.BlockTime())
suite.Require().Equal(gauge.NumEpochsPaidOver, uint64(1))
suite.Require().Equal(gauge.FilledEpochs, uint64(0))
suite.Require().Equal(gauge.DistributedCoins, sdk.Coins(nil))
// check delegation from intermediary account to validator
delegation, found := suite.App.StakingKeeper.GetDelegation(suite.Ctx, expAcc.GetAccAddress(), valAddr)
suite.Require().True(found)
suite.Require().Equal(tc.expInterDelegation[index], delegation.Shares)
}
// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)
// try delegating twice with same lockup
for _, lock := range locks {
err := suite.App.SuperfluidKeeper.SuperfluidDelegate(suite.Ctx, lock.Owner, lock.ID, valAddrs[0].String())
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestSuperfluidUndelegate() {
testCases := []struct {