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

feat(amm): weight recovery reward applied to weight balance bonuses #870

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 23 additions & 2 deletions app/setup_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
m "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
ammtypes "github.com/elys-network/elys/x/amm/types"
)

const (
Expand Down Expand Up @@ -50,9 +51,29 @@ func setUpgradeHandler(app *ElysApp) {
}

// initiate accounted pools
pools := app.AmmKeeper.GetAllPool(ctx)
pools := app.AmmKeeper.GetAllLegacyPool(ctx)
for _, pool := range pools {
err := app.AccountedPoolKeeper.InitiateAccountedPool(ctx, pool)
newPool := ammtypes.Pool{
PoolId: pool.PoolId,
Address: pool.Address,
PoolParams: ammtypes.PoolParams{
SwapFee: pool.PoolParams.SwapFee,
ExitFee: pool.PoolParams.ExitFee,
UseOracle: pool.PoolParams.UseOracle,
WeightBreakingFeeMultiplier: pool.PoolParams.WeightBreakingFeeMultiplier,
WeightBreakingFeeExponent: pool.PoolParams.WeightBreakingFeeExponent,
ExternalLiquidityRatio: pool.PoolParams.ExternalLiquidityRatio,
WeightRecoveryFeePortion: pool.PoolParams.WeightRecoveryFeePortion,
ThresholdWeightDifference: pool.PoolParams.ThresholdWeightDifference,
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: pool.PoolParams.FeeDenom,
},
TotalShares: pool.TotalShares,
PoolAssets: pool.PoolAssets,
TotalWeight: pool.TotalWeight,
RebalanceTreasury: pool.RebalanceTreasury,
}
err := app.AccountedPoolKeeper.InitiateAccountedPool(ctx, newPool)
if err != nil {
panic(err)
}
Expand Down
13 changes: 13 additions & 0 deletions proto/elys/amm/pool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "cosmos_proto/cosmos.proto";

message LegacyPool {
uint64 pool_id = 1;
string address = 2;
LegacyPoolParams pool_params = 3 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin total_shares = 4 [(gogoproto.nullable) = false];
repeated PoolAsset pool_assets = 5 [(gogoproto.nullable) = false];
string total_weight = 6 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string rebalance_treasury = 7;
}

message Pool {
uint64 pool_id = 1;
string address = 2;
Expand Down
39 changes: 38 additions & 1 deletion proto/elys/amm/pool_params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "cosmos_proto/cosmos.proto";

option go_package = "github.com/elys-network/elys/x/amm/types";

message PoolParams {
message LegacyPoolParams {
string swap_fee = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
Expand Down Expand Up @@ -38,3 +38,40 @@ message PoolParams {
];
string fee_denom = 8; // denom for fee collection
}

message PoolParams {
string swap_fee = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string exit_fee = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
bool use_oracle = 3;
string weight_breaking_fee_multiplier = 4 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string weight_breaking_fee_exponent = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string external_liquidity_ratio = 6 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string weight_recovery_fee_portion = 7 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string threshold_weight_difference = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string weight_breaking_fee_portion = 9 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string fee_denom = 10; // denom for fee collection
}
1 change: 1 addition & 0 deletions x/amm/client/cli/query_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func networkWithPoolObjects(t *testing.T, n int) (*network.Network, []types.Pool
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
}
Expand Down
3 changes: 3 additions & 0 deletions x/amm/keeper/msg_server_create_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (suite *KeeperTestSuite) TestMsgServerCreatePool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
poolAssets: []types.PoolAsset{
Expand Down Expand Up @@ -60,6 +61,7 @@ func (suite *KeeperTestSuite) TestMsgServerCreatePool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
poolAssets: []types.PoolAsset{
Expand Down Expand Up @@ -88,6 +90,7 @@ func (suite *KeeperTestSuite) TestMsgServerCreatePool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
poolAssets: []types.PoolAsset{
Expand Down
8 changes: 6 additions & 2 deletions x/amm/keeper/msg_server_exit_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func (suite *KeeperTestSuite) TestMsgServerExitPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareInAmount: types.OneShare.Quo(sdk.NewInt(5)),
Expand All @@ -56,6 +57,7 @@ func (suite *KeeperTestSuite) TestMsgServerExitPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareInAmount: types.OneShare.Quo(sdk.NewInt(5)),
Expand All @@ -76,6 +78,7 @@ func (suite *KeeperTestSuite) TestMsgServerExitPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.NewDecWithPrec(2, 1), // 20%
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareInAmount: types.OneShare.Quo(sdk.NewInt(10)),
Expand All @@ -97,13 +100,14 @@ func (suite *KeeperTestSuite) TestMsgServerExitPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.NewDecWithPrec(2, 1), // 20%
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareInAmount: types.OneShare.Quo(sdk.NewInt(10)),
tokenOutDenom: ptypes.BaseCurrency,
minAmountsOut: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 100000)},
minAmountsOut: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 86881)},
// expSenderBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 99197)}, // slippage enabled
expSenderBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 100000)}, // slippage disabled
expSenderBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 86881)}, // slippage disabled
expPass: true,
},
} {
Expand Down
7 changes: 6 additions & 1 deletion x/amm/keeper/msg_server_join_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (suite *KeeperTestSuite) TestMsgServerJoinPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareOutAmount: types.OneShare.Quo(sdk.NewInt(5)),
Expand All @@ -55,6 +56,7 @@ func (suite *KeeperTestSuite) TestMsgServerJoinPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareOutAmount: types.OneShare.Quo(sdk.NewInt(5)),
Expand All @@ -75,6 +77,7 @@ func (suite *KeeperTestSuite) TestMsgServerJoinPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.NewDecWithPrec(2, 1), // 20%
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
// shareOutAmount: sdk.NewInt(694444166666666666), // weight breaking fee - slippage enable
Expand All @@ -96,10 +99,11 @@ func (suite *KeeperTestSuite) TestMsgServerJoinPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.NewDecWithPrec(2, 1), // 20%
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
// shareOutAmount: sdk.NewInt(805987500000000000), // weight recovery direction - slippage enable
shareOutAmount: sdk.NewInt(1002500000000000000), // weight recovery direction - slippage disable
shareOutAmount: sdk.NewInt(1001000000000000000), // weight recovery direction - slippage disable
expSenderBalance: sdk.Coins{},
expTokenIn: sdk.Coins{sdk.NewInt64Coin("uusdt", 1000000)},
expPass: true,
Expand All @@ -117,6 +121,7 @@ func (suite *KeeperTestSuite) TestMsgServerJoinPool() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.NewDecWithPrec(2, 1), // 20%
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
shareOutAmount: sdk.NewInt(2000000000000000000),
Expand Down
5 changes: 5 additions & 0 deletions x/amm/keeper/msg_server_update_pool_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (suite *KeeperTestSuite) TestMsgServerUpdatePoolParams() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
updatedPoolParams: types.PoolParams{
Expand All @@ -45,6 +46,7 @@ func (suite *KeeperTestSuite) TestMsgServerUpdatePoolParams() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: "feedenom",
},
poolAssets: []types.PoolAsset{
Expand Down Expand Up @@ -73,6 +75,7 @@ func (suite *KeeperTestSuite) TestMsgServerUpdatePoolParams() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
updatedPoolParams: types.PoolParams{
Expand All @@ -84,6 +87,7 @@ func (suite *KeeperTestSuite) TestMsgServerUpdatePoolParams() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
poolAssets: []types.PoolAsset{
Expand Down Expand Up @@ -112,6 +116,7 @@ func (suite *KeeperTestSuite) TestMsgServerUpdatePoolParams() {
ExternalLiquidityRatio: sdk.NewDec(1),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
},
poolAssets: []types.PoolAsset{
Expand Down
16 changes: 16 additions & 0 deletions x/amm/keeper/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ func (k Keeper) GetAllPool(ctx sdk.Context) (list []types.Pool) {
return
}

// GetAllLegacyPool returns all legacy pool
func (k Keeper) GetAllLegacyPool(ctx sdk.Context) (list []types.LegacyPool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PoolKeyPrefix))
iterator := sdk.KVStorePrefixIterator(store, []byte{})

defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
var val types.LegacyPool
k.cdc.MustUnmarshal(iterator.Value(), &val)
list = append(list, val)
}

return
}

// GetLatestPool retrieves the latest pool item from the list of pools
func (k Keeper) GetLatestPool(ctx sdk.Context) (val types.Pool, found bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PoolKeyPrefix))
Expand Down
1 change: 1 addition & 0 deletions x/amm/keeper/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func createNPool(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Pool {
ExternalLiquidityRatio: sdk.ZeroDec(),
WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10%
ThresholdWeightDifference: sdk.ZeroDec(),
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: ptypes.BaseCurrency,
}

Expand Down
36 changes: 36 additions & 0 deletions x/amm/migrations/v5_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package migrations

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/amm/types"
)

func (m Migrator) V5Migration(ctx sdk.Context) error {
pools := m.keeper.GetAllLegacyPool(ctx)
for _, pool := range pools {
newPool := types.Pool{
PoolId: pool.PoolId,
Address: pool.Address,
PoolParams: types.PoolParams{
SwapFee: pool.PoolParams.SwapFee,
ExitFee: pool.PoolParams.ExitFee,
UseOracle: pool.PoolParams.UseOracle,
WeightBreakingFeeMultiplier: pool.PoolParams.WeightBreakingFeeMultiplier,
WeightBreakingFeeExponent: pool.PoolParams.WeightBreakingFeeExponent,
ExternalLiquidityRatio: pool.PoolParams.ExternalLiquidityRatio,
WeightRecoveryFeePortion: pool.PoolParams.WeightRecoveryFeePortion,
ThresholdWeightDifference: pool.PoolParams.ThresholdWeightDifference,
WeightBreakingFeePortion: sdk.NewDecWithPrec(50, 2), // 50%
FeeDenom: pool.PoolParams.FeeDenom,
},
TotalShares: pool.TotalShares,
PoolAssets: pool.PoolAssets,
TotalWeight: pool.TotalWeight,
RebalanceTreasury: pool.RebalanceTreasury,
}

m.keeper.RemovePool(ctx, pool.PoolId)
m.keeper.SetPool(ctx, newPool)
}
return nil
}
4 changes: 2 additions & 2 deletions x/amm/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
m := migrations.NewMigrator(am.keeper)
err := cfg.RegisterMigration(types.ModuleName, 3, m.V4Migration)
err := cfg.RegisterMigration(types.ModuleName, 4, m.V5Migration)
if err != nil {
panic(err)
}
Expand All @@ -144,7 +144,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
}

