Skip to content

Commit

Permalink
fix autoswap calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
jcompagni10 committed Oct 15, 2024
1 parent d23cca3 commit dde438c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 45 deletions.
51 changes: 30 additions & 21 deletions x/dex/keeper/integration_deposit_autoswap_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ func (s *DexTestSuite) TestAutoswapSingleSided0To1() {

// THEN his deposit is autoswapped
// He receives 49.985501 shares
// swapAmount = 27.491577 Token0 see pool.go for the math
// (50 - 27.491577) / ( 27.491577 / 1.0001^2000) = 1 ie. pool ratio is maintained
// depositValue = depositAmount - (autoswapedAmountAsToken0 * fee)
// = 50 - 50 * (1 - 1.0001^-2)
// = 49.9900014998
// = 50 - 27.491577 * (1 - 1.0001^-2)
// = 49.9945025092
// SharesIssued = depositValue * existing shares / (existingValue + autoSwapFee)
// = 49.9900014998 * 111.069527 / (111.069527 + 0.0099985002)
// = 49.985501
// = 49.9945025092 * 111.069527 / (111.069527 + .005497490762642563860802206452577)
// = 49.992027

s.assertAccountSharesInt(s.bob, 2000, 2, math.NewInt(49985501))
s.assertAccountSharesInt(s.bob, 2000, 2, math.NewInt(49992027))
}

