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

Feature/swap fees #3328

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
31 changes: 25 additions & 6 deletions docs/proposals/min_swap_fees.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ x - input amount
y - output amount
r - current ratio shifting running rate
f - swap fee rate, this must satisfy 0 =< f =< 1
min_fee - minimum fee for a swap
```

### Swapping to Rowan:
Expand Down Expand Up @@ -61,12 +62,24 @@ The fee calculation in equation (1) and (2) becomes:
fee = min(max(f * adjusted_output, min_fee), adjusted_output)
```

Where `min_fee` is a minimum fee parameter for the token being bought, which is set via an admin key. See CLI
section for more details.

The min function is required to ensure that the fee is not greater than the adjusted output.

If a `min-fee` has not been set for a token then it defaults to zero.
### Parameters

The `min_fee` must be in the same denomination as the buy token, in which case a single value for `min_fee` (greater than zero)
cannot be defined across all tokens. Consequently a default `min_fee` of zero must be applied and an admin account
must be able to specify override `min_fee` values for specific tokens. The admin account must
not be able to change the default `min_fee` value since zero is the only reasonable value.

The same `min_fee` must be used when buying a token
regardless of the sell token e.g. it will not be possible to set one `min_fee` for swapping atom to Rowan
and another `min_fee` for swapping usdc to Rowan.

Unlike the `min_fee` it is possible to define a swap fee rate, `f`, which can be applied on all swaps.
The admin account must be able to specify a default swap fee rate and specify override values for specific tokens.
As with the `min_fee` the same swap fee rate must be used regardless of the sell token.

See the CLI section for commands for setting and querying the swap fee params.

## Events

Expand Down Expand Up @@ -94,17 +107,20 @@ sifnoded tx clp set-swap-fee-params \

