Skip to content
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
237 changes: 237 additions & 0 deletions pkg/liquidity-source/fluid/dex-v2/compute_swap_step.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
package dexv2

import (
"github.com/KyberNetwork/uniswapv3-sdk-uint256/utils"
"github.com/samber/lo"
)

func computeSwapStepForSwapInWithoutFee(
sqrtRatioCurrentX96,
sqrtRatioTargetX96 *utils.Uint160,
liquidity *utils.Uint128,
amountRemaining *utils.Int256,

sqrtRatioNextX96 *utils.Uint160, amountIn, amountOut, feeAmount *utils.Uint256,
) error {
return utils.ComputeSwapStep(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, amountRemaining,
0, // set fee to 0
sqrtRatioNextX96, amountIn, amountOut, feeAmount)
}

func computeSwapStepForSwapInWithDynamicFee(
zeroToOne bool,
sqrtRatioCurrentX96,
sqrtRatioTargetX96 *utils.Uint160,
liquidity *utils.Uint128,
amountRemaining *utils.Int256,

d DynamicFeeVariablesUI,
protocolFee *utils.Uint128,

sqrtPriceNextX96 *utils.Uint160, amountIn, amountOut, feeAmount, protocolFeeAmount, lpFeeAmount *utils.Uint256,
) error {
sqrtPriceNextX96.Set(sqrtRatioCurrentX96)
var priceNextX96 utils.Uint256
err := utils.MulDivV2(sqrtPriceNextX96, sqrtPriceNextX96, Q96I, &priceNextX96, nil)
if err != nil {
return err
}

if lo.Ternary(
zeroToOne,
priceNextX96.Cmp(d.minFeeKinkPriceX96) > 0,
priceNextX96.Cmp(d.minFeeKinkPriceX96) < 0,
) {
err := computeSwapStepForSwapInWithoutFee(
sqrtRatioCurrentX96,
calculateStepTargetSqrtPriceX96(zeroToOne, d.minFeeKinkPriceX96, sqrtRatioTargetX96),
liquidity,
amountRemaining,
sqrtPriceNextX96,
amountIn,
amountOut,
feeAmount,
)
if err != nil {
return err
}

var amountInSigned utils.Int256
err = utils.ToInt256(amountIn, &amountInSigned)
if err != nil {
return err
}

amountRemaining.Sub(amountRemaining, &amountInSigned)
if amountOut.Cmp(X86UI) > 0 {
return ErrGreaterThanMaxAmountOut
}

var stepProtocolFee utils.Uint256
stepProtocolFee.Mul(amountOut, protocolFee).
Div(&stepProtocolFee, SIX_DECIMALS_UI)
protocolFeeAmount.Add(protocolFeeAmount, &stepProtocolFee)

amountOut.Sub(amountOut, &stepProtocolFee)

var stepLpFee utils.Uint256
stepLpFee.Mul(amountOut, d.minFee).
Div(&stepLpFee, SIX_DECIMALS_UI)
lpFeeAmount.Add(lpFeeAmount, &stepLpFee)

amountOut.Sub(amountOut, &stepLpFee)

if sqrtPriceNextX96.Cmp(sqrtRatioTargetX96) == 0 || amountRemaining.Sign() == 0 {
return nil
}

priceNextX96.Set(d.minFeeKinkPriceX96)
}

if lo.Ternary(
zeroToOne,
priceNextX96.Cmp(d.maxFeeKinkPriceX96) > 0,
priceNextX96.Cmp(d.maxFeeKinkPriceX96) < 0,
) {
var stepAmountIn, stepAmountOut utils.Uint256

err := computeSwapStepForSwapInWithoutFee(
sqrtPriceNextX96,
calculateStepTargetSqrtPriceX96(zeroToOne, d.maxFeeKinkPriceX96, sqrtRatioTargetX96),
liquidity,
amountRemaining,
sqrtPriceNextX96,
&stepAmountIn,
&stepAmountOut,
feeAmount,
)
if err != nil {
return err
}

var stepAmountInSigned utils.Int256
err = utils.ToInt256(amountIn, &stepAmountInSigned)
if err != nil {
return err
}

amountRemaining.Sub(amountRemaining, &stepAmountInSigned)

var stepDynamicFee, priceEndX96 utils.Uint256
err = utils.MulDivV2(sqrtPriceNextX96, sqrtPriceNextX96, Q96I, &priceEndX96, nil)
if err != nil {
return err
}

calculateStepDynamicFee(
zeroToOne,
&priceNextX96,
&priceEndX96,
d.zeroPriceImpactPriceX96,
d.priceImpactToFeeDivisionFactor,
&stepDynamicFee,
)

if stepAmountOut.Cmp(X86UI) > 0 {
return ErrGreaterThanMaxAmountOut
}

var stepProtocolFee utils.Uint256
stepProtocolFee.Mul(&stepAmountOut, protocolFee).
Div(&stepProtocolFee, SIX_DECIMALS_UI)
stepAmountOut.Sub(&stepAmountOut, &stepProtocolFee)

var stepLpFee utils.Uint256
stepLpFee.Mul(&stepAmountOut, &stepDynamicFee).
Div(&stepLpFee, SIX_DECIMALS_UI)
stepAmountOut.Sub(&stepAmountOut, &stepLpFee)

amountOut.Add(amountOut, &stepAmountOut)
amountIn.Add(amountIn, &stepAmountIn)
protocolFeeAmount.Add(protocolFeeAmount, &stepProtocolFee)
lpFeeAmount.Add(lpFeeAmount, &stepLpFee)

if sqrtPriceNextX96.Cmp(sqrtRatioTargetX96) == 0 || amountRemaining.Sign() == 0 {
return nil
}
}

var stepAmountIn, stepAmountOut utils.Uint256

err = computeSwapStepForSwapInWithoutFee(
sqrtPriceNextX96,
sqrtRatioTargetX96,
liquidity,
amountRemaining,
sqrtPriceNextX96,
&stepAmountIn,
&stepAmountOut,
feeAmount,
)
if err != nil {
return err
}

if stepAmountOut.Cmp(X86UI) > 0 {
return ErrGreaterThanMaxAmountOut
}

var stepProtocolFee utils.Uint256
stepProtocolFee.Mul(&stepAmountOut, protocolFee).
Div(&stepProtocolFee, SIX_DECIMALS_UI)
stepAmountOut.Sub(&stepAmountOut, &stepProtocolFee)

var stepLpFee utils.Uint256
stepLpFee.Mul(&stepAmountOut, d.maxFee).
Div(&stepLpFee, SIX_DECIMALS_UI)
stepAmountOut.Sub(&stepAmountOut, &stepLpFee)

amountOut.Add(amountOut, &stepAmountOut)
amountIn.Add(amountIn, &stepAmountIn)
protocolFeeAmount.Add(protocolFeeAmount, &stepProtocolFee)
lpFeeAmount.Add(lpFeeAmount, &stepLpFee)

return nil
}

