Skip to content

Commit def23f0

Browse files
sontrinh16alpe
andauthored
fix(x/accounts/default/lockup): Lockup account track undelegation when unbonding entry is mature (#22254)
Co-authored-by: Alexander Peters <[email protected]>
1 parent 0a89178 commit def23f0

26 files changed

+5374
-2750
lines changed

Diff for: api/cosmos/accounts/defaults/lockup/v1/lockup.pulsar.go

+1,323-47
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: api/cosmos/accounts/defaults/lockup/v1/query.pulsar.go

+2,238-254
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: api/cosmos/accounts/defaults/lockup/v1/tx.pulsar.go

+38-1,353
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: tests/integration/accounts/lockup/continous_lockup_test_suite.go

+16-34
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
2323
ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{
2424
Time: currentTime,
2525
})
26+
s.setupStakingParams(ctx, app)
2627
ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
2728
require.NoError(t, err)
2829
s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))})
2930
randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
30-
withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
3131

3232
_, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.CONTINUOUS_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{
3333
Owner: ownerAddrStr,
@@ -62,19 +62,6 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
6262
err := s.executeTx(ctx, msg, app, accountAddr, accOwner)
6363
require.NotNil(t, err)
6464
})
65-
t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) {
66-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
67-
require.NoError(t, err)
68-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
69-
require.NoError(t, err)
70-
msg := &types.MsgWithdraw{
71-
Withdrawer: ownerAddr,
72-
ToAddress: withdrawAddr,
73-
Denoms: []string{"stake"},
74-
}
75-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
76-
require.NotNil(t, err)
77-
})
7865

7966
// Update context time
8067
// 12 sec = 1/5 of a minute so 200stake should be released
@@ -95,23 +82,7 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
9582
balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake")
9683
require.True(t, balance.Amount.Equal(math.NewInt(100)))
9784
})
98-
t.Run("ok - execute withdraw message", func(t *testing.T) {
99-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
100-
require.NoError(t, err)
101-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
102-
require.NoError(t, err)
103-
msg := &types.MsgWithdraw{
104-
Withdrawer: ownerAddr,
105-
ToAddress: withdrawAddr,
106-
Denoms: []string{"stake"},
107-
}
108-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
109-
require.NoError(t, err)
11085

111-
// withdrawable amount should be 200 - 100 = 100stake
112-
balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake")
113-
require.True(t, balance.Amount.Equal(math.NewInt(100)))
114-
})
11586
t.Run("ok - execute delegate message", func(t *testing.T) {
11687
msg := &types.MsgDelegate{
11788
Sender: ownerAddrStr,
@@ -163,17 +134,22 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
163134
require.NoError(t, err)
164135
require.Equal(t, len(ubd.Entries), 1)
165136

166-
// check if tracking is updated accordingly
167-
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
168-
delLocking := lockupAccountInfoResponse.DelegatedLocking
169-
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
137+
// check if an entry is added
138+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
139+
entries := unbondingEntriesResponse.UnbondingEntries
140+
require.True(t, entries[0].Amount.Amount.Equal(math.NewInt(100)))
141+
require.True(t, entries[0].ValidatorAddress == val.OperatorAddress)
170142
})
171143

172144
// Update context time to end time
173145
ctx = ctx.WithHeaderInfo(header.Info{
174146
Time: currentTime.Add(time.Minute),
175147
})
176148

149+
// trigger endblock for staking to handle matured unbonding delegation
150+
_, err = app.StakingKeeper.EndBlocker(ctx)
151+
require.NoError(t, err)
152+
177153
// test if tracking delegate work perfectly
178154
t.Run("ok - execute delegate message", func(t *testing.T) {
179155
msg := &types.MsgDelegate{
@@ -196,8 +172,14 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
196172
// check if tracking is updated accordingly
197173
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
198174
delLocking := lockupAccountInfoResponse.DelegatedLocking
175+
// should be update as ubd entry is matured
199176
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
200177
delFree := lockupAccountInfoResponse.DelegatedFree
201178
require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100)))
179+
180+
// check if the entry is removed
181+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
182+
entries := unbondingEntriesResponse.UnbondingEntries
183+
require.Len(t, entries, 0)
202184
})
203185
}

Diff for: tests/integration/accounts/lockup/delayed_lockup_test_suite.go

+20-36
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ func (s *IntegrationTestSuite) TestDelayedLockingAccount() {
2323
ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{
2424
Time: currentTime,
2525
})
26+
s.setupStakingParams(ctx, app)
2627
ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
2728
require.NoError(t, err)
2829
s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))})
2930
randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
30-
withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
3131