func (s *DexTestSuite) TestAutoswapSingleSided1To0() {
Expand All @@ -43,21 +45,24 @@ func (s *DexTestSuite) TestAutoswapSingleSided1To0() {
// THEN his deposit is autoswapped
// He receives 61.0 shares
// depositAmountAsToken0 = 50 * 1.0001^2000 = 61.06952725039
// swapAmount = 22.508423 Token1 see pool.go for the math
// swapAmountAsToken0 = 27.4915750352
// (22.508423 * 1.0001^2000) / (50 - 22.508423) = 1 ie. pool ratio is maintained
// depositValue = depositAmountAsToken0 - (autoswapedAmountAsToken0 * fee)
// = 61.06952725039 - 61.06952725039 * (1 - 1.0001^-2)
// = 61.05731517678
// = 61.06952725039 - 27.4915750352 * (1 - 1.0001^-2)
// = 61.06402976002
// SharesIssued = depositValue * existing shares / (existingValue + autoSwapFee)
// = 61.05731517678 * 111.069527 / (111.069527 + 0.01221207361)
// = 61.050602
// = 61.06402976002 * 111.069527 / (111.069527 + 0.00549749037)
// = 61061007

s.assertAccountSharesInt(s.bob, 2000, 2, math.NewInt(61050602))
s.assertAccountSharesInt(s.bob, 2000, 2, math.NewInt(61061007))
}

func (s *DexTestSuite) TestAutoswapDoubleSided0To1() {
s.fundAliceBalances(30, 50)
s.fundBobBalances(50, 50)

// GIVEN a pool with double-sided liquidity
// GIVEN a pool with double-sided liquidity at ratio 3:5
s.aliceDeposits(NewDeposit(30, 50, -4000, 10))
s.assertAccountSharesInt(s.alice, -4000, 10, math.NewInt(63516672))

Expand All @@ -67,14 +72,16 @@ func (s *DexTestSuite) TestAutoswapDoubleSided0To1() {

// THEN his deposit is autoswapped
// He receives 83.5 shares
// swapAmount = 10.553662 Token0 see pool.go for the math
// (50 - 10.553662) / (50 + 10.553662 / 1.0001^-4000) = 3/5 ie. pool ratio is maintained
// depositValue = depositAmountAsToken0 - (autoswapedAmountAsToken0 * fee)
// = 83.5166725838 - 20 * (1 - 1.0001^-10)
// = 83.4966835794
// = 83.5166725838 - 10.553662 * (1 - 1.0001^-10)
// = 83.506124724
// SharesIssued = depositValue * existing shares / (existingValue + autoSwapFee)
// = 83.4966835794 * 63.516672 / (63.5166725838 + 0.0199890044)
// = 83.470414
// = 83.506124724 * 63.516672 / (63.516672 + .010547859)
// = 83.492258

s.assertAccountSharesInt(s.bob, -4000, 10, math.NewInt(83470414))
s.assertAccountSharesInt(s.bob, -4000, 10, math.NewInt(83492258))
}

func (s *DexTestSuite) TestAutoswapDoubleSided1To0() {
Expand All @@ -91,12 +98,14 @@ func (s *DexTestSuite) TestAutoswapDoubleSided1To0() {

// THEN his deposit is autoswapped
// He receives 83.5 shares
// swapAmount = 14.263300 Token1 see pool.go for the math
// swapAmountAsToken0 = 9.5611671213
// depositValue = depositAmountAsToken0 - (autoswapedAmountAsToken0 * fee)
// = 83.5166725838 - 13.4066690335 * (1 - 1.0001^-10)
// = 83.5032732855
// = 83.5166725838 - 9.5611671213 * (1 - 1.0001^-10)
// = 83.5071166732
// SharesIssued = depositValue * existing shares / (existingValue + autoSwapFee)
// = 83.5032732855 * 70.110003 / (70.1100035503 + 0.01339929831)
// = 83.487316
// = 83.5071166732 * 70.110003 / (70.1100035503 + .009555910582)
// = 83.495735

s.assertAccountSharesInt(s.bob, -4000, 10, math.NewInt(83487316))
s.assertAccountSharesInt(s.bob, -4000, 10, math.NewInt(83495735))
}
86 changes: 62 additions & 24 deletions x/dex/types/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,26 +123,31 @@ func (p *Pool) Deposit(
lowerReserve0 := &p.LowerTick0.ReservesMakerDenom
upperReserve1 := &p.UpperTick1.ReservesMakerDenom

inAmount0, inAmount1 = CalcGreatestMatchingRatio(
*lowerReserve0,
*upperReserve1,
maxAmount0,
maxAmount1,
)

centerPrice1To0 := p.MustCalcPrice1To0Center()
depositValueAsToken0 := CalcAmountAsToken0(inAmount0, inAmount1, centerPrice1To0)
var depositValueAsToken0 math_utils.PrecDec
autoswapFee := math_utils.ZeroPrecDec()
if autoswap {
residualAmount0 := maxAmount0.Sub(inAmount0)
residualAmount1 := maxAmount1.Sub(inAmount1)

// NOTE: Currently not doing anything with the error,
// but added error handling to all of the new functions for autoswap.
// Open to changing it however.
if !autoswap {
inAmount0, inAmount1 = CalcGreatestMatchingRatio(
*lowerReserve0,
*upperReserve1,
maxAmount0,
maxAmount1,
)
depositValueAsToken0 = CalcAmountAsToken0(inAmount0, inAmount1, centerPrice1To0)

} else {
residualAmount0, residualAmount1 := CalcAutoswapAmount(
*lowerReserve0, *upperReserve1,
maxAmount0, maxAmount1,
centerPrice1To0,
)

residualDepositValueAsToken0 := CalcAmountAsToken0(residualAmount0, residualAmount1, centerPrice1To0)
autoswapFee, _ = p.CalcAutoswapFee(residualDepositValueAsToken0)
depositValueAsToken0 = depositValueAsToken0.Add(residualDepositValueAsToken0.Sub(autoswapFee))
autoswapFee = p.CalcAutoswapFee(residualDepositValueAsToken0)

fullDepositValueAsToken0 := CalcAmountAsToken0(maxAmount0, maxAmount1, centerPrice1To0)
depositValueAsToken0 = fullDepositValueAsToken0.Sub(autoswapFee)

inAmount0 = maxAmount0
inAmount1 = maxAmount1
Expand Down Expand Up @@ -253,17 +258,50 @@ func CalcGreatestMatchingRatio(
return resultAmount0, resultAmount1
}

func (p *Pool) CalcAutoswapFee(
depositValueAsToken0 math_utils.PrecDec,
) (math_utils.PrecDec, error) {
// CalcAutoswapAmount calculates the smallest swap to match the current pool ratio.
// see: https://www.notion.so/Autoswap-Spec-ca5f35a4cd5b4dbf9ae27e0454ddd445?pvs=4#12032ea59b0e802c925efae10c3ca85f
func CalcAutoswapAmount(
reserves0,
reserves1,
depositAmount0,
depositAmount1 math.Int,
price1To0 math_utils.PrecDec,
) (resultAmount0, resultAmount1 math.Int) {

if reserves0.IsZero() && reserves1.IsZero() {
// The pool is empty, any deposit amount is allowed. Nothing to be swapped
return math.ZeroInt(), math.ZeroInt()
}

reserves0Dec := math_utils.NewPrecDecFromInt(reserves0)
reserves1Dec := math_utils.NewPrecDecFromInt(reserves1)
// swapAmount = (reserves0*depositAmount1 - reserves1*depositAmount0) / (price * reserves1 + reserves0)
swapAmount := reserves0Dec.MulInt(depositAmount1).Sub(reserves1Dec.MulInt(depositAmount0)).
Quo(reserves0Dec.Add(reserves1Dec.Mul(price1To0)))

switch {
case swapAmount.IsZero(): // nothing to be swapped
return math.ZeroInt(), math.ZeroInt()

case swapAmount.IsPositive(): // Token0 needs to be swapped
return math.ZeroInt(), swapAmount.Ceil().TruncateInt()

default: // Token0 needs to be swapped
amountSwappedAs1 := swapAmount.Neg()

amountSwapped0 := amountSwappedAs1.Mul(price1To0)
return amountSwapped0.Ceil().TruncateInt(), math.ZeroInt()
}

}

func (p *Pool) CalcAutoswapFee(depositValueAsToken0 math_utils.PrecDec) math_utils.PrecDec {
feeInt64 := utils.MustSafeUint64ToInt64(p.Fee())
feeAsPrice, err := CalcPrice(feeInt64)
feeAsPrice := MustCalcPrice(feeInt64)
autoSwapFee := math_utils.OnePrecDec().Sub(feeAsPrice)
if err != nil {
return math_utils.ZeroPrecDec(), err
}

// fee = depositValueAsToken0 * (1 - p(fee) )
return autoSwapFee.Mul(depositValueAsToken0), nil
return autoSwapFee.Mul(depositValueAsToken0)
}

func CalcAmountAsToken0(amount0, amount1 math.Int, price1To0 math_utils.PrecDec) math_utils.PrecDec {
Expand Down

0 comments on commit dde438c

Please sign in to comment.