diff --git a/.cargo/audit.toml b/.cargo/audit.toml index 85a6c72..e011882 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -1,2 +1,5 @@ [advisories] -informational_warnings = [] \ No newline at end of file +informational_warnings = [] +ignore = [ + "RUSTSEC-2026-0235", # rkyv vulnerability, but we don't actually use it +] diff --git a/Cargo.lock b/Cargo.lock index 71f1d18..6c94d34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,18 +31,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -117,13 +117,13 @@ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "async-trait" -version = "0.1.91" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -264,9 +264,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" dependencies = [ "borsh-derive", "bytes", @@ -275,15 +275,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f347189c62a579b8cd5f80714efa178f52e461dc2e6d701d264f5ff22e566c" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -328,9 +328,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.4.0" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" dependencies = [ "find-msvc-tools", "shlex", @@ -350,9 +350,9 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", "cipher", @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.4" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -408,9 +408,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.2" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -427,7 +427,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -459,9 +459,9 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" -version = "4.6.7" +version = "4.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" dependencies = [ "bytes", "memchr", @@ -564,9 +564,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" dependencies = [ "cfg-if", ] @@ -696,9 +696,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "der" @@ -750,7 +750,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -796,9 +796,9 @@ dependencies = [ [[package]] name = "either" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "embedded-io" @@ -862,9 +862,9 @@ checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "flate2" @@ -954,9 +954,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -969,9 +969,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -979,15 +979,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -996,38 +996,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-macro" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] name = "futures-sink" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-channel", "futures-core", @@ -1087,9 +1087,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.15" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" dependencies = [ "atomic-waker", "bytes", @@ -1197,9 +1197,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -1217,9 +1217,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1242,9 +1242,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" dependencies = [ "typenum", ] @@ -1348,9 +1348,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -1362,9 +1362,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1375,9 +1375,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1389,16 +1389,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1409,15 +1410,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", @@ -1470,9 +1471,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" [[package]] name = "is_terminal_polyfill" @@ -1555,9 +1556,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" dependencies = [ "cfg-if", "futures-util", @@ -1602,9 +1603,9 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" @@ -1623,9 +1624,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "matchers" @@ -1729,9 +1730,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] @@ -1882,7 +1883,8 @@ dependencies = [ "opentelemetry_sdk", "pallas-crypto", "pallas-primitives", - "rand 0.8.7", + "plutus-parser", + "rand 0.8.8", "reqwest", "rust_decimal", "rustls", @@ -1996,9 +1998,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" +checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf" dependencies = [ "memchr", "ucd-trie", @@ -2006,9 +2008,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" +checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d" dependencies = [ "pest", "pest_generator", @@ -2016,9 +2018,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" +checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a" dependencies = [ "pest", "pest_meta", @@ -2029,9 +2031,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" +checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496" dependencies = [ "pest", ] @@ -2053,7 +2055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.7", + "rand 0.8.8", ] [[package]] @@ -2114,6 +2116,29 @@ dependencies = [ "spki", ] +[[package]] +name = "plutus-parser" +version = "1.0.0" +source = "git+https://github.com/SundaeSwap-finance/plutus-parser?rev=cb27b9e#cb27b9ec28ff5d47f877fdd32fd5e2025d4dba43" +dependencies = [ + "hex", + "indexmap", + "minicbor", + "pallas-primitives", + "plutus-parser-derive", + "thiserror", +] + +[[package]] +name = "plutus-parser-derive" +version = "1.0.0" +source = "git+https://github.com/SundaeSwap-finance/plutus-parser?rev=cb27b9e#cb27b9ec28ff5d47f877fdd32fd5e2025d4dba43" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + [[package]] name = "poly1305" version = "0.9.1" @@ -2126,9 +2151,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "postcard" @@ -2145,9 +2170,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -2260,9 +2285,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -2345,9 +2370,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -2485,7 +2510,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand 0.8.7", + "rand 0.8.8", "rkyv", "serde", "serde_json", @@ -2503,9 +2528,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "log", "once_cell", @@ -2566,9 +2591,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "ring", "rustls-pki-types", @@ -2685,7 +2710,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2918,9 +2943,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" dependencies = [ "proc-macro2", "quote", @@ -2964,22 +2989,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -3002,9 +3027,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -3044,13 +3069,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -3447,9 +3472,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.24.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +checksum = "b5772d71c9be8a8a6ac2117d949c5b224c1b72241bb611d9a3012edcf8af7812" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -3515,9 +3540,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" dependencies = [ "cfg-if", "once_cell", @@ -3529,9 +3554,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" dependencies = [ "js-sys", "wasm-bindgen", @@ -3539,9 +3564,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3549,9 +3574,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" dependencies = [ "bumpalo", "proc-macro2", @@ -3562,18 +3587,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" dependencies = [ "js-sys", "wasm-bindgen", @@ -3792,9 +3817,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "wyz" @@ -3819,9 +3844,9 @@ dependencies = [ [[package]] name = "yaml-rust2" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631a50d867fafb7093e709d75aaee9e0e0d5deb934021fcea25ac2fe09edc51e" +checksum = "b36710ce3a279cfce8465dbab826f161675a262950b922cb2c3663852dfe9eb0" dependencies = [ "arraydeque", "encoding_rs", @@ -3853,18 +3878,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.55" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.55" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" dependencies = [ "proc-macro2", "quote", @@ -3914,9 +3939,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -3925,9 +3950,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -3936,13 +3961,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d07e5b7..dcf83b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,9 @@ num-traits = "0.2" opentelemetry = "0.32" opentelemetry-otlp = { version = "0.32", features = ["grpc-tonic", "gzip-tonic", "tls", "tls-webpki-roots"] } opentelemetry_sdk = { version = "0.32", features = ["rt-tokio"] } -pallas-crypto = "1.0.0-alpha.3" -pallas-primitives = "1.0.0-alpha.3" +pallas-crypto = "1" +pallas-primitives = "1" +plutus-parser = { git = "https://github.com/SundaeSwap-finance/plutus-parser", rev = "cb27b9e", features = ["derive"] } rand = "0.8.5" reqwest = { version = "0.13", default-features = false, features = ["json", "rustls-no-provider", "query"] } rust_decimal = "1" diff --git a/config.base.yaml b/config.base.yaml index 9532dc1..00fde96 100644 --- a/config.base.yaml +++ b/config.base.yaml @@ -64,55 +64,55 @@ currencies: - name: BTN asset_id: 016be5325fd988fea98ad422fcfd53e5352cacfced5c106a932a35a4.42544e digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: DJED asset_id: 8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61.446a65644d6963726f555344 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: ENCS asset_id: 9abf0afd2f236a19f2842d502d0450cbcd9c79f123a9708f96fd9b96.454e4353 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: EUR digits: 6 - name: FLDT asset_id: 577f0b1342f8f8f4aed3388b80a8535812950c7a892495c0ecdf0f1e.0014df10464c4454 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: IAG asset_id: 5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114.494147 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: iETH asset_id: f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b69880.69455448 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: iUSD asset_id: f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b69880.69555344 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: JPY digits: 6 - name: LENFI asset_id: 8fef2d34078659493ce161a6c7fba4b56afefa8535296a5743f69587.41414441 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: LQ asset_id: da8c30857834c6ae7203935b89278c532b3995245295456f993e1d24.4c51 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: MIN asset_id: 29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6.4d494e digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: myUSD asset_id: 92776616f1f32c65a173392e4410a3d8c39dcf6ef768c73af164779c.4d79555344 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: NIGHT asset_id: 0691b2fecca1ac4f53cb6dfb00b7013e561d1f34403b957cbb5af1fa.4e49474854 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: PAXG digits: 4 - name: POL @@ -120,17 +120,17 @@ currencies: - name: SHEN asset_id: 8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61.5368656e4d6963726f555344 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: SNEK asset_id: 279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f.534e454b digits: 0 - min_tvl: 20_000_000 + min_tvl: 500 - name: SOL digits: 9 - name: SUNDAE asset_id: 9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77.53554e444145 digits: 6 - min_tvl: 20_000_000 + min_tvl: 500 - name: USD digits: 6 - name: USDT diff --git a/src/config.rs b/src/config.rs index c8bb8a8..d74951a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -396,6 +396,8 @@ pub struct CurrencyConfig { pub name: String, pub asset_id: Option, pub digits: u32, + /// The minimum TVL, in whole USD, a source must report before its price for + /// this currency is considered. #[serde(default)] pub min_tvl: Decimal, } diff --git a/src/price_aggregator.rs b/src/price_aggregator.rs index abbdfbd..bdcb49d 100644 --- a/src/price_aggregator.rs +++ b/src/price_aggregator.rs @@ -19,6 +19,7 @@ use tracing::{debug, error, warn}; use crate::{ config::{OracleConfig, SyntheticConfig}, health::{HealthSink, HealthStatus, Origin}, + price_aggregator::synth_config_source::Collateral, price_feed::{ GenericPriceFeed, IntervalBound, PriceData, SyntheticPriceData, SyntheticPriceFeed, Validity, @@ -305,20 +306,19 @@ impl PriceAggregator { let mut prices = vec![]; for collateral in &collateral { - let collateral_digits = self.get_digits(collateral); - let Some(p) = converter.value_in_usd(collateral) else { - bail!("could not compute price for collateral {collateral}"); - }; - let p_scaled = p * BigInt::from(10i64.pow(synth_digits)) - / BigInt::from(10i64.pow(collateral_digits)); - prices.push(p_scaled / &synth_price); + prices.push(self.compute_collateral_price( + collateral, + converter, + synth_digits, + &synth_price, + )?); } // track prices before smoothing, to measure the effect of smoothing - for (collateral_name, collateral_price) in collateral.iter().zip(prices.iter()) { + for (collateral, collateral_price) in collateral.iter().zip(prices.iter()) { let price = collateral_price.to_f64().expect("infallible"); debug!( - collateral_name, + collateral_name = collateral.name, synthetic_name = synth.name, histogram.raw_collateral_price = price, "pre-smoothing price metrics", @@ -329,10 +329,10 @@ impl PriceAggregator { let prices = self.apply_synth_gema(&synth.name, prices); // track metrics for the different prices - for (collateral_name, collateral_price) in collateral.iter().zip(prices.iter()) { + for (collateral, collateral_price) in collateral.iter().zip(prices.iter()) { let price = collateral_price.to_f64().expect("infallible"); debug!( - collateral_name, + collateral_name = collateral.name, synthetic_name = synth.name, histogram.collateral_price = price, "price metrics", @@ -346,7 +346,7 @@ impl PriceAggregator { Ok(SyntheticPriceData { price: synth_price, feed: SyntheticPriceFeed { - collateral_names: Some(collateral), + collateral_names: Some(collateral.iter().map(|c| c.name.clone()).collect()), collateral_prices, synthetic: synth.name.clone(), denominator, @@ -358,6 +358,25 @@ impl PriceAggregator { }) } + fn compute_collateral_price( + &self, + collateral: &Collateral, + converter: &TokenPriceConverter, + synth_digits: u32, + synth_price: &BigRational, + ) -> Result { + if !collateral.enabled { + return Ok(BigRational::new(BigInt::ZERO, BigInt::ONE)); + } + let collateral_digits = self.get_digits(&collateral.name); + let Some(p) = converter.value_in_usd(&collateral.name) else { + bail!("could not compute price for collateral {}", collateral.name); + }; + let p_scaled = + p * BigInt::from(10i64.pow(synth_digits)) / BigInt::from(10i64.pow(collateral_digits)); + Ok(p_scaled / synth_price) + } + fn compute_generic_payload( &self, currency: &str, @@ -520,7 +539,7 @@ impl SourcePriceReporter { } fn normalize(prices: &[BigRational], max_bits: u64) -> (Vec, BigUint) { - assert!(prices.iter().all(|p| p.is_positive())); + assert!(prices.iter().all(|p| !p.is_negative())); let denominator = prices.iter().fold(BigInt::one(), |acc, p| acc * p.denom()); let normalized_numerators: Vec<_> = prices .iter() @@ -635,6 +654,26 @@ mod tests { ); } + #[test] + fn normalize_should_allow_zero_values() { + let prices = [decimal_rational(100, 0), decimal_rational(0, 0)]; + let (collateral_prices, denominator) = normalize(&prices, 1024); + assert_eq!( + (vec![100u128.into(), 0u128.into()], BigUint::one()), + (collateral_prices, denominator), + ); + } + + #[test] + fn normalize_should_allow_all_zero_values() { + let prices = [decimal_rational(0, 0), decimal_rational(0, 0)]; + let (collateral_prices, denominator) = normalize(&prices, 1024); + assert_eq!( + (vec![0u128.into(), 0u128.into()], BigUint::one()), + (collateral_prices, denominator), + ); + } + #[test] fn restrict_output_size_should_round_numerator_down_and_denominator_up() { let mut numerators = vec![0b1001u128.into()]; diff --git a/src/price_aggregator/conversions.rs b/src/price_aggregator/conversions.rs index 54c1f0f..2d9a274 100644 --- a/src/price_aggregator/conversions.rs +++ b/src/price_aggregator/conversions.rs @@ -878,20 +878,29 @@ mod tests { fn value_in_usd_should_ignore_source_with_tvl_below_threshold() { let source_prices = vec![ ( - "price for SUNDAE in USD".into(), + "price for SUNDAE in ADA".into(), PriceInfo { token: "SUNDAE".into(), - unit: "USD".into(), + unit: "ADA".into(), value: Decimal::new(100, 0), - reliability: Decimal::new(100, 0), + reliability: Decimal::new(1000, 0), }, ), ( - "price for SUNDAE in USD".into(), + "price for SUNDAE in ADA".into(), PriceInfo { token: "SUNDAE".into(), - unit: "USD".into(), + unit: "ADA".into(), value: Decimal::new(1000, 0), + reliability: Decimal::new(1667, 0), + }, + ), + ( + "price for ADA in USD".into(), + PriceInfo { + token: "ADA".into(), + unit: "USD".into(), + value: Decimal::new(6, 1), reliability: Decimal::new(1000, 0), }, ), @@ -915,7 +924,7 @@ mod tests { assert_eq!( converter.value_in_usd("SUNDAE"), - Some(decimal_rational(1000, 0)) + Some(decimal_rational(600, 0)) ); } diff --git a/src/price_aggregator/gema.rs b/src/price_aggregator/gema.rs index 48f3e9f..fc68f8e 100644 --- a/src/price_aggregator/gema.rs +++ b/src/price_aggregator/gema.rs @@ -2,7 +2,7 @@ use std::time::Duration; use num_bigint::BigUint; use num_rational::{BigRational, Ratio}; -use num_traits::One; +use num_traits::{One, Zero}; pub struct GemaCalculator { periods: usize, @@ -52,6 +52,10 @@ impl GemaCalculator { // Reflect downturns immediately return price; } + if prev_price.is_zero() { + // Price could only be zero if this currency was disabled, don't try smoothing after reenabling it + return price; + } (price * &curr_price_weight) + (prev_price * &prev_price_weight) }) .collect() @@ -96,6 +100,10 @@ impl GemaCalculator { // Reflect downturns immediately return price; } + if prev_price.is_zero() { + // Price could only be zero if this currency was disabled, don't try smoothing after reenabling it + return price; + } (price * curr_numer / curr_denom) + (prev_price * prev_numer / prev_denom) } } @@ -126,6 +134,19 @@ mod tests { assert_eq!(prices, vec![rational(3, 2), rational(1, 2)]); } + #[test] + fn should_not_smooth_reenabled_prices() { + let periods = 2; + let round_duration = Duration::from_secs(5); + let calculator = GemaCalculator::new(periods, round_duration); + + let prev_prices = vec![rational(0, 1), rational(1, 1)]; + let curr_prices = vec![rational(2, 1), rational(1, 2)]; + + let prices = calculator.smooth_synthetic_price(round_duration, &prev_prices, curr_prices); + assert_eq!(prices, vec![rational(2, 1), rational(1, 2)]); + } + #[test] fn should_count_rounds_based_on_time_elapsed() { let periods = 2; diff --git a/src/price_aggregator/synth_config_source.rs b/src/price_aggregator/synth_config_source.rs index e5c4089..38f3617 100644 --- a/src/price_aggregator/synth_config_source.rs +++ b/src/price_aggregator/synth_config_source.rs @@ -11,10 +11,11 @@ use anyhow::{Result, bail}; use futures::{StreamExt, stream::FuturesUnordered}; use kupon::MatchOptions; use pallas_primitives::{Constr, PlutusData}; +use plutus_parser::AsPlutus; struct CollateralState { config: CollateralConfig, - collateral: Option>, + collateral: Option>, } pub struct SyntheticConfigSource { @@ -129,20 +130,26 @@ impl SyntheticConfigSource { }; let mut collateral = vec![]; - for AssetClass { - policy_id, - asset_name, - } in collateral_assets - { - if policy_id.is_empty() && asset_name.is_empty() { - collateral.push("ADA".to_string()); + for (ac, enabled) in collateral_assets { + if ac.policy_id.is_empty() && ac.asset_name.is_empty() { + collateral.push(Collateral { + name: "ADA".to_string(), + enabled, + }); continue; } - let asset_id = format!("{policy_id}.{asset_name}"); + let asset_id = format!( + "{}.{}", + hex::encode(ac.policy_id), + hex::encode(ac.asset_name) + ); let Some(name) = asset_names.get(&asset_id) else { fail!(true, "unrecognized asset id {asset_id}"); }; - collateral.push(name.clone()); + collateral.push(Collateral { + name: name.clone(), + enabled, + }); } Ok((synthetic, collateral)) @@ -176,12 +183,22 @@ impl SyntheticConfigSource { self.next_refresh = now + Duration::from_secs(30); } - pub fn synthetic_collateral(&self, name: &str) -> Option> { + pub fn synthetic_collateral(&self, name: &str) -> Option> { let state = self.collateral.get(name)?; if let Some(collateral) = &state.collateral { Some(collateral.clone()) } else if !state.config.list.is_empty() { - Some(state.config.list.clone()) + Some( + state + .config + .list + .iter() + .map(|c| Collateral { + name: c.clone(), + enabled: true, + }) + .collect(), + ) } else { None } @@ -189,33 +206,25 @@ impl SyntheticConfigSource { } // input is a MonoDatum from the butane Aiken definition -fn extract_collateral_assets(datum: PlutusData) -> Result> { +fn extract_collateral_assets(datum: PlutusData) -> Result> { // extract the ParamsWrapper let [wrapper] = decode_struct(datum, 0)?; // extract the LiveParams let [params] = decode_struct(wrapper, 0)?; - // extract the collateral assets from the LiveParams - let [collateral_assets] = decode_struct(params, 0)?; - - let PlutusData::Array(collateral_assets) = collateral_assets else { - bail!("datum has invalid collateral assets"); - }; + // extract the collateral assets and weights from the LiveParams + let [collateral_assets, weights] = decode_struct(params, 0)?; - let mut assets = vec![]; - for (index, asset) in collateral_assets.to_vec().into_iter().enumerate() { - let [policy_id, asset_name] = decode_struct(asset, 0)?; - let PlutusData::BoundedBytes(policy_id) = policy_id else { - bail!("asset {index} has invalid policy id"); - }; - let PlutusData::BoundedBytes(asset_name) = asset_name else { - bail!("asset {index} has invalid asset name"); - }; - assets.push(AssetClass { - policy_id: policy_id.into(), - asset_name: asset_name.into(), - }); + let assets: Vec = AsPlutus::from_plutus(collateral_assets)?; + let weights: Vec = AsPlutus::from_plutus(weights)?; + if assets.len() != weights.len() { + bail!( + "mismatched number of assets ({}) and weights ({})", + assets.len(), + weights.len() + ); } - Ok(assets) + let enabled = weights.iter().map(|w| *w > 0); + Ok(assets.into_iter().zip(enabled).collect()) } fn decode_struct(datum: PlutusData, variant: u64) -> Result<[PlutusData; N]> { @@ -246,7 +255,141 @@ struct UpdateConfigError { clear: bool, } +#[derive(AsPlutus, PartialEq, Eq, Debug)] struct AssetClass { - policy_id: String, - asset_name: String, + policy_id: Vec, + asset_name: Vec, +} + +#[derive(Clone)] +pub struct Collateral { + pub name: String, + pub enabled: bool, +} + +#[cfg(test)] +mod tests { + use super::*; + + fn asset_class(policy_id: &str, asset_name: &str) -> AssetClass { + AssetClass { + policy_id: hex::decode(policy_id).unwrap(), + asset_name: hex::decode(asset_name).unwrap(), + } + } + + #[test] + fn should_parse_nft() { + let midas_nft_hex = "d8799fd8799fd8799f9fd8799f4040ffd8799f581c016be5325fd988fea98ad422fcfd53e5352cacfced5c106a932a35a44342544effd8799f581c279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f44534e454bffd8799f581c29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6434d494effd8799f581c577f0b1342f8f8f4aed3388b80a8535812950c7a892495c0ecdf0f1e480014df10464c4454ffd8799f581c5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d11443494147ffd8799f581c8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd614c5368656e4d6963726f555344ffd8799f581c8fef2d34078659493ce161a6c7fba4b56afefa8535296a5743f695874441414441ffd8799f581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d774653554e444145ffd8799f581c9abf0afd2f236a19f2842d502d0450cbcd9c79f123a9708f96fd9b9644454e4353ffd8799f581cda8c30857834c6ae7203935b89278c532b3995245295456f993e1d24424c51ffd8799f581cf66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b698804469455448ffff9f0c0f0f0f120f0c120f12120dff0a1a02625a009f9f3b000001952830e967190384ff9f00190384ffff9f192710191388191388191388190bb8191388191f400119138801191388190bb8ff193a98190fa01926de1913889f9f3b000001952830e9671901f4ffffffffff"; + let midas_nft_bytes = hex::decode(midas_nft_hex).unwrap(); + let midas_nft_datum: PlutusData = + minicbor::Decoder::new(&midas_nft_bytes).decode().unwrap(); + + let assets = extract_collateral_assets(midas_nft_datum).unwrap(); + assert_eq!( + assets, + vec![ + (asset_class("", ""), true), + ( + asset_class( + "016be5325fd988fea98ad422fcfd53e5352cacfced5c106a932a35a4", + "42544e" + ), + true + ), + ( + asset_class( + "279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f", + "534e454b" + ), + true + ), + ( + asset_class( + "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6", + "4d494e" + ), + true + ), + ( + asset_class( + "577f0b1342f8f8f4aed3388b80a8535812950c7a892495c0ecdf0f1e", + "0014df10464c4454" + ), + true + ), + ( + asset_class( + "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114", + "494147" + ), + true + ), + ( + asset_class( + "8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61", + "5368656e4d6963726f555344" + ), + true + ), + ( + asset_class( + "8fef2d34078659493ce161a6c7fba4b56afefa8535296a5743f69587", + "41414441" + ), + true + ), + ( + asset_class( + "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77", + "53554e444145" + ), + true + ), + ( + asset_class( + "9abf0afd2f236a19f2842d502d0450cbcd9c79f123a9708f96fd9b96", + "454e4353" + ), + true + ), + ( + asset_class( + "da8c30857834c6ae7203935b89278c532b3995245295456f993e1d24", + "4c51" + ), + true + ), + ( + asset_class( + "f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b69880", + "69455448" + ), + true + ), + ] + ); + } + + #[test] + fn should_parse_nft_with_disabled_asset() { + let fake_nft_hex = "d8799fd8799fd8799f9fd8799f4040ffd8799f581c016be5325fd988fea98ad422fcfd53e5352cacfced5c106a932a35a44342544effff9f0c00ff0a1a02625a009f9f3b000001952830e967190384ff9f00190384ffff9f192710191388ff193a98190fa01926de1913889f9f3b000001952830e9671901f4ffffffffff"; + let fake_nft_bytes = hex::decode(fake_nft_hex).unwrap(); + let fake_nft_datum: PlutusData = minicbor::Decoder::new(&fake_nft_bytes).decode().unwrap(); + + let assets = extract_collateral_assets(fake_nft_datum).unwrap(); + assert_eq!( + assets, + vec![ + (asset_class("", ""), true), + ( + asset_class( + "016be5325fd988fea98ad422fcfd53e5352cacfced5c106a932a35a4", + "42544e" + ), + false + ), + ], + ); + } } diff --git a/src/sources/minswap.rs b/src/sources/minswap.rs index 3ed3586..f332163 100644 --- a/src/sources/minswap.rs +++ b/src/sources/minswap.rs @@ -103,7 +103,7 @@ impl MinswapSource { } let value = Decimal::new(unit_value as i64, pool.unit_digits) / Decimal::new(token_value as i64, pool.token_digits); - let tvl = Decimal::new(unit_value as i64 * 2, 0); + let tvl = Decimal::new(unit_value as i64 * 2, pool.unit_digits); sink.send_named( PriceInfo { diff --git a/src/sources/source.rs b/src/sources/source.rs index b5130a3..f602848 100644 --- a/src/sources/source.rs +++ b/src/sources/source.rs @@ -12,6 +12,11 @@ pub struct PriceInfo { pub token: String, pub unit: String, pub value: Decimal, + /// How much weight this price should carry relative to other sources. + /// Sources which can measure liquidity (i.e. DEX pools) report the TVL of + /// the pool, denominated in whole `unit` tokens (not the smallest + /// denomination), so that multiplying by the price of `unit` in USD yields + /// a TVL in whole USD. Sources with no notion of liquidity report 1. pub reliability: Decimal, } diff --git a/src/sources/splash.rs b/src/sources/splash.rs index b22ed4e..cdacd94 100644 --- a/src/sources/splash.rs +++ b/src/sources/splash.rs @@ -89,7 +89,7 @@ impl SplashSource { } let value = Decimal::new(unit_value as i64, pool.unit_digits) / Decimal::new(token_value as i64, pool.token_digits); - let tvl = Decimal::new(unit_value as i64 * 2, 0); + let tvl = Decimal::new(unit_value as i64 * 2, pool.unit_digits); sink.send_named( PriceInfo { diff --git a/src/sources/sundaeswap.rs b/src/sources/sundaeswap.rs index 1072b45..65872d2 100644 --- a/src/sources/sundaeswap.rs +++ b/src/sources/sundaeswap.rs @@ -147,7 +147,7 @@ impl SundaeSwapSource { let value = Decimal::new(unit_value, pool.asset_a.decimals) / Decimal::new(token_value, pool.asset_b.decimals); - let tvl = Decimal::new(unit_value * 2, 0); + let tvl = Decimal::new(unit_value * 2, pool.asset_a.decimals); sink.send_named( PriceInfo { diff --git a/src/sources/sundaeswap_kupo.rs b/src/sources/sundaeswap_kupo.rs index 280f1a1..8ee8ca0 100644 --- a/src/sources/sundaeswap_kupo.rs +++ b/src/sources/sundaeswap_kupo.rs @@ -111,7 +111,7 @@ impl SundaeSwapKupoSource { let value = Decimal::new(unit_value as i64, pool.unit_digits) / Decimal::new(token_value as i64, pool.token_digits); - let tvl = Decimal::new(unit_value as i64 * 2, 0); + let tvl = Decimal::new(unit_value as i64 * 2, pool.unit_digits); sink.send_named( PriceInfo { diff --git a/src/sources/vyfi.rs b/src/sources/vyfi.rs index 9046641..defba87 100644 --- a/src/sources/vyfi.rs +++ b/src/sources/vyfi.rs @@ -87,7 +87,7 @@ impl VyFiSource { } let value = Decimal::new(unit_value as i64, pool.unit_digits) / Decimal::new(token_value as i64, pool.token_digits); - let tvl = Decimal::new(unit_value as i64 * 2, 0); + let tvl = Decimal::new(unit_value as i64 * 2, pool.unit_digits); sink.send_named( PriceInfo { diff --git a/src/sources/wingriders.rs b/src/sources/wingriders.rs index 5fc0e98..043c8df 100644 --- a/src/sources/wingriders.rs +++ b/src/sources/wingriders.rs @@ -89,7 +89,7 @@ impl WingRidersSource { } let value = Decimal::new(unit_value as i64, pool.unit_digits) / Decimal::new(token_value as i64, pool.token_digits); - let tvl = Decimal::new(unit_value as i64 * 2, 0); + let tvl = Decimal::new(unit_value as i64 * 2, pool.unit_digits); sink.send_named( PriceInfo {