Skip to content

Commit

Permalink
Calculate SpotPrice with Ratios and SigFigs (#1176)
Browse files Browse the repository at this point in the history
* spot price calculated with sigfigs, new test

* SigFigsExponent comment

* Update x/gamm/pool-models/balancer/amm.go

Co-authored-by: Dev Ojha <[email protected]>

* add sigfigs to tests

Co-authored-by: Dev Ojha <[email protected]>
  • Loading branch information
czarcas7ic and ValarDragon authored Mar 31, 2022
1 parent 12630b8 commit cc0ec41
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 12 deletions.
4 changes: 3 additions & 1 deletion x/gamm/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,7 @@ func (suite *KeeperTestSuite) TestQueryBalancerPoolSpotPrice() {
TokenOutDenom: "foo",
})
suite.NoError(err)
suite.Equal(sdk.NewDec(1).Quo(sdk.NewDec(3)).String(), res.SpotPrice)
s := sdk.NewDec(1).Quo(sdk.NewDec(3))
sp := s.Mul(types.SigFigs).RoundInt().ToDec().Quo(types.SigFigs)
suite.Equal(sp.String(), res.SpotPrice)
}
4 changes: 3 additions & 1 deletion x/gamm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func (suite *KeeperTestSuite) prepareBalancerPool() uint64 {
suite.Equal(sdk.NewDecWithPrec(15, 1).String(), spotPrice.String())
spotPrice, err = suite.app.GAMMKeeper.CalculateSpotPrice(suite.ctx, poolId, "baz", "foo")
suite.NoError(err)
suite.Equal(sdk.NewDec(1).Quo(sdk.NewDec(3)).String(), spotPrice.String())
s := sdk.NewDec(1).Quo(sdk.NewDec(3))
sp := s.Mul(types.SigFigs).RoundInt().ToDec().Quo(types.SigFigs)
suite.Equal(sp.String(), spotPrice.String())

return poolId
}
16 changes: 11 additions & 5 deletions x/gamm/pool-models/balancer/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/osmosis-labs/osmosis/v7/osmomath"
"github.com/osmosis-labs/osmosis/v7/x/gamm/types"
)

// solveConstantFunctionInvariant solves the constant function of an AMM
Expand Down Expand Up @@ -106,7 +107,10 @@ func (p *Pool) ApplySwap(ctx sdk.Context, tokensIn sdk.Coins, tokensOut sdk.Coin

// SpotPrice returns the spot price of the pool
// This is the weight-adjusted balance of the tokens in the pool.
// so spot_price = (Base_supply / Weight_base) / (Quote_supply / Weight_quote)
// In order reduce the propagated effect of incorrect trailing digits,
// we take the ratio of weights and divide this by ratio of supplies
// this is equivalent to spot_price = (Base_supply / Weight_base) / (Quote_supply / Weight_quote)
// but cancels out the common term in weight.
//
// panics if pool is misconfigured and has any weight as 0.
func (p Pool) SpotPrice(ctx sdk.Context, baseAsset, quoteAsset string) (sdk.Dec, error) {
Expand All @@ -118,10 +122,12 @@ func (p Pool) SpotPrice(ctx sdk.Context, baseAsset, quoteAsset string) (sdk.Dec,
return sdk.Dec{}, errors.New("pool is misconfigured, got 0 weight")
}

numerator := base.Token.Amount.ToDec().Quo(base.Weight.ToDec())
denom := quote.Token.Amount.ToDec().Quo(quote.Weight.ToDec())
ratio := numerator.Quo(denom)

// spot_price = (Base_supply / Weight_base) / (Quote_supply / Weight_quote)
// spot_price = (weight_quote / weight_base) * (base_supply / quote_supply)
invWeightRatio := quote.Weight.ToDec().Quo(base.Weight.ToDec())
supplyRatio := base.Token.Amount.ToDec().Quo(quote.Token.Amount.ToDec())
fullRatio := supplyRatio.Mul(invWeightRatio)
ratio := (fullRatio.Mul(types.SigFigs).RoundInt()).ToDec().Quo(types.SigFigs)
return ratio, nil
}

Expand Down
15 changes: 11 additions & 4 deletions x/gamm/pool-models/balancer/amm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,23 @@ func (suite *KeeperTestSuite) TestBalancerSpotPrice() {
{
name: "1:2 ratio",
baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 100),
quoteDenomPoolInput: sdk.NewInt64Coin("foo", 200),
quoteDenomPoolInput: sdk.NewInt64Coin(quoteDenom, 200),
expectError: false,
expectedOutput: sdk.MustNewDecFromStr("0.500000000002684355"),
expectedOutput: sdk.MustNewDecFromStr("0.500000000000000000"),
},
{
name: "2:1 ratio",
baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 200),
quoteDenomPoolInput: sdk.NewInt64Coin("foo", 100),
quoteDenomPoolInput: sdk.NewInt64Coin(quoteDenom, 100),
expectError: false,
expectedOutput: sdk.MustNewDecFromStr("2.000000000000000000"),
},
{
name: "rounding after sigfig ratio",
baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 220),
quoteDenomPoolInput: sdk.NewInt64Coin(quoteDenom, 115),
expectError: false,
expectedOutput: sdk.MustNewDecFromStr("1.999999999989262582"),
expectedOutput: sdk.MustNewDecFromStr("1.913043480000000000"), // ans is 1.913043478260869565, rounded is 1.91304348
},
}

Expand Down
6 changes: 6 additions & 0 deletions x/gamm/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const (
MaxPoolAssets = 8

OneShareExponent = 18
// Raise 10 to the power of SigFigsExponent to determine number of significant figures.
// i.e. SigFigExponent = 8 is 10^8 which is 100000000. This gives 8 significant figures.
SigFigsExponent = 8
)

var (
Expand All @@ -17,4 +20,7 @@ var (

// InitPoolSharesSupply is the amount of new shares to initialize a pool with.
InitPoolSharesSupply = OneShare.MulRaw(100)

// SigFigs is the amount of significant figures used to calculate SpotPrice
SigFigs = sdk.NewDec(10).Power(SigFigsExponent)
)
4 changes: 3 additions & 1 deletion x/pool-incentives/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ func (suite *KeeperTestSuite) prepareBalancerPool() uint64 {
suite.Equal(sdk.NewDecWithPrec(15, 1).String(), spotPrice.String())
spotPrice, err = suite.app.GAMMKeeper.CalculateSpotPrice(suite.ctx, poolId, "baz", "foo")
suite.NoError(err)
suite.Equal(sdk.NewDec(1).Quo(sdk.NewDec(3)).String(), spotPrice.String())
s := sdk.NewDec(1).Quo(sdk.NewDec(3))
sp := s.Mul(gammtypes.SigFigs).RoundInt().ToDec().Quo(gammtypes.SigFigs)
suite.Equal(sp.String(), spotPrice.String())

return poolId
}
Expand Down

0 comments on commit cc0ec41

Please sign in to comment.