Skip to content

Commit

Permalink
migrate stXXX/XXX constant product pool -> stableswap pool (backport #…
Browse files Browse the repository at this point in the history
…4384) (#4410)

Co-authored-by: Roman <[email protected]>
  • Loading branch information
mergify[bot] and p0mvn authored Feb 23, 2023
1 parent 54fa74d commit 3831121
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Misc Improvements
* [#4131](https://github.com/osmosis-labs/osmosis/pull/4141) Add GatherValuesFromStorePrefixWithKeyParser function to osmoutils.
* [#4388](https://github.com/osmosis-labs/osmosis/pull/4388) Increase the max allowed contract size for non-proposal contracts to 3MB
* [#4384](https://github.com/osmosis-labs/osmosis/pull/4384) migrate stXXX/XXX constant product pools 833, 817, 810 to stable swap

### API breaks

Expand Down
5 changes: 5 additions & 0 deletions app/upgrades/v15/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import (
// UpgradeName defines the on-chain upgrade name for the Osmosis v15 upgrade.
const UpgradeName = "v15"

// pool ids to migrate
const stOSMO_OSMOPoolId = 833
const stJUNO_JUNOPoolId = 817
const stSTARS_STARSPoolId = 810

var Upgrade = upgrades.Upgrade{
UpgradeName: UpgradeName,
CreateUpgradeHandler: CreateUpgradeHandler,
Expand Down
8 changes: 7 additions & 1 deletion app/upgrades/v15/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
ibcratelimit "github.com/osmosis-labs/osmosis/v14/x/ibc-rate-limit"
icqkeeper "github.com/strangelove-ventures/async-icq/v4/keeper"

ibcratelimit "github.com/osmosis-labs/osmosis/v14/x/ibc-rate-limit"

bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"

gammkeeper "github.com/osmosis-labs/osmosis/v14/x/gamm/keeper"
"github.com/osmosis-labs/osmosis/v14/x/poolmanager"
poolmanagerkeeper "github.com/osmosis-labs/osmosis/v14/x/poolmanager"
)

Expand All @@ -25,6 +27,10 @@ func SetICQParams(ctx sdk.Context, icqKeeper *icqkeeper.Keeper) {
setICQParams(ctx, icqKeeper)
}

func MigrateBalancerPoolToSolidlyStable(ctx sdk.Context, gammKeeper *gammkeeper.Keeper, poolmanagerKeeper *poolmanager.Keeper, bankKeeper bankkeeper.Keeper, poolId uint64) {
migrateBalancerPoolToSolidlyStable(ctx, gammKeeper, poolmanagerKeeper, bankKeeper, poolId)
}

func SetRateLimits(ctx sdk.Context, accountKeeper *authkeeper.AccountKeeper, rateLimitingICS4Wrapper *ibcratelimit.ICS4Wrapper, wasmKeeper *wasmkeeper.Keeper) {
setRateLimits(ctx, accountKeeper, rateLimitingICS4Wrapper, wasmKeeper)
}
101 changes: 99 additions & 2 deletions app/upgrades/v15/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,30 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"

"github.com/osmosis-labs/osmosis/osmoutils/osmoassert"
ibcratelimittypes "github.com/osmosis-labs/osmosis/v14/x/ibc-rate-limit/types"

gamm "github.com/osmosis-labs/osmosis/v14/x/gamm/keeper"

"github.com/stretchr/testify/suite"

"github.com/osmosis-labs/osmosis/v14/app/apptesting"
v15 "github.com/osmosis-labs/osmosis/v14/app/upgrades/v15"
gamm "github.com/osmosis-labs/osmosis/v14/x/gamm/keeper"
balancer "github.com/osmosis-labs/osmosis/v14/x/gamm/pool-models/balancer"
balancertypes "github.com/osmosis-labs/osmosis/v14/x/gamm/pool-models/balancer"
poolmanagertypes "github.com/osmosis-labs/osmosis/v14/x/poolmanager/types"
)

type UpgradeTestSuite struct {
apptesting.KeeperTestHelper
}

var DefaultAcctFunds sdk.Coins = sdk.NewCoins(
sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
sdk.NewCoin("foo", sdk.NewInt(10000000)),
sdk.NewCoin("bar", sdk.NewInt(10000000)),
sdk.NewCoin("baz", sdk.NewInt(10000000)),
)

func (suite *UpgradeTestSuite) SetupTest() {
suite.Setup()
}
Expand Down Expand Up @@ -77,6 +87,84 @@ func (suite *UpgradeTestSuite) TestMigrateNextPoolIdAndCreatePool() {
suite.Require().Equal(gammPoolCreationFee, poolmanagerPoolCreationFee)
}

func (suite *UpgradeTestSuite) TestMigrateBalancerToStablePools() {
suite.SetupTest() // reset

ctx := suite.Ctx
gammKeeper := suite.App.GAMMKeeper
poolmanagerKeeper := suite.App.PoolManagerKeeper
// bankKeeper := suite.App.BankKeeper
testAccount := suite.TestAccs[0]

// Mint some assets to the accounts.
suite.FundAcc(testAccount, DefaultAcctFunds)

// Create the balancer pool
swapFee := sdk.MustNewDecFromStr("0.003")
exitFee := sdk.MustNewDecFromStr("0.025")
poolID, err := suite.App.PoolManagerKeeper.CreatePool(
suite.Ctx,
balancer.NewMsgCreateBalancerPool(suite.TestAccs[0],
balancer.PoolParams{
SwapFee: swapFee,
ExitFee: exitFee,
},
[]balancertypes.PoolAsset{
{
Weight: sdk.NewInt(100),
Token: sdk.NewCoin("foo", sdk.NewInt(5000000)),
},
{
Weight: sdk.NewInt(200),
Token: sdk.NewCoin("bar", sdk.NewInt(5000000)),
},
},
""),
)
suite.Require().NoError(err)

// join the pool
shareOutAmount := sdk.NewInt(1_000_000_000_000_000)
tokenInMaxs := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(5000000)), sdk.NewCoin("bar", sdk.NewInt(5000000)))
tokenIn, sharesOut, err := suite.App.GAMMKeeper.JoinPoolNoSwap(suite.Ctx, testAccount, poolID, shareOutAmount, tokenInMaxs)
suite.Require().NoError(err)

// shares before migration
balancerPool, err := gammKeeper.GetPool(suite.Ctx, poolID)
suite.Require().NoError(err)
balancerShares := balancerPool.GetTotalShares()
balancerLiquidity := balancerPool.GetTotalPoolLiquidity(ctx).String()
// check balancer pool liquidity using the bank module
balancerBalances := suite.App.BankKeeper.GetAllBalances(ctx, balancerPool.GetAddress())

// test migrating the balancer pool to a stable pool
v15.MigrateBalancerPoolToSolidlyStable(ctx, gammKeeper, poolmanagerKeeper, suite.App.BankKeeper, poolID)

// check that the pool is now a stable pool
stablepool, err := gammKeeper.GetPool(ctx, poolID)
suite.Require().NoError(err)
suite.Require().Equal(stablepool.GetType(), poolmanagertypes.Stableswap)
// check that the number of stableswap LP shares is the same as the number of balancer LP shares
suite.Require().Equal(balancerShares.String(), stablepool.GetTotalShares().String())
// check that the pool liquidity is the same
suite.Require().Equal(balancerLiquidity, stablepool.GetTotalPoolLiquidity(ctx).String())
// check pool liquidity using the bank module
stableBalances := suite.App.BankKeeper.GetAllBalances(ctx, stablepool.GetAddress())
suite.Require().Equal(balancerBalances, stableBalances)

// exit the pool
exitCoins, err := suite.App.GAMMKeeper.ExitPool(suite.Ctx, testAccount, poolID, sharesOut, sdk.NewCoins())
suite.Require().NoError(err)

suite.validateCons(exitCoins, tokenIn)

// join again
tokenInStable, _, err := suite.App.GAMMKeeper.JoinPoolNoSwap(suite.Ctx, testAccount, poolID, shareOutAmount, tokenInMaxs)
suite.Require().NoError(err)

suite.validateCons(tokenInStable, tokenIn)
}

func (suite *UpgradeTestSuite) TestRegisterOsmoIonMetadata() {
suite.SetupTest() // reset

Expand Down Expand Up @@ -159,3 +247,12 @@ func (suite *UpgradeTestSuite) TestSetRateLimits() {
suite.Require().Greaterf(len(state), 0, "state should not be empty")

}

func (suite *UpgradeTestSuite) validateCons(coinsA, coinsB sdk.Coins) {
suite.Require().Equal(len(coinsA), len(coinsB))
for _, coinA := range coinsA {
coinBAmount := coinsB.AmountOf(coinA.Denom)
// minor tolerance due to fees and rounding
osmoassert.DecApproxEq(suite.T(), coinBAmount.ToDec(), coinA.Amount.ToDec(), sdk.NewDec(2))
}
}
53 changes: 53 additions & 0 deletions app/upgrades/v15/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
appParams "github.com/osmosis-labs/osmosis/v14/app/params"
"github.com/osmosis-labs/osmosis/v14/app/upgrades"
gammkeeper "github.com/osmosis-labs/osmosis/v14/x/gamm/keeper"
"github.com/osmosis-labs/osmosis/v14/x/gamm/pool-models/stableswap"
gammtypes "github.com/osmosis-labs/osmosis/v14/x/gamm/types"
"github.com/osmosis-labs/osmosis/v14/x/poolmanager"
)

Expand Down Expand Up @@ -59,6 +61,10 @@ func CreateUpgradeHandler(
// They are added in this upgrade.
registerOsmoIonMetadata(ctx, keepers.BankKeeper)

// Stride stXXX/XXX pools are being migrated from the standard balancer curve to the
// solidly stable curve.
migrateBalancerPoolsToSolidlyStable(ctx, keepers.GAMMKeeper, keepers.PoolManagerKeeper, keepers.BankKeeper)

setRateLimits(ctx, keepers.AccountKeeper, keepers.RateLimitingICS4Wrapper, keepers.WasmKeeper)

return mm.RunMigrations(ctx, configurator, fromVM)
Expand All @@ -73,6 +79,53 @@ func setICQParams(ctx sdk.Context, icqKeeper *icqkeeper.Keeper) {
icqKeeper.SetParams(ctx, icqparams)
}

func migrateBalancerPoolsToSolidlyStable(ctx sdk.Context, gammKeeper *gammkeeper.Keeper, poolmanagerKeeper *poolmanager.Keeper, bankKeeper bankkeeper.Keeper) {
// migrate stOSMO_OSMOPoolId, stJUNO_JUNOPoolId, stSTARS_STARSPoolId
pools := []uint64{stOSMO_OSMOPoolId, stJUNO_JUNOPoolId, stSTARS_STARSPoolId}
for _, poolId := range pools {
migrateBalancerPoolToSolidlyStable(ctx, gammKeeper, poolmanagerKeeper, bankKeeper, poolId)
}
}

func migrateBalancerPoolToSolidlyStable(ctx sdk.Context, gammKeeper *gammkeeper.Keeper, poolmanagerKeeper *poolmanager.Keeper, bankKeeper bankkeeper.Keeper, poolId uint64) {
// fetch the pool with the given poolId
balancerPool, err := gammKeeper.GetPool(ctx, poolId)
if err != nil {
panic(err)
}

// initialize the stableswap pool
stableswapPool, err := stableswap.NewStableswapPool(
poolId,
stableswap.PoolParams{SwapFee: balancerPool.GetSwapFee(ctx), ExitFee: balancerPool.GetExitFee(ctx)},
balancerPool.GetTotalPoolLiquidity(ctx),
[]uint64{1, 1},
"osmo1k8c2m5cn322akk5wy8lpt87dd2f4yh9afcd7af", // Stride Foundation 2/3 multisig
"",
)
if err != nil {
panic(err)
}

// ensure the number of stableswap LP shares is the same as the number of balancer LP shares
totalShares := sdk.NewCoin(
gammtypes.GetPoolShareDenom(poolId),
balancerPool.GetTotalShares(),
)
stableswapPool.TotalShares = totalShares

balancesBefore := bankKeeper.GetAllBalances(ctx, balancerPool.GetAddress())
// overwrite the balancer pool with the new stableswap pool
err = gammKeeper.OverwritePoolV15MigrationUnsafe(ctx, &stableswapPool)
if err != nil {
panic(err)
}
balancesAfter := bankKeeper.GetAllBalances(ctx, stableswapPool.GetAddress())
if !balancesBefore.IsEqual(balancesAfter) {
panic("balances before and after migration are not equal")
}
}

func setRateLimits(ctx sdk.Context, accountKeeper *authkeeper.AccountKeeper, rateLimitingICS4Wrapper *ibcratelimit.ICS4Wrapper, wasmKeeper *wasmkeeper.Keeper) {
govModule := accountKeeper.GetModuleAddress(govtypes.ModuleName)
contractKeeper := wasmkeeper.NewGovPermissionKeeper(wasmKeeper)
Expand Down
16 changes: 16 additions & 0 deletions tests/e2e/configurer/chain/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ func (n *NodeConfig) SwapExactAmountIn(tokenInCoin, tokenOutMinAmountInt string,
n.LogActionF("successfully swapped")
}

func (n *NodeConfig) JoinPoolExactAmountIn(tokenIn string, poolId uint64, shareOutMinAmount string, from string) {
n.LogActionF("join-swap-extern-amount-in (%s) (%s) from (%s), pool id (%d)", tokenIn, shareOutMinAmount, from, poolId)
cmd := []string{"osmosisd", "tx", "gamm", "join-swap-extern-amount-in", tokenIn, shareOutMinAmount, fmt.Sprintf("--pool-id=%d", poolId), fmt.Sprintf("--from=%s", from)}
_, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd)
require.NoError(n.t, err)
n.LogActionF("successfully joined pool")
}

func (n *NodeConfig) ExitPool(from, minAmountsOut string, poolId uint64, shareAmountIn string) {
n.LogActionF("exiting gamm pool")
cmd := []string{"osmosisd", "tx", "gamm", "exit-pool", fmt.Sprintf("--min-amounts-out=%s", minAmountsOut), fmt.Sprintf("--share-amount-in=%s", shareAmountIn), fmt.Sprintf("--pool-id=%d", poolId), fmt.Sprintf("--from=%s", from)}
_, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd)
require.NoError(n.t, err)
n.LogActionF("successfully exited pool %d, minAmountsOut %s, shareAmountIn %s", poolId, minAmountsOut, shareAmountIn)
}

func (n *NodeConfig) SubmitUpgradeProposal(upgradeVersion string, upgradeHeight int64, initialDeposit sdk.Coin) {
n.LogActionF("submitting upgrade proposal %s for height %d", upgradeVersion, upgradeHeight)
cmd := []string{"osmosisd", "tx", "gov", "submit-proposal", "software-upgrade", upgradeVersion, fmt.Sprintf("--title=\"%s upgrade\"", upgradeVersion), "--description=\"upgrade proposal submission\"", fmt.Sprintf("--upgrade-height=%d", upgradeHeight), "--upgrade-info=\"\"", "--from=val", fmt.Sprintf("--deposit=%s", initialDeposit)}
Expand Down
12 changes: 12 additions & 0 deletions tests/e2e/configurer/chain/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ func (n *NodeConfig) QueryNumPools() uint64 {
return numPools.NumPools
}

func (n *NodeConfig) QueryPoolType(poolId string) string {
path := fmt.Sprintf("/osmosis/gamm/v1beta1/pool_type/%s", poolId)
bz, err := n.QueryGRPCGateway(path)
require.NoError(n.t, err)

var poolTypeResponse gammtypes.QueryPoolTypeResponse
err = util.Cdc.UnmarshalJSON(bz, &poolTypeResponse)
require.NoError(n.t, err)

return poolTypeResponse.PoolType
}

// QueryBalancer returns balances at the address.
func (n *NodeConfig) QueryBalances(address string) (sdk.Coins, error) {
path := fmt.Sprintf("cosmos/bank/v1beta1/balances/%s", address)
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e/configurer/config/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ var (
// creation in case more pools are added to genesis
// in the future
PreUpgradePoolId uint64 = 2

StrideMigrateWallet = "stride-migration"
)
20 changes: 20 additions & 0 deletions tests/e2e/configurer/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,26 @@ func (uc *UpgradeConfigurer) CreatePreUpgradeState() error {
// test lock and add to existing lock for both regular and superfluid lockups (only chainA)
chainA.LockAndAddToExistingLock(sdk.NewInt(1000000000000000000), poolShareDenom, lockupWalletAddrA, lockupWalletSuperfluidAddrA)

// LP to pools 833, 817, 810
// initialize lp wallets
amountOfEachTokenToLP := initialization.DefaultStrideDenomBalance / 1_000_000
shareOutMin := "1"

config.StrideMigrateWallet = chainANode.CreateWalletAndFund(config.StrideMigrateWallet, []string{
fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StOsmoDenom),
fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StJunoDenom),
fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StStarsDenom),
})

tokenInStOsmo := fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StOsmoDenom)
chainANode.JoinPoolExactAmountIn(tokenInStOsmo, initialization.StOSMO_OSMOPoolId, shareOutMin, config.StrideMigrateWallet)

tokenInStJuno := fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StJunoDenom)
chainANode.JoinPoolExactAmountIn(tokenInStJuno, initialization.StJUNO_JUNOPoolId, shareOutMin, config.StrideMigrateWallet)

