From cb5b3226b98b421752ceec0cdc04b86a3a939f6a Mon Sep 17 00:00:00 2001 From: Markus Waas Date: Fri, 29 Apr 2022 19:15:48 +1200 Subject: [PATCH] feat: add FPDecimals (#24) * chore: make volatility query response optional * chore: fix linting * chore: remove schema and failed tests from CI until fixed * feat: add math lib from nebula-contracts * taken from https://github.com/nebula-protocol/nebula-contracts/tree/a5ff0e3e4285e38a310c7a6e024f6e3e2b75c538/libraries/cluster-math * feat: use new FPDecimal * fix: add cargo debug config * fix: update injective math dependencies --- Cargo.lock | 686 +++++++++++++++++- packages/injective-cosmwasm/Cargo.toml | 3 +- packages/injective-cosmwasm/src/msg.rs | 23 +- packages/injective-cosmwasm/src/query.rs | 67 +- packages/injective-math/.cargo/config | 5 + packages/injective-math/Cargo.toml | 27 + packages/injective-math/README.md | 1 + .../src/fp_decimal/arithmetic.rs | 350 +++++++++ .../injective-math/src/fp_decimal/display.rs | 56 ++ packages/injective-math/src/fp_decimal/exp.rs | 87 +++ .../injective-math/src/fp_decimal/from_str.rs | 70 ++ .../injective-math/src/fp_decimal/hyper.rs | 68 ++ packages/injective-math/src/fp_decimal/log.rs | 129 ++++ packages/injective-math/src/fp_decimal/mod.rs | 150 ++++ .../injective-math/src/fp_decimal/serde.rs | 45 ++ packages/injective-math/src/lib.rs | 69 ++ packages/injective-math/src/vector.rs | 38 + 17 files changed, 1820 insertions(+), 54 deletions(-) create mode 100644 packages/injective-math/.cargo/config create mode 100644 packages/injective-math/Cargo.toml create mode 100644 packages/injective-math/README.md create mode 100644 packages/injective-math/src/fp_decimal/arithmetic.rs create mode 100644 packages/injective-math/src/fp_decimal/display.rs create mode 100644 packages/injective-math/src/fp_decimal/exp.rs create mode 100644 packages/injective-math/src/fp_decimal/from_str.rs create mode 100644 packages/injective-math/src/fp_decimal/hyper.rs create mode 100644 packages/injective-math/src/fp_decimal/log.rs create mode 100644 packages/injective-math/src/fp_decimal/mod.rs create mode 100644 packages/injective-math/src/fp_decimal/serde.rs create mode 100644 packages/injective-math/src/lib.rs create mode 100644 packages/injective-math/src/vector.rs diff --git a/Cargo.lock b/Cargo.lock index 8df72c63..de66b21c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,34 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bigint" +version = "4.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0e8c8a600052b52482eff2cf4d810e462fdff1f656ac1ecb6232132a1ed7def" +dependencies = [ + "byteorder", + "crunchy 0.1.6", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -23,18 +45,49 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -44,12 +97,80 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "const-oid" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + [[package]] name = "cosmwasm-crypto" version = "1.0.0-beta8" @@ -118,6 +239,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" + [[package]] name = "crunchy" version = "0.2.2" @@ -182,6 +318,16 @@ dependencies = [ "serde", ] +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "der" version = "0.4.5" @@ -200,6 +346,39 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "dyn-clone" version = "1.0.5" @@ -255,7 +434,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" dependencies = [ - "crunchy", + "crunchy 0.2.2", "fixed-hash", "impl-rlp", "impl-serde", @@ -268,7 +447,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b054df51e53f253837ea422681215b42823c02824bde982699d0dceecf6165a1" dependencies = [ - "crunchy", + "crunchy 0.2.2", "ethbloom", "ethereum-types-serialize", "fixed-hash", @@ -285,6 +464,16 @@ dependencies = [ "serde", ] +[[package]] +name = "expat-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" +dependencies = [ + "cmake", + "pkg-config", +] + [[package]] name = "ff" version = "0.10.1" @@ -308,12 +497,79 @@ dependencies = [ "static_assertions 0.2.5", ] +[[package]] +name = "float-ord" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" + +[[package]] +name = "font-kit" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c9a156ec38864999bc9c4156e5f3b50224d4a5578028a64e5a3875caa9ee28" +dependencies = [ + "bitflags", + "byteorder", + "core-foundation", + "core-graphics", + "core-text", + "dirs-next", + "dwrote", + "float-ord", + "freetype", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "servo-fontconfig", + "walkdir", + "winapi", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "forward_ref" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" +[[package]] +name = "freetype" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6" +dependencies = [ + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -349,7 +605,17 @@ checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gif" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b" +dependencies = [ + "color_quant", + "weezl", ] [[package]] @@ -388,6 +654,22 @@ dependencies = [ "digest", ] +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-iter", + "num-rational", + "num-traits", + "png", +] + [[package]] name = "impl-rlp" version = "0.2.1" @@ -408,11 +690,26 @@ dependencies = [ [[package]] name = "injective-cosmwasm" -version = "0.1.6" +version = "0.1.9" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "ethereum-types", + "injective-math", + "schemars", + "serde", + "subtle-encoding", +] + +[[package]] +name = "injective-math" +version = "0.1.2" +dependencies = [ + "bigint", + "cosmwasm-schema", + "cosmwasm-std", + "ethereum-types", + "plotters", "schemars", "serde", "subtle-encoding", @@ -434,6 +731,21 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.9.6" @@ -446,18 +758,111 @@ dependencies = [ "sha2", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "opaque-debug" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pkcs8" version = "0.7.6" @@ -468,6 +873,70 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "chrono", + "font-kit", + "image", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-bitmap" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21362fa905695e5618aefd169358f52e0e8bc4a8e05333cf780fda8cddc00b54" +dependencies = [ + "gif", + "image", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + [[package]] name = "proc-macro2" version = "1.0.37" @@ -532,6 +1001,26 @@ dependencies = [ "getrandom 0.2.6", ] +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.6", + "redox_syscall", + "thiserror", +] + [[package]] name = "registry" version = "0.1.0" @@ -561,12 +1050,30 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schemars" version = "0.8.8" @@ -591,6 +1098,24 @@ dependencies = [ "syn", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.136" @@ -642,6 +1167,27 @@ dependencies = [ "serde", ] +[[package]] +name = "servo-fontconfig" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" +dependencies = [ + "libc", + "servo-fontconfig-sys", +] + +[[package]] +name = "servo-fontconfig-sys" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" +dependencies = [ + "expat-sys", + "freetype-sys", + "pkg-config", +] + [[package]] name = "sha2" version = "0.9.9" @@ -732,21 +1278,44 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "tiny-keccak" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" dependencies = [ - "crunchy", + "crunchy 0.2.2", ] +[[package]] +name = "ttf-parser" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" + [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "uint" version = "0.5.0" @@ -754,7 +1323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436" dependencies = [ "byteorder", - "crunchy", + "crunchy 0.2.2", "heapsize", "rustc-hex", ] @@ -766,7 +1335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" dependencies = [ "byteorder", - "crunchy", + "crunchy 0.2.2", "hex", "static_assertions 1.1.0", ] @@ -783,6 +1352,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -791,9 +1371,79 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" [[package]] name = "winapi" @@ -811,12 +1461,30 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "zeroize" version = "1.4.3" diff --git a/packages/injective-cosmwasm/Cargo.toml b/packages/injective-cosmwasm/Cargo.toml index c3260186..54134129 100644 --- a/packages/injective-cosmwasm/Cargo.toml +++ b/packages/injective-cosmwasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "injective-cosmwasm" -version = "0.1.6" +version = "0.1.9" authors = ["Albert Chon "] edition = "2018" description = "Bindings for CosmWasm contracts to call into custom modules of Injective Core" @@ -16,6 +16,7 @@ schemars = "0.8.8" serde = { version = "1.0.136", default-features = false, features = ["derive"] } ethereum-types = "0.5.2" subtle-encoding = { version = "0.5.1", features = ["bech32-preview"] } +injective-math = { path = "../injective-math", version = "0.1.2" } [dev-dependencies] cosmwasm-schema = { version = "1.0.0-beta10" } diff --git a/packages/injective-cosmwasm/src/msg.rs b/packages/injective-cosmwasm/src/msg.rs index 34bbf17c..0ab15a4e 100644 --- a/packages/injective-cosmwasm/src/msg.rs +++ b/packages/injective-cosmwasm/src/msg.rs @@ -1,8 +1,9 @@ +use injective_math::FPDecimal; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::route::InjectiveRoute; -use cosmwasm_std::{Addr, Coin, CosmosMsg, CustomMsg, Decimal256 as Decimal}; +use cosmwasm_std::{Addr, Coin, CosmosMsg, CustomMsg}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -30,8 +31,8 @@ pub struct OrderData { pub struct OrderInfo { pub subaccount_id: String, pub fee_recipient: String, - pub price: Decimal, - pub quantity: Decimal, + pub price: FPDecimal, + pub quantity: FPDecimal, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -47,15 +48,15 @@ pub struct DerivativeOrder { pub market_id: String, pub order_info: OrderInfo, pub order_type: i32, - pub margin: Decimal, + pub margin: FPDecimal, pub trigger_price: Option, } impl DerivativeOrder { pub fn new( - price: Decimal, - quantity: Decimal, - margin: Decimal, + price: FPDecimal, + quantity: FPDecimal, + margin: FPDecimal, is_buy: bool, market_id: &str, subaccount_id: &str, @@ -77,16 +78,16 @@ impl DerivativeOrder { pub fn is_reduce_only(&self) -> bool { self.margin.is_zero() } - pub fn get_price(&self) -> Decimal { + pub fn get_price(&self) -> FPDecimal { self.order_info.price } - pub fn get_qty(&self) -> Decimal { + pub fn get_qty(&self) -> FPDecimal { self.order_info.quantity } - pub fn get_val(&self) -> Decimal { + pub fn get_val(&self) -> FPDecimal { self.get_price() * self.get_qty() } - pub fn get_margin(&self) -> Decimal { + pub fn get_margin(&self) -> FPDecimal { self.margin } pub fn non_reduce_only_is_invalid(&self) -> bool { diff --git a/packages/injective-cosmwasm/src/query.rs b/packages/injective-cosmwasm/src/query.rs index 19e7d939..1b200d79 100644 --- a/packages/injective-cosmwasm/src/query.rs +++ b/packages/injective-cosmwasm/src/query.rs @@ -1,8 +1,9 @@ +use injective_math::FPDecimal; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::{msg::OrderInfo, route::InjectiveRoute}; -use cosmwasm_std::{CustomQuery, Decimal256 as Decimal}; +use cosmwasm_std::CustomQuery; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -65,39 +66,39 @@ pub struct SubaccountDepositResponse { pub struct Position { #[serde(default)] pub isLong: bool, - pub quantity: Decimal, - pub entry_price: Decimal, + pub quantity: FPDecimal, + pub entry_price: FPDecimal, #[serde(default)] - pub margin: Decimal, - pub cumulative_funding_entry: Decimal, + pub margin: FPDecimal, + pub cumulative_funding_entry: FPDecimal, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct EffectivePosition { #[serde(default)] pub is_long: bool, - pub quantity: Decimal, - pub entry_price: Decimal, + pub quantity: FPDecimal, + pub entry_price: FPDecimal, #[serde(default)] - pub effective_margin: Decimal, + pub effective_margin: FPDecimal, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct DerivativeLimitOrder { pub order_info: OrderInfo, pub order_type: i32, - pub margin: Decimal, - pub fillable: Decimal, - pub trigger_price: Option, + pub margin: FPDecimal, + pub fillable: FPDecimal, + pub trigger_price: Option, pub order_hash: String, } impl DerivativeLimitOrder { pub fn new( - margin: Decimal, - fillable: Decimal, + margin: FPDecimal, + fillable: FPDecimal, order_hash: String, - trigger_price: Option, + trigger_price: Option, order_type: i32, order_info: OrderInfo, ) -> DerivativeLimitOrder { @@ -130,10 +131,10 @@ pub struct SubaccountEffectivePositionInMarketResponse { #[allow(non_snake_case)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct TrimmedDerivativeLimitOrder { - pub price: Decimal, - pub quantity: Decimal, - pub margin: Decimal, - pub fillable: Decimal, + pub price: FPDecimal, + pub quantity: FPDecimal, + pub margin: FPDecimal, + pub fillable: FPDecimal, pub isBuy: bool, pub order_hash: String, } @@ -155,12 +156,12 @@ pub struct PerpetualMarketFundingResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct DerivativeMarketVolatilityResponse { - pub volatility: Option, + pub volatility: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct SpotMarketVolatilityResponse { - pub volatility: Option, + pub volatility: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -172,18 +173,18 @@ pub struct DerivativeMarketResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Deposit { #[serde(default)] - pub available_balance: Decimal, + pub available_balance: FPDecimal, #[serde(default)] - pub total_balance: Decimal, + pub total_balance: FPDecimal, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct PerpetualMarketInfo { pub market_id: String, #[serde(default)] - pub hourly_funding_rate_cap: Decimal, + pub hourly_funding_rate_cap: FPDecimal, #[serde(default)] - pub hourly_interest_rate: Decimal, + pub hourly_interest_rate: FPDecimal, #[serde(default)] pub next_funding_timestamp: i64, pub funding_interval: i64, @@ -192,9 +193,9 @@ pub struct PerpetualMarketInfo { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct PerpetualMarketFunding { #[serde(default)] - pub cumulative_funding: Decimal, + pub cumulative_funding: FPDecimal, #[serde(default)] - pub cumulative_price: Decimal, + pub cumulative_price: FPDecimal, #[serde(default)] pub last_timestamp: i64, } @@ -214,7 +215,7 @@ pub struct FullDerivativeMarketPerpetualInfo { pub struct FullDerivativeMarket { pub market: Option, pub info: Option, - pub mark_price: Decimal, + pub mark_price: FPDecimal, } #[allow(non_snake_case)] @@ -229,14 +230,14 @@ pub struct DerivativeMarket { pub oracle_scale_factor: u32, pub quote_denom: String, pub market_id: String, - pub initial_margin_ratio: Decimal, - pub maintenance_margin_ratio: Decimal, - pub maker_fee_rate: Decimal, - pub taker_fee_rate: Decimal, + pub initial_margin_ratio: FPDecimal, + pub maintenance_margin_ratio: FPDecimal, + pub maker_fee_rate: FPDecimal, + pub taker_fee_rate: FPDecimal, #[serde(default)] pub isPerpetual: bool, #[serde(default)] pub status: i32, - pub min_price_tick_size: Decimal, - pub min_quantity_tick_size: Decimal, + pub min_price_tick_size: FPDecimal, + pub min_quantity_tick_size: FPDecimal, } diff --git a/packages/injective-math/.cargo/config b/packages/injective-math/.cargo/config new file mode 100644 index 00000000..8c7cbe46 --- /dev/null +++ b/packages/injective-math/.cargo/config @@ -0,0 +1,5 @@ +[alias] +wasm = "build --release --target wasm32-unknown-unknown" +wasm-debug = "build --target wasm32-unknown-unknown" +unit-test = "test --lib --features backtraces" +schema = "run --example schema" diff --git a/packages/injective-math/Cargo.toml b/packages/injective-math/Cargo.toml new file mode 100644 index 00000000..1c2dc9a4 --- /dev/null +++ b/packages/injective-math/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "injective-math" +version = "0.1.2" +authors = ["Markus Waas "] +edition = "2018" +description = "Math library for CosmWasm contracts in Injective Protocol" +repository = "https://github.com/InjectiveLabs/cw-injective/tree/master/packages/injective-math" +license = "Apache-2.0" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] + +[dependencies] +cosmwasm-std = { version = "1.0.0-beta10" } +schemars = "0.8.8" +serde = { version = "1.0.136", default-features = false, features = ["derive"] } +ethereum-types = "0.5.2" +subtle-encoding = { version = "0.5.1", features = ["bech32-preview"] } +bigint = "4" + +[dev-dependencies] +cosmwasm-schema = { version = "1.0.0-beta10" } +plotters = "^0.3.0" diff --git a/packages/injective-math/README.md b/packages/injective-math/README.md new file mode 100644 index 00000000..212c4b65 --- /dev/null +++ b/packages/injective-math/README.md @@ -0,0 +1 @@ +# injective-math diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs new file mode 100644 index 00000000..200de36b --- /dev/null +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -0,0 +1,350 @@ +/// Arithmetic operators for FPDecimal +use crate::fp_decimal::{FPDecimal, U256}; +use std::ops; + +impl FPDecimal { + pub fn _add(x: FPDecimal, y: FPDecimal) -> FPDecimal { + if x.sign == y.sign { + return FPDecimal { + num: x.num + y.num, + sign: x.sign, + }; + } + + if x.num > y.num { + return FPDecimal { + num: x.num - y.num, + sign: x.sign, + }; + } + let mut sign = y.sign; + if y.num == x.num { + sign = 1; + } + + FPDecimal { num: y.num - x.num, sign } + } + + pub fn add(&self, other: i128) -> FPDecimal { + FPDecimal::_add(*self, FPDecimal::from(other)) + } + + pub fn _sub(x: FPDecimal, y: FPDecimal) -> FPDecimal { + let neg_y = FPDecimal { + num: y.num, + sign: 1 - y.sign, + }; + FPDecimal::_add(x, neg_y) + } + + pub fn sub(&self, other: i128) -> FPDecimal { + FPDecimal::_sub(*self, FPDecimal::from(other)) + } + + pub fn _mul(x: FPDecimal, y: FPDecimal) -> FPDecimal { + let mut sign = 1; + if x.sign != y.sign { + sign = 0; + } + let x1: U256 = FPDecimal::_int(x).num / FPDecimal::ONE.num; + let mut x2: U256 = FPDecimal::_fraction(x).num; + let y1: U256 = FPDecimal::_int(y).num / FPDecimal::ONE.num; + let mut y2: U256 = FPDecimal::_fraction(y).num; + let mut x1y1 = x1 * y1; + let dec_x1y1 = x1y1 * FPDecimal::ONE.num; + x1y1 = dec_x1y1; + let x2y1 = x2 * y1; + let x1y2 = x1 * y2; + x2 = x2 / FPDecimal::MUL_PRECISION.num; + y2 = y2 / FPDecimal::MUL_PRECISION.num; + let x2y2 = x2 * y2; + let mut result = x1y1; + result = result + x2y1; + result = result + x1y2; + result = result + x2y2; + FPDecimal { num: result, sign } + } + + pub fn mul(&self, other: i128) -> FPDecimal { + FPDecimal::_mul(*self, FPDecimal::from(other)) + } + + pub fn _div(x: FPDecimal, y: FPDecimal) -> FPDecimal { + if y == FPDecimal::ONE { + return x; + } + + assert_ne!(y.num, U256::zero()); + FPDecimal { + num: FPDecimal::ONE.num * x.num / y.num, + sign: 1 ^ x.sign ^ y.sign, + } + } + + pub fn div(&self, other: i128) -> FPDecimal { + FPDecimal::_div(*self, FPDecimal::from(other)) + } + + pub fn reciprocal(x: FPDecimal) -> FPDecimal { + assert!(x.num != U256::zero()); + FPDecimal { + num: FPDecimal::ONE.num * FPDecimal::ONE.num / x.num, + sign: x.sign, + } + } + + pub fn abs(&self) -> FPDecimal { + FPDecimal { num: self.num, sign: 1i8 } + } +} + +impl ops::Add for FPDecimal { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + FPDecimal::_add(self, rhs) + } +} + +impl ops::Sub for FPDecimal { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + FPDecimal::_sub(self, rhs) + } +} + +impl ops::Mul for FPDecimal { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + FPDecimal::_mul(self, rhs) + } +} + +impl ops::Div for FPDecimal { + type Output = Self; + + fn div(self, rhs: Self) -> Self { + FPDecimal::_div(self, rhs) + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use bigint::U256; + + #[test] + fn test_into_u128() { + let first_num: u128 = FPDecimal::from(1234567890123456789u128).into(); + assert_eq!(first_num, 1234567890123456789u128); + + let num: u128 = FPDecimal::from(u128::MAX).into(); + assert_eq!(num, u128::MAX); + } + + #[test] + #[should_panic(expected = "overflow")] + fn panic_into_u128() { + let _: u128 = (FPDecimal::from(u128::MAX) + FPDecimal::ONE).into(); + } + + // #[test] + // fn test_overflow() { + // let num1 = FPDecimal::from(1701411834604692317316873037158841i128); + // assert_eq!(num1, FPDecimal::one()); + // } + + #[test] + fn test_add() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let eight = FPDecimal { + num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_add(five, three), eight); + } + + #[test] + fn test_add_neg() { + let neg_five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let neg_three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let neg_eight = FPDecimal { + num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + assert_eq!(FPDecimal::_add(neg_five, neg_three), neg_eight); + } + + #[test] + fn test_sub() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let two = FPDecimal { + num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_sub(five, three), two); + } + + #[test] + fn test_sub_neg() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let neg_three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let eight = FPDecimal { + num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_sub(five, neg_three), eight); + } + + #[test] + fn test_mul() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let fifteen = FPDecimal { + num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_mul(five, three), fifteen); + } + + #[test] + fn test_mul_pos_neg() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let neg_three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let neg_fifteen = FPDecimal { + num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + assert_eq!(FPDecimal::_mul(five, neg_three), neg_fifteen); + } + + #[test] + fn test_mul_neg_pos() { + let neg_five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let neg_fifteen = FPDecimal { + num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + assert_eq!(FPDecimal::_mul(neg_five, three), neg_fifteen); + } + + #[test] + fn test_mul_neg_neg() { + let neg_five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let neg_three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let fifteen = FPDecimal { + num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_mul(neg_five, neg_three), fifteen); + } + + #[test] + fn test_div() { + let hundred = FPDecimal { + num: U256([100, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let twenty = FPDecimal { + num: U256([20, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(FPDecimal::_div(hundred, five), twenty); + } + + #[test] + fn test_reciprocal() { + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let point_2 = FPDecimal { + num: FPDecimal::ONE.num / U256([5, 0, 0, 0]), + sign: 1, + }; + assert_eq!(FPDecimal::reciprocal(five), point_2); + } + + #[test] + fn test_abs() { + let neg_five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 0, + }; + let five = FPDecimal { + num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + assert_eq!(neg_five.abs(), five); + } + + #[test] + fn test_div_identity() { + for i in 1..10000 { + let a = FPDecimal { + num: U256([i, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + + assert_eq!(a / a, FPDecimal::ONE); + } + } +} diff --git a/packages/injective-math/src/fp_decimal/display.rs b/packages/injective-math/src/fp_decimal/display.rs new file mode 100644 index 00000000..44653d2c --- /dev/null +++ b/packages/injective-math/src/fp_decimal/display.rs @@ -0,0 +1,56 @@ +use crate::fp_decimal::FPDecimal; +use std::fmt; + +impl fmt::Display for FPDecimal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let sign = if self.sign == 0 { "-" } else { "" }; + let integer = self.int().abs(); + let fraction = (FPDecimal::_fraction(*self)).abs(); + + if fraction == FPDecimal::zero() { + write!(f, "{}{}", sign, integer.num / FPDecimal::ONE.num) + } else { + let fraction_string = fraction.num.to_string(); // + let fraction_string = "0".repeat(FPDecimal::DIGITS - fraction_string.len()) + &fraction_string; + let integer_num = integer.num / FPDecimal::ONE.num; + f.write_str(sign)?; + f.write_str(&integer_num.to_string())?; + f.write_str(".")?; + f.write_str(fraction_string.trim_end_matches('0'))?; + + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use bigint::U256; + + #[test] + fn test_fmt_sub() { + let input: FPDecimal = FPDecimal::ONE + FPDecimal::from(3u128).div(100i128); + assert_eq!(&format!("{}", input), "1.03"); + } + + #[test] + fn test_fmt() { + assert_eq!(&format!("{}", FPDecimal::LN_1_5), "0.405465108108164382"); + } + + #[test] + fn test_fmt_neg() { + assert_eq!( + &format!( + "{}", + FPDecimal { + num: FPDecimal::ONE.num * U256([5, 0, 0, 0]), + sign: 0 + } + ), + "-5" + ); + } +} diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs new file mode 100644 index 00000000..bab7df96 --- /dev/null +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -0,0 +1,87 @@ +/// Exponential functions for FPDecimal +use crate::fp_decimal::{FPDecimal, U256}; + +impl FPDecimal { + // a^b + pub fn _pow(a: FPDecimal, b: FPDecimal) -> FPDecimal { + if a == FPDecimal::zero() { + return FPDecimal::zero(); + } + FPDecimal::_exp(FPDecimal::_mul(FPDecimal::_ln(a), b)) + } + + // e^(a) + pub fn _exp(a: FPDecimal) -> FPDecimal { + // this throws underflow with a sufficiently large negative exponent + // short circuit and just return 0 above a certain threshold + // otherwise if there is a long enough delay between updates on a cluster + // the penalty function will be bricked + if a.sign == 0 && a.num >= FPDecimal::from(45i128).num { + return FPDecimal::zero(); + } + let mut x = a.num; + let mut r = FPDecimal::ONE; + while x >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { + x = x - U256([10, 0, 0, 0]) * FPDecimal::ONE.num; + r = FPDecimal::_mul(r, FPDecimal::E_10); + } + if x == FPDecimal::ONE.num { + let val = FPDecimal::_mul(r, FPDecimal::E); + if a.sign == 0 { + return FPDecimal::reciprocal(val); + } + return val; + } else if x == FPDecimal::zero().num { + let val = r; + if a.sign == 0 { + return FPDecimal::reciprocal(val); + } + return val; + } + let mut tr = FPDecimal::ONE.num; + let mut d = tr; + for i in 1..((2 * FPDecimal::DIGITS + 1) as u64) { + d = (d * x) / (FPDecimal::ONE.num * U256([i, 0, 0, 0])); + tr = tr + d; + } + let val = FPDecimal::_mul(FPDecimal { num: tr, sign: 1 }, r); + if a.sign == 0 { + return FPDecimal::reciprocal(val); + } + val + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use bigint::U256; + + #[test] + fn test_exp() { + assert_eq!(FPDecimal::_exp(FPDecimal::ONE), FPDecimal::E); + } + + #[test] + fn test_exp0() { + assert_eq!(FPDecimal::_exp(FPDecimal::zero()), FPDecimal::ONE); + } + + #[test] + fn test_exp10() { + assert_eq!( + FPDecimal::_exp(FPDecimal { + num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1 + }), + FPDecimal::E_10 + ); + } + + #[test] + fn test_zero() { + // FPDecimal::_ln(FPDecimal::zero()); + FPDecimal::_pow(FPDecimal::zero(), FPDecimal::one().div(2i128)); + } +} diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs new file mode 100644 index 00000000..42721b2c --- /dev/null +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -0,0 +1,70 @@ +use bigint::U256; +use cosmwasm_std::StdError; +use std::str::FromStr; + +use crate::fp_decimal::FPDecimal; + +impl FromStr for FPDecimal { + type Err = StdError; + + /// Converts the decimal string to a FPDecimal + /// Possible inputs: "1.23", "1", "000012", "1.123000000" + /// Disallowed: "", ".23" + /// + /// This never performs any kind of rounding. + /// More than 18 fractional digits, even zeros, result in an error. + fn from_str(input: &str) -> Result { + let sign = if input.starts_with('-') { 0 } else { 1 }; + let parts: Vec<&str> = input.trim_start_matches('-').split('.').collect(); + match parts.len() { + 1 => { + let integer = U256::from_dec_str(parts[0]).map_err(|_| StdError::generic_err("Error parsing integer"))?; + Ok(FPDecimal { + num: integer * FPDecimal::ONE.num, + sign, + }) + } + 2 => { + let integer = U256::from_dec_str(parts[0]).map_err(|_| StdError::generic_err("Error parsing integer"))?; + let fraction = U256::from_dec_str(parts[1]).map_err(|_| StdError::generic_err("Error parsing fraction"))?; + let exp = FPDecimal::DIGITS + .checked_sub(parts[1].len()) + .ok_or_else(|| StdError::generic_err(format!("Cannot parse more than {} fractional digits", FPDecimal::DIGITS)))?; + + Ok(FPDecimal { + num: integer * FPDecimal::ONE.num + fraction * U256::exp10(exp), + sign, + }) + } + _ => Err(StdError::generic_err("Unexpected number of dots")), + } + + //Ok(FPDecimal {num: num * FPDecimal::ONE.num, sign: sign}) + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use bigint::U256; + use std::str::FromStr; + + #[test] + fn test_from_str() { + let val = FPDecimal::from_str("-1.23"); + assert_eq!( + val.unwrap(), + FPDecimal { + num: U256([123, 0, 0, 0]) * FPDecimal::ONE.num / U256::from(100), + sign: 0 + } + ); + } + + #[test] + fn test_from_str_one() { + let val = FPDecimal::from_str("1"); + assert_eq!(val.unwrap(), FPDecimal::ONE); + } +} diff --git a/packages/injective-math/src/fp_decimal/hyper.rs b/packages/injective-math/src/fp_decimal/hyper.rs new file mode 100644 index 00000000..0c79da6e --- /dev/null +++ b/packages/injective-math/src/fp_decimal/hyper.rs @@ -0,0 +1,68 @@ +/// Hyperbolic Trig functions for FPDecimal +use crate::fp_decimal::{FPDecimal, U256}; + +impl FPDecimal { + pub fn _sinh(x: FPDecimal) -> FPDecimal { + let neg_x: FPDecimal = FPDecimal { + num: x.num, + sign: 1 - x.sign, + }; + let denominator = FPDecimal { + num: FPDecimal::ONE.num * U256([2, 0, 0, 0]), + sign: 1, + }; + let numerator: FPDecimal = FPDecimal::_sub(FPDecimal::_exp(x), FPDecimal::_exp(neg_x)); + FPDecimal::_div(numerator, denominator) + } + + pub fn sinh(&self) -> FPDecimal { + FPDecimal::_sinh(*self) + } + + pub fn _cosh(x: FPDecimal) -> FPDecimal { + let neg_x: FPDecimal = FPDecimal { + num: x.num, + sign: 1 - x.sign, + }; + let denominator = FPDecimal { + num: FPDecimal::ONE.num * U256([2, 0, 0, 0]), + sign: 1, + }; + let numerator: FPDecimal = FPDecimal::_add(FPDecimal::_exp(x), FPDecimal::_exp(neg_x)); + FPDecimal::_div(numerator, denominator) + } + + pub fn cosh(&self) -> FPDecimal { + FPDecimal::_cosh(*self) + } + + pub fn _tanh(x: FPDecimal) -> FPDecimal { + FPDecimal::_div(FPDecimal::_sinh(x), FPDecimal::_cosh(x)) + } + + pub fn tanh(&self) -> FPDecimal { + FPDecimal::_tanh(*self) + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use std::str::FromStr; + + #[test] + fn test_sinh() { + assert_eq!(FPDecimal::_sinh(FPDecimal::ONE), FPDecimal::from_str("1.175201193643801457").unwrap()); + } + + #[test] + fn test_cosh() { + assert_eq!(FPDecimal::_cosh(FPDecimal::ONE), FPDecimal::from_str("1.543080634815243778").unwrap()); + } + + #[test] + fn test_tanh() { + assert_eq!(FPDecimal::_tanh(FPDecimal::ONE), FPDecimal::from_str("0.761594155955764888").unwrap()); + } +} diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs new file mode 100644 index 00000000..8f7d661f --- /dev/null +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -0,0 +1,129 @@ +/// Logarithmic functions for FPDecimal +use crate::fp_decimal::{FPDecimal, U256}; + +impl FPDecimal { + /// natural logarithm + #[allow(clippy::many_single_char_names)] + pub fn _ln(a: FPDecimal) -> FPDecimal { + assert!(a.sign != 0); + assert!(a != FPDecimal::zero()); + let mut v = a.num; + let mut r = FPDecimal::zero(); + while v <= FPDecimal::ONE.num / U256([10, 0, 0, 0]) { + v = v * U256([10, 0, 0, 0]); + r = r - FPDecimal::LN_10; + } + while v >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { + v = v / U256([10, 0, 0, 0]); + r = r + FPDecimal::LN_10; + } + while v < FPDecimal::ONE.num { + v = FPDecimal::_mul(FPDecimal { num: v, sign: 1 }, FPDecimal::E).num; + r = r - FPDecimal::ONE; + } + while v > FPDecimal::E.num { + v = FPDecimal::_div(FPDecimal { num: v, sign: 1 }, FPDecimal::E).num; + r = r + FPDecimal::ONE; + } + if v == FPDecimal::ONE.num { + return r; + // return FPDecimal { num: r, sign: 1 }; + } + if v == FPDecimal::E.num { + return r + FPDecimal::ONE; + // return FPDecimal { + // num: FPDecimal::ONE.num + r, + // sign: 1, + // }; + } + + let frac_1_5_fpdec = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num / U256([2, 0, 0, 0]), + sign: 1, + }; + let v = FPDecimal { num: v, sign: 1 } - frac_1_5_fpdec; + + r = r + FPDecimal::LN_1_5; + + let mut m = FPDecimal::ONE * v + / (v + FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }); + + r = r + FPDecimal { + num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + } * m; + let m2 = m * m / FPDecimal::ONE; + let mut i: u64 = 3; + + loop { + m = m * m2 / FPDecimal::ONE; + + let fpdec_i = FPDecimal { + num: U256([i, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + r = r + FPDecimal { + num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + } * m + / fpdec_i; + i += 2; + if i >= 3 + 2 * FPDecimal::DIGITS as u64 { + break; + } + } + r + } + + pub fn ln(&self) -> FPDecimal { + FPDecimal::_ln(*self) + } +} + +#[cfg(test)] +mod tests { + + use crate::FPDecimal; + use bigint::U256; + + #[test] + fn test_ln_sanity() { + let half = FPDecimal::one().div(2i128); + println!("{}", FPDecimal::_ln(half)); // works if you comment this out + let num = FPDecimal::one().mul(5).div(4); + println!("{}", FPDecimal::_pow(num, half)); + } + + #[test] + fn test_ln() { + assert_eq!(FPDecimal::_ln(FPDecimal::E), FPDecimal::ONE); + } + + #[test] + fn test_ln10() { + assert_eq!( + FPDecimal::_ln(FPDecimal { + num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1 + }), + FPDecimal::LN_10 + ); + } + + #[test] + fn test_ln1_5() { + let three = FPDecimal { + num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let two = FPDecimal { + num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1, + }; + let one_point_five = FPDecimal::_div(three, two); + assert_eq!(FPDecimal::_ln(one_point_five), FPDecimal::LN_1_5); + } +} diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs new file mode 100644 index 00000000..29ea515b --- /dev/null +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -0,0 +1,150 @@ +use bigint::U256; +use schemars::JsonSchema; +// pub struct FPDecimal(#[schemars(with = "String")] pub i128); + +#[allow(clippy::upper_case_acronyms)] +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] +pub struct FPDecimal { + #[schemars(with = "String")] + pub num: U256, + pub sign: i8, +} + +impl From for FPDecimal { + fn from(x: u128) -> FPDecimal { + FPDecimal { + num: U256::from_little_endian(&x.to_le_bytes()) * FPDecimal::ONE.num, + sign: 1, + } + } +} + +impl From for FPDecimal { + fn from(x: i128) -> FPDecimal { + let mut sign = 1; + if x < 0 { + sign = 0; + } + + let abs_x: u128 = x.abs() as u128; + FPDecimal { + num: U256::from_little_endian(&abs_x.to_le_bytes()) * FPDecimal::ONE.num, + sign, + } + } +} + +impl From for u128 { + fn from(x: FPDecimal) -> u128 { + let num: U256 = x.int().num / FPDecimal::ONE.num; + if num.bits() > 128 { + panic!("overflow"); + } + + let mut array: [u8; 32] = [0; 32]; + num.to_little_endian(&mut array); + + let mut arr2: [u8; 16] = Default::default(); + arr2.copy_from_slice(&array[0..16]); + u128::from_le_bytes(arr2) + } +} + +// #[cfg(not(target_arch = "wasm32"))] +// impl convert::From for f32 { +// fn from(x: FPDecimal) -> f32 { +// f32::from_str(&x.to_string()).unwrap() +// } +// } + +impl FPDecimal { + pub const MAX: FPDecimal = FPDecimal { num: U256::MAX, sign: 1 }; + pub const MIN: FPDecimal = FPDecimal { num: U256::MAX, sign: 0 }; + pub const DIGITS: usize = 18; + pub const ONE: FPDecimal = FPDecimal { + num: U256([1_000_000_000_000_000_000, 0, 0, 0]), + sign: 1, + }; + pub const MUL_PRECISION: FPDecimal = FPDecimal { + num: U256([1_000_000_000, 0, 0, 0]), + sign: 1, + }; + pub const E_10: FPDecimal = FPDecimal { + num: U256([1053370797511887454u64, 1194u64, 0, 0]), + sign: 1, + }; // e^10 + pub const E: FPDecimal = FPDecimal { + num: U256([2718281828459045235, 0, 0, 0]), + sign: 1, + }; + pub const LN_10: FPDecimal = FPDecimal { + num: U256([2302585092994045684, 0, 0, 0]), + sign: 1, + }; // ln(10) + pub const LN_1_5: FPDecimal = FPDecimal { + num: U256([405465108108164382, 0, 0, 0]), + sign: 1, + }; // ln(1.5) + + pub const fn one() -> FPDecimal { + FPDecimal::ONE + } + + pub const fn zero() -> FPDecimal { + FPDecimal { + num: U256([0, 0, 0, 0]), + sign: 1, + } + } + + pub fn is_zero(&self) -> bool { + self.num.is_zero() + } + + pub const fn max() -> FPDecimal { + FPDecimal::MAX + } + + pub const fn min() -> FPDecimal { + FPDecimal::MIN + } + + pub const fn e() -> FPDecimal { + FPDecimal::E + } + + pub fn _int(x: FPDecimal) -> FPDecimal { + let x1 = x.num; + let x1_1 = x1 / FPDecimal::ONE.num; + let x_final = x1_1 * FPDecimal::ONE.num; + FPDecimal { num: x_final, sign: x.sign } + } + + pub fn int(&self) -> FPDecimal { + FPDecimal::_int(*self) + } + + pub fn _sign(x: FPDecimal) -> i8 { + x.sign + } + + pub fn _fraction(x: FPDecimal) -> FPDecimal { + let x1 = x.num; + FPDecimal { + num: x1 - FPDecimal::_int(x).num, + sign: x.sign, + } + } + + pub fn fraction(&self) -> FPDecimal { + FPDecimal::_fraction(*self) + } +} + +mod arithmetic; +mod display; +mod exp; +mod from_str; +mod hyper; +mod log; +mod serde; // cosmwasm serialization diff --git a/packages/injective-math/src/fp_decimal/serde.rs b/packages/injective-math/src/fp_decimal/serde.rs new file mode 100644 index 00000000..6b726150 --- /dev/null +++ b/packages/injective-math/src/fp_decimal/serde.rs @@ -0,0 +1,45 @@ +use crate::fp_decimal::FPDecimal; +use serde::{de, ser, Deserialize, Deserializer, Serialize}; +use std::fmt; +use std::str::FromStr; + +#[allow(clippy::upper_case_acronyms)] +struct FPDecimalVisitor; + +impl<'de> de::Visitor<'de> for FPDecimalVisitor { + type Value = FPDecimal; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("FPDecimal (string-encoded)") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + match FPDecimal::from_str(v) { + Ok(d) => Ok(d), + Err(e) => Err(E::custom(format!("Error parsing FPDecimal '{}': {}", v, e))), + } + } +} + +/// Serializes as a decimal string +impl Serialize for FPDecimal { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_str(&format!("{}", &self)) + } +} + +/// Deserializes as a base64 string +impl<'de> Deserialize<'de> for FPDecimal { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(FPDecimalVisitor) + } +} diff --git a/packages/injective-math/src/lib.rs b/packages/injective-math/src/lib.rs new file mode 100644 index 00000000..5844e286 --- /dev/null +++ b/packages/injective-math/src/lib.rs @@ -0,0 +1,69 @@ +pub mod fp_decimal; +pub mod vector; + +use cosmwasm_std::{StdResult, Uint128}; +pub use fp_decimal::*; +use std::str::FromStr; +pub use vector::*; + +/// ## Description +/// Calculates the cluster imbalance. +/// +/// ## Params +/// - **i** is a reference to an array containing objects of type [`FPDecimal`] which +/// is the asset inventory. +/// +/// - **p** is a reference to an array containing objects of type [`FPDecimal`] which +/// are the prices of the assets. +/// +/// - **w** is a reference to an array containing objects of type [`FPDecimal`] which +/// are the target weights of the assets. +pub fn imbalance(i: &[FPDecimal], p: &[FPDecimal], w: &[FPDecimal]) -> FPDecimal { + // Target weights with prices + // -- u = elem_mul(targets, prices) + let u = mul(w, p); + // NAV with target weights instead of inventory + // -- wp = dot(targets, prices) + let wp = dot(w, p); + + // Suppose + // A is the capital allocation + // -- A = elem_mul(inventory, prices) + // A_opt is the optimal capital allocation + // -- A_opt = u * rescale_to_actual_NAV + // = u * dot(inventory, prices) / wp + + // Compute imbalance + // -- imb = | A_opt - A | + // = | u * dot(inventory, prices) / wp - elem_mul(inventory, prices) | + // = | u * dot(inventory, prices) - elem_mul(inventory, prices) * wp | / wp + let err_portfolio = sub(&mul_const(&u, dot(i, p)), &mul_const(&mul(i, p), wp)); + sum(&abs(&err_portfolio)) / wp +} + +/// ## Description +/// Converts an int32 array to a FPDecimal array. +/// +/// ## Params +/// - **arr** is a reference to an array containing objects of type [`u32`]. +pub fn int32_vec_to_fpdec(arr: &[u32]) -> Vec { + arr.iter().map(|val| FPDecimal::from(*val as u128)).collect() +} + +/// ## Description +/// Converts an Uint128 array to a FPDecimal array. +/// +/// ## Params +/// - **arr** is a reference to an array containing objects of type [`Uint128`]. +pub fn int_vec_to_fpdec(arr: &[Uint128]) -> Vec { + arr.iter().map(|val| FPDecimal::from(val.u128())).collect() +} + +/// ## Description +/// Converts an String array to a FPDecimal array. +/// +/// ## Params +/// - **arr** is a reference to an array containing objects of type [`String`]. +pub fn str_vec_to_fpdec(arr: &[String]) -> StdResult> { + arr.iter().map(|val| FPDecimal::from_str(val)).collect::>>() +} diff --git a/packages/injective-math/src/vector.rs b/packages/injective-math/src/vector.rs new file mode 100644 index 00000000..16b954ee --- /dev/null +++ b/packages/injective-math/src/vector.rs @@ -0,0 +1,38 @@ +use crate::fp_decimal::FPDecimal; + +pub fn sum(vec: &[FPDecimal]) -> FPDecimal { + vec.iter().fold(FPDecimal::zero(), |acc, &el| acc + el) +} + +pub fn dot(vec: &[FPDecimal], other: &[FPDecimal]) -> FPDecimal { + let mut sum = FPDecimal::zero(); + let mul_result: Vec = mul(vec, other); + for item in mul_result { + sum = sum + item; + } + sum +} + +pub fn mul(vec: &[FPDecimal], other: &[FPDecimal]) -> Vec { + vec.iter().zip(other).map(|(&i1, &i2)| i1 * i2).collect() +} + +pub fn mul_const(vec: &[FPDecimal], other: FPDecimal) -> Vec { + vec.iter().map(|&i| i * other).collect() +} + +pub fn div_const(vec: &[FPDecimal], other: FPDecimal) -> Vec { + vec.iter().map(|&i| i / other).collect() +} + +pub fn add(vec: &[FPDecimal], other: &[FPDecimal]) -> Vec { + vec.iter().zip(other).map(|(&i1, &i2)| i1 + i2).collect() +} + +pub fn sub(vec: &[FPDecimal], other: &[FPDecimal]) -> Vec { + vec.iter().zip(other).map(|(&i1, &i2)| i1 - i2).collect() +} + +pub fn abs(vec: &[FPDecimal]) -> Vec { + vec.iter().map(|&i| i.abs()).collect() +}