func calculateStepTargetSqrtPriceX96(
zeroToOne bool,
sqrtPriceKinkX96 *utils.Uint256,
sqrtPriceTargetX96 *utils.Uint256,
) *utils.Uint256 {
if zeroToOne {
if sqrtPriceKinkX96.Cmp(sqrtPriceTargetX96) < 0 {
return sqrtPriceTargetX96
}
return sqrtPriceKinkX96
}

if sqrtPriceKinkX96.Cmp(sqrtPriceTargetX96) > 0 {
return sqrtPriceTargetX96
}
return sqrtPriceKinkX96
}

func calculateStepDynamicFee(
zeroToOne bool,
priceStartX96 *utils.Uint256,
priceEndX96 *utils.Uint256,
zeroPriceImpactX96 *utils.Uint256,
priceImpactToFeeDivisionFactor *utils.Uint256,

stepDynamicFee *utils.Uint256,
) {
var stepMeanPriceImpact, priceMeanX96 utils.Uint256

priceMeanX96.Add(priceStartX96, priceEndX96).Rsh(&priceMeanX96, 1)

if zeroToOne {
stepMeanPriceImpact.Sub(zeroPriceImpactX96, &priceMeanX96)
} else {
stepMeanPriceImpact.Sub(&priceMeanX96, zeroPriceImpactX96)
}
stepMeanPriceImpact.Mul(&stepMeanPriceImpact, SIX_DECIMALS_UI).
Div(&stepMeanPriceImpact, zeroPriceImpactX96)

stepDynamicFee.Div(&stepMeanPriceImpact, priceImpactToFeeDivisionFactor)
}
30 changes: 25 additions & 5 deletions pkg/liquidity-source/fluid/dex-v2/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dexv2
import (
"math/big"

"github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/big256"
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber"
)

