From d14700e94f388880965ec4a752b5e58e8fa123ae Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 18 Sep 2023 17:18:26 -0400 Subject: [PATCH] feat(osmoutils): coin math helpers (#6427) * feat(osmoutils): coin math helpers * updates * go mod (cherry picked from commit d00cb3e5ff59ef30b84f44d40b43025fc9ca5b57) # Conflicts: # CHANGELOG.md # go.mod # go.sum --- CHANGELOG.md | 10 +++ go.mod | 7 ++ go.sum | 13 +++ osmoutils/coins/coin_math.go | 138 ++++++++++++++++++++++++++++++ osmoutils/coins/coin_math_test.go | 135 +++++++++++++++++++++++++++++ 5 files changed, 303 insertions(+) create mode 100644 osmoutils/coins/coin_math.go create mode 100644 osmoutils/coins/coin_math_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b5831065164..e046f42a3dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +<<<<<<< HEAD +======= +### Features + +* [#6427](https://github.com/osmosis-labs/osmosis/pull/6427) sdk.Coins Mul and Quo helpers in osmoutils + +### Misc Improvements + +* [#6309](https://github.com/osmosis-labs/osmosis/pull/6309) Add Cosmwasm Pool Queries to Stargate Query +>>>>>>> d00cb3e5 (feat(osmoutils): coin math helpers (#6427)) ### Features * [#6416](https://github.com/osmosis-labs/osmosis/pull/6416) feat[CL]: add num initialized ticks query diff --git a/go.mod b/go.mod index 36ca5a53468..1b0dfdd1118 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,17 @@ require ( github.com/mattn/go-sqlite3 v1.14.17 github.com/ory/dockertest/v3 v3.10.0 github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 +<<<<<<< HEAD github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230908171738-9abfe2e61cf4 github.com/osmosis-labs/osmosis/osmoutils v0.0.6 github.com/osmosis-labs/osmosis/x/epochs v0.0.2 github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.8 +======= + github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230918184012-da92c9cdf6bd + github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230911120014-b14342e08daf + github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20230911120014-b14342e08daf + github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20230911120014-b14342e08daf +>>>>>>> d00cb3e5 (feat(osmoutils): coin math helpers (#6427)) github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.5.1 diff --git a/go.sum b/go.sum index deb01a46f48..28a6fec72af 100644 --- a/go.sum +++ b/go.sum @@ -962,6 +962,7 @@ github.com/osmosis-labs/cosmos-sdk v0.45.0-rc1.0.20230703010110-ed4eb883f2a6 h1: github.com/osmosis-labs/cosmos-sdk v0.45.0-rc1.0.20230703010110-ed4eb883f2a6/go.mod h1:9KGhMg+7ZWgZ50Wa/x8w/jN19O0TSqYLlqUj+2wwxLU= github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:YlmchqTmlwdWSmrRmXKR+PcU96ntOd8u10vTaTZdcNY= github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI= +<<<<<<< HEAD github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230908171738-9abfe2e61cf4 h1:pX9LmOgvRZTQVROZroz5sENUn0/DgdNRS5fbNIjk4Oo= github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230908171738-9abfe2e61cf4/go.mod h1:UlftwozB+QObT3o0YfkuuyL9fsVdgoWt0dm6J7MLYnU= github.com/osmosis-labs/osmosis/osmoutils v0.0.6 h1:VI4wPzxXpdg5XEUaBugY9lADwxzw3H6lEJ0D+TZc4oE= @@ -970,6 +971,18 @@ github.com/osmosis-labs/osmosis/x/epochs v0.0.2 h1:aEeXHGCSJMgMtAvCucsD2RSaWZ8lI github.com/osmosis-labs/osmosis/x/epochs v0.0.2/go.mod h1:8dvJFHTpu6SIxmOaSaEw0tHnQ/Z9blf5qsF/ZJnMVHo= github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.8 h1:BUGowctYQT0vdPgULrvwraEsW+sS6DnbzndTLKLmWVY= github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.8/go.mod h1:sR0lpev9mcm9/9RY50T1og3UC3WpZAsINh/OmgrmFlg= +======= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230911120014-b14342e08daf h1:sXSC/RG9sxQCB5QJ5JB+M9Bok7Xbpv2zx9ee6287glw= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230911120014-b14342e08daf/go.mod h1:pIItelRYvonB+H8A6KqucOi7xFnJxzDHaWJqOdFNLI4= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230918184012-da92c9cdf6bd h1:U7r0uBLTWeLrgGOu1re0aTl10yreX1j3dNDu12KqBpE= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230918184012-da92c9cdf6bd/go.mod h1:pIItelRYvonB+H8A6KqucOi7xFnJxzDHaWJqOdFNLI4= +github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230911120014-b14342e08daf h1:r5R/L3tzH+vGPahAdvnVB2Vo0KPhZR0oMNyX4+G2FEo= +github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230911120014-b14342e08daf/go.mod h1:7VoXHwrSSx8Sii0UFc9YIixF6C/9XfV1pdU2Dliu4WA= +github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20230911120014-b14342e08daf h1:8lkIsAj3L7zxvOZbqVLNJRpSdDxaYhYfAIG7XjPaJiU= +github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20230911120014-b14342e08daf/go.mod h1:C0Uqe6X4N5ASA+1xZ6guaaJyUVKLcaVJIQa4Q4LG9Vk= +github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20230911120014-b14342e08daf h1:ZEi+yJJPgpYtmNwZ1bMiP5cMBDQ83FK/YGgmTnWmoAI= +github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20230911120014-b14342e08daf/go.mod h1:pqkAsS04Er1kFM41gg3aWTSaYHyLe8C9Dw3Sj8KMXk8= +>>>>>>> d00cb3e5 (feat(osmoutils): coin math helpers (#6427)) github.com/osmosis-labs/wasmd v0.31.0-osmo-v16 h1:X747cZYdnqc/+RV48iPVeGprpVb/fUWSaKGsZUWrdbg= github.com/osmosis-labs/wasmd v0.31.0-osmo-v16/go.mod h1:Rf8zW/GgBQyFRRB4s62VQHWA6sTlMFSjoDQQpoq64iI= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= diff --git a/osmoutils/coins/coin_math.go b/osmoutils/coins/coin_math.go new file mode 100644 index 00000000000..009a036e9e8 --- /dev/null +++ b/osmoutils/coins/coin_math.go @@ -0,0 +1,138 @@ +package coins + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/osmomath" +) + +// Mutative helpers that mutate the input coins + +// MulIntMut multiplies the coins by the given integer +// Mutates the input coins +func MulIntMut(coins sdk.Coins, num osmomath.Int) { + for i := range coins { + coins[i].Amount = coins[i].Amount.Mul(num) + } +} + +// MulRawMut multiplies the coins by the given integer +// Mutates the input coins +func MulRawMut(coins sdk.Coins, num int64) sdk.Coins { + for i := range coins { + coins[i].Amount = coins[i].Amount.MulRaw(num) + } + return coins +} + +// MulDecMut multiplies the coins by the given decimal +// Mutates the input coins +func MulDecMut(coins sdk.Coins, num osmomath.Dec) { + for i := range coins { + coins[i].Amount = coins[i].Amount.ToLegacyDec().Mul(num).TruncateInt() + } +} + +// QuoIntMut divides the coins by the given integer +// Mutates the input coins +func QuoIntMut(coins sdk.Coins, num osmomath.Int) { + for i := range coins { + coins[i].Amount = coins[i].Amount.Quo(num) + } +} + +// QuoRawMut divides the coins by the given integer +// Mutates the input coins +func QuoRawMut(coins sdk.Coins, num int64) { + for i := range coins { + coins[i].Amount = coins[i].Amount.QuoRaw(num) + } +} + +// QuoIntMut divides the coins by the given decimal +// Mutates the input coins +func QuoDecMut(coins sdk.Coins, num osmomath.Dec) { + for i := range coins { + coins[i].Amount = coins[i].Amount.ToLegacyDec().Quo(num).TruncateInt() + } +} + +// Non-mutative coin helpers that reallocate and return new coins + +// MulInt multiplies the coins by the given integer +// Does not mutate the input coins and returns new coins. +func MulInt(coins sdk.Coins, num osmomath.Int) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.Mul(num) + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} + +// MulRaw multiplies the coins by the given integer +// Does not mutate the input coins and returns new coins. +func MulRaw(coins sdk.Coins, num int64) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.MulRaw(num) + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} + +// MulDec multiplies the coins by the given decimal +// Does not mutate the input coins and returns new coins. +func MulDec(coins sdk.Coins, num osmomath.Dec) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.ToLegacyDec().Mul(num).TruncateInt() + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} + +// QuoInt divides the coins by the given integer +// Does not mutate the input coins and returns new coins. +func QuoInt(coins sdk.Coins, num osmomath.Int) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.Quo(num) + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} + +// QuoRaw divides the coins by the given integer +// Does not mutate the input coins and returns new coins. +func QuoRaw(coins sdk.Coins, num int64) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.QuoRaw(num) + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} + +// QuoDec divides the coins by the given integer +// Does not mutate the input coins and returns new coins. +func QuoDec(coins sdk.Coins, num osmomath.Dec) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + + for i := range coins { + newCoins[i].Amount = coins[i].Amount.ToLegacyDec().Quo(num).TruncateInt() + newCoins[i].Denom = coins[i].Denom + } + + return newCoins +} diff --git a/osmoutils/coins/coin_math_test.go b/osmoutils/coins/coin_math_test.go new file mode 100644 index 00000000000..7e8a7fae160 --- /dev/null +++ b/osmoutils/coins/coin_math_test.go @@ -0,0 +1,135 @@ +package coins_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/osmosis-labs/osmosis/osmomath" + "github.com/osmosis-labs/osmosis/osmoutils/coins" +) + +var ( + defaultCoins = sdk.NewCoins( + sdk.NewCoin("foo", sdk.NewInt(100)), + sdk.NewCoin("bar", sdk.NewInt(200)), + ) + + defaultMultiplier = osmomath.NewInt(2) + + defaultMulExpectedResult = sdk.NewCoins( + sdk.NewCoin(defaultCoins[0].Denom, defaultCoins[0].Amount.Mul(defaultMultiplier)), + sdk.NewCoin(defaultCoins[1].Denom, defaultCoins[1].Amount.Mul(defaultMultiplier)), + ) + + defaultQuoExpectedResult = sdk.NewCoins( + sdk.NewCoin(defaultCoins[0].Denom, defaultCoins[0].Amount.Quo(defaultMultiplier)), + sdk.NewCoin(defaultCoins[1].Denom, defaultCoins[1].Amount.Quo(defaultMultiplier)), + ) +) + +// makes a deep copy to avoid accidentally mutating the input to a test. +func deepCopy(coins sdk.Coins) sdk.Coins { + newCoins := make(sdk.Coins, len(coins)) + for i := range coins { + newCoins[i].Amount = coins[i].Amount + newCoins[i].Denom = coins[i].Denom + } + return newCoins +} + +// Basic multiplication test. +func TestMul(t *testing.T) { + t.Run("test mutative multiplication", func(t *testing.T) { + t.Run("MulIntMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.MulIntMut(defaulCoins, defaultMultiplier) + require.Equal(t, defaultMulExpectedResult, defaulCoins) + }) + + t.Run("MulIntRawMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.MulRawMut(defaulCoins, defaultMultiplier.Int64()) + require.Equal(t, defaultMulExpectedResult, defaulCoins) + }) + + t.Run("MulDecMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.MulDecMut(defaulCoins, osmomath.NewDecFromInt(defaultMultiplier)) + require.Equal(t, defaultMulExpectedResult, defaulCoins) + }) + }) + + // Make a deep copy of the default coins for the input. + // Validate that the copy input coins are not mutated. + t.Run("test non-mutative multiplication", func(t *testing.T) { + t.Run("MulInt", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.MulInt(defaulCoinsCopy, defaultMultiplier) + require.Equal(t, defaultMulExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + + t.Run("MulIntRaw", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.MulRaw(defaulCoinsCopy, defaultMultiplier.Int64()) + require.Equal(t, defaultMulExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + + t.Run("MulDec", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.MulDec(defaulCoinsCopy, osmomath.NewDecFromInt(defaultMultiplier)) + require.Equal(t, defaultMulExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + }) +} + +func TestQuo(t *testing.T) { + t.Run("test mutative division", func(t *testing.T) { + t.Run("QuoIntMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.QuoIntMut(defaulCoins, defaultMultiplier) + require.Equal(t, defaultQuoExpectedResult, defaulCoins) + }) + + t.Run("QuoIntRawMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.QuoRawMut(defaulCoins, defaultMultiplier.Int64()) + require.Equal(t, defaultQuoExpectedResult, defaulCoins) + }) + + t.Run("QuoDecMut", func(t *testing.T) { + defaulCoins := deepCopy(defaultCoins) + coins.QuoDecMut(defaulCoins, osmomath.NewDecFromInt(defaultMultiplier)) + require.Equal(t, defaultQuoExpectedResult, defaulCoins) + }) + }) + + // Make a deep copy of the default coins for the input. + // Validate that the copy input coins are not mutated. + t.Run("test non-mutative division", func(t *testing.T) { + t.Run("QuoInt", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.QuoInt(defaulCoinsCopy, defaultMultiplier) + require.Equal(t, defaultQuoExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + + t.Run("QuoIntRaw", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.QuoRaw(defaulCoinsCopy, defaultMultiplier.Int64()) + require.Equal(t, defaultQuoExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + + t.Run("QuoDec", func(t *testing.T) { + defaulCoinsCopy := deepCopy(defaultCoins) + result := coins.QuoDec(defaulCoinsCopy, osmomath.NewDecFromInt(defaultMultiplier)) + require.Equal(t, defaultQuoExpectedResult, result) + require.Equal(t, defaultCoins, defaulCoinsCopy) + }) + }) +}