Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

batching delegations/undelegations + stTIA migration #1223

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
10a1abd
Batched delegations (#1201)
sampocs Jun 13, 2024
74c51cb
batched undelegations (#1195)
sampocs Jun 13, 2024
99d773f
staketia migration (#1212)
sampocs Jun 13, 2024
a5b31a6
fixed unit tests
sampocs Jun 13, 2024
1582770
V23 upgrade handler (batching and stTIA) (#1219)
sampocs Jun 13, 2024
95f12fd
added TODO
sampocs Jun 14, 2024
cd8d976
[AUDIT FIX] - short circuit callback on completed records
sampocs Jun 14, 2024
def6f4a
[AUDIT FIX] - decrement remaining delegated balance in redeem stake
sampocs Jun 20, 2024
f1fe92c
[AUDIT FIX] - set min/max inner redemption rate after migration
sampocs Jun 20, 2024
df38a31
[AUDIT FIX] - updated total delegations in confirm delegation
sampocs Jun 20, 2024
c3ffbf6
Merge branch 'main' into v23
sampocs Jun 20, 2024
25ed61b
[AUDIT FIX] migrate halted field, remove prepare delegation, clarifyi…
sampocs Jun 29, 2024
66041f3
[AUDIT FIX] decrement total delegations in adjust delegated balance
sampocs Jul 9, 2024
82a007b
[AUDIT FIX] enable stakeibc redemptions with if exact remaining amoun…
sampocs Jul 9, 2024
7e4a9a9
[AUDIT FIX] set delegation/undelegationTxsInProgress in migration
sampocs Jul 10, 2024
07d8a83
reset delegation txs in progress to 0 in restore-ica
sampocs Jul 18, 2024
639777d
addressed riley and vishal pr comments
sampocs Jul 26, 2024
38555eb
updated package from v22 -> v23
sampocs Jul 26, 2024
81f7cc9
generated protos
sampocs Jul 26, 2024
68deb54
moved upgrade to v24
sampocs Jul 26, 2024
8fdf6c6
removed trade route migration from v24 upgrade
sampocs Jul 26, 2024
d35a8e8
Merge branch 'main' into v23
sampocs Jul 26, 2024
72b9b41
fixed unit tests
sampocs Jul 26, 2024
13288dd
copied over the redemption rate update functions into staketia migration
sampocs Jul 26, 2024
ec24683
fixed build errors and updated RR functions
sampocs Jul 26, 2024
046f992
added invariant from RR change
sampocs Jul 26, 2024
5c79959
removed debug logs
sampocs Jul 26, 2024
07f1411
fixed unit test
sampocs Jul 26, 2024
c9b390d
nit
sampocs Jul 26, 2024
059843d
moved up RR invariant check and removed balance check
sampocs Aug 6, 2024
a57552d
nit, used GetActiveHostZone and moved epoch tracker
sampocs Aug 6, 2024
f5574b1
fixed unit tests
sampocs Aug 6, 2024
19e3617
nit: fixed comment typo in icacallbacks_undelegate.go
sampocs Aug 7, 2024
b58fea0
Merge branch 'main' into v23
assafmo Aug 8, 2024
afa4bfb
Merge branch 'main' into v23
sampocs Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ func NewStrideApp(
app.BankKeeper,
app.ICAOracleKeeper,
app.RatelimitKeeper,
app.RecordsKeeper,
app.StakeibcKeeper,
app.TransferKeeper,
)
stakeTiaModule := staketia.NewAppModule(appCodec, app.StaketiaKeeper)
Expand Down
2 changes: 1 addition & 1 deletion app/apptesting/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (s *AppTestHelper) Setup() {
GRPCQueryRouter: s.App.GRPCQueryRouter(),
Ctx: s.Ctx,
}
s.TestAccs = CreateRandomAccounts(3)
s.TestAccs = CreateRandomAccounts(4)
s.IbcEnabled = false
s.IcaAddresses = make(map[string]string)

Expand Down
14 changes: 14 additions & 0 deletions app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
v21 "github.com/Stride-Labs/stride/v23/app/upgrades/v21"
v22 "github.com/Stride-Labs/stride/v23/app/upgrades/v22"
v23 "github.com/Stride-Labs/stride/v23/app/upgrades/v23"
v24 "github.com/Stride-Labs/stride/v23/app/upgrades/v24"
v3 "github.com/Stride-Labs/stride/v23/app/upgrades/v3"
v4 "github.com/Stride-Labs/stride/v23/app/upgrades/v4"
v5 "github.com/Stride-Labs/stride/v23/app/upgrades/v5"
Expand Down Expand Up @@ -311,6 +312,19 @@ func (app *StrideApp) setupUpgradeHandlers(appOpts servertypes.AppOptions) {
),
)

// v24 upgrade handler
app.UpgradeKeeper.SetUpgradeHandler(
v24.UpgradeName,
v24.CreateUpgradeHandler(
app.mm,
app.configurator,
app.BankKeeper,
app.RecordsKeeper,
app.StakeibcKeeper,
app.StaketiaKeeper,
),
)

upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(fmt.Errorf("Failed to read upgrade info from disk: %w", err))
Expand Down
8 changes: 4 additions & 4 deletions app/upgrades/v10/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ func (s *UpgradeTestSuite) TestMigrateCallbackData() {
}
initialUndelegateCallbackArgs := stakeibctypes.UndelegateCallback{
HostZoneId: "host-0",
SplitDelegations: []*types.SplitDelegation{{
Validator: "val-0",
Amount: sdkmath.NewInt(1),
}},
// SplitDelegations: []*types.SplitDelegation{{
// Validator: "val-0",
// Amount: sdkmath.NewInt(1),
// }},
}
initialTransferCallbackArgs := recordstypes.TransferCallback{
DepositRecordId: 1,
Expand Down
128 changes: 128 additions & 0 deletions app/upgrades/v24/upgrades.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package v24

import (
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

recordskeeper "github.com/Stride-Labs/stride/v23/x/records/keeper"
recordstypes "github.com/Stride-Labs/stride/v23/x/records/types"
stakeibckeeper "github.com/Stride-Labs/stride/v23/x/stakeibc/keeper"
staketiakeeper "github.com/Stride-Labs/stride/v23/x/staketia/keeper"
)

var (
UpgradeName = "v24"
)

// CreateUpgradeHandler creates an SDK upgrade handler for v23
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
bankKeeper bankkeeper.Keeper,
recordsKeeper recordskeeper.Keeper,
stakeibcKeeper stakeibckeeper.Keeper,
staketiaKeeper staketiakeeper.Keeper,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
ctx.Logger().Info("Starting upgrade v24...")

// Migrate data structures
MigrateHostZones(ctx, stakeibcKeeper)
MigrateEpochUnbondingRecords(ctx, recordsKeeper)

// Migrate staketia to stakeibc
if err := staketiakeeper.InitiateMigration(ctx, staketiaKeeper, bankKeeper, recordsKeeper, stakeibcKeeper); err != nil {
return vm, errorsmod.Wrapf(err, "unable to migrate staketia to stakeibc")
}

// TODO: add celestia validator set

ctx.Logger().Info("Running module migrations...")
return mm.RunMigrations(ctx, configurator, vm)
}
}

// Migrate host zones to accomodate the staketia migration changes, adding a
// redemptions enabled field to each host zone
func MigrateHostZones(ctx sdk.Context, k stakeibckeeper.Keeper) {
ctx.Logger().Info("Migrating host zones...")

for _, hostZone := range k.GetAllHostZone(ctx) {
hostZone.RedemptionsEnabled = true
k.SetHostZone(ctx, hostZone)
}
}

// Migrates the deposit records to set the DelegationTxsInProgress field
// which should be 1 if the status was DELEGATION_IN_PROGRESS, and 0 otherwise
func MigrateDepositRecords(ctx sdk.Context, k recordskeeper.Keeper) {
ctx.Logger().Info("Migrating deposit records...")

for _, depositRecord := range k.GetAllDepositRecord(ctx) {
if depositRecord.Status == recordstypes.DepositRecord_DELEGATION_IN_PROGRESS {
depositRecord.DelegationTxsInProgress = 1
} else {
depositRecord.DelegationTxsInProgress = 0
}
k.SetDepositRecord(ctx, depositRecord)
}
}

// Migrates a single host zone unbonding record to add the new fields: StTokensToBurn,
// NativeTokensToUnbond, and ClaimableNativeTokens
//
// If the record is in status: UNBONDING_QUEUE, EXIT_TRANSFER_QUEUE, or EXIT_TRANSFER_IN_PROGRESS,
// set stTokensToBurn, NativeTokensToUnbond, and ClaimableNativeTokens all to 0
//
// If the record is in status: UNBONDING_IN_PROGRESS
// set StTokensToBurn to the value of StTokenAmount, NativeTokensToUnbond to the value of NativeTokenAmount,
// and ClaimableNativeTokens to 0
//
// If the record is in status CLAIMABLE,
// set StTokensToBurn and NativeTokensToUnbond to 0, and set ClaimableNativeTokens to the value of NativeTokenAmount
//
// If the record is in status UNBONDING_IN_PROGRESS, we need to also set UndelegationTxsInProgress to 1;
// otherwise, it should be set to 0
func MigrateHostZoneUnbondingRecords(hostZoneUnbonding *recordstypes.HostZoneUnbonding) *recordstypes.HostZoneUnbonding {
if hostZoneUnbonding.Status == recordstypes.HostZoneUnbonding_UNBONDING_QUEUE ||
hostZoneUnbonding.Status == recordstypes.HostZoneUnbonding_EXIT_TRANSFER_QUEUE ||
hostZoneUnbonding.Status == recordstypes.HostZoneUnbonding_EXIT_TRANSFER_IN_PROGRESS {

hostZoneUnbonding.StTokensToBurn = sdkmath.ZeroInt()
hostZoneUnbonding.NativeTokensToUnbond = sdkmath.ZeroInt()
hostZoneUnbonding.ClaimableNativeTokens = sdkmath.ZeroInt()
hostZoneUnbonding.UndelegationTxsInProgress = 0

} else if hostZoneUnbonding.Status == recordstypes.HostZoneUnbonding_UNBONDING_IN_PROGRESS {
hostZoneUnbonding.StTokensToBurn = hostZoneUnbonding.StTokenAmount
hostZoneUnbonding.NativeTokensToUnbond = hostZoneUnbonding.NativeTokenAmount
hostZoneUnbonding.ClaimableNativeTokens = sdkmath.ZeroInt()
hostZoneUnbonding.UndelegationTxsInProgress = 1

} else if hostZoneUnbonding.Status == recordstypes.HostZoneUnbonding_CLAIMABLE {
hostZoneUnbonding.StTokensToBurn = sdkmath.ZeroInt()
hostZoneUnbonding.NativeTokensToUnbond = sdkmath.ZeroInt()
hostZoneUnbonding.ClaimableNativeTokens = hostZoneUnbonding.NativeTokenAmount
hostZoneUnbonding.UndelegationTxsInProgress = 0
}

return hostZoneUnbonding
}

// Migrate epoch unbonding records to accomodate the batched undelegations code changes,
// adding the new accounting fields to the host zone unbonding records
func MigrateEpochUnbondingRecords(ctx sdk.Context, k recordskeeper.Keeper) {
ctx.Logger().Info("Migrating epoch unbonding records...")

for _, epochUnbondingRecord := range k.GetAllEpochUnbondingRecord(ctx) {
for i, oldHostZoneUnbondingRecord := range epochUnbondingRecord.HostZoneUnbondings {
updatedHostZoneUnbondingRecord := MigrateHostZoneUnbondingRecords(oldHostZoneUnbondingRecord)
epochUnbondingRecord.HostZoneUnbondings[i] = updatedHostZoneUnbondingRecord
}
k.SetEpochUnbondingRecord(ctx, epochUnbondingRecord)
}
}
205 changes: 205 additions & 0 deletions app/upgrades/v24/upgrades_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package v24_test

import (
"testing"

"github.com/stretchr/testify/suite"

sdkmath "cosmossdk.io/math"

"github.com/Stride-Labs/stride/v23/app/apptesting"
v24 "github.com/Stride-Labs/stride/v23/app/upgrades/v24"
recordstypes "github.com/Stride-Labs/stride/v23/x/records/types"
stakeibctypes "github.com/Stride-Labs/stride/v23/x/stakeibc/types"
)

type UpgradeTestSuite struct {
apptesting.AppTestHelper
}

func (s *UpgradeTestSuite) SetupTest() {
s.Setup()
}

func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(UpgradeTestSuite))
}

