0g-chain/x/bep3/keeper/asset_test.go
2024-04-25 15:31:20 +08:00

704 lines
16 KiB
Go

package keeper_test
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/suite"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmtime "github.com/cometbft/cometbft/types/time"
"github.com/0glabs/0g-chain/app"
"github.com/0glabs/0g-chain/x/bep3/keeper"
"github.com/0glabs/0g-chain/x/bep3/types"
)
type AssetTestSuite struct {
suite.Suite
keeper keeper.Keeper
app app.TestApp
ctx sdk.Context
}
func (suite *AssetTestSuite) SetupTest() {
config := sdk.GetConfig()
app.SetBech32AddressPrefixes(config)
// Initialize test app and set context
tApp := app.NewTestApp()
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()})
// Initialize genesis state
deputy, _ := sdk.AccAddressFromBech32(TestDeputy)
tApp.InitializeFromGenesisStates(NewBep3GenStateMulti(tApp.AppCodec(), deputy))
keeper := tApp.GetBep3Keeper()
params := keeper.GetParams(ctx)
params.AssetParams[0].SupplyLimit.Limit = sdkmath.NewInt(50)
params.AssetParams[1].SupplyLimit.Limit = sdkmath.NewInt(100)
params.AssetParams[1].SupplyLimit.TimeBasedLimit = sdkmath.NewInt(15)
keeper.SetParams(ctx, params)
// Set asset supply with standard value for testing
supply := types.NewAssetSupply(c("bnb", 5), c("bnb", 5), c("bnb", 40), c("bnb", 0), time.Duration(0))
keeper.SetAssetSupply(ctx, supply, supply.IncomingSupply.Denom)
supply = types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Duration(0))
keeper.SetAssetSupply(ctx, supply, supply.IncomingSupply.Denom)
keeper.SetPreviousBlockTime(ctx, ctx.BlockTime())
suite.app = tApp
suite.ctx = ctx
suite.keeper = keeper
}
func (suite *AssetTestSuite) TestIncrementCurrentAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 5),
},
true,
},
{
"equal limit",
args{
coin: c("bnb", 10),
},
true,
},
{
"exceeds limit",
args{
coin: c("bnb", 11),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 5),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.IncrementCurrentAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.Equal(preSupply.CurrentSupply.Add(tc.args.coin), postSupply.CurrentSupply)
} else {
suite.Error(err)
suite.Equal(preSupply.CurrentSupply, postSupply.CurrentSupply)
}
})
}
}
func (suite *AssetTestSuite) TestIncrementTimeLimitedCurrentAssetSupply() {
type args struct {
coin sdk.Coin
expectedSupply types.AssetSupply
}
type errArgs struct {
expectPass bool
contains string
}
testCases := []struct {
name string
args args
errArgs errArgs
}{
{
"normal",
args{
coin: c("inc", 5),
expectedSupply: types.AssetSupply{
IncomingSupply: c("inc", 10),
OutgoingSupply: c("inc", 5),
CurrentSupply: c("inc", 10),
TimeLimitedCurrentSupply: c("inc", 5),
TimeElapsed: time.Duration(0),
},
},
errArgs{
expectPass: true,
contains: "",
},
},
{
"over limit",
args{
coin: c("inc", 16),
expectedSupply: types.AssetSupply{},
},
errArgs{
expectPass: false,
contains: "asset supply over limit for current time period",
},
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
err := suite.keeper.IncrementCurrentAssetSupply(suite.ctx, tc.args.coin)
if tc.errArgs.expectPass {
suite.Require().NoError(err)
supply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
suite.Require().Equal(tc.args.expectedSupply, supply)
} else {
suite.Require().Error(err)
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
}
})
}
}
func (suite *AssetTestSuite) TestDecrementCurrentAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 30),
},
true,
},
{
"equal current",
args{
coin: c("bnb", 40),
},
true,
},
{
"exceeds current",
args{
coin: c("bnb", 41),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 30),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.DecrementCurrentAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.True(preSupply.CurrentSupply.Sub(tc.args.coin).IsEqual(postSupply.CurrentSupply))
} else {
suite.Error(err)
suite.Equal(preSupply.CurrentSupply, postSupply.CurrentSupply)
}
})
}
}
func (suite *AssetTestSuite) TestIncrementIncomingAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 2),
},
true,
},
{
"incoming + current = limit",
args{
coin: c("bnb", 5),
},
true,
},
{
"incoming + current > limit",
args{
coin: c("bnb", 6),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 2),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.IncrementIncomingAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.Equal(preSupply.IncomingSupply.Add(tc.args.coin), postSupply.IncomingSupply)
} else {
suite.Error(err)
suite.Equal(preSupply.IncomingSupply, postSupply.IncomingSupply)
}
})
}
}
func (suite *AssetTestSuite) TestIncrementTimeLimitedIncomingAssetSupply() {
type args struct {
coin sdk.Coin
expectedSupply types.AssetSupply
}
type errArgs struct {
expectPass bool
contains string
}
testCases := []struct {
name string
args args
errArgs errArgs
}{
{
"normal",
args{
coin: c("inc", 5),
expectedSupply: types.AssetSupply{
IncomingSupply: c("inc", 15),
OutgoingSupply: c("inc", 5),
CurrentSupply: c("inc", 5),
TimeLimitedCurrentSupply: c("inc", 0),
TimeElapsed: time.Duration(0),
},
},
errArgs{
expectPass: true,
contains: "",
},
},
{
"over limit",
args{
coin: c("inc", 6),
expectedSupply: types.AssetSupply{},
},
errArgs{
expectPass: false,
contains: "asset supply over limit for current time period",
},
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
err := suite.keeper.IncrementIncomingAssetSupply(suite.ctx, tc.args.coin)
if tc.errArgs.expectPass {
suite.Require().NoError(err)
supply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
suite.Require().Equal(tc.args.expectedSupply, supply)
} else {
suite.Require().Error(err)
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
}
})
}
}
func (suite *AssetTestSuite) TestDecrementIncomingAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 4),
},
true,
},
{
"equal incoming",
args{
coin: c("bnb", 5),
},
true,
},
{
"exceeds incoming",
args{
coin: c("bnb", 6),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 4),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.DecrementIncomingAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.True(preSupply.IncomingSupply.Sub(tc.args.coin).IsEqual(postSupply.IncomingSupply))
} else {
suite.Error(err)
suite.Equal(preSupply.IncomingSupply, postSupply.IncomingSupply)
}
})
}
}
func (suite *AssetTestSuite) TestIncrementOutgoingAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 30),
},
true,
},
{
"outgoing + amount = current",
args{
coin: c("bnb", 35),
},
true,
},
{
"outoing + amount > current",
args{
coin: c("bnb", 36),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 30),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.IncrementOutgoingAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.Equal(preSupply.OutgoingSupply.Add(tc.args.coin), postSupply.OutgoingSupply)
} else {
suite.Error(err)
suite.Equal(preSupply.OutgoingSupply, postSupply.OutgoingSupply)
}
})
}
}
func (suite *AssetTestSuite) TestDecrementOutgoingAssetSupply() {
type args struct {
coin sdk.Coin
}
testCases := []struct {
name string
args args
expectPass bool
}{
{
"normal",
args{
coin: c("bnb", 4),
},
true,
},
{
"equal outgoing",
args{
coin: c("bnb", 5),
},
true,
},
{
"exceeds outgoing",
args{
coin: c("bnb", 6),
},
false,
},
{
"unsupported asset",
args{
coin: c("xyz", 4),
},
false,
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
preSupply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
err := suite.keeper.DecrementOutgoingAssetSupply(suite.ctx, tc.args.coin)
postSupply, _ := suite.keeper.GetAssetSupply(suite.ctx, tc.args.coin.Denom)
if tc.expectPass {
suite.True(found)
suite.NoError(err)
suite.True(preSupply.OutgoingSupply.Sub(tc.args.coin).IsEqual(postSupply.OutgoingSupply))
} else {
suite.Error(err)
suite.Equal(preSupply.OutgoingSupply, postSupply.OutgoingSupply)
}
})
}
}
func (suite *AssetTestSuite) TestUpdateTimeBasedSupplyLimits() {
type args struct {
asset string
duration time.Duration
expectedSupply types.AssetSupply
}
type errArgs struct {
expectPanic bool
contains string
}
testCases := []struct {
name string
args args
errArgs errArgs
}{
{
"rate-limited increment time",
args{
asset: "inc",
duration: time.Second,
expectedSupply: types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Second),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"rate-limited increment time half",
args{
asset: "inc",
duration: time.Minute * 30,
expectedSupply: types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Minute*30),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"rate-limited period change",
args{
asset: "inc",
duration: time.Hour + time.Second,
expectedSupply: types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Duration(0)),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"rate-limited period change exact",
args{
asset: "inc",
duration: time.Hour,
expectedSupply: types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Duration(0)),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"rate-limited period change big",
args{
asset: "inc",
duration: time.Hour * 4,
expectedSupply: types.NewAssetSupply(c("inc", 10), c("inc", 5), c("inc", 5), c("inc", 0), time.Duration(0)),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"non rate-limited increment time",
args{
asset: "bnb",
duration: time.Second,
expectedSupply: types.NewAssetSupply(c("bnb", 5), c("bnb", 5), c("bnb", 40), c("bnb", 0), time.Duration(0)),
},
errArgs{
expectPanic: false,
contains: "",
},
},
{
"new asset increment time",
args{
asset: "lol",
duration: time.Second,
expectedSupply: types.NewAssetSupply(c("lol", 0), c("lol", 0), c("lol", 0), c("lol", 0), time.Second),
},
errArgs{
expectPanic: false,
contains: "",
},
},
}
for _, tc := range testCases {
suite.SetupTest()
suite.Run(tc.name, func() {
deputy, _ := sdk.AccAddressFromBech32(TestDeputy)
newParams := types.Params{
AssetParams: types.AssetParams{
{
Denom: "bnb",
CoinID: 714,
SupplyLimit: types.SupplyLimit{
Limit: sdkmath.NewInt(350000000000000),
TimeLimited: false,
TimeBasedLimit: sdk.ZeroInt(),
TimePeriod: time.Hour,
},
Active: true,
DeputyAddress: deputy,
FixedFee: sdkmath.NewInt(1000),
MinSwapAmount: sdk.OneInt(),
MaxSwapAmount: sdkmath.NewInt(1000000000000),
MinBlockLock: types.DefaultMinBlockLock,
MaxBlockLock: types.DefaultMaxBlockLock,
},
{
Denom: "inc",
CoinID: 9999,
SupplyLimit: types.SupplyLimit{
Limit: sdkmath.NewInt(100),
TimeLimited: true,
TimeBasedLimit: sdkmath.NewInt(10),
TimePeriod: time.Hour,
},
Active: false,
DeputyAddress: deputy,
FixedFee: sdkmath.NewInt(1000),
MinSwapAmount: sdk.OneInt(),
MaxSwapAmount: sdkmath.NewInt(1000000000000),
MinBlockLock: types.DefaultMinBlockLock,
MaxBlockLock: types.DefaultMaxBlockLock,
},
{
Denom: "lol",
CoinID: 9999,
SupplyLimit: types.SupplyLimit{
Limit: sdkmath.NewInt(100),
TimeLimited: true,
TimeBasedLimit: sdkmath.NewInt(10),
TimePeriod: time.Hour,
},
Active: false,
DeputyAddress: deputy,
FixedFee: sdkmath.NewInt(1000),
MinSwapAmount: sdk.OneInt(),
MaxSwapAmount: sdkmath.NewInt(1000000000000),
MinBlockLock: types.DefaultMinBlockLock,
MaxBlockLock: types.DefaultMaxBlockLock,
},
},
}
suite.keeper.SetParams(suite.ctx, newParams)
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(tc.args.duration))
suite.NotPanics(
func() {
suite.keeper.UpdateTimeBasedSupplyLimits(suite.ctx)
},
)
if !tc.errArgs.expectPanic {
supply, found := suite.keeper.GetAssetSupply(suite.ctx, tc.args.asset)
suite.Require().True(found)
suite.Require().Equal(tc.args.expectedSupply, supply)
}
})
}
}
func TestAssetTestSuite(t *testing.T) {
suite.Run(t, new(AssetTestSuite))
}