// ConsensusVersion is a sequence number for state-breaking change of the module. It should be incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty versions, the initial version should be set to 1
func (AppModule) ConsensusVersion() uint64 { return 4 }
func (AppModule) ConsensusVersion() uint64 { return 5 }

// BeginBlock contains the logic that is automatically triggered at the beginning of each block
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
Expand Down
23 changes: 8 additions & 15 deletions x/amm/types/calc_exit_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ func CalcExitPool(

// refundedShares = exitingShares * (1 - exit fee)
// with 0 exit fee optimization
var refundedShares sdk.Dec
refundedShares = sdk.NewDecFromInt(exitingShares)
refundedShares := sdk.NewDecFromInt(exitingShares)

shareOutRatio := refundedShares.QuoInt(totalShares.Amount)
// exitedCoins = shareOutRatio * pool liquidity
Expand Down Expand Up @@ -133,21 +132,15 @@ func CalcExitPool(

weightDistance := pool.WeightDistanceFromTarget(ctx, oracleKeeper, newAssetPools)
distanceDiff := weightDistance.Sub(initialWeightDistance)
weightBreakingFee := sdk.ZeroDec()
if distanceDiff.IsPositive() {
// old weight breaking fee implementation
// weightBreakingFee = pool.PoolParams.WeightBreakingFeeMultiplier.Mul(distanceDiff)

// target weight
targetWeightOut := NormalizedWeight(ctx, pool.PoolAssets, tokenOutDenom)
targetWeightIn := sdk.OneDec().Sub(targetWeightOut)
// target weight
targetWeightOut := NormalizedWeight(ctx, pool.PoolAssets, tokenOutDenom)
targetWeightIn := sdk.OneDec().Sub(targetWeightOut)

// weight breaking fee as in Plasma pool
weightOut := OracleAssetWeight(ctx, oracleKeeper, newAssetPools, tokenOutDenom)
weightIn := sdk.OneDec().Sub(weightOut)

weightBreakingFee = GetWeightBreakingFee(weightIn, weightOut, targetWeightIn, targetWeightOut, pool.PoolParams)
}
// weight breaking fee as in Plasma pool
weightOut := OracleAssetWeight(ctx, oracleKeeper, newAssetPools, tokenOutDenom)
weightIn := sdk.OneDec().Sub(weightOut)
weightBreakingFee := GetWeightBreakingFee(weightIn, weightOut, targetWeightIn, targetWeightOut, pool.PoolParams, distanceDiff)

tokenOutAmount := oracleOutAmount.Mul(sdk.OneDec().Sub(weightBreakingFee)).RoundInt()
return sdk.Coins{sdk.NewCoin(tokenOutDenom, tokenOutAmount)}, weightBreakingFee.Neg(), nil
Expand Down
Loading
Loading