Expand Down Expand Up @@ -32,10 +33,18 @@ const (
BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219
BITS_EXCHANGE_PRICES_BORROW_RATIO = 234

BITS_DEX_V2_VARIABLES2_PROTOCOL_FEE_0_TO_1 = 0
BITS_DEX_V2_VARIABLES2_PROTOCOL_FEE_1_TO_0 = 12
BITS_DEX_V2_VARIABLES2_POOL_ACCOUNTING_FLAG = 140
BITS_DEX_V2_VARIABLES2_LP_FEE = 156
BITS_DEX_V2_VARIABLES2_PROTOCOL_FEE_0_TO_1 = 0
BITS_DEX_V2_VARIABLES2_PROTOCOL_FEE_1_TO_0 = 12
BITS_DEX_V2_VARIABLES2_POOL_ACCOUNTING_FLAG = 140
BITS_DEX_V2_VARIABLES2_FEE_VERSION = 152
BITS_DEX_V2_VARIABLES2_LP_FEE = 156
BITS_DEX_V2_VARIABLES2_PRICE_IMPACT_TO_FEE_DIVISION_FACTOR = 168
BITS_DEX_V2_VARIABLES2_MIN_FEE = 176
BITS_DEX_V2_VARIABLES2_MAX_FEE = 192
BITS_DEX_V2_VARIABLES2_NET_PRICE_IMPACT_SIGN = 208
BITS_DEX_V2_VARIABLES2_ABSOLUTE_NET_PRICE_IMPACT = 209
BITS_DEX_V2_VARIABLES2_LAST_UPDATE_TIMESTAMP = 229
BITS_DEX_V2_VARIABLES2_DECAY_TIME_REMAINING = 244

BITS_DEX_V2_VARIABLES2_TOKEN_0_DECIMALS = 30
BITS_DEX_V2_VARIABLES2_TOKEN_1_DECIMALS = 34
Expand All @@ -50,26 +59,37 @@ var (
SECONDS_PER_YEAR = big.NewInt(365 * 24 * 60 * 60)

FOUR_DECIMALS = bignumber.TenPowInt(4)
SIX_DECIMALS = bignumber.TenPowInt(6)
TEN_DECIMALS = bignumber.TenPowInt(10)
EXCHANGE_PRICES_PRECISION = bignumber.TenPowInt(12)
TenPow27 = bignumber.TenPowInt(27)
TenPow54 = bignumber.TenPowInt(54)

MIN_PRICE_X96 = bignumber.NewBig("1350587")
MAX_PRICE_X96 = bignumber.NewBig("4647680745692069522618647333321942173198062861119228")

two255 = new(big.Int).Lsh(bignumber.One, 255)
two256 = new(big.Int).Lsh(bignumber.One, 256)

X4 = bignumber.NewBig("0xf")
X8 = bignumber.NewBig("0xff")
X12 = bignumber.NewBig("0xfff")
X14 = bignumber.NewBig("0x3fff")
X15 = bignumber.NewBig("0x7fff")
X16 = bignumber.NewBig("0xffff")
X20 = bignumber.NewBig("0xfffff")
X33 = bignumber.NewBig("0x1ffffffff")
X64 = bignumber.NewBig("0xffffffffffffffff")
X86 = bignumber.NewBig("0x3fffffffffffffffffffff")
X128 = bignumber.NewBig("0xffffffffffffffffffffffffffffffff")
X160 = bignumber.NewBig("0x00ffffffffffffffffffffffffffffffffffffffff")

X16UI = big256.FromBig(X16)
X86UI = big256.FromBig(X86)

MAX_SQRT_PRICE_CHANGE_PERCENTAGE = big.NewInt(2_000_000_000)
MIN_SQRT_PRICE_CHANGE_PERCENTAGE = big.NewInt(5)

Q96 = new(big.Int).Lsh(bignumber.One, 96)
Q96 = new(big.Int).Lsh(bignumber.One, 96)
Q96I = big256.FromBig(Q96)
)
1 change: 1 addition & 0 deletions pkg/liquidity-source/fluid/dex-v2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var (
ErrAdjustedAmountOutOfLimits = errors.New("adjusted amount out of limits")
ErrAmountOutOfLimits = errors.New("amount out of limits")
ErrFluidLiquidityCalcsError = errors.New("fluid liquidity calcs error")
ErrGreaterThanMaxAmountOut = errors.New("amount out greater than max amount out allowed")
ErrNextTickOutOfBounds = errors.New("next tick out of bounds")
ErrOverflow = errors.New("bigInt overflow int/uint256")
ErrSqrtPriceChangeOutOfBounds = errors.New("sqrt price change out of bounds")
Expand Down
Loading