func (s *UpgradeTestSuite) TestUpgrade() {
}

func (s *UpgradeTestSuite) TestMigrateHostZones() {
// Create a host zone with redemptions enabled set to false
hostZone := stakeibctypes.HostZone{
ChainId: "chain-0",
RedemptionsEnabled: false,
}
s.App.StakeibcKeeper.SetHostZone(s.Ctx, hostZone)

// Call migration function
v24.MigrateHostZones(s.Ctx, s.App.StakeibcKeeper)

// Confirm host route was migrated
for _, hostZone := range s.App.StakeibcKeeper.GetAllHostZone(s.Ctx) {
s.Require().True(hostZone.RedemptionsEnabled)
}
}

func (s *UpgradeTestSuite) TestMigrateDepositRecords() {
// Create initial deposit records across each status
testCases := []struct {
status recordstypes.DepositRecord_Status
expectedDelegationTxsInProgress uint64
}{
{
status: recordstypes.DepositRecord_TRANSFER_QUEUE,
expectedDelegationTxsInProgress: 0,
},
{
status: recordstypes.DepositRecord_TRANSFER_IN_PROGRESS,
expectedDelegationTxsInProgress: 0,
},
{
status: recordstypes.DepositRecord_DELEGATION_QUEUE,
expectedDelegationTxsInProgress: 0,
},
{
status: recordstypes.DepositRecord_DELEGATION_IN_PROGRESS,
expectedDelegationTxsInProgress: 1,
},
}

for id, tc := range testCases {
s.App.RecordsKeeper.SetDepositRecord(s.Ctx, recordstypes.DepositRecord{
Id: uint64(id),
Status: tc.status,
})
}

// Migrate the records
v24.MigrateDepositRecords(s.Ctx, s.App.RecordsKeeper)

// Confirm the expected status for each
for id, tc := range testCases {
depositRecord, found := s.App.RecordsKeeper.GetDepositRecord(s.Ctx, uint64(id))
s.Require().True(found, "deposit record %d should have been found", id)
s.Require().Equal(tc.expectedDelegationTxsInProgress, depositRecord.DelegationTxsInProgress,
"delegation txs in progress for record %d", id)
}
}

