diff --git a/migrate/v0_15/bep3.go b/migrate/v0_15/bep3.go new file mode 100644 index 00000000..db75700f --- /dev/null +++ b/migrate/v0_15/bep3.go @@ -0,0 +1,34 @@ +package v0_15 + +import ( + "fmt" + + v0_15bep3 "github.com/kava-labs/kava/x/bep3/types" +) + +// Bep3 resets the swap expire/close heights for a chain starting at height 0. +func Bep3(genesisState v0_15bep3.GenesisState) v0_15bep3.GenesisState { + + var newSwaps v0_15bep3.AtomicSwaps + for _, swap := range genesisState.AtomicSwaps { + + switch status := swap.Status; status { + case v0_15bep3.Completed: + // reset closed block to one so completed swaps are removed from long term storage properly + swap.ClosedBlock = 1 + + case v0_15bep3.Open, v0_15bep3.Expired: + swap.Status = v0_15bep3.Expired // set open swaps to expired so they can be refunded (by tx) after chain start + swap.ExpireHeight = 1 // set expire on first block as well to be safe + + default: + panic(fmt.Sprintf("unknown bep3 swap status '%s'", status)) + } + + newSwaps = append(newSwaps, swap) + } + + genesisState.AtomicSwaps = newSwaps + + return genesisState +} diff --git a/migrate/v0_15/bep3_test.go b/migrate/v0_15/bep3_test.go new file mode 100644 index 00000000..5188bc1f --- /dev/null +++ b/migrate/v0_15/bep3_test.go @@ -0,0 +1,99 @@ +package v0_15 + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/kava-labs/kava/x/bep3" +) + +var ( + exampleExportTime = time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + exampleBep3Params = bep3.NewParams(bep3.AssetParams{ + bep3.NewAssetParam( + "xrpb", + 144, + bep3.SupplyLimit{}, + true, + sdk.AccAddress("testAddress"), + sdk.NewInt(1e4), + sdk.NewInt(1e4), + sdk.NewInt(1e14), + 24686, + 86400, + ), + }) + exampleAssetSupplies = bep3.AssetSupplies{ + bep3.NewAssetSupply( + sdk.NewInt64Coin("xrpb", 1e10), + sdk.NewInt64Coin("xrpb", 1e9), + sdk.NewInt64Coin("xrpb", 1e15), + sdk.NewInt64Coin("xrpb", 0), + 0, + ), + } + exampleBep3GenState = bep3.NewGenesisState( + exampleBep3Params, + bep3.AtomicSwaps{}, + exampleAssetSupplies, + exampleExportTime, + ) +) + +func exampleBep3Swap(expireHeight uint64, closeHeight int64, status bep3.SwapStatus) bep3.AtomicSwap { + return bep3.NewAtomicSwap( + sdk.NewCoins(sdk.NewInt64Coin("xrpb", 1e10)), + []byte("random number hash"), + expireHeight, + exampleExportTime.Unix(), + sdk.AccAddress("sender address"), + sdk.AccAddress("recipient address"), + "sender other chain address", + "recipient other chain address", + closeHeight, + status, + true, + bep3.Outgoing, + ) +} + +func TestBep3_SwapHeightsAreReset(t *testing.T) { + + oldState := bep3.NewGenesisState( + exampleBep3Params, + bep3.AtomicSwaps{ + exampleBep3Swap(7e5, 6e5, bep3.Open), + exampleBep3Swap(4e5, 3e5, bep3.Expired), + exampleBep3Swap(2e5, 1e5, bep3.Completed), + }, + exampleAssetSupplies, + exampleExportTime, + ) + + newState := Bep3(oldState) + + expectedSwaps := bep3.AtomicSwaps{ + exampleBep3Swap(1, 6e5, bep3.Expired), + exampleBep3Swap(1, 3e5, bep3.Expired), + exampleBep3Swap(2e5, 1, bep3.Completed), + } + + require.Equal(t, expectedSwaps, newState.AtomicSwaps) +} + +func TestBep3_OnlySwapHeightsModified(t *testing.T) { + + oldState := bep3.NewGenesisState( + exampleBep3Params, + nil, + exampleAssetSupplies, + exampleExportTime, + ) + + newState := Bep3(oldState) + + require.Equal(t, oldState, newState) +} diff --git a/migrate/v0_15/migrate.go b/migrate/v0_15/migrate.go index 24693360..3adb7596 100644 --- a/migrate/v0_15/migrate.go +++ b/migrate/v0_15/migrate.go @@ -15,6 +15,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/kava-labs/kava/app" + v0_15bep3 "github.com/kava-labs/kava/x/bep3/types" v0_15cdp "github.com/kava-labs/kava/x/cdp/types" v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" v0_15committee "github.com/kava-labs/kava/x/committee/types" @@ -27,7 +28,6 @@ import ( ) var ( - // TODO: update GenesisTime and chain-id for kava-8 launch GenesisTime = time.Date(2021, 8, 30, 15, 0, 0, 0, time.UTC) ChainID = "kava-8" SwpDelegatorRewardsPerSecond = sdk.NewCoin("swp", sdk.NewInt(198186)) @@ -114,6 +114,16 @@ func MigrateAppState(v0_14AppState genutil.AppMap) { v0_14AppState[v0_15committee.ModuleName] = v0_15Codec.MustMarshalJSON(Committee(committeeGS)) } + // Migrate bep3 app state + if v0_14AppState[v0_15bep3.ModuleName] != nil { + // Unmarshal genesis state and delete it. The genesis format was not changed between v0.14 and v0.15. + var bep3GenState v0_15bep3.GenesisState + v0_14Codec.MustUnmarshalJSON(v0_14AppState[v0_15bep3.ModuleName], &bep3GenState) + delete(v0_14AppState, v0_15bep3.ModuleName) + + v0_14AppState[v0_15bep3.ModuleName] = v0_15Codec.MustMarshalJSON(Bep3(bep3GenState)) + } + v0_14AppState[v0_15swap.ModuleName] = v0_15Codec.MustMarshalJSON(Swap()) } @@ -127,6 +137,7 @@ func makeV014Codec() *codec.Codec { v0_14validator_vesting.RegisterCodec(cdc) v0_14committee.RegisterCodec(cdc) v0_14incentive.RegisterCodec(cdc) + // TODO bep3? return cdc } diff --git a/migrate/v0_15/migrate_test.go b/migrate/v0_15/migrate_test.go index f328243d..6fbe7822 100644 --- a/migrate/v0_15/migrate_test.go +++ b/migrate/v0_15/migrate_test.go @@ -19,6 +19,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/kava-labs/kava/app" + v0_15bep3 "github.com/kava-labs/kava/x/bep3/types" v0_15cdp "github.com/kava-labs/kava/x/cdp/types" v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" v0_15committee "github.com/kava-labs/kava/x/committee/types" @@ -728,3 +729,45 @@ func TestAuth_SwpSupply_SpendableCoins(t *testing.T) { require.True(t, foundEcosystem) } + +func TestBep3_Full(t *testing.T) { + t.Skip() // skip to avoid having to commit a large genesis file to the repo + + genDoc, err := tmtypes.GenesisDocFromFile(filepath.Join("testdata", "genesis.json")) + require.NoError(t, err) + + cdc := makeV014Codec() + + var oldState genutil.AppMap + cdc.MustUnmarshalJSON(genDoc.AppState, &oldState) + + var oldGenState v0_15bep3.GenesisState + cdc.MustUnmarshalJSON(oldState[v0_15bep3.ModuleName], &oldGenState) + + newGenState := Bep3(oldGenState) + + require.NoError(t, newGenState.Validate()) + + require.Equal(t, oldGenState.Params, newGenState.Params) + require.Equal(t, oldGenState.Supplies, newGenState.Supplies) + require.Equal(t, oldGenState.PreviousBlockTime, newGenState.PreviousBlockTime) + + require.Equal(t, len(oldGenState.AtomicSwaps), len(newGenState.AtomicSwaps)) + + for i, swap := range oldGenState.AtomicSwaps { + newSwap := newGenState.AtomicSwaps[i] + + require.Equal(t, swap.Amount, newSwap.Amount) + require.Equal(t, swap.GetSwapID(), newSwap.GetSwapID()) + + // check heights were reset + switch newSwap.Status { + case v0_15bep3.Completed: + require.Equal(t, int64(1), newSwap.ClosedBlock) + case v0_15bep3.Expired: + require.Equal(t, uint64(1), newSwap.ExpireHeight) + default: + t.Fatalf(fmt.Sprintf("found swap with unexpected state '%s'", newSwap.Status)) + } + } +}