3232
_, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.DELAYED_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{
3333
Owner: ownerAddrStr,
@@ -61,19 +61,6 @@ func (s *IntegrationTestSuite) TestDelayedLockingAccount() {
6161
err := s.executeTx(ctx, msg, app, accountAddr, accOwner)
6262
require.NotNil(t, err)
6363
})
64-
t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) {
65-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
66-
require.NoError(t, err)
67-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
68-
require.NoError(t, err)
69-
msg := &types.MsgWithdraw{
70-
Withdrawer: ownerAddr,
71-
ToAddress: withdrawAddr,
72-
Denoms: []string{"stake"},
73-
}
74-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
75-
require.NotNil(t, err)
76-
})
7764
t.Run("ok - execute delegate message", func(t *testing.T) {
7865
msg := &types.MsgDelegate{
7966
Sender: ownerAddrStr,
@@ -125,18 +112,24 @@ func (s *IntegrationTestSuite) TestDelayedLockingAccount() {
125112
require.NoError(t, err)
126113
require.Equal(t, len(ubd.Entries), 1)
127114

128-
// check if tracking is updated accordingly
129-
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
130-
delLocking := lockupAccountInfoResponse.DelegatedLocking
131-
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
115+
// check if an entry is added
116+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
117+
entries := unbondingEntriesResponse.UnbondingEntries
118+
require.True(t, entries[0].Amount.Amount.Equal(math.NewInt(100)))
119+
require.True(t, entries[0].ValidatorAddress == val.OperatorAddress)
132120
})
133121

134122
// Update context time
135123
// After endtime fund should be unlock
124+
// And unbond time elapsed
136125
ctx = ctx.WithHeaderInfo(header.Info{
137126
Time: currentTime.Add(time.Second * 61),
138127
})
139128

129+
// trigger endblock for staking to handle matured unbonding delegation
130+
_, err = app.StakingKeeper.EndBlocker(ctx)
131+
require.NoError(t, err)
132+
140133
// Check if token is sendable after unlock
141134
t.Run("ok - execute send message", func(t *testing.T) {
142135
msg := &types.MsgSend{
@@ -149,24 +142,15 @@ func (s *IntegrationTestSuite) TestDelayedLockingAccount() {
149142

150143
balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake")
151144
require.True(t, balance.Amount.Equal(math.NewInt(100)))
152-
})
153-
// Test to withdraw all the remain funds to an account of choice
154-
t.Run("ok - execute withdraw message", func(t *testing.T) {
155-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
156-
require.NoError(t, err)
157-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
158-
require.NoError(t, err)
159-
msg := &types.MsgWithdraw{
160-
Withdrawer: ownerAddr,
161-
ToAddress: withdrawAddr,
162-
Denoms: []string{"stake"},
163-
}
164-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
165-
require.NoError(t, err)
166145

167-
// withdrawable amount should be
168-
// 1000stake - 100stake( above sent amt ) - 100stake(above delegate amt) = 800stake
169-
balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake")
170-
require.True(t, balance.Amount.Equal(math.NewInt(800)))
146+
// check if tracking ubd entry is updated accordingly
147+
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
148+
delLocking := lockupAccountInfoResponse.DelegatedLocking
149+
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
150+
151+
// check if the entry is removed
152+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
153+
entries := unbondingEntriesResponse.UnbondingEntries
154+
require.Len(t, entries, 0)
171155
})
172156
}

Diff for: tests/integration/accounts/lockup/periodic_lockup_test_suite.go

+18-37
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
2323
ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{
2424
Time: currentTime,
2525
})
26+
s.setupStakingParams(ctx, app)
2627
ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
2728
require.NoError(t, err)
2829
s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))})
2930
randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
30-
withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
3131

3232
_, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.PERIODIC_LOCKING_ACCOUNT, accOwner, &types.MsgInitPeriodicLockingAccount{
3333
Owner: ownerAddrStr,
@@ -75,19 +75,6 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
7575
err := s.executeTx(ctx, msg, app, accountAddr, accOwner)
7676
require.NotNil(t, err)
7777
})
78-
t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) {
79-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
80-
require.NoError(t, err)
81-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
82-
require.NoError(t, err)
83-
msg := &types.MsgWithdraw{
84-
Withdrawer: ownerAddr,
85-
ToAddress: withdrawAddr,
86-
Denoms: []string{"stake"},
87-
}
88-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
89-
require.NotNil(t, err)
90-
})
9178

9279
// Update context time
9380
// After first period 500stake should be unlock
@@ -115,25 +102,6 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
115102
Time: currentTime.Add(time.Minute * 2),
116103
})
117104