func (s *UpgradeTestSuite) TestMigrateEpochUnbondingRecords() {
recordTestCases := []struct {
epochNumber uint64
chainId string
status recordstypes.HostZoneUnbonding_Status
stTokenAmount int64
nativeTokenAmount int64
expectedStTokensToBurn int64
expectedNativeTokensToUnbond int64
expectedClaimableNativeTokens int64
expectedUndelegationTxsInProgress uint64
}{
{
epochNumber: 1,
chainId: "chain-1",
status: recordstypes.HostZoneUnbonding_UNBONDING_QUEUE,

stTokenAmount: 1,
nativeTokenAmount: 2,

expectedStTokensToBurn: 0,
expectedNativeTokensToUnbond: 0,
expectedClaimableNativeTokens: 0,
expectedUndelegationTxsInProgress: 0,
},
{
epochNumber: 1,
chainId: "chain-2",
status: recordstypes.HostZoneUnbonding_UNBONDING_IN_PROGRESS,

stTokenAmount: 3,
nativeTokenAmount: 4,

expectedStTokensToBurn: 3,
expectedNativeTokensToUnbond: 4,
expectedClaimableNativeTokens: 0,
expectedUndelegationTxsInProgress: 1,
},
{
epochNumber: 2,
chainId: "chain-3",
status: recordstypes.HostZoneUnbonding_EXIT_TRANSFER_QUEUE,

stTokenAmount: 5,
nativeTokenAmount: 6,

expectedStTokensToBurn: 0,
expectedNativeTokensToUnbond: 0,
expectedClaimableNativeTokens: 0,
expectedUndelegationTxsInProgress: 0,
},
{
epochNumber: 2,
chainId: "chain-4",
status: recordstypes.HostZoneUnbonding_EXIT_TRANSFER_IN_PROGRESS,

stTokenAmount: 7,
nativeTokenAmount: 8,

expectedStTokensToBurn: 0,
expectedNativeTokensToUnbond: 0,
expectedClaimableNativeTokens: 0,
expectedUndelegationTxsInProgress: 0,
},
{
epochNumber: 4,
chainId: "chain-5",
status: recordstypes.HostZoneUnbonding_CLAIMABLE,

stTokenAmount: 9,
nativeTokenAmount: 10,

expectedStTokensToBurn: 0,
expectedNativeTokensToUnbond: 0,
expectedClaimableNativeTokens: 10,
expectedUndelegationTxsInProgress: 0,
},
}

// Create the initial host zone unbonding and epoch unbonding records
for _, tc := range recordTestCases {
if _, found := s.App.RecordsKeeper.GetEpochUnbondingRecord(s.Ctx, tc.epochNumber); !found {
s.App.RecordsKeeper.SetEpochUnbondingRecord(s.Ctx, recordstypes.EpochUnbondingRecord{
EpochNumber: tc.epochNumber,
})
}

hostZoneUnbonding := recordstypes.HostZoneUnbonding{
HostZoneId: tc.chainId,
Status: tc.status,
StTokenAmount: sdkmath.NewInt(tc.stTokenAmount),
NativeTokenAmount: sdkmath.NewInt(tc.nativeTokenAmount),
}
err := s.App.RecordsKeeper.SetHostZoneUnbondingRecord(s.Ctx, tc.epochNumber, tc.chainId, hostZoneUnbonding)
s.Require().NoError(err, "no error expected when creating epoch unbonding records")
}

// Call migration function
v24.MigrateEpochUnbondingRecords(s.Ctx, s.App.RecordsKeeper)

// Confirm new fields were added
for _, tc := range recordTestCases {
hostZoneUnbonding, found := s.App.RecordsKeeper.GetHostZoneUnbondingByChainId(s.Ctx, tc.epochNumber, tc.chainId)
s.Require().True(found, "host zone unbonding should have been found for %d and %s", tc.epochNumber, tc.chainId)

s.Require().Equal(tc.expectedStTokensToBurn, hostZoneUnbonding.StTokensToBurn.Int64(),
"%s stTokens to burn", tc.chainId)
s.Require().Equal(tc.expectedNativeTokensToUnbond, hostZoneUnbonding.NativeTokensToUnbond.Int64(),
"%s native to unbond", tc.chainId)
s.Require().Equal(tc.expectedClaimableNativeTokens, hostZoneUnbonding.ClaimableNativeTokens.Int64(),
"%s claimable native", tc.chainId)
s.Require().Equal(tc.expectedUndelegationTxsInProgress, hostZoneUnbonding.UndelegationTxsInProgress,
"%s undelegation txs in progress", tc.chainId)
}
}
Loading
Loading