diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a4d11cb57..db84e10f9c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#6427](https://github.com/osmosis-labs/osmosis/pull/6427) sdk.Coins Mul and Quo helpers in osmoutils * [#6437](https://github.com/osmosis-labs/osmosis/pull/6437) mutative version for QuoRoundUp +* [#6261](https://github.com/osmosis-labs/osmosis/pull/6261) mutative and efficient BigDec truncations with arbitrary decimals ### Misc Improvements diff --git a/go.mod b/go.mod index dfe45a05c81..eb42dd125a7 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ 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 - github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920134650-28712c635b4f + github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920192334-7fb82821ef90 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 @@ -57,15 +57,15 @@ require ( github.com/benbjohnson/clock v1.3.0 // indirect github.com/butuzov/mirror v1.1.0 // indirect github.com/ccojocar/zxcvbn-go v1.0.1 // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/cosmos/gogoproto v1.4.11 // indirect github.com/cosmos/iavl v0.19.5 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/go-playground/locales v0.14.1 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/gateway v1.1.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/kkHAIKE/contextcheck v1.1.4 // indirect @@ -79,7 +79,6 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/timonwong/loggercheck v0.9.4 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/xen0n/gosmopolitan v1.2.1 // indirect github.com/ykadowak/zerologlint v0.1.3 // indirect github.com/zimmski/go-mutesting v0.0.0-20210610104036-6d9217011a00 // indirect @@ -88,6 +87,7 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/goleak v1.1.12 // indirect go.uber.org/zap v1.24.0 // indirect + golang.org/x/arch v0.5.0 // indirect google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect ) diff --git a/go.sum b/go.sum index e916fad6013..998cab2cf10 100644 --- a/go.sum +++ b/go.sum @@ -197,6 +197,8 @@ github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacM github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -220,7 +222,10 @@ github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoG github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 h1:W9o46d2kbNL06lq7UNDPV0zYLzkrde/bjIqO02eoll0= github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -383,8 +388,6 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= @@ -425,7 +428,7 @@ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/Nu github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -460,6 +463,7 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -650,8 +654,8 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -924,8 +928,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -963,6 +967,10 @@ github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920134402-0622c30178eb h1 github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920134402-0622c30178eb/go.mod h1:pIItelRYvonB+H8A6KqucOi7xFnJxzDHaWJqOdFNLI4= github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920134650-28712c635b4f h1:SwZwcklK2EHIQLD8gVTqMsUTD1GpTyF6X8HlMywrxTc= github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920134650-28712c635b4f/go.mod h1:pIItelRYvonB+H8A6KqucOi7xFnJxzDHaWJqOdFNLI4= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920190757-3f566b965c22 h1:D2Qx9OPINxTQVaXQZwklajC04XUYGvY5g+8Z8rMMXas= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920190757-3f566b965c22/go.mod h1:pIItelRYvonB+H8A6KqucOi7xFnJxzDHaWJqOdFNLI4= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920192334-7fb82821ef90 h1:GRKUSGlACYPYFfU5Beu7NBILX8UYHGTWw09gzTfsdwc= +github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230920192334-7fb82821ef90/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= @@ -1239,7 +1247,7 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= @@ -1329,7 +1337,9 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= +golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/osmomath/decimal.go b/osmomath/decimal.go index 43033a2f2e2..9eb12bbe348 100644 --- a/osmomath/decimal.go +++ b/osmomath/decimal.go @@ -55,6 +55,9 @@ var ( // initialized in init() since requires // precision to be defined. twoBigDec BigDec = MustNewBigDecFromStr("2") + + // precisionFactors are used to adjust the scale of big.Int values to match the desired precision + precisionFactors = make(map[uint64]*big.Int) ) // Decimal errors @@ -70,6 +73,11 @@ func init() { for i := 0; i <= PrecisionBigDec; i++ { precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) } + + for precision := uint64(0); precision <= PrecisionBigDec; precision++ { + precisionFactor := new(big.Int).Exp(big.NewInt(10), big.NewInt(PrecisionBigDec-int64(precision)), nil) + precisionFactors[precision] = precisionFactor + } } func precisionInt() *big.Int { @@ -104,7 +112,7 @@ func NewBigDec(i int64) BigDec { } // create a new BigDec from integer with decimal place at prec -// CONTRACT: prec <= Precision +// CONTRACT: prec <= PrecisionBigDec func NewBigDecWithPrec(i, prec int64) BigDec { return BigDec{ new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), @@ -112,13 +120,13 @@ func NewBigDecWithPrec(i, prec int64) BigDec { } // create a new BigDec from big integer assuming whole numbers -// CONTRACT: prec <= Precision +// CONTRACT: prec <= PrecisionBigDec func NewBigDecFromBigInt(i *big.Int) BigDec { return NewBigDecFromBigIntWithPrec(i, 0) } // create a new BigDec from big integer assuming whole numbers -// CONTRACT: prec <= Precision +// CONTRACT: prec <= PrecisionBigDec func NewBigDecFromBigIntWithPrec(i *big.Int, prec int64) BigDec { return BigDec{ new(big.Int).Mul(i, precisionMultiplier(prec)), @@ -126,13 +134,13 @@ func NewBigDecFromBigIntWithPrec(i *big.Int, prec int64) BigDec { } // create a new BigDec from big integer assuming whole numbers -// CONTRACT: prec <= Precision +// CONTRACT: prec <= PrecisionBigDec func NewBigDecFromInt(i BigInt) BigDec { return NewBigDecFromIntWithPrec(i, 0) } // create a new BigDec from big integer with decimal place at prec -// CONTRACT: prec <= Precision +// CONTRACT: prec <= PrecisionBigDec func NewBigDecFromIntWithPrec(i BigInt, prec int64) BigDec { return BigDec{ new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), @@ -567,11 +575,21 @@ func (d BigDec) MustFloat64() float64 { // Dec returns the osmomath.Dec representation of a BigDec. // Values in any additional decimal places are truncated. func (d BigDec) Dec() Dec { - precisionDiff := PrecisionBigDec - PrecisionDec - precisionFactor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(precisionDiff)), nil) - - if precisionDiff < 0 { - panic("invalid decimal precision") + return d.DecWithPrecision(PrecisionDec) +} + +// DecWithPrecision converts BigDec to Dec with desired precision +// Example: +// BigDec: 1.010100000000153000000000000000000000 +// precision: 4 +// Output Dec: 1.010100000000000000 +// Panics if precision exceeds PrecisionDec +func (d BigDec) DecWithPrecision(precision uint64) Dec { + var precisionFactor *big.Int + if precision > PrecisionDec { + panic(fmt.Sprintf("maximum Dec precision is (%v), provided (%v)", PrecisionDec, precision)) + } else { + precisionFactor = precisionFactors[precision] } // Truncate any additional decimal values that exist due to BigDec's additional precision @@ -579,11 +597,34 @@ func (d BigDec) Dec() Dec { intRepresentation := new(big.Int).Quo(d.BigInt(), precisionFactor) // convert int representation back to SDK Dec precision - truncatedDec := NewDecFromBigIntWithPrec(intRepresentation, PrecisionDec) + truncatedDec := NewDecFromBigIntWithPrec(intRepresentation, int64(precision)) return truncatedDec } +// ChopPrecisionMut truncates all decimals after precision numbers after decimal point. Mutative +// CONTRACT: precision <= PrecisionBigDec +// Panics if precision exceeds PrecisionBigDec +func (d *BigDec) ChopPrecisionMut(precision uint64) BigDec { + if precision > PrecisionBigDec { + panic(fmt.Sprintf("maximum BigDec precision is (%v), provided (%v)", PrecisionDec, precision)) + } + + precisionFactor := precisionFactors[precision] + // big.Quo truncates numbers that would have been after decimal point + d.i.Quo(d.i, precisionFactor) + d.i.Mul(d.i, precisionFactor) + return BigDec{d.i} +} + +// ChopPrecision truncates all decimals after precision numbers after decimal point +// CONTRACT: precision <= PrecisionBigDec +// Panics if precision exceeds PrecisionBigDec +func (d *BigDec) ChopPrecision(precision uint64) BigDec { + copy := d.Clone() + return copy.ChopPrecisionMut(precision) +} + // DecRoundUp returns the osmomath.Dec representation of a BigDec. // Round up at precision end. // Values in any additional decimal places are truncated. @@ -676,7 +717,7 @@ func chopPrecisionAndRoundUpBigDec(d *big.Int) *big.Int { return chopPrecisionAndRoundUpMut(copy, precisionReuse) } -// chopPrecisionAndRoundUpDec removes sdk.Precision amount of rightmost digits and rounds up. +// chopPrecisionAndRoundUpDec removes PrecisionDec amount of rightmost digits and rounds up. // Non-mutative. func chopPrecisionAndRoundUpDec(d *big.Int) *big.Int { copy := new(big.Int).Set(d) diff --git a/osmomath/decimal_test.go b/osmomath/decimal_test.go index 1c477bbb716..8d5a589ddb2 100644 --- a/osmomath/decimal_test.go +++ b/osmomath/decimal_test.go @@ -7,6 +7,7 @@ import ( "math/big" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "gopkg.in/yaml.v2" @@ -1503,6 +1504,84 @@ func (s *decimalTestSuite) TestPower() { } } +func (s *decimalTestSuite) TestDec_WithPrecision() { + tests := []struct { + d osmomath.BigDec + want osmomath.Dec + precision uint64 + expPanic bool + }{ + // test cases for basic SDKDec() conversion + {osmomath.NewBigDec(0), sdk.MustNewDecFromStr("0.000000000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDec(1), sdk.MustNewDecFromStr("1.000000000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDec(10), sdk.MustNewDecFromStr("10.000000000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDec(12340), sdk.MustNewDecFromStr("12340.000000000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDecWithPrec(12340, 4), sdk.MustNewDecFromStr("1.234000000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDecWithPrec(12340, 5), sdk.MustNewDecFromStr("0.123400000000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDecWithPrec(12340, 8), sdk.MustNewDecFromStr("0.000123400000000000"), osmomath.PrecisionDec, false}, + {osmomath.NewBigDecWithPrec(1009009009009009009, 17), sdk.MustNewDecFromStr("10.090090090090090090"), osmomath.PrecisionDec, false}, + // test cases with custom precision: + {osmomath.NewBigDec(0), sdk.MustNewDecFromStr("0.000000000000"), 12, false}, + {osmomath.NewBigDec(1), sdk.MustNewDecFromStr("1.000000000000"), 12, false}, + // specified precision is the same as the initial precision: 12.3453123123 -> 12.3453123123 + {osmomath.NewBigDecWithPrec(123453123123, 10), sdk.MustNewDecFromStr("12.3453123123"), 10, false}, + // cut precision to 5 decimals: 3212.4623423462346 - 3212.46234 + {osmomath.NewBigDecWithPrec(32124623423462346, 13), sdk.MustNewDecFromStr("3212.46234"), 5, false}, + // no decimal point: 18012004 -> 18012004 + {osmomath.NewBigDecWithPrec(18012004, 0), sdk.MustNewDecFromStr("18012004"), 13, false}, + // if we try to convert to osmomath.Dec while specifying bigger precision than sdk.Dec has, panics + {osmomath.NewBigDecWithPrec(1009009009009009009, 17), sdk.MustNewDecFromStr("10.090090090090090090"), osmomath.PrecisionDec + 2, true}, + } + + for tcIndex, tc := range tests { + if tc.expPanic { + s.Require().Panics(func() { tc.d.DecWithPrecision(tc.precision) }) + } else { + var got osmomath.Dec + if tc.precision == osmomath.PrecisionDec { + got = tc.d.Dec() + } else { + got = tc.d.DecWithPrecision(tc.precision) + } + s.Require().Equal(tc.want, got, "bad Dec conversion, index: %v", tcIndex) + } + } +} + +func (s *decimalTestSuite) TestChopPrecision_Mutative() { + tests := []struct { + startValue osmomath.BigDec + expectedMutResult osmomath.BigDec + precision uint64 + }{ + {osmomath.NewBigDec(0), osmomath.MustNewBigDecFromStr("0"), 0}, + {osmomath.NewBigDec(1), osmomath.MustNewBigDecFromStr("1"), 0}, + {osmomath.NewBigDec(10), osmomath.MustNewBigDecFromStr("10"), 2}, + // how to read these comments: ab.cde(fgh) -> ab.cdefgh = initial BigDec; (fgh) = decimal places that will be truncated + // 5.1() + {osmomath.NewBigDecWithPrec(51, 1), osmomath.MustNewBigDecFromStr("5.1"), 1}, + // 1.(0010) + {osmomath.NewBigDecWithPrec(10010, 4), osmomath.MustNewBigDecFromStr("1"), 0}, + // 1009.31254(83952) + {osmomath.NewBigDecWithPrec(10093125483952, 10), osmomath.MustNewBigDecFromStr("1009.31254"), 5}, + // 0.1009312548(3952) + {osmomath.NewBigDecWithPrec(10093125483952, 14), osmomath.MustNewBigDecFromStr("0.1009312548"), 10}, + // Edge case: max precision. Should remain unchanged + {osmomath.MustNewBigDecFromStr("1.000000000000000000000000000000000001"), osmomath.MustNewBigDecFromStr("1.000000000000000000000000000000000001"), osmomath.PrecisionBigDec}, + } + for id, tc := range tests { + name := "testcase_" + fmt.Sprint(id) + s.Run(name, func() { + startMut := tc.startValue.Clone() + startNonMut := tc.startValue.Clone() + + resultMut := startMut.ChopPrecisionMut(tc.precision) + resultNonMut := startNonMut.ChopPrecision(tc.precision) + + s.assertMutResult(tc.expectedMutResult, tc.startValue, resultMut, resultNonMut, startMut, startNonMut) + }) + } +} func (s *decimalTestSuite) TestQuoRoundUp_MutativeAndNonMutative() { tests := []struct { d1, d2, expQuoRoundUpMut osmomath.BigDec diff --git a/simulation/simtypes/random/sdkrand.go b/simulation/simtypes/random/sdkrand.go index 7c6dc8f0274..4203f9ce846 100644 --- a/simulation/simtypes/random/sdkrand.go +++ b/simulation/simtypes/random/sdkrand.go @@ -84,7 +84,7 @@ func RandomDecAmount(r *rand.Rand, max osmomath.Dec) osmomath.Dec { randInt = big.NewInt(0).Rand(r, max.BigInt()) } - return osmomath.NewDecFromBigIntWithPrec(randInt, sdk.Precision) + return osmomath.NewDecFromBigIntWithPrec(randInt, osmomath.PrecisionDec) } // RandTimestamp generates a random timestamp diff --git a/x/concentrated-liquidity/math/tick.go b/x/concentrated-liquidity/math/tick.go index 276876e3ab4..e571edaf2b3 100644 --- a/x/concentrated-liquidity/math/tick.go +++ b/x/concentrated-liquidity/math/tick.go @@ -199,10 +199,9 @@ func CalculatePriceToTick(price osmomath.BigDec) (tickIndex int64, err error) { // N.B. this exists to maintain backwards compatibility with // the old version of the function that operated on decimal with precision of 18. if price.GTE(types.MinSpotPriceBigDec) { - // TODO: implement efficient big decimal truncation. // It is acceptable to truncate price as the minimum we support is // 10**-12 which is above the smallest value of sdk.Dec. - price = osmomath.BigDecFromDec(price.Dec()) + price.ChopPrecisionMut(osmomath.PrecisionDec) } // The approach here is to try determine which "geometric spacing" are we in. diff --git a/x/epochs/go.mod b/x/epochs/go.mod index d80be37d351..e7c1e59954d 100644 --- a/x/epochs/go.mod +++ b/x/epochs/go.mod @@ -28,10 +28,10 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/btcsuite/btcd v0.22.3 // indirect - github.com/bytedance/sonic v1.10.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -103,7 +103,6 @@ require ( github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.27.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -122,11 +121,11 @@ require ( go.opencensus.io v0.24.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.12.0 // indirect + golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.0 // indirect google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/x/epochs/go.sum b/x/epochs/go.sum index b0dd9ad5af3..c888a8d58ee 100644 --- a/x/epochs/go.sum +++ b/x/epochs/go.sum @@ -147,7 +147,6 @@ github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= -github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -831,7 +830,6 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1273,7 +1271,6 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=