-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(vpool): sqrt of liquidity depth tracked on pool (#1243)
* feat: implement function for getting the exact square root of an sdk.Dec * (vpool): get vpool/types passing * (vpool): keeper tests passing again * CHANGELOG #wip * #wip all vpool tests passing. perp in progress * fix tests in perp module * feat(common): SqrtDec changes * add changes from refactor * run golangci-lint * fix(vpool): cli_test.go * rm unused file * test(common): Finalize new functions, add fn docs, add large number test cases * more fn docs * refactor!: change proto order so that the Vpool.Config is still on 4 * refactor: rename MICRO → TO_MICRO * refactor(vpool): types.NewVpool abstraction for simplified constructor --------- Co-authored-by: Kevin Yang <5478483+k-yang@users.noreply.github.com>
- Loading branch information
1 parent
73dd798
commit b7149d1
Showing
52 changed files
with
988 additions
and
485 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package common | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"strings" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
// MustSqrtDec computes the square root of the input decimal using its | ||
// underlying big.Int. The big.Int.Sqrt method is part of the standard library, | ||
// thoroughly tested, works at seemingly unbound precision (e.g. for numbers as | ||
// large as 10**99. | ||
// - NOTE, MustSqrtDec panics if it is called on a negative number, similar to the | ||
// sdk.NewCoin and SqrtBigInt functions. A panic safe version of MustSqrtDec | ||
// is available in the SqrtDec method. | ||
func MustSqrtDec(dec sdk.Dec) sdk.Dec { | ||
sqrtBigInt := MustSqrtBigInt(dec.BigInt()) | ||
precision := sdk.NewDecFromBigInt(PRECISION_MULT) | ||
return sdk.NewDecFromBigInt(sqrtBigInt).Quo(precision) | ||
} | ||
|
||
// SqrtDec computes the square root of the input decimal using its | ||
// underlying big.Int. SqrtDec is panic-safe and returns an error if the input | ||
// decimal is negative. | ||
// | ||
// The big.Int.Sqrt method is part of the standard library, | ||
// thoroughly tested, works at seemingly unbound precision (e.g. for numbers as | ||
// large as 10**99. | ||
func SqrtDec(dec sdk.Dec) (sdk.Dec, error) { | ||
var sqrtDec sdk.Dec | ||
var panicErr error = TryCatch(func() { | ||
sqrtDec = MustSqrtDec(dec) | ||
})() | ||
return sqrtDec, panicErr | ||
} | ||
|
||
// MustSqrtBigInt returns the square root of the input. | ||
// - NOTE: MustSqrtBigInt panics if it is called on a negative number because it uses | ||
// the `big.Int.Sqrt` from the "math/big" package. | ||
func MustSqrtBigInt(i *big.Int) *big.Int { | ||
sqrtInt := &big.Int{} | ||
return sqrtInt.Sqrt(i) | ||
} | ||
|
||
// SqrtInt is the panic-safe version of MustSqrtBigInt | ||
func SqrtBigInt(i *big.Int) (*big.Int, error) { | ||
sqrtInt := new(big.Int) | ||
var panicErr error = TryCatch(func() { | ||
*sqrtInt = *MustSqrtBigInt(i) | ||
})() | ||
return sqrtInt, panicErr | ||
} | ||
|
||
// BigIntPow10 returns a big int that is a power of 10, e.g. BigIngPow10(3) | ||
// returns 1000. This function is useful for creating large numbers outside the | ||
// range of an int64 or 18 decimal precision. | ||
func BigIntPow10(power int64) *big.Int { | ||
bigInt, _ := new(big.Int).SetString("1"+strings.Repeat("0", int(power)), 10) | ||
return bigInt | ||
} | ||
|
||
// ———————————————————————————————————————————————— | ||
// Logic needed from private code in the Cosmos-SDK | ||
// See https://github.com/cosmos/cosmos-sdk/blob/v0.45.12/types/decimal.go | ||
// | ||
|
||
const ( | ||
PRECISION = 18 | ||
) | ||
|
||
var ( | ||
PRECISION_MULT = calcPrecisionMultiplier(0) | ||
PRECISION_SQRT = int64(PRECISION / 2) | ||
tenInt = big.NewInt(10) | ||
) | ||
|
||
// calcPrecisionMultiplier computes a multiplier needed to maintain a target | ||
// precision defined by 10 ** (PRECISION_SQRT - prec). | ||
// The maximum available precision is PRECISION_SQRT (9). | ||
func calcPrecisionMultiplier(prec int64) *big.Int { | ||
if prec > PRECISION_SQRT { | ||
panic(fmt.Sprintf("too much precision, maximum %v, provided %v", PRECISION_SQRT, prec)) | ||
} | ||
zerosToAdd := PRECISION_SQRT - prec | ||
multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) | ||
return multiplier | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package common_test | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"testing" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/NibiruChain/nibiru/x/common" | ||
) | ||
|
||
func TestSqrtBigInt(t *testing.T) { | ||
testCases := []struct { | ||
bigInt *big.Int | ||
sqrtBigInt *big.Int | ||
}{ | ||
{bigInt: big.NewInt(1), sqrtBigInt: big.NewInt(1)}, | ||
{bigInt: big.NewInt(4), sqrtBigInt: big.NewInt(2)}, | ||
{bigInt: big.NewInt(250_000), sqrtBigInt: big.NewInt(500)}, | ||
{bigInt: big.NewInt(4_819_136_400), sqrtBigInt: big.NewInt(69_420)}, | ||
{ | ||
bigInt: new(big.Int).Mul(big.NewInt(4_819_136_400), common.BigIntPow10(32)), | ||
sqrtBigInt: new(big.Int).Mul(big.NewInt(69_420), common.BigIntPow10(16)), | ||
}, | ||
{ | ||
bigInt: new(big.Int).Mul(big.NewInt(9), common.BigIntPow10(100)), | ||
sqrtBigInt: new(big.Int).Mul(big.NewInt(3), common.BigIntPow10(50)), | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
tc := testCase | ||
t.Run(fmt.Sprintf(`bigInt: %s, sqrtBigInt: %s`, tc.bigInt, tc.sqrtBigInt), func(t *testing.T) { | ||
sqrtInt := common.MustSqrtBigInt(tc.bigInt) | ||
assert.Equal(t, tc.sqrtBigInt.String(), sqrtInt.String()) | ||
}) | ||
} | ||
} | ||
|
||
func TestSqrtDec(t *testing.T) { | ||
testCases := []struct { | ||
dec sdk.Dec | ||
sqrtDec sdk.Dec | ||
}{ | ||
// -------------------------------------------------------------------- | ||
// Cases: 1 or higher | ||
{dec: sdk.NewDec(1), sqrtDec: sdk.NewDec(1)}, | ||
{dec: sdk.NewDec(4), sqrtDec: sdk.NewDec(2)}, | ||
{dec: sdk.NewDec(250_000), sqrtDec: sdk.NewDec(500)}, | ||
{dec: sdk.NewDec(4_819_136_400), sqrtDec: sdk.NewDec(69_420)}, | ||
|
||
// -------------------------------------------------------------------- | ||
// Cases: Between 0 and 1 | ||
{dec: sdk.MustNewDecFromStr("0.81"), sqrtDec: sdk.MustNewDecFromStr("0.9")}, | ||
{dec: sdk.MustNewDecFromStr("0.25"), sqrtDec: sdk.MustNewDecFromStr("0.5")}, | ||
// ↓ dec 1e-12, sqrtDec: 1e-6 | ||
{dec: sdk.MustNewDecFromStr("0.000000000001"), sqrtDec: sdk.MustNewDecFromStr("0.000001")}, | ||
|
||
// -------------------------------------------------------------------- | ||
// The math/big library panics if you call sqrt() on a negative number. | ||
} | ||
|
||
t.Run("negative sqrt should panic", func(t *testing.T) { | ||
panicString := common.TryCatch(func() { | ||
common.MustSqrtDec(sdk.NewDec(-9)) | ||
})().Error() | ||
|
||
assert.Contains(t, panicString, "square root of negative number") | ||
}) | ||
|
||
for _, testCase := range testCases { | ||
tc := testCase | ||
t.Run(fmt.Sprintf(`dec: %s, sqrtDec: %s`, tc.dec, tc.sqrtDec), func(t *testing.T) { | ||
sqrtDec := common.MustSqrtDec(tc.dec) | ||
assert.Equal(t, tc.sqrtDec.String(), sqrtDec.String()) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.