refactor(x/accounts/defaults/lockup): Add lockup unit tests (#20721)
This commit is contained in:
parent
25e99c54ba
commit
c349885084
235
x/accounts/defaults/lockup/continuous_locking_account_test.go
Normal file
235
x/accounts/defaults/lockup/continuous_locking_account_test.go
Normal file
@ -0,0 +1,235 @@
|
||||
package lockup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
lockuptypes "cosmossdk.io/x/accounts/defaults/lockup/types"
|
||||
)
|
||||
|
||||
func setupContinousAccount(t *testing.T, ctx context.Context, ss store.KVStoreService) *ContinuousLockingAccount {
|
||||
t.Helper()
|
||||
deps := makeMockDependencies(ss)
|
||||
owner := "owner"
|
||||
|
||||
acc, err := NewContinuousLockingAccount(deps)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.Init(ctx, &lockuptypes.MsgInitLockupAccount{
|
||||
Owner: owner,
|
||||
EndTime: time.Now().Add(time.Minute * 2),
|
||||
StartTime: time.Now(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func TestContinousAccountDelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupContinousAccount(t, sdkCtx, ss)
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked half of the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(5)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(5)))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(1)))
|
||||
}
|
||||
|
||||
func TestContinousAccountUndelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupContinousAccount(t, sdkCtx, ss)
|
||||
// Delegate first
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.ZeroInt()))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked half of the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(6)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(5)))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(4)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(2)))
|
||||
|
||||
delFree, err = acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.ZeroInt()))
|
||||
}
|
||||
|
||||
func TestContinousAccountSendCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupContinousAccount(t, sdkCtx, ss)
|
||||
_, err := acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked half of the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestContinousAccountWithdrawUnlockedCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupContinousAccount(t, sdkCtx, ss)
|
||||
_, err := acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked half of the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestContinousAccountGetLockCoinInfo(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupContinousAccount(t, sdkCtx, ss)
|
||||
|
||||
unlocked, locked, err := acc.GetLockCoinsInfo(sdkCtx, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// unlocked half locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, startTime.Add(time.Minute*1))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(5)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(5)))
|
||||
|
||||
// unlocked full locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, startTime.Add(time.Minute*2))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
}
|
||||
224
x/accounts/defaults/lockup/delayed_locking_account_test.go
Normal file
224
x/accounts/defaults/lockup/delayed_locking_account_test.go
Normal file
@ -0,0 +1,224 @@
|
||||
package lockup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
lockuptypes "cosmossdk.io/x/accounts/defaults/lockup/types"
|
||||
)
|
||||
|
||||
func setupDelayedAccount(t *testing.T, ctx context.Context, ss store.KVStoreService) *DelayedLockingAccount {
|
||||
t.Helper()
|
||||
deps := makeMockDependencies(ss)
|
||||
owner := "owner"
|
||||
|
||||
acc, err := NewDelayedLockingAccount(deps)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.Init(ctx, &lockuptypes.MsgInitLockupAccount{
|
||||
Owner: owner,
|
||||
EndTime: time.Now().Add(time.Minute * 2),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func TestDelayedAccountDelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupDelayedAccount(t, sdkCtx, ss)
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
endTime, err := acc.EndTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked all the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: endTime.Add(time.Second),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(5)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(5)))
|
||||
}
|
||||
|
||||
func TestDelayedAccountUndelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupDelayedAccount(t, sdkCtx, ss)
|
||||
// Delegate first
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.ZeroInt()))
|
||||
|
||||
endTime, err := acc.EndTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked all the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: endTime.Add(time.Second),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(6)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.ZeroInt()))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(6)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(4)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delFree, err = acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(2)))
|
||||
}
|
||||
|
||||
func TestDelayedAccountSendCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupDelayedAccount(t, sdkCtx, ss)
|
||||
_, err := acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
endTime, err := acc.EndTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked all the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: endTime.Add(time.Second),
|
||||
})
|
||||
|
||||
_, err = acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDelayedAccountWithdrawUnlockedCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupDelayedAccount(t, sdkCtx, ss)
|
||||
_, err := acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
endTime, err := acc.EndTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked all the original locking amount
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: endTime.Add(time.Second),
|
||||
})
|
||||
|
||||
_, err = acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDelayedAccountGetLockCoinInfo(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupDelayedAccount(t, sdkCtx, ss)
|
||||
|
||||
unlocked, locked, err := acc.GetLockCoinsInfo(sdkCtx, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
|
||||
endTime, err := acc.EndTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// unlocked full locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, endTime.Add(time.Second*1))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
}
|
||||
@ -33,7 +33,7 @@ require (
|
||||
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
|
||||
cosmossdk.io/api v0.7.5 // indirect
|
||||
cosmossdk.io/errors v1.0.1
|
||||
cosmossdk.io/log v1.3.1 // indirect
|
||||
cosmossdk.io/log v1.3.1
|
||||
cosmossdk.io/math v1.3.0
|
||||
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect
|
||||
cosmossdk.io/x/auth v0.0.0-00010101000000-000000000000 // indirect
|
||||
@ -81,7 +81,7 @@ require (
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
|
||||
@ -273,6 +273,8 @@ func TestQueryLockupAccountBaseInfo(t *testing.T) {
|
||||
|
||||
baseLockup := setup(t, ctx, ss)
|
||||
|
||||
_, err := baseLockup.QueryLockupAccountBaseInfo(ctx, &lockuptypes.QueryLockupAccountInfoRequest{})
|
||||
res, err := baseLockup.QueryLockupAccountBaseInfo(ctx, &lockuptypes.QueryLockupAccountInfoRequest{})
|
||||
require.Equal(t, res.OriginalLocking.AmountOf("test"), math.NewInt(10))
|
||||
require.Equal(t, res.Owner, "owner")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
274
x/accounts/defaults/lockup/periodic_locking_account_test.go
Normal file
274
x/accounts/defaults/lockup/periodic_locking_account_test.go
Normal file
@ -0,0 +1,274 @@
|
||||
package lockup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
lockuptypes "cosmossdk.io/x/accounts/defaults/lockup/types"
|
||||
)
|
||||
|
||||
func setupPeriodicAccount(t *testing.T, ctx context.Context, ss store.KVStoreService) *PeriodicLockingAccount {
|
||||
t.Helper()
|
||||
deps := makeMockDependencies(ss)
|
||||
owner := "owner"
|
||||
|
||||
acc, err := NewPeriodicLockingAccount(deps)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.Init(ctx, &lockuptypes.MsgInitPeriodicLockingAccount{
|
||||
Owner: owner,
|
||||
StartTime: time.Now(),
|
||||
LockingPeriods: []lockuptypes.Period{
|
||||
{
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
Length: time.Minute,
|
||||
},
|
||||
{
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(2))),
|
||||
Length: time.Minute,
|
||||
},
|
||||
{
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(3))),
|
||||
Length: time.Minute,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func TestPeriodicAccountDelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPeriodicAccount(t, sdkCtx, ss)
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked first period token
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(5)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(5)))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(1)))
|
||||
|
||||
// Update context time to unlocked all token
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 3),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(4)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(5)))
|
||||
|
||||
delFree, err = acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(5)))
|
||||
}
|
||||
|
||||
func TestPeriodicAccountUndelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPeriodicAccount(t, sdkCtx, ss)
|
||||
// Delegate first
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.ZeroInt()))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked first period token
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(6)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(5)))
|
||||
|
||||
delFree, err := acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(4)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(2)))
|
||||
|
||||
delFree, err = acc.DelegatedFree.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delFree.Equal(math.ZeroInt()))
|
||||
}
|
||||
|
||||
func TestPeriodicAccountSendCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPeriodicAccount(t, sdkCtx, ss)
|
||||
_, err := acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked first period token
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPeriodicAccountWithdrawUnlockedCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPeriodicAccount(t, sdkCtx, ss)
|
||||
_, err := acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update context time to unlocked first period token
|
||||
sdkCtx = sdkCtx.WithHeaderInfo(header.Info{
|
||||
Time: startTime.Add(time.Minute * 1),
|
||||
})
|
||||
|
||||
_, err = acc.WithdrawUnlockedCoins(sdkCtx, &lockuptypes.MsgWithdraw{
|
||||
Withdrawer: "owner",
|
||||
ToAddress: "receiver",
|
||||
Denoms: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPeriodicAccountGetLockCoinInfo(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPeriodicAccount(t, sdkCtx, ss)
|
||||
|
||||
unlocked, locked, err := acc.GetLockCoinsInfo(sdkCtx, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
|
||||
startTime, err := acc.StartTime.Get(sdkCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// unlocked first period locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, startTime.Add(time.Minute*1))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(5)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(5)))
|
||||
|
||||
// unlocked second period locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, startTime.Add(time.Minute*2))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(7)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.NewInt(3)))
|
||||
|
||||
// unlocked third period locked token
|
||||
unlocked, locked, err = acc.GetLockCoinsInfo(sdkCtx, startTime.Add(time.Minute*3))
|
||||
require.NoError(t, err)
|
||||
require.True(t, unlocked.AmountOf("test").Equal(math.NewInt(10)))
|
||||
require.True(t, locked.AmountOf("test").Equal(math.ZeroInt()))
|
||||
}
|
||||
@ -100,8 +100,9 @@ func (plva PermanentLockingAccount) RegisterInitHandler(builder *accountstd.Init
|
||||
|
||||
func (plva PermanentLockingAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) {
|
||||
accountstd.RegisterExecuteHandler(builder, plva.Delegate)
|
||||
accountstd.RegisterExecuteHandler(builder, plva.Undelegate)
|
||||
accountstd.RegisterExecuteHandler(builder, plva.SendCoins)
|
||||
plva.BaseLockup.RegisterExecuteHandlers(builder)
|
||||
accountstd.RegisterExecuteHandler(builder, plva.WithdrawReward)
|
||||
}
|
||||
|
||||
func (plva PermanentLockingAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) {
|
||||
|
||||
97
x/accounts/defaults/lockup/permanent_locking_account_test.go
Normal file
97
x/accounts/defaults/lockup/permanent_locking_account_test.go
Normal file
@ -0,0 +1,97 @@
|
||||
package lockup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
lockuptypes "cosmossdk.io/x/accounts/defaults/lockup/types"
|
||||
)
|
||||
|
||||
func setupPermanentAccount(t *testing.T, ctx context.Context, ss store.KVStoreService) *PermanentLockingAccount {
|
||||
t.Helper()
|
||||
deps := makeMockDependencies(ss)
|
||||
owner := "owner"
|
||||
|
||||
acc, err := NewPermanentLockingAccount(deps)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.Init(ctx, &lockuptypes.MsgInitLockupAccount{
|
||||
Owner: owner,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func TestPermanentAccountDelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPermanentAccount(t, sdkCtx, ss)
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
}
|
||||
|
||||
func TestPermanentAccountUndelegate(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPermanentAccount(t, sdkCtx, ss)
|
||||
// Delegate first
|
||||
_, err := acc.Delegate(sdkCtx, &lockuptypes.MsgDelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err := acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.NewInt(1)))
|
||||
|
||||
// Undelegate
|
||||
_, err = acc.Undelegate(sdkCtx, &lockuptypes.MsgUndelegate{
|
||||
Sender: "owner",
|
||||
ValidatorAddress: "val_address",
|
||||
Amount: sdk.NewCoin("test", math.NewInt(1)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
delLocking, err = acc.DelegatedLocking.Get(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, delLocking.Equal(math.ZeroInt()))
|
||||
}
|
||||
|
||||
func TestPermanentAccountSendCoins(t *testing.T) {
|
||||
ctx, ss := newMockContext(t)
|
||||
sdkCtx := sdk.NewContext(nil, true, log.NewNopLogger()).WithContext(ctx).WithHeaderInfo(header.Info{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
acc := setupPermanentAccount(t, sdkCtx, ss)
|
||||
_, err := acc.SendCoins(sdkCtx, &lockuptypes.MsgSend{
|
||||
Sender: "owner",
|
||||
ToAddress: "receiver",
|
||||
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(5))),
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
@ -2,19 +2,25 @@ package lockup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
gogoproto "github.com/cosmos/gogoproto/proto"
|
||||
"github.com/golang/protobuf/proto" // nolint: staticcheck // needed because gogoproto.Merge does not work consistently. See NOTE: comments.
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/runtime/protoiface"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
"cosmossdk.io/core/appmodule/v2"
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/x/accounts/accountstd"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
distrtypes "cosmossdk.io/x/distribution/types"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -23,7 +29,11 @@ type ProtoMsg = protoiface.MessageV1
|
||||
var TestFunds = sdk.NewCoins(sdk.NewCoin("test", math.NewInt(10)))
|
||||
|
||||
// mock statecodec
|
||||
type mockStateCodec struct{}
|
||||
type mockStateCodec struct {
|
||||
codec.Codec
|
||||
}
|
||||
|
||||
var _ codec.Codec = mockStateCodec{}
|
||||
|
||||
func (c mockStateCodec) Marshal(m gogoproto.Message) ([]byte, error) {
|
||||
// Size() check can catch the typed nil value.
|
||||
@ -53,13 +63,32 @@ type addressCodec struct{}
|
||||
func (a addressCodec) StringToBytes(text string) ([]byte, error) { return []byte(text), nil }
|
||||
func (a addressCodec) BytesToString(bz []byte) (string, error) { return string(bz), nil }
|
||||
|
||||
// mock header service
|
||||
type headerService struct{}
|
||||
|
||||
func (h headerService) HeaderInfo(ctx context.Context) header.Info {
|
||||
return sdk.UnwrapSDKContext(ctx).HeaderInfo()
|
||||
}
|
||||
|
||||
func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
|
||||
t.Helper()
|
||||
return accountstd.NewMockContext(
|
||||
0, []byte("lockup_account"), []byte("sender"), TestFunds, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
|
||||
return nil
|
||||
}, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
|
||||
return nil, nil
|
||||
typeUrl := sdk.MsgTypeURL(msg)
|
||||
switch typeUrl {
|
||||
case "/cosmos.staking.v1beta1.MsgDelegate":
|
||||
return &stakingtypes.MsgDelegateResponse{}, nil
|
||||
case "/cosmos.staking.v1beta1.MsgUndelegate":
|
||||
return &stakingtypes.MsgUndelegate{}, nil
|
||||
case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward":
|
||||
return &distrtypes.MsgWithdrawDelegatorRewardResponse{}, nil
|
||||
case "/cosmos.bank.v1beta1.MsgSend":
|
||||
return &banktypes.MsgSendResponse{}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized request type")
|
||||
}
|
||||
}, func(ctx context.Context, req, resp ProtoMsg) error {
|
||||
_, ok := req.(*banktypes.QueryBalanceRequest)
|
||||
if !ok {
|
||||
@ -70,14 +99,16 @@ func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
|
||||
BondDenom: "test",
|
||||
},
|
||||
})
|
||||
return nil
|
||||
} else {
|
||||
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
|
||||
// using proto.Merge with gogo messages seems to work fine.
|
||||
proto.Merge(resp.(gogoproto.Message), &banktypes.QueryBalanceResponse{
|
||||
Balance: &(sdk.Coin{
|
||||
Denom: "test",
|
||||
Amount: TestFunds.AmountOf("test"),
|
||||
}),
|
||||
})
|
||||
}
|
||||
gogoproto.Merge(resp.(gogoproto.Message), &banktypes.QueryBalanceResponse{
|
||||
Balance: &sdk.Coin{
|
||||
Denom: "test",
|
||||
Amount: math.NewInt(5),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
},
|
||||
@ -91,5 +122,8 @@ func makeMockDependencies(storeservice store.KVStoreService) accountstd.Dependen
|
||||
SchemaBuilder: sb,
|
||||
AddressCodec: addressCodec{},
|
||||
LegacyStateCodec: mockStateCodec{},
|
||||
Environment: appmodule.Environment{
|
||||
HeaderService: headerService{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user