tokenInStStars := fmt.Sprintf("%d%s", amountOfEachTokenToLP, initialization.StStarsDenom)
chainANode.JoinPoolExactAmountIn(tokenInStStars, initialization.StSTARS_STARSPoolId, shareOutMin, config.StrideMigrateWallet)

return nil
}

Expand Down
28 changes: 22 additions & 6 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (
"time"

transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"

"github.com/iancoleman/orderedmap"

poolmanagertypes "github.com/osmosis-labs/osmosis/v14/x/poolmanager/types"

"github.com/osmosis-labs/osmosis/v14/tests/e2e/configurer/chain"
"github.com/osmosis-labs/osmosis/v14/tests/e2e/util"

Expand Down Expand Up @@ -960,25 +961,40 @@ func (s *IntegrationTestSuite) TestGeometricTWAP() {
// This test is to be re-enabled for upgrade once the upgrade handler logic is added and
// the balancer pool genesis is backported to v14.
func (s *IntegrationTestSuite) TestStridePoolMigration() {
if s.skipUpgrade {
s.T().Log("Skipping migration test when upgrade is disable. This test depends on running v15 upgrade handler.")
}

const (
// Configurations for tests/e2e/scripts/pool1A.json
// This pool gets initialized pre-upgrade.
minAmountOut = "1"
migrationWallet = "stride-migration"
minAmountOut = "1"
shareAmountIn = "1"
)

chainA := s.configurer.GetChainConfig(0)
node, err := chainA.GetDefaultNode()
s.Require().NoError(err)

fundTokens := []string{fmt.Sprintf("1000000%s", initialization.StOsmoDenom), fmt.Sprintf("1000000%s", initialization.StJunoDenom), fmt.Sprintf("1000000%s", initialization.StStarsDenom)}
for _, token := range fundTokens {
node.BankSend(token, initialization.ValidatorWalletName, config.StrideMigrateWallet)
}

otherDenoms := []string{initialization.OsmoDenom, initialization.JunoDenom, initialization.StarsDenom}
swapWalletAddr := node.CreateWalletAndFund(migrationWallet, fundTokens)

migrationPools := []uint64{initialization.StOSMO_OSMOPoolId, initialization.StJUNO_JUNOPoolId, initialization.StSTARS_STARSPoolId}

for i, poolId := range migrationPools {
// Swap to make sure that
node.SwapExactAmountIn(fundTokens[i], minAmountOut, fmt.Sprintf("%d", poolId), otherDenoms[i], swapWalletAddr)
// Query and assert to make sure that pool type is stableswap
poolType := node.QueryPoolType(fmt.Sprintf("%d", poolId))
stableswapType := poolmanagertypes.Stableswap.String()
s.Require().Equal(poolType, stableswapType, "Pool type should be stableswap after upgrade")

// Swap to make sure that migrations did not break anything critical.
node.SwapExactAmountIn(fundTokens[i], minAmountOut, fmt.Sprintf("%d", poolId), otherDenoms[i], config.StrideMigrateWallet)

// Exit one share
node.ExitPool(config.StrideMigrateWallet, "", poolId, shareAmountIn)
}
}
6 changes: 6 additions & 0 deletions x/gamm/keeper/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ func (k Keeper) setPool(ctx sdk.Context, pool poolmanagertypes.PoolI) error {
return nil
}

// OverwritePoolV15MigrationUnsafe is a temporary method for calling from the v15 upgrade handler
// for balancer to stableswap pool migration. Do not use for other purposes.
func (k Keeper) OverwritePoolV15MigrationUnsafe(ctx sdk.Context, pool poolmanagertypes.PoolI) error {
return k.setPool(ctx, pool)
}

func (k Keeper) DeletePool(ctx sdk.Context, poolId uint64) error {
store := ctx.KVStore(k.storeKey)
poolKey := types.GetKeyPrefixPools(poolId)
Expand Down

0 comments on commit 3831121

Please sign in to comment.