Skip to content

Commit

Permalink
Merge pull request #2686 from Sifchain/feature/symmetry-threshold-master
Browse files Browse the repository at this point in the history
hotfix: symmetry threshold
  • Loading branch information
AustinoBombino authored Apr 27, 2022
2 parents f0ff5cf + ddcf390 commit 70cc6d4
Show file tree
Hide file tree
Showing 17 changed files with 783 additions and 179 deletions.
4 changes: 4 additions & 0 deletions proto/sifnode/clp/v1/querier.proto
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ message ParamsReq {}

message ParamsRes {
Params params = 1;
string symmetry_threshold = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message RewardParamsReq {}
Expand Down
13 changes: 12 additions & 1 deletion proto/sifnode/clp/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ service Msg {
rpc ModifyPmtpRates(MsgModifyPmtpRates) returns (MsgModifyPmtpRatesResponse);
rpc UpdatePmtpParams(MsgUpdatePmtpParams) returns (MsgUpdatePmtpParamsResponse);
rpc UpdateStakingRewardParams(MsgUpdateStakingRewardParams) returns (MsgUpdateStakingRewardParamsResponse);
rpc SetSymmetryThreshold(MsgSetSymmetryThreshold) returns (MsgSetSymmetryThresholdResponse);
}

//message MsgUpdateStakingRewardParams{
Expand Down Expand Up @@ -198,4 +199,14 @@ message MsgAddRewardPeriodRequest {
repeated RewardPeriod reward_periods = 2;
}

message MsgAddRewardPeriodResponse {}
message MsgAddRewardPeriodResponse {}

message MsgSetSymmetryThreshold {
string signer = 1;
string threshold = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message MsgSetSymmetryThresholdResponse {}
1 change: 1 addition & 0 deletions x/clp/client/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
FlagNewPolicy = "newPolicy"
FlagMintParams = "mint-params"
FlagMinter = "minter"
FlagSymmetryThreshold = "threshold"
)

// common flagsets to add to various functions
Expand Down
36 changes: 35 additions & 1 deletion x/clp/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package cli
import (
"encoding/json"
"fmt"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"io/ioutil"
"path/filepath"

minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"

"log"

"github.com/Sifchain/sifnode/x/clp/types"
Expand Down Expand Up @@ -41,6 +42,7 @@ func GetTxCmd() *cobra.Command {
GetCmdModifyPmtpRates(),
GetCmdUpdatePmtpParams(),
GetCmdUpdateStakingRewards(),
GetCmdSetSymmetryThreshold(),
)

return clpTxCmd
Expand Down Expand Up @@ -113,6 +115,38 @@ func GetCmdUpdateRewardParams() *cobra.Command {
return cmd
}

func GetCmdSetSymmetryThreshold() *cobra.Command {
cmd := &cobra.Command{
Use: "set-symmetry-threshold",
Short: "Set symmetry threshold",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
signer := clientCtx.GetFromAddress()
if err != nil {
return err
}
threshold, err := sdk.NewDecFromStr(viper.GetString(FlagSymmetryThreshold))
if err != nil {
return err
}
msg := types.MsgSetSymmetryThreshold{
Signer: signer.String(),
Threshold: threshold,
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
cmd.Flags().String(FlagSymmetryThreshold, "", "")
flags.AddTxFlagsToCmd(cmd)
return cmd
}

func GetCmdCreatePool() *cobra.Command {
cmd := &cobra.Command{
Use: "create-pool --from [key] --symbol [asset-symbol] --nativeAmount [amount] --externalAmount [amount]",
Expand Down
35 changes: 23 additions & 12 deletions x/clp/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ func TestAddLiquidity(t *testing.T) {
require.NotNil(t, res)
msg = clptypes.NewMsgAddLiquidity(signer, asset, sdk.ZeroUint(), addLiquidityAmount)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)
require.EqualError(t, err, "Cannot add liquidity asymmetrically")
require.Nil(t, res)
// Subtracted twice , during create and add
externalCoin = sdk.NewCoin(asset.Symbol, sdk.Int(initialBalance.Sub(addLiquidityAmount).Sub(addLiquidityAmount)))
nativeCoin = sdk.NewCoin(clptypes.NativeSymbol, sdk.Int(initialBalance.Sub(addLiquidityAmount).Sub(sdk.ZeroUint())))
Expand Down Expand Up @@ -155,8 +155,8 @@ func TestAddLiquidity_LargeValue(t *testing.T) {
require.NotNil(t, res)
msg := clptypes.NewMsgAddLiquidity(signer, asset, addLiquidityAmountRowan, addLiquidityAmountCaCoin)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)
require.EqualError(t, err, "Cannot add liquidity asymmetrically")
require.Nil(t, res)
}

func TestRemoveLiquidity(t *testing.T) {
Expand Down Expand Up @@ -194,8 +194,8 @@ func TestRemoveLiquidity(t *testing.T) {
coins := CalculateWithdraw(t, clpKeeper, ctx, asset, signer.String(), wBasis.String(), asymmetry)
msg = clptypes.NewMsgRemoveLiquidity(signer, asset, wBasis, asymmetry)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res)
for _, coin := range coins {
ok := clpKeeper.HasBalance(ctx, signer, coin)
assert.True(t, ok, "")
Expand All @@ -205,8 +205,8 @@ func TestRemoveLiquidity(t *testing.T) {
coins = CalculateWithdraw(t, clpKeeper, ctx, asset, signer.String(), wBasis.String(), asymmetry)
msg = clptypes.NewMsgRemoveLiquidity(signer, asset, wBasis, asymmetry)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res)
for _, coin := range coins {
ok := clpKeeper.HasBalance(ctx, signer, coin)
assert.True(t, ok, "")
Expand All @@ -227,8 +227,8 @@ func TestRemoveLiquidity(t *testing.T) {
coins = CalculateWithdraw(t, clpKeeper, ctx, asset, signer.String(), wBasis.String(), asymmetry)
msg = clptypes.NewMsgRemoveLiquidity(signer, asset, wBasis, asymmetry)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res)
for _, coin := range coins {
ok := clpKeeper.HasBalance(ctx, signer, coin)
assert.True(t, ok, "")
Expand Down Expand Up @@ -256,8 +256,8 @@ func TestRemoveLiquidity(t *testing.T) {

msg = clptypes.NewMsgRemoveLiquidity(newLP, asset, wBasis, asymmetry)
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res, "Can withdraw now as new LP has added liquidity")
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res, "Cannot withdraw now as new LP hasnt added liquidity")
}

func TestSwap(t *testing.T) {
Expand Down Expand Up @@ -352,6 +352,11 @@ func TestDecommisionPool(t *testing.T) {

msgrm := clptypes.NewMsgRemoveLiquidity(signer, asset, sdk.NewInt(5001), sdk.NewInt(1))
res, err = handler(ctx, &msgrm)
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res)

msgrm = clptypes.NewMsgRemoveLiquidity(signer, asset, sdk.NewInt(5001), sdk.NewInt(0))
res, err = handler(ctx, &msgrm)
require.NoError(t, err)
require.NotNil(t, res)

Expand Down Expand Up @@ -468,8 +473,14 @@ func TestUnlockLiquidity(t *testing.T) {

msg = clptypes.NewMsgRemoveLiquidity(signer, asset, wBasis, asymmetry)
res, err = handler(ctx, &msg)
require.EqualError(t, err, "Cannot remove liquidity asymmetrically")
require.Nil(t, res)

msg = clptypes.NewMsgRemoveLiquidity(signer, asset, sdk.NewInt(5001), sdk.NewInt(0))
res, err = handler(ctx, &msg)
require.NoError(t, err)
require.NotNil(t, res)

for _, coin := range coins {
ok := clpKeeper.HasBalance(ctx, signer, coin)
assert.True(t, ok, "")
Expand Down
7 changes: 6 additions & 1 deletion x/clp/keeper/calculations.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func CalculateWithdrawalFromUnits(poolUnits sdk.Uint, nativeAssetBalance string,
// units = ((P (a R + A r))/(2 A R))*slidAdjustment

func CalculatePoolUnits(oldPoolUnits, nativeAssetBalance, externalAssetBalance, nativeAssetAmount,
externalAssetAmount sdk.Uint, normalizationFactor sdk.Dec, adjustExternalToken bool) (sdk.Uint, sdk.Uint, error) {
externalAssetAmount sdk.Uint, normalizationFactor sdk.Dec, adjustExternalToken bool, symmetryThreshold sdk.Dec) (sdk.Uint, sdk.Uint, error) {
nf := sdk.NewUintFromBigInt(normalizationFactor.RoundInt().BigInt())

if adjustExternalToken {
Expand Down Expand Up @@ -281,6 +281,11 @@ func CalculatePoolUnits(oldPoolUnits, nativeAssetBalance, externalAssetBalance,
slipAdjustment = r.Mul(A).Sub(R.Mul(a)).Quo(slipAdjDenominator)
}
slipAdjustment = sdk.NewDec(1).Sub(slipAdjustment)

if sdk.OneDec().Sub(slipAdjustment).GT(symmetryThreshold) {
return sdk.ZeroUint(), sdk.ZeroUint(), types.ErrAsymmetricAdd
}

numerator := P.Mul(a.Mul(R).Add(A.Mul(r)))
denominator := sdk.NewDec(2).Mul(A).Mul(R)
stakeUnits := numerator.Quo(denominator).Mul(slipAdjustment)
Expand Down
6 changes: 4 additions & 2 deletions x/clp/keeper/calculations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ func TestKeeper_CalculatePoolUnits(t *testing.T) {
poolUnits: sdk.ZeroUint(),
lpunits: sdk.ZeroUint(),
},
{
/*{
name: "successful",
oldPoolUnits: sdk.ZeroUint(),
nativeAssetBalance: sdk.NewUint(10000),
Expand All @@ -1084,7 +1084,7 @@ func TestKeeper_CalculatePoolUnits(t *testing.T) {
adjustExternalToken: false,
poolUnits: sdk.ZeroUint(),
lpunits: sdk.ZeroUint(),
},
},*/
}

for _, tc := range testcases {
Expand All @@ -1101,6 +1101,7 @@ func TestKeeper_CalculatePoolUnits(t *testing.T) {
tc.externalAssetAmount,
tc.normalizationFactor,
tc.adjustExternalToken,
sdk.NewDecWithPrec(1, 4),
)
})
return
Expand All @@ -1114,6 +1115,7 @@ func TestKeeper_CalculatePoolUnits(t *testing.T) {
tc.externalAssetAmount,
tc.normalizationFactor,
tc.adjustExternalToken,
sdk.NewDecWithPrec(1, 4),
)

if tc.errString != nil {
Expand Down
3 changes: 2 additions & 1 deletion x/clp/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,9 @@ func (k Querier) GetPmtpParams(c context.Context, _ *types.PmtpParamsReq) (*type
func (k Querier) GetParams(c context.Context, _ *types.ParamsReq) (*types.ParamsRes, error) {
ctx := sdk.UnwrapSDKContext(c)
params := k.Keeper.GetParams(ctx)
threshold := k.Keeper.GetSymmetryThreshold(ctx)

return &types.ParamsRes{Params: &params}, nil
return &types.ParamsRes{Params: &params, SymmetryThreshold: threshold}, nil
}

func (k Querier) GetRewardParams(c context.Context, _ *types.RewardParamsReq) (*types.RewardParamsRes, error) {
Expand Down
18 changes: 18 additions & 0 deletions x/clp/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"fmt"

tokenregistrytypes "github.com/Sifchain/sifnode/x/tokenregistry/types"
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"

Expand Down Expand Up @@ -97,3 +98,20 @@ func (k Keeper) GetNormalizationFactorFromAsset(ctx sdk.Context, asset types.Ass
}
return k.GetNormalizationFactor(registryEntry.Decimals)
}

func (k Keeper) GetSymmetryThreshold(ctx sdk.Context) sdk.Dec {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.SymmetryThresholdPrefix)
if bz == nil {
return sdk.NewDecWithPrec(5, 5)
}
var setThreshold types.MsgSetSymmetryThreshold
k.cdc.MustUnmarshal(bz, &setThreshold)
return setThreshold.Threshold
}

func (k Keeper) SetSymmetryThreshold(ctx sdk.Context, setThreshold *types.MsgSetSymmetryThreshold) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(setThreshold)
store.Set(types.SymmetryThresholdPrefix, bz)
}
27 changes: 25 additions & 2 deletions x/clp/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ type msgServer struct {
Keeper
}

func (k msgServer) SetSymmetryThreshold(goCtx context.Context, threshold *types.MsgSetSymmetryThreshold) (*types.MsgSetSymmetryThresholdResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
signer, err := sdk.AccAddressFromBech32(threshold.Signer)
if err != nil {
return nil, err
}
if !k.tokenRegistryKeeper.IsAdminAccount(ctx, tokenregistrytypes.AdminType_CLPDEX, signer) {
return nil, errors.Wrap(types.ErrNotEnoughPermissions, fmt.Sprintf("Sending Account : %s", threshold.Signer))
}

k.Keeper.SetSymmetryThreshold(sdk.UnwrapSDKContext(goCtx), threshold)

return &types.MsgSetSymmetryThresholdResponse{}, nil
}

func (k msgServer) UpdateStakingRewardParams(goCtx context.Context, msg *types.MsgUpdateStakingRewardParams) (*types.MsgUpdateStakingRewardParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
signer, err := sdk.AccAddressFromBech32(msg.Signer)
Expand Down Expand Up @@ -469,6 +484,10 @@ func (k msgServer) RemoveLiquidity(goCtx context.Context, msg *types.MsgRemoveLi
params := k.GetRewardsParams(ctx)
k.PruneUnlockRecords(ctx, &lp, params.LiquidityRemovalLockPeriod, params.LiquidityRemovalCancelPeriod)

if !msg.Asymmetry.IsZero() {
return nil, types.ErrAsymmetricRemove
}

//Calculate amount to withdraw
withdrawNativeAssetAmount, withdrawExternalAssetAmount, lpUnitsLeft, swapAmount := CalculateWithdrawal(pool.PoolUnits,
pool.NativeAssetBalance.String(), pool.ExternalAssetBalance.String(), lp.LiquidityProviderUnits.String(),
Expand Down Expand Up @@ -666,7 +685,9 @@ func (k msgServer) CreatePool(goCtx context.Context, msg *types.MsgCreatePool) (
nativeBalance := msg.NativeAssetAmount
externalBalance := msg.ExternalAssetAmount
normalizationFactor, adjustExternalToken := k.GetNormalizationFactor(eAsset.Decimals)
poolUnits, lpunits, err := CalculatePoolUnits(sdk.ZeroUint(), sdk.ZeroUint(), sdk.ZeroUint(), nativeBalance, externalBalance, normalizationFactor, adjustExternalToken)
symmetryThreshold := k.GetSymmetryThreshold(ctx)
poolUnits, lpunits, err := CalculatePoolUnits(sdk.ZeroUint(), sdk.ZeroUint(), sdk.ZeroUint(),
nativeBalance, externalBalance, normalizationFactor, adjustExternalToken, symmetryThreshold)
if err != nil {
return nil, sdkerrors.Wrap(types.ErrUnableToCreatePool, err.Error())
}
Expand Down Expand Up @@ -716,14 +737,16 @@ func (k msgServer) AddLiquidity(goCtx context.Context, msg *types.MsgAddLiquidit
return nil, types.ErrPoolDoesNotExist
}
normalizationFactor, adjustExternalToken := k.GetNormalizationFactor(eAsset.Decimals)
symmetryThreshold := k.GetSymmetryThreshold(ctx)
newPoolUnits, lpUnits, err := CalculatePoolUnits(
pool.PoolUnits,
pool.NativeAssetBalance,
pool.ExternalAssetBalance,
msg.NativeAssetAmount,
msg.ExternalAssetAmount,
normalizationFactor,
adjustExternalToken)
adjustExternalToken,
symmetryThreshold)
if err != nil {
return nil, err
}
Expand Down
2 changes: 2 additions & 0 deletions x/clp/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ func TestMsgServer_RemoveLiquidity(t *testing.T) {
WBasisPoints: sdk.NewInt(1),
Asymmetry: sdk.NewInt(1),
},
err: types.ErrAsymmetricRemove,
},
{
name: "received amount below expected",
Expand All @@ -566,6 +567,7 @@ func TestMsgServer_RemoveLiquidity(t *testing.T) {
WBasisPoints: sdk.NewInt(1),
Asymmetry: sdk.NewInt(1),
},
err: types.ErrAsymmetricRemove,
},
}

Expand Down
2 changes: 2 additions & 0 deletions x/clp/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ var (
ErrAmountTooLow = sdkerrors.Register(ModuleName, 32, "Tx amount is too low")
ErrNotEnoughPermissions = sdkerrors.Register(ModuleName, 33, "Signer does not have permissions to execute this action")
ErrCannotStartPolicy = sdkerrors.Register(ModuleName, 34, "A new policy can be started only after the current policy has ended")
ErrAsymmetricAdd = sdkerrors.Register(ModuleName, 35, "Cannot add liquidity asymmetrically")
ErrAsymmetricRemove = sdkerrors.Register(ModuleName, 36, "Cannot remove liquidity asymmetrically")
)
1 change: 1 addition & 0 deletions x/clp/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
PmtpEpochPrefix = []byte{0x04} // Key to store the Epoch
PmtpParamsPrefix = []byte{0x05} // Key to store the Pmtp params
RewardParamPrefix = []byte{0x06}
SymmetryThresholdPrefix = []byte{0x07}
)

// Generates a key for storing a specific pool
Expand Down
Loading

0 comments on commit 70cc6d4

Please sign in to comment.