118-
t.Run("oke - execute withdraw message", func(t *testing.T) {
119-
ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
120-
require.NoError(t, err)
121-
withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc)
122-
require.NoError(t, err)
123-
msg := &types.MsgWithdraw{
124-
Withdrawer: ownerAddr,
125-
ToAddress: withdrawAddr,
126-
Denoms: []string{"stake"},
127-
}
128-
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
129-
require.NoError(t, err)
130-
131-
// withdrawable amount should be
132-
// 1000stake - 500stake( above sent amt ) = 500stake
133-
balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake")
134-
require.True(t, balance.Amount.Equal(math.NewInt(500)))
135-
})
136-
137105
t.Run("ok - execute delegate message", func(t *testing.T) {
138106
msg := &types.MsgDelegate{
139107
Sender: ownerAddrStr,
@@ -185,10 +153,11 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
185153
require.NoError(t, err)
186154
require.Equal(t, len(ubd.Entries), 1)
187155

188-
// check if tracking is updated accordingly
189-
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
190-
delLocking := lockupAccountInfoResponse.DelegatedLocking
191-
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
156+
// check if an entry is added
157+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
158+
entries := unbondingEntriesResponse.UnbondingEntries
159+
require.True(t, entries[0].Amount.Amount.Equal(math.NewInt(100)))
160+
require.True(t, entries[0].ValidatorAddress == val.OperatorAddress)
192161
})
193162

194163
// Update context time
@@ -197,6 +166,10 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
197166
Time: currentTime.Add(time.Minute * 3),
198167
})
199168

169+
// trigger endblock for staking to handle matured unbonding delegation
170+
_, err = app.StakingKeeper.EndBlocker(ctx)
171+
require.NoError(t, err)
172+
200173
t.Run("ok - execute delegate message", func(t *testing.T) {
201174
msg := &types.MsgDelegate{
202175
Sender: ownerAddrStr,
@@ -217,7 +190,15 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
217190

218191
// check if tracking is updated accordingly
219192
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
193+
// check if matured ubd entry cleared
194+
delLocking := lockupAccountInfoResponse.DelegatedLocking
195+
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
220196
delFree := lockupAccountInfoResponse.DelegatedFree
221197
require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100)))
198+
199+
// check if the entry is removed
200+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
201+
entries := unbondingEntriesResponse.UnbondingEntries
202+
require.Len(t, entries, 0)
222203
})
223204
}

Diff for: tests/integration/accounts/lockup/permanent_lockup_test_suite.go

+45-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func (s *IntegrationTestSuite) TestPermanentLockingAccount() {
2323
ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{
2424
Time: currentTime,
2525
})
26+
s.setupStakingParams(ctx, app)
2627
ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner)
2728
require.NoError(t, err)
2829
s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))})
@@ -109,10 +110,11 @@ func (s *IntegrationTestSuite) TestPermanentLockingAccount() {
109110
require.NoError(t, err)
110111
require.Equal(t, len(ubd.Entries), 1)
111112

112-
// check if tracking is updated accordingly
113-
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
114-
delLocking := lockupAccountInfoResponse.DelegatedLocking
115-
require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt()))
113+
// check if an entry is added
114+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
115+
entries := unbondingEntriesResponse.UnbondingEntries
116+
require.True(t, entries[0].Amount.Amount.Equal(math.NewInt(100)))
117+
require.True(t, entries[0].ValidatorAddress == val.OperatorAddress)
116118
})
117119

118120
s.fundAccount(app, ctx, accountAddr, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))})
@@ -129,4 +131,43 @@ func (s *IntegrationTestSuite) TestPermanentLockingAccount() {
129131
balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake")
130132
require.True(t, balance.Amount.Equal(math.NewInt(100)))
131133
})
134+
135+
// Update context time
136+
ctx = ctx.WithHeaderInfo(header.Info{
137+
Time: currentTime.Add(time.Second * 11),
138+
})
139+
140+
// trigger endblock for staking to handle matured unbonding delegation
141+
_, err = app.StakingKeeper.EndBlocker(ctx)
142+
require.NoError(t, err)
143+
144+
t.Run("ok - execute delegate message", func(t *testing.T) {
145+
msg := &types.MsgDelegate{
146+
Sender: ownerAddrStr,
147+
ValidatorAddress: val.OperatorAddress,
148+
Amount: sdk.NewCoin("stake", math.NewInt(10)),
149+
}
150+
err = s.executeTx(ctx, msg, app, accountAddr, accOwner)
151+
require.NoError(t, err)
152+
153+
valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress)
154+
require.NoError(t, err)
155+
156+
del, err := app.StakingKeeper.Delegations.Get(
157+
ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)),
158+
)
159+
require.NoError(t, err)
160+
require.NotNil(t, del)
161+
162+
// check if tracking is updated accordingly
163+
lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr)
164+
delLocking := lockupAccountInfoResponse.DelegatedLocking
165+
// matured ubd entry should be cleared so del locking should only be 10
166+
require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(10)))
167+
168+
// check if the entry is removed
169+
unbondingEntriesResponse := s.queryUnbondingEntries(ctx, app, accountAddr, val.OperatorAddress)
170+
entries := unbondingEntriesResponse.UnbondingEntries
171+
require.Len(t, entries, 0)
172+
})
132173
}

0 commit comments

Comments
 (0)