```json
{
"swap_fee_rate": "0.003",
"default_swap_fee_rate": "0.003",
"token_params": [{
"asset": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
"swap_fee_rate": "0.002",
"min_swap_fee": "12"
},
{
"asset": "cusdc",
"swap_fee_rate": "0.002",
"min_swap_fee": "800"
},
{
"asset": "rowan",
"swap_fee_rate": "0.001",
"min_swap_fee": "12"
}
]
Expand All @@ -119,17 +135,20 @@ sifnoded q clp swap-fee-params --output json

```json
{
"swap_fee_rate": "0.003000000000000000",
"default_swap_fee_rate": "0.003",
"token_params": [{
"asset": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
"swap_fee_rate": "0.002",
"min_swap_fee": "12"
},
{
"asset": "cusdc",
"swap_fee_rate": "0.002",
"min_swap_fee": "800"
},
{
"asset": "rowan",
"swap_fee_rate": "0.001",
"min_swap_fee": "12"
}
]
Expand Down
52 changes: 41 additions & 11 deletions docs/tutorials/min_swap_fees.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Minimum swap fees

This tutorial demonstrates the behaviour of the min swap fee functionality
This tutorial demonstrates the behaviour of the min swap fee functionality.

1. Start and run the chain:

Expand Down Expand Up @@ -75,7 +75,7 @@ sifnoded q clp swap-fee-params --output json | jq

```json
{
"swap_fee_rate": "0.003000000000000000",
"default_swap_fee_rate": "0.003000000000000000",
"token_params": []
}
```
Expand All @@ -91,43 +91,47 @@ sifnoded tx clp set-swap-fee-params \
--fees 100000000000000000rowan \
-y \
--path <( echo '{
"swap_fee_rate": "0.003",
"default_swap_fee_rate": "0.003",
"token_params": [{
"asset": "ceth",
"swap_fee_rate": "0.004",
"min_swap_fee": "0"
},
{
"asset": "rowan",
"swap_fee_rate": "0.002",
"min_swap_fee": "600000000000"
}
]
}' )
```


4. Check swap fee params have been updated:
6. Check swap fee params have been updated:

```bash
sifnoded q clp swap-fee-params --output json | jq
```

```json
{
"swap_fee_rate": "0.003000000000000000",
"default_swap_fee_rate": "0.003000000000000000",
"token_params": [
{
"asset": "ceth",
"min_swap_fee": "0"
"min_swap_fee": "0",
"swap_fee_rate": "0.004000000000000000"
},
{
"asset": "rowan",
"min_swap_fee": "600000000000"
"min_swap_fee": "600000000000",
"swap_fee_rate": "0.002000000000000000"
}
]
}
```

6. Do a swap:
7. Do a swap:

```bash
sifnoded tx clp swap \
Expand Down Expand Up @@ -164,11 +168,37 @@ adjusted_output = x * Y / ((x + X)(1 + r))
= 199980001999800

fee = min(max(f * adjusted_output, min_swap_fee), adjusted_output)
= min(max(0.003 * 199980001999800, 600000000000), adjusted_output)
= min(max(599940005999, 600000000000), 199980001999800)
= 600000000000
= min(max(0.002 * 199980001999800, 600000000000), adjusted_output)
= min(max(399960003999, 600000000000), 199980001999800)
= 600000000000

y = adjusted_amount - fee
= 199980001999800 - 600000000000
= 199380001999800
```

8. Confirm that setting swap fee rate greater than one fails:

```bash
sifnoded tx clp set-swap-fee-params \
--from sif \
--keyring-backend test \
--chain-id localnet \
--broadcast-mode block \
--fees 100000000000000000rowan \
-y \
--path <( echo '{
"default_swap_fee_rate": "0.003",
"token_params": [{
"asset": "ceth",
"swap_fee_rate": "1.2",
"min_swap_fee": "0"
},
{
"asset": "rowan",
"swap_fee_rate": "0.002",
"min_swap_fee": "600000000000"
}
]
}' )
```
6 changes: 5 additions & 1 deletion proto/sifnode/clp/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ message ProviderDistributionParams {
}

message SwapFeeParams {
string swap_fee_rate = 1 [
string default_swap_fee_rate = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
Expand All @@ -110,4 +110,8 @@ message SwapFeeTokenParams {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint",
(gogoproto.nullable) = false
];
string swap_fee_rate = 3 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
2 changes: 1 addition & 1 deletion proto/sifnode/clp/v1/querier.proto
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ message ProviderDistributionParamsRes {
message SwapFeeParamsReq {}

message SwapFeeParamsRes {
string swap_fee_rate = 1 [
string default_swap_fee_rate = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
Expand Down
2 changes: 1 addition & 1 deletion proto/sifnode/clp/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ message MsgAddProviderDistributionPeriodResponse {}

message MsgUpdateSwapFeeParamsRequest {
string signer = 1 [ (gogoproto.moretags) = "yaml:\"signer\"" ];
string swap_fee_rate = 2 [
string default_swap_fee_rate = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
Expand Down
6 changes: 3 additions & 3 deletions x/clp/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ func GetCmdSetSwapFeeParams() *cobra.Command {
return err
}
msg := types.MsgUpdateSwapFeeParamsRequest{
Signer: signer.String(),
SwapFeeRate: swapFeeParams.SwapFeeRate,
TokenParams: swapFeeParams.TokenParams,
Signer: signer.String(),
DefaultSwapFeeRate: swapFeeParams.DefaultSwapFeeRate,
TokenParams: swapFeeParams.TokenParams,
}
if err := msg.ValidateBasic(); err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions x/clp/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func CalculateWithdraw(t *testing.T, keeper clpkeeper.Keeper, ctx sdk.Context, a
ctx, app := test.CreateTestAppClp(false)
registry := app.TokenRegistryKeeper.GetRegistry(ctx)
_, err = app.TokenRegistryKeeper.GetEntry(registry, pool.ExternalAsset.Symbol)
swapFeeParams := clptypes.SwapFeeParams{SwapFeeRate: sdk.NewDecWithPrec(3, 3)}
swapFeeParams := clptypes.SwapFeeParams{DefaultSwapFeeRate: sdk.NewDecWithPrec(3, 3)}
assert.NoError(t, err)
if asymmetry.IsPositive() {
swapResult, _, _, _, err := clpkeeper.SwapOne(clptypes.GetSettlementAsset(), swapAmount, asset, pool, sdk.OneDec(), swapFeeParams)
Expand All @@ -418,7 +418,7 @@ func CalculateWithdraw(t *testing.T, keeper clpkeeper.Keeper, ctx sdk.Context, a
}

func CalculateSwapReceived(t *testing.T, keeper clpkeeper.Keeper, tokenRegistryKeeper tokenregistrytypes.Keeper, ctx sdk.Context, assetSent clptypes.Asset, assetReceived clptypes.Asset, swapAmount sdk.Uint) sdk.Uint {
swapFeeParams := clptypes.SwapFeeParams{SwapFeeRate: sdk.NewDecWithPrec(3, 3)}
swapFeeParams := clptypes.SwapFeeParams{DefaultSwapFeeRate: sdk.NewDecWithPrec(3, 3)}
inPool, err := keeper.GetPool(ctx, assetSent.Symbol)
assert.NoError(t, err)
outPool, err := keeper.GetPool(ctx, assetReceived.Symbol)
Expand Down
13 changes: 7 additions & 6 deletions x/clp/keeper/calculations.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,13 +415,13 @@ func CalculateWithdrawalRowanValue(
pool types.Pool,
pmtpCurrentRunningRate sdk.Dec, swapFeeParams types.SwapFeeParams) sdk.Uint {

minSwapFee := GetMinSwapFee(to, swapFeeParams.TokenParams)
swapFeeRate, minSwapFee := GetAssetSwapFeeParams(to, &swapFeeParams)

X, Y, toRowan := pool.ExtractValues(to)

X, Y = pool.ExtractDebt(X, Y, toRowan)

value, _ := CalcSwapResult(toRowan, X, sentAmount, Y, pmtpCurrentRunningRate, swapFeeParams.SwapFeeRate, minSwapFee)
value, _ := CalcSwapResult(toRowan, X, sentAmount, Y, pmtpCurrentRunningRate, swapFeeRate, minSwapFee)

return value
}
Expand All @@ -432,7 +432,7 @@ func SwapOne(from types.Asset,
pool types.Pool,
pmtpCurrentRunningRate sdk.Dec, swapFeeParams types.SwapFeeParams) (sdk.Uint, sdk.Uint, sdk.Uint, types.Pool, error) {

minSwapFee := GetMinSwapFee(to, swapFeeParams.TokenParams)
swapFeeRate, minSwapFee := GetAssetSwapFeeParams(to, &swapFeeParams)

X, Y, toRowan := pool.ExtractValues(to)

Expand All @@ -441,7 +441,7 @@ func SwapOne(from types.Asset,
Xincl, Yincl = pool.ExtractDebt(X, Y, toRowan)

priceImpact := calcPriceImpact(Xincl, sentAmount)
swapResult, liquidityFee := CalcSwapResult(toRowan, Xincl, sentAmount, Yincl, pmtpCurrentRunningRate, swapFeeParams.SwapFeeRate, minSwapFee)
swapResult, liquidityFee := CalcSwapResult(toRowan, Xincl, sentAmount, Yincl, pmtpCurrentRunningRate, swapFeeRate, minSwapFee)

// NOTE: impossible... pre-pmtp at least
if swapResult.GTE(Y) {
Expand All @@ -457,13 +457,14 @@ func GetSwapFee(sentAmount sdk.Uint,
to types.Asset,
pool types.Pool,
pmtpCurrentRunningRate sdk.Dec, swapFeeParams types.SwapFeeParams) sdk.Uint {
minSwapFee := GetMinSwapFee(to, swapFeeParams.TokenParams)

swapFeeRate, minSwapFee := GetAssetSwapFeeParams(to, &swapFeeParams)

X, Y, toRowan := pool.ExtractValues(to)

X, Y = pool.ExtractDebt(X, Y, toRowan)

swapResult, _ := CalcSwapResult(toRowan, X, sentAmount, Y, pmtpCurrentRunningRate, swapFeeParams.SwapFeeRate, minSwapFee)
swapResult, _ := CalcSwapResult(toRowan, X, sentAmount, Y, pmtpCurrentRunningRate, swapFeeRate, minSwapFee)

if swapResult.GTE(Y) {
return sdk.ZeroUint()
Expand Down
Loading