├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── README.md ├── examples ├── get_lp_balance.rs ├── get_pool_price.rs └── optimal_swap_for_price.rs └── src ├── alloy_pool ├── factory.rs ├── mod.rs └── pool.rs ├── constants.rs ├── error.rs ├── lib.rs ├── macros.rs ├── macros ├── token_amount.rs └── wrappers.rs ├── math.rs ├── math ├── liquidity.rs ├── swap.rs ├── tick.rs └── wrappers.rs ├── pool.rs ├── pool ├── price.rs └── swap.rs ├── position.rs ├── traits ├── basis_points.rs ├── batch.rs ├── float.rs └── mod.rs └── types ├── amount.rs ├── deltas.rs ├── mod.rs └── price.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | setup_env.sh -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": [] 3 | } 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "allocator-api2" 22 | version = "0.2.18" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 25 | 26 | [[package]] 27 | name = "alloy" 28 | version = "0.4.2" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "056f2c01b2aed86e15b43c47d109bfc8b82553dc34e66452875e51247ec31ab2" 31 | dependencies = [ 32 | "alloy-consensus", 33 | "alloy-contract", 34 | "alloy-core", 35 | "alloy-eips", 36 | "alloy-genesis", 37 | "alloy-network", 38 | "alloy-provider", 39 | "alloy-pubsub", 40 | "alloy-rpc-client", 41 | "alloy-rpc-types", 42 | "alloy-serde", 43 | "alloy-signer", 44 | "alloy-signer-local", 45 | "alloy-transport", 46 | "alloy-transport-http", 47 | "alloy-transport-ipc", 48 | "alloy-transport-ws", 49 | ] 50 | 51 | [[package]] 52 | name = "alloy-chains" 53 | version = "0.1.37" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "c54e2fbc026948a0f638bf6a94fc0ce6e44652280fed40bb0dd970e3357bc5f2" 56 | dependencies = [ 57 | "alloy-primitives", 58 | "num_enum", 59 | "strum", 60 | ] 61 | 62 | [[package]] 63 | name = "alloy-consensus" 64 | version = "0.4.2" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" 67 | dependencies = [ 68 | "alloy-eips", 69 | "alloy-primitives", 70 | "alloy-rlp", 71 | "alloy-serde", 72 | "auto_impl", 73 | "c-kzg", 74 | "derive_more", 75 | "serde", 76 | ] 77 | 78 | [[package]] 79 | name = "alloy-contract" 80 | version = "0.4.2" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "917f7d12cf3971dc8c11c9972f732b35ccb9aaaf5f28f2f87e9e6523bee3a8ad" 83 | dependencies = [ 84 | "alloy-dyn-abi", 85 | "alloy-json-abi", 86 | "alloy-network", 87 | "alloy-network-primitives", 88 | "alloy-primitives", 89 | "alloy-provider", 90 | "alloy-pubsub", 91 | "alloy-rpc-types-eth", 92 | "alloy-sol-types", 93 | "alloy-transport", 94 | "futures", 95 | "futures-util", 96 | "thiserror", 97 | ] 98 | 99 | [[package]] 100 | name = "alloy-core" 101 | version = "0.8.7" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "eeb750349efda145ca6aada68d0336067f7f364d7d44ef09e2cf000b040c5e99" 104 | dependencies = [ 105 | "alloy-dyn-abi", 106 | "alloy-json-abi", 107 | "alloy-primitives", 108 | "alloy-rlp", 109 | "alloy-sol-types", 110 | ] 111 | 112 | [[package]] 113 | name = "alloy-dyn-abi" 114 | version = "0.8.7" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "f95d76a38cae906fd394a5afb0736aaceee5432efe76addfd71048e623e208af" 117 | dependencies = [ 118 | "alloy-json-abi", 119 | "alloy-primitives", 120 | "alloy-sol-type-parser", 121 | "alloy-sol-types", 122 | "const-hex", 123 | "itoa", 124 | "serde", 125 | "serde_json", 126 | "winnow", 127 | ] 128 | 129 | [[package]] 130 | name = "alloy-eip2930" 131 | version = "0.1.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" 134 | dependencies = [ 135 | "alloy-primitives", 136 | "alloy-rlp", 137 | "serde", 138 | ] 139 | 140 | [[package]] 141 | name = "alloy-eip7702" 142 | version = "0.1.1" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" 145 | dependencies = [ 146 | "alloy-primitives", 147 | "alloy-rlp", 148 | "k256", 149 | "serde", 150 | ] 151 | 152 | [[package]] 153 | name = "alloy-eips" 154 | version = "0.4.2" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" 157 | dependencies = [ 158 | "alloy-eip2930", 159 | "alloy-eip7702", 160 | "alloy-primitives", 161 | "alloy-rlp", 162 | "alloy-serde", 163 | "c-kzg", 164 | "derive_more", 165 | "once_cell", 166 | "serde", 167 | "sha2", 168 | ] 169 | 170 | [[package]] 171 | name = "alloy-genesis" 172 | version = "0.4.2" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "8429cf4554eed9b40feec7f4451113e76596086447550275e3def933faf47ce3" 175 | dependencies = [ 176 | "alloy-primitives", 177 | "alloy-serde", 178 | "serde", 179 | ] 180 | 181 | [[package]] 182 | name = "alloy-json-abi" 183 | version = "0.8.7" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "03c66eec1acdd96b39b995b8f5ee5239bc0c871d62c527ae1ac9fd1d7fecd455" 186 | dependencies = [ 187 | "alloy-primitives", 188 | "alloy-sol-type-parser", 189 | "serde", 190 | "serde_json", 191 | ] 192 | 193 | [[package]] 194 | name = "alloy-json-rpc" 195 | version = "0.4.2" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "f8fa8a1a3c4cbd221f2b8e3693aeb328fca79a757fe556ed08e47bbbc2a70db7" 198 | dependencies = [ 199 | "alloy-primitives", 200 | "alloy-sol-types", 201 | "serde", 202 | "serde_json", 203 | "thiserror", 204 | "tracing", 205 | ] 206 | 207 | [[package]] 208 | name = "alloy-network" 209 | version = "0.4.2" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd" 212 | dependencies = [ 213 | "alloy-consensus", 214 | "alloy-eips", 215 | "alloy-json-rpc", 216 | "alloy-network-primitives", 217 | "alloy-primitives", 218 | "alloy-rpc-types-eth", 219 | "alloy-serde", 220 | "alloy-signer", 221 | "alloy-sol-types", 222 | "async-trait", 223 | "auto_impl", 224 | "futures-utils-wasm", 225 | "thiserror", 226 | ] 227 | 228 | [[package]] 229 | name = "alloy-network-primitives" 230 | version = "0.4.2" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" 233 | dependencies = [ 234 | "alloy-consensus", 235 | "alloy-eips", 236 | "alloy-primitives", 237 | "alloy-serde", 238 | "serde", 239 | ] 240 | 241 | [[package]] 242 | name = "alloy-primitives" 243 | version = "0.8.7" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "8ecb848c43f6b06ae3de2e4a67496cbbabd78ae87db0f1248934f15d76192c6a" 246 | dependencies = [ 247 | "alloy-rlp", 248 | "bytes", 249 | "cfg-if", 250 | "const-hex", 251 | "derive_more", 252 | "foldhash", 253 | "hashbrown 0.15.0", 254 | "hex-literal", 255 | "indexmap", 256 | "itoa", 257 | "k256", 258 | "keccak-asm", 259 | "paste", 260 | "proptest", 261 | "rand", 262 | "ruint", 263 | "rustc-hash", 264 | "serde", 265 | "sha3", 266 | "tiny-keccak", 267 | ] 268 | 269 | [[package]] 270 | name = "alloy-provider" 271 | version = "0.4.2" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6" 274 | dependencies = [ 275 | "alloy-chains", 276 | "alloy-consensus", 277 | "alloy-eips", 278 | "alloy-json-rpc", 279 | "alloy-network", 280 | "alloy-network-primitives", 281 | "alloy-primitives", 282 | "alloy-pubsub", 283 | "alloy-rpc-client", 284 | "alloy-rpc-types-eth", 285 | "alloy-rpc-types-trace", 286 | "alloy-transport", 287 | "alloy-transport-http", 288 | "alloy-transport-ipc", 289 | "alloy-transport-ws", 290 | "async-stream", 291 | "async-trait", 292 | "auto_impl", 293 | "dashmap", 294 | "futures", 295 | "futures-utils-wasm", 296 | "lru", 297 | "pin-project", 298 | "reqwest", 299 | "serde", 300 | "serde_json", 301 | "thiserror", 302 | "tokio", 303 | "tracing", 304 | "url", 305 | ] 306 | 307 | [[package]] 308 | name = "alloy-pubsub" 309 | version = "0.4.2" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "f32cef487122ae75c91eb50154c70801d71fabdb976fec6c49e0af5e6486ab15" 312 | dependencies = [ 313 | "alloy-json-rpc", 314 | "alloy-primitives", 315 | "alloy-transport", 316 | "bimap", 317 | "futures", 318 | "serde", 319 | "serde_json", 320 | "tokio", 321 | "tokio-stream", 322 | "tower", 323 | "tracing", 324 | ] 325 | 326 | [[package]] 327 | name = "alloy-rlp" 328 | version = "0.3.8" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" 331 | dependencies = [ 332 | "alloy-rlp-derive", 333 | "arrayvec", 334 | "bytes", 335 | ] 336 | 337 | [[package]] 338 | name = "alloy-rlp-derive" 339 | version = "0.3.8" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" 342 | dependencies = [ 343 | "proc-macro2", 344 | "quote", 345 | "syn 2.0.79", 346 | ] 347 | 348 | [[package]] 349 | name = "alloy-rpc-client" 350 | version = "0.4.2" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "370143ed581aace6e663342d21d209c6b2e34ee6142f7d6675adb518deeaf0dc" 353 | dependencies = [ 354 | "alloy-json-rpc", 355 | "alloy-primitives", 356 | "alloy-pubsub", 357 | "alloy-transport", 358 | "alloy-transport-http", 359 | "alloy-transport-ipc", 360 | "alloy-transport-ws", 361 | "futures", 362 | "pin-project", 363 | "reqwest", 364 | "serde", 365 | "serde_json", 366 | "tokio", 367 | "tokio-stream", 368 | "tower", 369 | "tracing", 370 | "url", 371 | ] 372 | 373 | [[package]] 374 | name = "alloy-rpc-types" 375 | version = "0.4.2" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "9ffc534b7919e18f35e3aa1f507b6f3d9d92ec298463a9f6beaac112809d8d06" 378 | dependencies = [ 379 | "alloy-primitives", 380 | "alloy-rpc-types-engine", 381 | "alloy-rpc-types-eth", 382 | "alloy-rpc-types-trace", 383 | "alloy-serde", 384 | "serde", 385 | ] 386 | 387 | [[package]] 388 | name = "alloy-rpc-types-engine" 389 | version = "0.4.2" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "e0285c4c09f838ab830048b780d7f4a4f460f309aa1194bb049843309524c64c" 392 | dependencies = [ 393 | "alloy-consensus", 394 | "alloy-eips", 395 | "alloy-primitives", 396 | "alloy-rlp", 397 | "derive_more", 398 | "strum", 399 | ] 400 | 401 | [[package]] 402 | name = "alloy-rpc-types-eth" 403 | version = "0.4.2" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" 406 | dependencies = [ 407 | "alloy-consensus", 408 | "alloy-eips", 409 | "alloy-network-primitives", 410 | "alloy-primitives", 411 | "alloy-rlp", 412 | "alloy-serde", 413 | "alloy-sol-types", 414 | "derive_more", 415 | "itertools 0.13.0", 416 | "serde", 417 | "serde_json", 418 | ] 419 | 420 | [[package]] 421 | name = "alloy-rpc-types-trace" 422 | version = "0.4.2" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" 425 | dependencies = [ 426 | "alloy-primitives", 427 | "alloy-rpc-types-eth", 428 | "alloy-serde", 429 | "serde", 430 | "serde_json", 431 | "thiserror", 432 | ] 433 | 434 | [[package]] 435 | name = "alloy-serde" 436 | version = "0.4.2" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" 439 | dependencies = [ 440 | "alloy-primitives", 441 | "serde", 442 | "serde_json", 443 | ] 444 | 445 | [[package]] 446 | name = "alloy-signer" 447 | version = "0.4.2" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "2fd4e0ad79c81a27ca659be5d176ca12399141659fef2bcbfdc848da478f4504" 450 | dependencies = [ 451 | "alloy-primitives", 452 | "async-trait", 453 | "auto_impl", 454 | "elliptic-curve", 455 | "k256", 456 | "thiserror", 457 | ] 458 | 459 | [[package]] 460 | name = "alloy-signer-local" 461 | version = "0.4.2" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "494e0a256f3e99f2426f994bcd1be312c02cb8f88260088dacb33a8b8936475f" 464 | dependencies = [ 465 | "alloy-consensus", 466 | "alloy-network", 467 | "alloy-primitives", 468 | "alloy-signer", 469 | "async-trait", 470 | "k256", 471 | "rand", 472 | "thiserror", 473 | ] 474 | 475 | [[package]] 476 | name = "alloy-sol-macro" 477 | version = "0.8.7" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "661c516eb1fa3294cc7f2fb8955b3b609d639c282ac81a4eedb14d3046db503a" 480 | dependencies = [ 481 | "alloy-sol-macro-expander", 482 | "alloy-sol-macro-input", 483 | "proc-macro-error2", 484 | "proc-macro2", 485 | "quote", 486 | "syn 2.0.79", 487 | ] 488 | 489 | [[package]] 490 | name = "alloy-sol-macro-expander" 491 | version = "0.8.7" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "ecbabb8fc3d75a0c2cea5215be22e7a267e3efde835b0f2a8922f5e3f5d47683" 494 | dependencies = [ 495 | "alloy-json-abi", 496 | "alloy-sol-macro-input", 497 | "const-hex", 498 | "heck", 499 | "indexmap", 500 | "proc-macro-error2", 501 | "proc-macro2", 502 | "quote", 503 | "syn 2.0.79", 504 | "syn-solidity", 505 | "tiny-keccak", 506 | ] 507 | 508 | [[package]] 509 | name = "alloy-sol-macro-input" 510 | version = "0.8.7" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "16517f2af03064485150d89746b8ffdcdbc9b6eeb3d536fb66efd7c2846fbc75" 513 | dependencies = [ 514 | "alloy-json-abi", 515 | "const-hex", 516 | "dunce", 517 | "heck", 518 | "proc-macro2", 519 | "quote", 520 | "serde_json", 521 | "syn 2.0.79", 522 | "syn-solidity", 523 | ] 524 | 525 | [[package]] 526 | name = "alloy-sol-type-parser" 527 | version = "0.8.7" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "c07ebb0c1674ff8cbb08378d7c2e0e27919d2a2dae07ad3bca26174deda8d389" 530 | dependencies = [ 531 | "serde", 532 | "winnow", 533 | ] 534 | 535 | [[package]] 536 | name = "alloy-sol-types" 537 | version = "0.8.7" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "8e448d879903624863f608c552d10efb0e0905ddbee98b0049412799911eb062" 540 | dependencies = [ 541 | "alloy-json-abi", 542 | "alloy-primitives", 543 | "alloy-sol-macro", 544 | "const-hex", 545 | "serde", 546 | ] 547 | 548 | [[package]] 549 | name = "alloy-transport" 550 | version = "0.4.2" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "2ac3e97dad3d31770db0fc89bd6a63b789fbae78963086733f960cf32c483904" 553 | dependencies = [ 554 | "alloy-json-rpc", 555 | "base64", 556 | "futures-util", 557 | "futures-utils-wasm", 558 | "serde", 559 | "serde_json", 560 | "thiserror", 561 | "tokio", 562 | "tower", 563 | "tracing", 564 | "url", 565 | ] 566 | 567 | [[package]] 568 | name = "alloy-transport-http" 569 | version = "0.4.2" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" 572 | dependencies = [ 573 | "alloy-json-rpc", 574 | "alloy-transport", 575 | "reqwest", 576 | "serde_json", 577 | "tower", 578 | "tracing", 579 | "url", 580 | ] 581 | 582 | [[package]] 583 | name = "alloy-transport-ipc" 584 | version = "0.4.2" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "b90cf9cde7f2fce617da52768ee28f522264b282d148384a4ca0ea85af04fa3a" 587 | dependencies = [ 588 | "alloy-json-rpc", 589 | "alloy-pubsub", 590 | "alloy-transport", 591 | "bytes", 592 | "futures", 593 | "interprocess", 594 | "pin-project", 595 | "serde_json", 596 | "tokio", 597 | "tokio-util", 598 | "tracing", 599 | ] 600 | 601 | [[package]] 602 | name = "alloy-transport-ws" 603 | version = "0.4.2" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "7153b88690de6a50bba81c11e1d706bc41dbb90126d607404d60b763f6a3947f" 606 | dependencies = [ 607 | "alloy-pubsub", 608 | "alloy-transport", 609 | "futures", 610 | "http", 611 | "rustls", 612 | "serde_json", 613 | "tokio", 614 | "tokio-tungstenite", 615 | "tracing", 616 | "ws_stream_wasm", 617 | ] 618 | 619 | [[package]] 620 | name = "anyhow" 621 | version = "1.0.89" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" 624 | 625 | [[package]] 626 | name = "ark-ff" 627 | version = "0.3.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" 630 | dependencies = [ 631 | "ark-ff-asm 0.3.0", 632 | "ark-ff-macros 0.3.0", 633 | "ark-serialize 0.3.0", 634 | "ark-std 0.3.0", 635 | "derivative", 636 | "num-bigint", 637 | "num-traits", 638 | "paste", 639 | "rustc_version 0.3.3", 640 | "zeroize", 641 | ] 642 | 643 | [[package]] 644 | name = "ark-ff" 645 | version = "0.4.2" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" 648 | dependencies = [ 649 | "ark-ff-asm 0.4.2", 650 | "ark-ff-macros 0.4.2", 651 | "ark-serialize 0.4.2", 652 | "ark-std 0.4.0", 653 | "derivative", 654 | "digest 0.10.7", 655 | "itertools 0.10.5", 656 | "num-bigint", 657 | "num-traits", 658 | "paste", 659 | "rustc_version 0.4.1", 660 | "zeroize", 661 | ] 662 | 663 | [[package]] 664 | name = "ark-ff-asm" 665 | version = "0.3.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" 668 | dependencies = [ 669 | "quote", 670 | "syn 1.0.109", 671 | ] 672 | 673 | [[package]] 674 | name = "ark-ff-asm" 675 | version = "0.4.2" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" 678 | dependencies = [ 679 | "quote", 680 | "syn 1.0.109", 681 | ] 682 | 683 | [[package]] 684 | name = "ark-ff-macros" 685 | version = "0.3.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" 688 | dependencies = [ 689 | "num-bigint", 690 | "num-traits", 691 | "quote", 692 | "syn 1.0.109", 693 | ] 694 | 695 | [[package]] 696 | name = "ark-ff-macros" 697 | version = "0.4.2" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" 700 | dependencies = [ 701 | "num-bigint", 702 | "num-traits", 703 | "proc-macro2", 704 | "quote", 705 | "syn 1.0.109", 706 | ] 707 | 708 | [[package]] 709 | name = "ark-serialize" 710 | version = "0.3.0" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" 713 | dependencies = [ 714 | "ark-std 0.3.0", 715 | "digest 0.9.0", 716 | ] 717 | 718 | [[package]] 719 | name = "ark-serialize" 720 | version = "0.4.2" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" 723 | dependencies = [ 724 | "ark-std 0.4.0", 725 | "digest 0.10.7", 726 | "num-bigint", 727 | ] 728 | 729 | [[package]] 730 | name = "ark-std" 731 | version = "0.3.0" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" 734 | dependencies = [ 735 | "num-traits", 736 | "rand", 737 | ] 738 | 739 | [[package]] 740 | name = "ark-std" 741 | version = "0.4.0" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" 744 | dependencies = [ 745 | "num-traits", 746 | "rand", 747 | ] 748 | 749 | [[package]] 750 | name = "arrayvec" 751 | version = "0.7.6" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 754 | 755 | [[package]] 756 | name = "async-stream" 757 | version = "0.3.6" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 760 | dependencies = [ 761 | "async-stream-impl", 762 | "futures-core", 763 | "pin-project-lite", 764 | ] 765 | 766 | [[package]] 767 | name = "async-stream-impl" 768 | version = "0.3.6" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 771 | dependencies = [ 772 | "proc-macro2", 773 | "quote", 774 | "syn 2.0.79", 775 | ] 776 | 777 | [[package]] 778 | name = "async-trait" 779 | version = "0.1.83" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 782 | dependencies = [ 783 | "proc-macro2", 784 | "quote", 785 | "syn 2.0.79", 786 | ] 787 | 788 | [[package]] 789 | name = "async_io_stream" 790 | version = "0.3.3" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" 793 | dependencies = [ 794 | "futures", 795 | "pharos", 796 | "rustc_version 0.4.1", 797 | ] 798 | 799 | [[package]] 800 | name = "auto_impl" 801 | version = "1.2.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" 804 | dependencies = [ 805 | "proc-macro2", 806 | "quote", 807 | "syn 2.0.79", 808 | ] 809 | 810 | [[package]] 811 | name = "autocfg" 812 | version = "1.4.0" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 815 | 816 | [[package]] 817 | name = "az" 818 | version = "1.2.1" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 821 | 822 | [[package]] 823 | name = "backtrace" 824 | version = "0.3.74" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 827 | dependencies = [ 828 | "addr2line", 829 | "cfg-if", 830 | "libc", 831 | "miniz_oxide", 832 | "object", 833 | "rustc-demangle", 834 | "windows-targets", 835 | ] 836 | 837 | [[package]] 838 | name = "base16ct" 839 | version = "0.2.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 842 | 843 | [[package]] 844 | name = "base64" 845 | version = "0.22.1" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 848 | 849 | [[package]] 850 | name = "base64ct" 851 | version = "1.6.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 854 | 855 | [[package]] 856 | name = "bimap" 857 | version = "0.6.3" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" 860 | 861 | [[package]] 862 | name = "bit-set" 863 | version = "0.5.3" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 866 | dependencies = [ 867 | "bit-vec", 868 | ] 869 | 870 | [[package]] 871 | name = "bit-vec" 872 | version = "0.6.3" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 875 | 876 | [[package]] 877 | name = "bitflags" 878 | version = "2.6.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 881 | 882 | [[package]] 883 | name = "bitvec" 884 | version = "1.0.1" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 887 | dependencies = [ 888 | "funty", 889 | "radium", 890 | "tap", 891 | "wyz", 892 | ] 893 | 894 | [[package]] 895 | name = "block-buffer" 896 | version = "0.10.4" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 899 | dependencies = [ 900 | "generic-array", 901 | ] 902 | 903 | [[package]] 904 | name = "blst" 905 | version = "0.3.13" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" 908 | dependencies = [ 909 | "cc", 910 | "glob", 911 | "threadpool", 912 | "zeroize", 913 | ] 914 | 915 | [[package]] 916 | name = "bumpalo" 917 | version = "3.16.0" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 920 | 921 | [[package]] 922 | name = "byte-slice-cast" 923 | version = "1.2.2" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" 926 | 927 | [[package]] 928 | name = "byteorder" 929 | version = "1.5.0" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 932 | 933 | [[package]] 934 | name = "bytes" 935 | version = "1.7.2" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" 938 | dependencies = [ 939 | "serde", 940 | ] 941 | 942 | [[package]] 943 | name = "c-kzg" 944 | version = "1.0.3" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" 947 | dependencies = [ 948 | "blst", 949 | "cc", 950 | "glob", 951 | "hex", 952 | "libc", 953 | "once_cell", 954 | "serde", 955 | ] 956 | 957 | [[package]] 958 | name = "cc" 959 | version = "1.1.28" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" 962 | dependencies = [ 963 | "shlex", 964 | ] 965 | 966 | [[package]] 967 | name = "cfg-if" 968 | version = "1.0.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 971 | 972 | [[package]] 973 | name = "const-hex" 974 | version = "1.13.1" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" 977 | dependencies = [ 978 | "cfg-if", 979 | "cpufeatures", 980 | "hex", 981 | "proptest", 982 | "serde", 983 | ] 984 | 985 | [[package]] 986 | name = "const-oid" 987 | version = "0.9.6" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 990 | 991 | [[package]] 992 | name = "core-foundation" 993 | version = "0.9.4" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 996 | dependencies = [ 997 | "core-foundation-sys", 998 | "libc", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "core-foundation-sys" 1003 | version = "0.8.7" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 1006 | 1007 | [[package]] 1008 | name = "cpufeatures" 1009 | version = "0.2.14" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" 1012 | dependencies = [ 1013 | "libc", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "crossbeam-utils" 1018 | version = "0.8.20" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 1021 | 1022 | [[package]] 1023 | name = "crunchy" 1024 | version = "0.2.2" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 1027 | 1028 | [[package]] 1029 | name = "crypto-bigint" 1030 | version = "0.5.5" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 1033 | dependencies = [ 1034 | "generic-array", 1035 | "rand_core", 1036 | "subtle", 1037 | "zeroize", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "crypto-common" 1042 | version = "0.1.6" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 1045 | dependencies = [ 1046 | "generic-array", 1047 | "typenum", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "dashmap" 1052 | version = "6.1.0" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 1055 | dependencies = [ 1056 | "cfg-if", 1057 | "crossbeam-utils", 1058 | "hashbrown 0.14.5", 1059 | "lock_api", 1060 | "once_cell", 1061 | "parking_lot_core", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "data-encoding" 1066 | version = "2.6.0" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 1069 | 1070 | [[package]] 1071 | name = "der" 1072 | version = "0.7.9" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 1075 | dependencies = [ 1076 | "const-oid", 1077 | "zeroize", 1078 | ] 1079 | 1080 | [[package]] 1081 | name = "derivative" 1082 | version = "2.2.0" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 1085 | dependencies = [ 1086 | "proc-macro2", 1087 | "quote", 1088 | "syn 1.0.109", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "derive_more" 1093 | version = "1.0.0" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" 1096 | dependencies = [ 1097 | "derive_more-impl", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "derive_more-impl" 1102 | version = "1.0.0" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" 1105 | dependencies = [ 1106 | "proc-macro2", 1107 | "quote", 1108 | "syn 2.0.79", 1109 | "unicode-xid", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "digest" 1114 | version = "0.9.0" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 1117 | dependencies = [ 1118 | "generic-array", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "digest" 1123 | version = "0.10.7" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 1126 | dependencies = [ 1127 | "block-buffer", 1128 | "const-oid", 1129 | "crypto-common", 1130 | "subtle", 1131 | ] 1132 | 1133 | [[package]] 1134 | name = "doctest-file" 1135 | version = "1.0.0" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" 1138 | 1139 | [[package]] 1140 | name = "dunce" 1141 | version = "1.0.5" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 1144 | 1145 | [[package]] 1146 | name = "ecdsa" 1147 | version = "0.16.9" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 1150 | dependencies = [ 1151 | "der", 1152 | "digest 0.10.7", 1153 | "elliptic-curve", 1154 | "rfc6979", 1155 | "signature", 1156 | "spki", 1157 | ] 1158 | 1159 | [[package]] 1160 | name = "either" 1161 | version = "1.13.0" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 1164 | 1165 | [[package]] 1166 | name = "elliptic-curve" 1167 | version = "0.13.8" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 1170 | dependencies = [ 1171 | "base16ct", 1172 | "crypto-bigint", 1173 | "digest 0.10.7", 1174 | "ff", 1175 | "generic-array", 1176 | "group", 1177 | "pkcs8", 1178 | "rand_core", 1179 | "sec1", 1180 | "subtle", 1181 | "zeroize", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "equivalent" 1186 | version = "1.0.1" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 1189 | 1190 | [[package]] 1191 | name = "errno" 1192 | version = "0.3.9" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 1195 | dependencies = [ 1196 | "libc", 1197 | "windows-sys 0.52.0", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "fastrand" 1202 | version = "2.1.1" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" 1205 | 1206 | [[package]] 1207 | name = "fastrlp" 1208 | version = "0.3.1" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" 1211 | dependencies = [ 1212 | "arrayvec", 1213 | "auto_impl", 1214 | "bytes", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "ff" 1219 | version = "0.13.0" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" 1222 | dependencies = [ 1223 | "rand_core", 1224 | "subtle", 1225 | ] 1226 | 1227 | [[package]] 1228 | name = "fixed-hash" 1229 | version = "0.8.0" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" 1232 | dependencies = [ 1233 | "byteorder", 1234 | "rand", 1235 | "rustc-hex", 1236 | "static_assertions", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "fnv" 1241 | version = "1.0.7" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 1244 | 1245 | [[package]] 1246 | name = "foldhash" 1247 | version = "0.1.3" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" 1250 | 1251 | [[package]] 1252 | name = "foreign-types" 1253 | version = "0.3.2" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 1256 | dependencies = [ 1257 | "foreign-types-shared", 1258 | ] 1259 | 1260 | [[package]] 1261 | name = "foreign-types-shared" 1262 | version = "0.1.1" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 1265 | 1266 | [[package]] 1267 | name = "form_urlencoded" 1268 | version = "1.2.1" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 1271 | dependencies = [ 1272 | "percent-encoding", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "funty" 1277 | version = "2.0.0" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 1280 | 1281 | [[package]] 1282 | name = "futures" 1283 | version = "0.3.31" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 1286 | dependencies = [ 1287 | "futures-channel", 1288 | "futures-core", 1289 | "futures-executor", 1290 | "futures-io", 1291 | "futures-sink", 1292 | "futures-task", 1293 | "futures-util", 1294 | ] 1295 | 1296 | [[package]] 1297 | name = "futures-channel" 1298 | version = "0.3.31" 1299 | source = "registry+https://github.com/rust-lang/crates.io-index" 1300 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 1301 | dependencies = [ 1302 | "futures-core", 1303 | "futures-sink", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "futures-core" 1308 | version = "0.3.31" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 1311 | 1312 | [[package]] 1313 | name = "futures-executor" 1314 | version = "0.3.31" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 1317 | dependencies = [ 1318 | "futures-core", 1319 | "futures-task", 1320 | "futures-util", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "futures-io" 1325 | version = "0.3.31" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 1328 | 1329 | [[package]] 1330 | name = "futures-macro" 1331 | version = "0.3.31" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 1334 | dependencies = [ 1335 | "proc-macro2", 1336 | "quote", 1337 | "syn 2.0.79", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "futures-sink" 1342 | version = "0.3.31" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 1345 | 1346 | [[package]] 1347 | name = "futures-task" 1348 | version = "0.3.31" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 1351 | 1352 | [[package]] 1353 | name = "futures-util" 1354 | version = "0.3.31" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 1357 | dependencies = [ 1358 | "futures-channel", 1359 | "futures-core", 1360 | "futures-io", 1361 | "futures-macro", 1362 | "futures-sink", 1363 | "futures-task", 1364 | "memchr", 1365 | "pin-project-lite", 1366 | "pin-utils", 1367 | "slab", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "futures-utils-wasm" 1372 | version = "0.1.0" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" 1375 | 1376 | [[package]] 1377 | name = "generic-array" 1378 | version = "0.14.7" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 1381 | dependencies = [ 1382 | "typenum", 1383 | "version_check", 1384 | "zeroize", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "getrandom" 1389 | version = "0.2.15" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 1392 | dependencies = [ 1393 | "cfg-if", 1394 | "libc", 1395 | "wasi", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "gimli" 1400 | version = "0.31.1" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 1403 | 1404 | [[package]] 1405 | name = "glob" 1406 | version = "0.3.1" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 1409 | 1410 | [[package]] 1411 | name = "gmp-mpfr-sys" 1412 | version = "1.6.4" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "b0205cd82059bc63b63cf516d714352a30c44f2c74da9961dfda2617ae6b5918" 1415 | dependencies = [ 1416 | "libc", 1417 | "windows-sys 0.52.0", 1418 | ] 1419 | 1420 | [[package]] 1421 | name = "group" 1422 | version = "0.13.0" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 1425 | dependencies = [ 1426 | "ff", 1427 | "rand_core", 1428 | "subtle", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "hashbrown" 1433 | version = "0.14.5" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 1436 | 1437 | [[package]] 1438 | name = "hashbrown" 1439 | version = "0.15.0" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 1442 | dependencies = [ 1443 | "allocator-api2", 1444 | "equivalent", 1445 | "foldhash", 1446 | "serde", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "heck" 1451 | version = "0.5.0" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1454 | 1455 | [[package]] 1456 | name = "hermit-abi" 1457 | version = "0.3.9" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 1460 | 1461 | [[package]] 1462 | name = "hex" 1463 | version = "0.4.3" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1466 | dependencies = [ 1467 | "serde", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "hex-literal" 1472 | version = "0.4.1" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" 1475 | 1476 | [[package]] 1477 | name = "hmac" 1478 | version = "0.12.1" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 1481 | dependencies = [ 1482 | "digest 0.10.7", 1483 | ] 1484 | 1485 | [[package]] 1486 | name = "http" 1487 | version = "1.1.0" 1488 | source = "registry+https://github.com/rust-lang/crates.io-index" 1489 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 1490 | dependencies = [ 1491 | "bytes", 1492 | "fnv", 1493 | "itoa", 1494 | ] 1495 | 1496 | [[package]] 1497 | name = "http-body" 1498 | version = "1.0.1" 1499 | source = "registry+https://github.com/rust-lang/crates.io-index" 1500 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 1501 | dependencies = [ 1502 | "bytes", 1503 | "http", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "http-body-util" 1508 | version = "0.1.2" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 1511 | dependencies = [ 1512 | "bytes", 1513 | "futures-util", 1514 | "http", 1515 | "http-body", 1516 | "pin-project-lite", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "httparse" 1521 | version = "1.9.5" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 1524 | 1525 | [[package]] 1526 | name = "hyper" 1527 | version = "1.4.1" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 1530 | dependencies = [ 1531 | "bytes", 1532 | "futures-channel", 1533 | "futures-util", 1534 | "http", 1535 | "http-body", 1536 | "httparse", 1537 | "itoa", 1538 | "pin-project-lite", 1539 | "smallvec", 1540 | "tokio", 1541 | "want", 1542 | ] 1543 | 1544 | [[package]] 1545 | name = "hyper-tls" 1546 | version = "0.6.0" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 1549 | dependencies = [ 1550 | "bytes", 1551 | "http-body-util", 1552 | "hyper", 1553 | "hyper-util", 1554 | "native-tls", 1555 | "tokio", 1556 | "tokio-native-tls", 1557 | "tower-service", 1558 | ] 1559 | 1560 | [[package]] 1561 | name = "hyper-util" 1562 | version = "0.1.9" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" 1565 | dependencies = [ 1566 | "bytes", 1567 | "futures-channel", 1568 | "futures-util", 1569 | "http", 1570 | "http-body", 1571 | "hyper", 1572 | "pin-project-lite", 1573 | "socket2", 1574 | "tokio", 1575 | "tower-service", 1576 | "tracing", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "idna" 1581 | version = "0.5.0" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 1584 | dependencies = [ 1585 | "unicode-bidi", 1586 | "unicode-normalization", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "impl-codec" 1591 | version = "0.6.0" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" 1594 | dependencies = [ 1595 | "parity-scale-codec", 1596 | ] 1597 | 1598 | [[package]] 1599 | name = "impl-trait-for-tuples" 1600 | version = "0.2.2" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" 1603 | dependencies = [ 1604 | "proc-macro2", 1605 | "quote", 1606 | "syn 1.0.109", 1607 | ] 1608 | 1609 | [[package]] 1610 | name = "indexmap" 1611 | version = "2.6.0" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 1614 | dependencies = [ 1615 | "equivalent", 1616 | "hashbrown 0.15.0", 1617 | "serde", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "interprocess" 1622 | version = "2.2.1" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" 1625 | dependencies = [ 1626 | "doctest-file", 1627 | "futures-core", 1628 | "libc", 1629 | "recvmsg", 1630 | "tokio", 1631 | "widestring", 1632 | "windows-sys 0.52.0", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "ipnet" 1637 | version = "2.10.1" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" 1640 | 1641 | [[package]] 1642 | name = "itertools" 1643 | version = "0.10.5" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 1646 | dependencies = [ 1647 | "either", 1648 | ] 1649 | 1650 | [[package]] 1651 | name = "itertools" 1652 | version = "0.13.0" 1653 | source = "registry+https://github.com/rust-lang/crates.io-index" 1654 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 1655 | dependencies = [ 1656 | "either", 1657 | ] 1658 | 1659 | [[package]] 1660 | name = "itoa" 1661 | version = "1.0.11" 1662 | source = "registry+https://github.com/rust-lang/crates.io-index" 1663 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 1664 | 1665 | [[package]] 1666 | name = "js-sys" 1667 | version = "0.3.72" 1668 | source = "registry+https://github.com/rust-lang/crates.io-index" 1669 | checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" 1670 | dependencies = [ 1671 | "wasm-bindgen", 1672 | ] 1673 | 1674 | [[package]] 1675 | name = "k256" 1676 | version = "0.13.4" 1677 | source = "registry+https://github.com/rust-lang/crates.io-index" 1678 | checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" 1679 | dependencies = [ 1680 | "cfg-if", 1681 | "ecdsa", 1682 | "elliptic-curve", 1683 | "once_cell", 1684 | "sha2", 1685 | ] 1686 | 1687 | [[package]] 1688 | name = "keccak" 1689 | version = "0.1.5" 1690 | source = "registry+https://github.com/rust-lang/crates.io-index" 1691 | checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" 1692 | dependencies = [ 1693 | "cpufeatures", 1694 | ] 1695 | 1696 | [[package]] 1697 | name = "keccak-asm" 1698 | version = "0.1.4" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" 1701 | dependencies = [ 1702 | "digest 0.10.7", 1703 | "sha3-asm", 1704 | ] 1705 | 1706 | [[package]] 1707 | name = "lazy_static" 1708 | version = "1.5.0" 1709 | source = "registry+https://github.com/rust-lang/crates.io-index" 1710 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1711 | 1712 | [[package]] 1713 | name = "libc" 1714 | version = "0.2.159" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" 1717 | 1718 | [[package]] 1719 | name = "libm" 1720 | version = "0.2.8" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 1723 | 1724 | [[package]] 1725 | name = "linux-raw-sys" 1726 | version = "0.4.14" 1727 | source = "registry+https://github.com/rust-lang/crates.io-index" 1728 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 1729 | 1730 | [[package]] 1731 | name = "lock_api" 1732 | version = "0.4.12" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1735 | dependencies = [ 1736 | "autocfg", 1737 | "scopeguard", 1738 | ] 1739 | 1740 | [[package]] 1741 | name = "log" 1742 | version = "0.4.22" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1745 | 1746 | [[package]] 1747 | name = "lru" 1748 | version = "0.12.5" 1749 | source = "registry+https://github.com/rust-lang/crates.io-index" 1750 | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 1751 | dependencies = [ 1752 | "hashbrown 0.15.0", 1753 | ] 1754 | 1755 | [[package]] 1756 | name = "memchr" 1757 | version = "2.7.4" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1760 | 1761 | [[package]] 1762 | name = "mime" 1763 | version = "0.3.17" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1766 | 1767 | [[package]] 1768 | name = "miniz_oxide" 1769 | version = "0.8.0" 1770 | source = "registry+https://github.com/rust-lang/crates.io-index" 1771 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 1772 | dependencies = [ 1773 | "adler2", 1774 | ] 1775 | 1776 | [[package]] 1777 | name = "mio" 1778 | version = "1.0.2" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 1781 | dependencies = [ 1782 | "hermit-abi", 1783 | "libc", 1784 | "wasi", 1785 | "windows-sys 0.52.0", 1786 | ] 1787 | 1788 | [[package]] 1789 | name = "native-tls" 1790 | version = "0.2.12" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 1793 | dependencies = [ 1794 | "libc", 1795 | "log", 1796 | "openssl", 1797 | "openssl-probe", 1798 | "openssl-sys", 1799 | "schannel", 1800 | "security-framework", 1801 | "security-framework-sys", 1802 | "tempfile", 1803 | ] 1804 | 1805 | [[package]] 1806 | name = "nu-ansi-term" 1807 | version = "0.46.0" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1810 | dependencies = [ 1811 | "overload", 1812 | "winapi", 1813 | ] 1814 | 1815 | [[package]] 1816 | name = "num-bigint" 1817 | version = "0.4.6" 1818 | source = "registry+https://github.com/rust-lang/crates.io-index" 1819 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 1820 | dependencies = [ 1821 | "num-integer", 1822 | "num-traits", 1823 | ] 1824 | 1825 | [[package]] 1826 | name = "num-integer" 1827 | version = "0.1.46" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1830 | dependencies = [ 1831 | "num-traits", 1832 | ] 1833 | 1834 | [[package]] 1835 | name = "num-traits" 1836 | version = "0.2.19" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1839 | dependencies = [ 1840 | "autocfg", 1841 | "libm", 1842 | ] 1843 | 1844 | [[package]] 1845 | name = "num_cpus" 1846 | version = "1.16.0" 1847 | source = "registry+https://github.com/rust-lang/crates.io-index" 1848 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1849 | dependencies = [ 1850 | "hermit-abi", 1851 | "libc", 1852 | ] 1853 | 1854 | [[package]] 1855 | name = "num_enum" 1856 | version = "0.7.3" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" 1859 | dependencies = [ 1860 | "num_enum_derive", 1861 | ] 1862 | 1863 | [[package]] 1864 | name = "num_enum_derive" 1865 | version = "0.7.3" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" 1868 | dependencies = [ 1869 | "proc-macro2", 1870 | "quote", 1871 | "syn 2.0.79", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "object" 1876 | version = "0.36.5" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1879 | dependencies = [ 1880 | "memchr", 1881 | ] 1882 | 1883 | [[package]] 1884 | name = "once_cell" 1885 | version = "1.20.2" 1886 | source = "registry+https://github.com/rust-lang/crates.io-index" 1887 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1888 | 1889 | [[package]] 1890 | name = "openssl" 1891 | version = "0.10.66" 1892 | source = "registry+https://github.com/rust-lang/crates.io-index" 1893 | checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" 1894 | dependencies = [ 1895 | "bitflags", 1896 | "cfg-if", 1897 | "foreign-types", 1898 | "libc", 1899 | "once_cell", 1900 | "openssl-macros", 1901 | "openssl-sys", 1902 | ] 1903 | 1904 | [[package]] 1905 | name = "openssl-macros" 1906 | version = "0.1.1" 1907 | source = "registry+https://github.com/rust-lang/crates.io-index" 1908 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1909 | dependencies = [ 1910 | "proc-macro2", 1911 | "quote", 1912 | "syn 2.0.79", 1913 | ] 1914 | 1915 | [[package]] 1916 | name = "openssl-probe" 1917 | version = "0.1.5" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1920 | 1921 | [[package]] 1922 | name = "openssl-sys" 1923 | version = "0.9.103" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" 1926 | dependencies = [ 1927 | "cc", 1928 | "libc", 1929 | "pkg-config", 1930 | "vcpkg", 1931 | ] 1932 | 1933 | [[package]] 1934 | name = "overload" 1935 | version = "0.1.1" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1938 | 1939 | [[package]] 1940 | name = "parity-scale-codec" 1941 | version = "3.6.12" 1942 | source = "registry+https://github.com/rust-lang/crates.io-index" 1943 | checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" 1944 | dependencies = [ 1945 | "arrayvec", 1946 | "bitvec", 1947 | "byte-slice-cast", 1948 | "impl-trait-for-tuples", 1949 | "parity-scale-codec-derive", 1950 | "serde", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "parity-scale-codec-derive" 1955 | version = "3.6.12" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" 1958 | dependencies = [ 1959 | "proc-macro-crate", 1960 | "proc-macro2", 1961 | "quote", 1962 | "syn 1.0.109", 1963 | ] 1964 | 1965 | [[package]] 1966 | name = "parking_lot" 1967 | version = "0.12.3" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1970 | dependencies = [ 1971 | "lock_api", 1972 | "parking_lot_core", 1973 | ] 1974 | 1975 | [[package]] 1976 | name = "parking_lot_core" 1977 | version = "0.9.10" 1978 | source = "registry+https://github.com/rust-lang/crates.io-index" 1979 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1980 | dependencies = [ 1981 | "cfg-if", 1982 | "libc", 1983 | "redox_syscall", 1984 | "smallvec", 1985 | "windows-targets", 1986 | ] 1987 | 1988 | [[package]] 1989 | name = "paste" 1990 | version = "1.0.15" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1993 | 1994 | [[package]] 1995 | name = "percent-encoding" 1996 | version = "2.3.1" 1997 | source = "registry+https://github.com/rust-lang/crates.io-index" 1998 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1999 | 2000 | [[package]] 2001 | name = "pest" 2002 | version = "2.7.13" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" 2005 | dependencies = [ 2006 | "memchr", 2007 | "thiserror", 2008 | "ucd-trie", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "pharos" 2013 | version = "0.5.3" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" 2016 | dependencies = [ 2017 | "futures", 2018 | "rustc_version 0.4.1", 2019 | ] 2020 | 2021 | [[package]] 2022 | name = "phf" 2023 | version = "0.11.2" 2024 | source = "registry+https://github.com/rust-lang/crates.io-index" 2025 | checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 2026 | dependencies = [ 2027 | "phf_macros", 2028 | "phf_shared", 2029 | ] 2030 | 2031 | [[package]] 2032 | name = "phf_generator" 2033 | version = "0.11.2" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" 2036 | dependencies = [ 2037 | "phf_shared", 2038 | "rand", 2039 | ] 2040 | 2041 | [[package]] 2042 | name = "phf_macros" 2043 | version = "0.11.2" 2044 | source = "registry+https://github.com/rust-lang/crates.io-index" 2045 | checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" 2046 | dependencies = [ 2047 | "phf_generator", 2048 | "phf_shared", 2049 | "proc-macro2", 2050 | "quote", 2051 | "syn 2.0.79", 2052 | ] 2053 | 2054 | [[package]] 2055 | name = "phf_shared" 2056 | version = "0.11.2" 2057 | source = "registry+https://github.com/rust-lang/crates.io-index" 2058 | checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 2059 | dependencies = [ 2060 | "siphasher", 2061 | ] 2062 | 2063 | [[package]] 2064 | name = "pin-project" 2065 | version = "1.1.6" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" 2068 | dependencies = [ 2069 | "pin-project-internal", 2070 | ] 2071 | 2072 | [[package]] 2073 | name = "pin-project-internal" 2074 | version = "1.1.6" 2075 | source = "registry+https://github.com/rust-lang/crates.io-index" 2076 | checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" 2077 | dependencies = [ 2078 | "proc-macro2", 2079 | "quote", 2080 | "syn 2.0.79", 2081 | ] 2082 | 2083 | [[package]] 2084 | name = "pin-project-lite" 2085 | version = "0.2.14" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 2088 | 2089 | [[package]] 2090 | name = "pin-utils" 2091 | version = "0.1.0" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 2094 | 2095 | [[package]] 2096 | name = "pkcs8" 2097 | version = "0.10.2" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 2100 | dependencies = [ 2101 | "der", 2102 | "spki", 2103 | ] 2104 | 2105 | [[package]] 2106 | name = "pkg-config" 2107 | version = "0.3.31" 2108 | source = "registry+https://github.com/rust-lang/crates.io-index" 2109 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 2110 | 2111 | [[package]] 2112 | name = "ppv-lite86" 2113 | version = "0.2.20" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 2116 | dependencies = [ 2117 | "zerocopy", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "primitive-types" 2122 | version = "0.12.2" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" 2125 | dependencies = [ 2126 | "fixed-hash", 2127 | "impl-codec", 2128 | "uint", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "proc-macro-crate" 2133 | version = "3.2.0" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" 2136 | dependencies = [ 2137 | "toml_edit", 2138 | ] 2139 | 2140 | [[package]] 2141 | name = "proc-macro-error-attr2" 2142 | version = "2.0.0" 2143 | source = "registry+https://github.com/rust-lang/crates.io-index" 2144 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 2145 | dependencies = [ 2146 | "proc-macro2", 2147 | "quote", 2148 | ] 2149 | 2150 | [[package]] 2151 | name = "proc-macro-error2" 2152 | version = "2.0.1" 2153 | source = "registry+https://github.com/rust-lang/crates.io-index" 2154 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 2155 | dependencies = [ 2156 | "proc-macro-error-attr2", 2157 | "proc-macro2", 2158 | "quote", 2159 | "syn 2.0.79", 2160 | ] 2161 | 2162 | [[package]] 2163 | name = "proc-macro2" 2164 | version = "1.0.87" 2165 | source = "registry+https://github.com/rust-lang/crates.io-index" 2166 | checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" 2167 | dependencies = [ 2168 | "unicode-ident", 2169 | ] 2170 | 2171 | [[package]] 2172 | name = "proptest" 2173 | version = "1.5.0" 2174 | source = "registry+https://github.com/rust-lang/crates.io-index" 2175 | checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" 2176 | dependencies = [ 2177 | "bit-set", 2178 | "bit-vec", 2179 | "bitflags", 2180 | "lazy_static", 2181 | "num-traits", 2182 | "rand", 2183 | "rand_chacha", 2184 | "rand_xorshift", 2185 | "regex-syntax", 2186 | "rusty-fork", 2187 | "tempfile", 2188 | "unarray", 2189 | ] 2190 | 2191 | [[package]] 2192 | name = "quick-error" 2193 | version = "1.2.3" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 2196 | 2197 | [[package]] 2198 | name = "quote" 2199 | version = "1.0.37" 2200 | source = "registry+https://github.com/rust-lang/crates.io-index" 2201 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 2202 | dependencies = [ 2203 | "proc-macro2", 2204 | ] 2205 | 2206 | [[package]] 2207 | name = "radium" 2208 | version = "0.7.0" 2209 | source = "registry+https://github.com/rust-lang/crates.io-index" 2210 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 2211 | 2212 | [[package]] 2213 | name = "rand" 2214 | version = "0.8.5" 2215 | source = "registry+https://github.com/rust-lang/crates.io-index" 2216 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 2217 | dependencies = [ 2218 | "libc", 2219 | "rand_chacha", 2220 | "rand_core", 2221 | "serde", 2222 | ] 2223 | 2224 | [[package]] 2225 | name = "rand_chacha" 2226 | version = "0.3.1" 2227 | source = "registry+https://github.com/rust-lang/crates.io-index" 2228 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 2229 | dependencies = [ 2230 | "ppv-lite86", 2231 | "rand_core", 2232 | ] 2233 | 2234 | [[package]] 2235 | name = "rand_core" 2236 | version = "0.6.4" 2237 | source = "registry+https://github.com/rust-lang/crates.io-index" 2238 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 2239 | dependencies = [ 2240 | "getrandom", 2241 | ] 2242 | 2243 | [[package]] 2244 | name = "rand_xorshift" 2245 | version = "0.3.0" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" 2248 | dependencies = [ 2249 | "rand_core", 2250 | ] 2251 | 2252 | [[package]] 2253 | name = "recvmsg" 2254 | version = "1.0.0" 2255 | source = "registry+https://github.com/rust-lang/crates.io-index" 2256 | checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" 2257 | 2258 | [[package]] 2259 | name = "redox_syscall" 2260 | version = "0.5.7" 2261 | source = "registry+https://github.com/rust-lang/crates.io-index" 2262 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 2263 | dependencies = [ 2264 | "bitflags", 2265 | ] 2266 | 2267 | [[package]] 2268 | name = "regex-syntax" 2269 | version = "0.8.5" 2270 | source = "registry+https://github.com/rust-lang/crates.io-index" 2271 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 2272 | 2273 | [[package]] 2274 | name = "reqwest" 2275 | version = "0.12.8" 2276 | source = "registry+https://github.com/rust-lang/crates.io-index" 2277 | checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" 2278 | dependencies = [ 2279 | "base64", 2280 | "bytes", 2281 | "futures-core", 2282 | "futures-util", 2283 | "http", 2284 | "http-body", 2285 | "http-body-util", 2286 | "hyper", 2287 | "hyper-tls", 2288 | "hyper-util", 2289 | "ipnet", 2290 | "js-sys", 2291 | "log", 2292 | "mime", 2293 | "native-tls", 2294 | "once_cell", 2295 | "percent-encoding", 2296 | "pin-project-lite", 2297 | "rustls-pemfile", 2298 | "serde", 2299 | "serde_json", 2300 | "serde_urlencoded", 2301 | "sync_wrapper 1.0.1", 2302 | "tokio", 2303 | "tokio-native-tls", 2304 | "tower-service", 2305 | "url", 2306 | "wasm-bindgen", 2307 | "wasm-bindgen-futures", 2308 | "web-sys", 2309 | "windows-registry", 2310 | ] 2311 | 2312 | [[package]] 2313 | name = "rfc6979" 2314 | version = "0.4.0" 2315 | source = "registry+https://github.com/rust-lang/crates.io-index" 2316 | checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 2317 | dependencies = [ 2318 | "hmac", 2319 | "subtle", 2320 | ] 2321 | 2322 | [[package]] 2323 | name = "ring" 2324 | version = "0.17.8" 2325 | source = "registry+https://github.com/rust-lang/crates.io-index" 2326 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 2327 | dependencies = [ 2328 | "cc", 2329 | "cfg-if", 2330 | "getrandom", 2331 | "libc", 2332 | "spin", 2333 | "untrusted", 2334 | "windows-sys 0.52.0", 2335 | ] 2336 | 2337 | [[package]] 2338 | name = "rlp" 2339 | version = "0.5.2" 2340 | source = "registry+https://github.com/rust-lang/crates.io-index" 2341 | checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" 2342 | dependencies = [ 2343 | "bytes", 2344 | "rustc-hex", 2345 | ] 2346 | 2347 | [[package]] 2348 | name = "rug" 2349 | version = "1.26.1" 2350 | source = "registry+https://github.com/rust-lang/crates.io-index" 2351 | checksum = "97ae2c1089ec0575193eb9222881310cc1ed8bce3646ef8b81b44b518595b79d" 2352 | dependencies = [ 2353 | "az", 2354 | "gmp-mpfr-sys", 2355 | "libc", 2356 | "libm", 2357 | ] 2358 | 2359 | [[package]] 2360 | name = "ruint" 2361 | version = "1.12.3" 2362 | source = "registry+https://github.com/rust-lang/crates.io-index" 2363 | checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" 2364 | dependencies = [ 2365 | "alloy-rlp", 2366 | "ark-ff 0.3.0", 2367 | "ark-ff 0.4.2", 2368 | "bytes", 2369 | "fastrlp", 2370 | "num-bigint", 2371 | "num-traits", 2372 | "parity-scale-codec", 2373 | "primitive-types", 2374 | "proptest", 2375 | "rand", 2376 | "rlp", 2377 | "ruint-macro", 2378 | "serde", 2379 | "valuable", 2380 | "zeroize", 2381 | ] 2382 | 2383 | [[package]] 2384 | name = "ruint-macro" 2385 | version = "1.2.1" 2386 | source = "registry+https://github.com/rust-lang/crates.io-index" 2387 | checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" 2388 | 2389 | [[package]] 2390 | name = "rustc-demangle" 2391 | version = "0.1.24" 2392 | source = "registry+https://github.com/rust-lang/crates.io-index" 2393 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 2394 | 2395 | [[package]] 2396 | name = "rustc-hash" 2397 | version = "2.0.0" 2398 | source = "registry+https://github.com/rust-lang/crates.io-index" 2399 | checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" 2400 | 2401 | [[package]] 2402 | name = "rustc-hex" 2403 | version = "2.1.0" 2404 | source = "registry+https://github.com/rust-lang/crates.io-index" 2405 | checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" 2406 | 2407 | [[package]] 2408 | name = "rustc_version" 2409 | version = "0.3.3" 2410 | source = "registry+https://github.com/rust-lang/crates.io-index" 2411 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 2412 | dependencies = [ 2413 | "semver 0.11.0", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "rustc_version" 2418 | version = "0.4.1" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 2421 | dependencies = [ 2422 | "semver 1.0.23", 2423 | ] 2424 | 2425 | [[package]] 2426 | name = "rustix" 2427 | version = "0.38.37" 2428 | source = "registry+https://github.com/rust-lang/crates.io-index" 2429 | checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" 2430 | dependencies = [ 2431 | "bitflags", 2432 | "errno", 2433 | "libc", 2434 | "linux-raw-sys", 2435 | "windows-sys 0.52.0", 2436 | ] 2437 | 2438 | [[package]] 2439 | name = "rustls" 2440 | version = "0.23.14" 2441 | source = "registry+https://github.com/rust-lang/crates.io-index" 2442 | checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" 2443 | dependencies = [ 2444 | "once_cell", 2445 | "ring", 2446 | "rustls-pki-types", 2447 | "rustls-webpki", 2448 | "subtle", 2449 | "zeroize", 2450 | ] 2451 | 2452 | [[package]] 2453 | name = "rustls-pemfile" 2454 | version = "2.2.0" 2455 | source = "registry+https://github.com/rust-lang/crates.io-index" 2456 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 2457 | dependencies = [ 2458 | "rustls-pki-types", 2459 | ] 2460 | 2461 | [[package]] 2462 | name = "rustls-pki-types" 2463 | version = "1.9.0" 2464 | source = "registry+https://github.com/rust-lang/crates.io-index" 2465 | checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" 2466 | 2467 | [[package]] 2468 | name = "rustls-webpki" 2469 | version = "0.102.8" 2470 | source = "registry+https://github.com/rust-lang/crates.io-index" 2471 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 2472 | dependencies = [ 2473 | "ring", 2474 | "rustls-pki-types", 2475 | "untrusted", 2476 | ] 2477 | 2478 | [[package]] 2479 | name = "rustversion" 2480 | version = "1.0.17" 2481 | source = "registry+https://github.com/rust-lang/crates.io-index" 2482 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 2483 | 2484 | [[package]] 2485 | name = "rusty-fork" 2486 | version = "0.3.0" 2487 | source = "registry+https://github.com/rust-lang/crates.io-index" 2488 | checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" 2489 | dependencies = [ 2490 | "fnv", 2491 | "quick-error", 2492 | "tempfile", 2493 | "wait-timeout", 2494 | ] 2495 | 2496 | [[package]] 2497 | name = "ryu" 2498 | version = "1.0.18" 2499 | source = "registry+https://github.com/rust-lang/crates.io-index" 2500 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 2501 | 2502 | [[package]] 2503 | name = "schannel" 2504 | version = "0.1.26" 2505 | source = "registry+https://github.com/rust-lang/crates.io-index" 2506 | checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" 2507 | dependencies = [ 2508 | "windows-sys 0.59.0", 2509 | ] 2510 | 2511 | [[package]] 2512 | name = "scopeguard" 2513 | version = "1.2.0" 2514 | source = "registry+https://github.com/rust-lang/crates.io-index" 2515 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2516 | 2517 | [[package]] 2518 | name = "sec1" 2519 | version = "0.7.3" 2520 | source = "registry+https://github.com/rust-lang/crates.io-index" 2521 | checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 2522 | dependencies = [ 2523 | "base16ct", 2524 | "der", 2525 | "generic-array", 2526 | "pkcs8", 2527 | "subtle", 2528 | "zeroize", 2529 | ] 2530 | 2531 | [[package]] 2532 | name = "security-framework" 2533 | version = "2.11.1" 2534 | source = "registry+https://github.com/rust-lang/crates.io-index" 2535 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 2536 | dependencies = [ 2537 | "bitflags", 2538 | "core-foundation", 2539 | "core-foundation-sys", 2540 | "libc", 2541 | "security-framework-sys", 2542 | ] 2543 | 2544 | [[package]] 2545 | name = "security-framework-sys" 2546 | version = "2.12.0" 2547 | source = "registry+https://github.com/rust-lang/crates.io-index" 2548 | checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" 2549 | dependencies = [ 2550 | "core-foundation-sys", 2551 | "libc", 2552 | ] 2553 | 2554 | [[package]] 2555 | name = "semver" 2556 | version = "0.11.0" 2557 | source = "registry+https://github.com/rust-lang/crates.io-index" 2558 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 2559 | dependencies = [ 2560 | "semver-parser", 2561 | ] 2562 | 2563 | [[package]] 2564 | name = "semver" 2565 | version = "1.0.23" 2566 | source = "registry+https://github.com/rust-lang/crates.io-index" 2567 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 2568 | 2569 | [[package]] 2570 | name = "semver-parser" 2571 | version = "0.10.2" 2572 | source = "registry+https://github.com/rust-lang/crates.io-index" 2573 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 2574 | dependencies = [ 2575 | "pest", 2576 | ] 2577 | 2578 | [[package]] 2579 | name = "send_wrapper" 2580 | version = "0.6.0" 2581 | source = "registry+https://github.com/rust-lang/crates.io-index" 2582 | checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" 2583 | 2584 | [[package]] 2585 | name = "serde" 2586 | version = "1.0.210" 2587 | source = "registry+https://github.com/rust-lang/crates.io-index" 2588 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" 2589 | dependencies = [ 2590 | "serde_derive", 2591 | ] 2592 | 2593 | [[package]] 2594 | name = "serde_derive" 2595 | version = "1.0.210" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 2598 | dependencies = [ 2599 | "proc-macro2", 2600 | "quote", 2601 | "syn 2.0.79", 2602 | ] 2603 | 2604 | [[package]] 2605 | name = "serde_json" 2606 | version = "1.0.128" 2607 | source = "registry+https://github.com/rust-lang/crates.io-index" 2608 | checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" 2609 | dependencies = [ 2610 | "itoa", 2611 | "memchr", 2612 | "ryu", 2613 | "serde", 2614 | ] 2615 | 2616 | [[package]] 2617 | name = "serde_urlencoded" 2618 | version = "0.7.1" 2619 | source = "registry+https://github.com/rust-lang/crates.io-index" 2620 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2621 | dependencies = [ 2622 | "form_urlencoded", 2623 | "itoa", 2624 | "ryu", 2625 | "serde", 2626 | ] 2627 | 2628 | [[package]] 2629 | name = "sha1" 2630 | version = "0.10.6" 2631 | source = "registry+https://github.com/rust-lang/crates.io-index" 2632 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 2633 | dependencies = [ 2634 | "cfg-if", 2635 | "cpufeatures", 2636 | "digest 0.10.7", 2637 | ] 2638 | 2639 | [[package]] 2640 | name = "sha2" 2641 | version = "0.10.8" 2642 | source = "registry+https://github.com/rust-lang/crates.io-index" 2643 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 2644 | dependencies = [ 2645 | "cfg-if", 2646 | "cpufeatures", 2647 | "digest 0.10.7", 2648 | ] 2649 | 2650 | [[package]] 2651 | name = "sha3" 2652 | version = "0.10.8" 2653 | source = "registry+https://github.com/rust-lang/crates.io-index" 2654 | checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" 2655 | dependencies = [ 2656 | "digest 0.10.7", 2657 | "keccak", 2658 | ] 2659 | 2660 | [[package]] 2661 | name = "sha3-asm" 2662 | version = "0.1.4" 2663 | source = "registry+https://github.com/rust-lang/crates.io-index" 2664 | checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" 2665 | dependencies = [ 2666 | "cc", 2667 | "cfg-if", 2668 | ] 2669 | 2670 | [[package]] 2671 | name = "sharded-slab" 2672 | version = "0.1.7" 2673 | source = "registry+https://github.com/rust-lang/crates.io-index" 2674 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 2675 | dependencies = [ 2676 | "lazy_static", 2677 | ] 2678 | 2679 | [[package]] 2680 | name = "shlex" 2681 | version = "1.3.0" 2682 | source = "registry+https://github.com/rust-lang/crates.io-index" 2683 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2684 | 2685 | [[package]] 2686 | name = "signal-hook-registry" 2687 | version = "1.4.2" 2688 | source = "registry+https://github.com/rust-lang/crates.io-index" 2689 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 2690 | dependencies = [ 2691 | "libc", 2692 | ] 2693 | 2694 | [[package]] 2695 | name = "signature" 2696 | version = "2.2.0" 2697 | source = "registry+https://github.com/rust-lang/crates.io-index" 2698 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 2699 | dependencies = [ 2700 | "digest 0.10.7", 2701 | "rand_core", 2702 | ] 2703 | 2704 | [[package]] 2705 | name = "siphasher" 2706 | version = "0.3.11" 2707 | source = "registry+https://github.com/rust-lang/crates.io-index" 2708 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 2709 | 2710 | [[package]] 2711 | name = "slab" 2712 | version = "0.4.9" 2713 | source = "registry+https://github.com/rust-lang/crates.io-index" 2714 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2715 | dependencies = [ 2716 | "autocfg", 2717 | ] 2718 | 2719 | [[package]] 2720 | name = "smallvec" 2721 | version = "1.13.2" 2722 | source = "registry+https://github.com/rust-lang/crates.io-index" 2723 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2724 | 2725 | [[package]] 2726 | name = "socket2" 2727 | version = "0.5.7" 2728 | source = "registry+https://github.com/rust-lang/crates.io-index" 2729 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 2730 | dependencies = [ 2731 | "libc", 2732 | "windows-sys 0.52.0", 2733 | ] 2734 | 2735 | [[package]] 2736 | name = "spin" 2737 | version = "0.9.8" 2738 | source = "registry+https://github.com/rust-lang/crates.io-index" 2739 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 2740 | 2741 | [[package]] 2742 | name = "spki" 2743 | version = "0.7.3" 2744 | source = "registry+https://github.com/rust-lang/crates.io-index" 2745 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 2746 | dependencies = [ 2747 | "base64ct", 2748 | "der", 2749 | ] 2750 | 2751 | [[package]] 2752 | name = "static_assertions" 2753 | version = "1.1.0" 2754 | source = "registry+https://github.com/rust-lang/crates.io-index" 2755 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2756 | 2757 | [[package]] 2758 | name = "strum" 2759 | version = "0.26.3" 2760 | source = "registry+https://github.com/rust-lang/crates.io-index" 2761 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 2762 | dependencies = [ 2763 | "strum_macros", 2764 | ] 2765 | 2766 | [[package]] 2767 | name = "strum_macros" 2768 | version = "0.26.4" 2769 | source = "registry+https://github.com/rust-lang/crates.io-index" 2770 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 2771 | dependencies = [ 2772 | "heck", 2773 | "proc-macro2", 2774 | "quote", 2775 | "rustversion", 2776 | "syn 2.0.79", 2777 | ] 2778 | 2779 | [[package]] 2780 | name = "subtle" 2781 | version = "2.6.1" 2782 | source = "registry+https://github.com/rust-lang/crates.io-index" 2783 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2784 | 2785 | [[package]] 2786 | name = "syn" 2787 | version = "1.0.109" 2788 | source = "registry+https://github.com/rust-lang/crates.io-index" 2789 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2790 | dependencies = [ 2791 | "proc-macro2", 2792 | "quote", 2793 | "unicode-ident", 2794 | ] 2795 | 2796 | [[package]] 2797 | name = "syn" 2798 | version = "2.0.79" 2799 | source = "registry+https://github.com/rust-lang/crates.io-index" 2800 | checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" 2801 | dependencies = [ 2802 | "proc-macro2", 2803 | "quote", 2804 | "unicode-ident", 2805 | ] 2806 | 2807 | [[package]] 2808 | name = "syn-solidity" 2809 | version = "0.8.7" 2810 | source = "registry+https://github.com/rust-lang/crates.io-index" 2811 | checksum = "20e7b52ad118b2153644eea95c6fc740b6c1555b2344fdab763fc9de4075f665" 2812 | dependencies = [ 2813 | "paste", 2814 | "proc-macro2", 2815 | "quote", 2816 | "syn 2.0.79", 2817 | ] 2818 | 2819 | [[package]] 2820 | name = "sync_wrapper" 2821 | version = "0.1.2" 2822 | source = "registry+https://github.com/rust-lang/crates.io-index" 2823 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2824 | 2825 | [[package]] 2826 | name = "sync_wrapper" 2827 | version = "1.0.1" 2828 | source = "registry+https://github.com/rust-lang/crates.io-index" 2829 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 2830 | dependencies = [ 2831 | "futures-core", 2832 | ] 2833 | 2834 | [[package]] 2835 | name = "tap" 2836 | version = "1.0.1" 2837 | source = "registry+https://github.com/rust-lang/crates.io-index" 2838 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 2839 | 2840 | [[package]] 2841 | name = "tempfile" 2842 | version = "3.13.0" 2843 | source = "registry+https://github.com/rust-lang/crates.io-index" 2844 | checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" 2845 | dependencies = [ 2846 | "cfg-if", 2847 | "fastrand", 2848 | "once_cell", 2849 | "rustix", 2850 | "windows-sys 0.59.0", 2851 | ] 2852 | 2853 | [[package]] 2854 | name = "thiserror" 2855 | version = "1.0.64" 2856 | source = "registry+https://github.com/rust-lang/crates.io-index" 2857 | checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" 2858 | dependencies = [ 2859 | "thiserror-impl", 2860 | ] 2861 | 2862 | [[package]] 2863 | name = "thiserror-impl" 2864 | version = "1.0.64" 2865 | source = "registry+https://github.com/rust-lang/crates.io-index" 2866 | checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" 2867 | dependencies = [ 2868 | "proc-macro2", 2869 | "quote", 2870 | "syn 2.0.79", 2871 | ] 2872 | 2873 | [[package]] 2874 | name = "thread_local" 2875 | version = "1.1.8" 2876 | source = "registry+https://github.com/rust-lang/crates.io-index" 2877 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2878 | dependencies = [ 2879 | "cfg-if", 2880 | "once_cell", 2881 | ] 2882 | 2883 | [[package]] 2884 | name = "threadpool" 2885 | version = "1.8.1" 2886 | source = "registry+https://github.com/rust-lang/crates.io-index" 2887 | checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" 2888 | dependencies = [ 2889 | "num_cpus", 2890 | ] 2891 | 2892 | [[package]] 2893 | name = "tiny-keccak" 2894 | version = "2.0.2" 2895 | source = "registry+https://github.com/rust-lang/crates.io-index" 2896 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 2897 | dependencies = [ 2898 | "crunchy", 2899 | ] 2900 | 2901 | [[package]] 2902 | name = "tinyvec" 2903 | version = "1.8.0" 2904 | source = "registry+https://github.com/rust-lang/crates.io-index" 2905 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 2906 | dependencies = [ 2907 | "tinyvec_macros", 2908 | ] 2909 | 2910 | [[package]] 2911 | name = "tinyvec_macros" 2912 | version = "0.1.1" 2913 | source = "registry+https://github.com/rust-lang/crates.io-index" 2914 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2915 | 2916 | [[package]] 2917 | name = "tokio" 2918 | version = "1.40.0" 2919 | source = "registry+https://github.com/rust-lang/crates.io-index" 2920 | checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" 2921 | dependencies = [ 2922 | "backtrace", 2923 | "bytes", 2924 | "libc", 2925 | "mio", 2926 | "parking_lot", 2927 | "pin-project-lite", 2928 | "signal-hook-registry", 2929 | "socket2", 2930 | "tokio-macros", 2931 | "windows-sys 0.52.0", 2932 | ] 2933 | 2934 | [[package]] 2935 | name = "tokio-macros" 2936 | version = "2.4.0" 2937 | source = "registry+https://github.com/rust-lang/crates.io-index" 2938 | checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 2939 | dependencies = [ 2940 | "proc-macro2", 2941 | "quote", 2942 | "syn 2.0.79", 2943 | ] 2944 | 2945 | [[package]] 2946 | name = "tokio-native-tls" 2947 | version = "0.3.1" 2948 | source = "registry+https://github.com/rust-lang/crates.io-index" 2949 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2950 | dependencies = [ 2951 | "native-tls", 2952 | "tokio", 2953 | ] 2954 | 2955 | [[package]] 2956 | name = "tokio-rustls" 2957 | version = "0.26.0" 2958 | source = "registry+https://github.com/rust-lang/crates.io-index" 2959 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 2960 | dependencies = [ 2961 | "rustls", 2962 | "rustls-pki-types", 2963 | "tokio", 2964 | ] 2965 | 2966 | [[package]] 2967 | name = "tokio-stream" 2968 | version = "0.1.16" 2969 | source = "registry+https://github.com/rust-lang/crates.io-index" 2970 | checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" 2971 | dependencies = [ 2972 | "futures-core", 2973 | "pin-project-lite", 2974 | "tokio", 2975 | "tokio-util", 2976 | ] 2977 | 2978 | [[package]] 2979 | name = "tokio-tungstenite" 2980 | version = "0.24.0" 2981 | source = "registry+https://github.com/rust-lang/crates.io-index" 2982 | checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" 2983 | dependencies = [ 2984 | "futures-util", 2985 | "log", 2986 | "rustls", 2987 | "rustls-pki-types", 2988 | "tokio", 2989 | "tokio-rustls", 2990 | "tungstenite", 2991 | "webpki-roots", 2992 | ] 2993 | 2994 | [[package]] 2995 | name = "tokio-util" 2996 | version = "0.7.12" 2997 | source = "registry+https://github.com/rust-lang/crates.io-index" 2998 | checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" 2999 | dependencies = [ 3000 | "bytes", 3001 | "futures-core", 3002 | "futures-sink", 3003 | "pin-project-lite", 3004 | "tokio", 3005 | ] 3006 | 3007 | [[package]] 3008 | name = "toml_datetime" 3009 | version = "0.6.8" 3010 | source = "registry+https://github.com/rust-lang/crates.io-index" 3011 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 3012 | 3013 | [[package]] 3014 | name = "toml_edit" 3015 | version = "0.22.22" 3016 | source = "registry+https://github.com/rust-lang/crates.io-index" 3017 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 3018 | dependencies = [ 3019 | "indexmap", 3020 | "toml_datetime", 3021 | "winnow", 3022 | ] 3023 | 3024 | [[package]] 3025 | name = "tower" 3026 | version = "0.5.1" 3027 | source = "registry+https://github.com/rust-lang/crates.io-index" 3028 | checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" 3029 | dependencies = [ 3030 | "futures-core", 3031 | "futures-util", 3032 | "pin-project-lite", 3033 | "sync_wrapper 0.1.2", 3034 | "tower-layer", 3035 | "tower-service", 3036 | ] 3037 | 3038 | [[package]] 3039 | name = "tower-layer" 3040 | version = "0.3.3" 3041 | source = "registry+https://github.com/rust-lang/crates.io-index" 3042 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 3043 | 3044 | [[package]] 3045 | name = "tower-service" 3046 | version = "0.3.3" 3047 | source = "registry+https://github.com/rust-lang/crates.io-index" 3048 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 3049 | 3050 | [[package]] 3051 | name = "tracing" 3052 | version = "0.1.40" 3053 | source = "registry+https://github.com/rust-lang/crates.io-index" 3054 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 3055 | dependencies = [ 3056 | "pin-project-lite", 3057 | "tracing-attributes", 3058 | "tracing-core", 3059 | ] 3060 | 3061 | [[package]] 3062 | name = "tracing-attributes" 3063 | version = "0.1.27" 3064 | source = "registry+https://github.com/rust-lang/crates.io-index" 3065 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 3066 | dependencies = [ 3067 | "proc-macro2", 3068 | "quote", 3069 | "syn 2.0.79", 3070 | ] 3071 | 3072 | [[package]] 3073 | name = "tracing-core" 3074 | version = "0.1.32" 3075 | source = "registry+https://github.com/rust-lang/crates.io-index" 3076 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 3077 | dependencies = [ 3078 | "once_cell", 3079 | "valuable", 3080 | ] 3081 | 3082 | [[package]] 3083 | name = "tracing-log" 3084 | version = "0.2.0" 3085 | source = "registry+https://github.com/rust-lang/crates.io-index" 3086 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 3087 | dependencies = [ 3088 | "log", 3089 | "once_cell", 3090 | "tracing-core", 3091 | ] 3092 | 3093 | [[package]] 3094 | name = "tracing-subscriber" 3095 | version = "0.3.18" 3096 | source = "registry+https://github.com/rust-lang/crates.io-index" 3097 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 3098 | dependencies = [ 3099 | "nu-ansi-term", 3100 | "sharded-slab", 3101 | "smallvec", 3102 | "thread_local", 3103 | "tracing-core", 3104 | "tracing-log", 3105 | ] 3106 | 3107 | [[package]] 3108 | name = "try-lock" 3109 | version = "0.2.5" 3110 | source = "registry+https://github.com/rust-lang/crates.io-index" 3111 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 3112 | 3113 | [[package]] 3114 | name = "tungstenite" 3115 | version = "0.24.0" 3116 | source = "registry+https://github.com/rust-lang/crates.io-index" 3117 | checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" 3118 | dependencies = [ 3119 | "byteorder", 3120 | "bytes", 3121 | "data-encoding", 3122 | "http", 3123 | "httparse", 3124 | "log", 3125 | "rand", 3126 | "rustls", 3127 | "rustls-pki-types", 3128 | "sha1", 3129 | "thiserror", 3130 | "utf-8", 3131 | ] 3132 | 3133 | [[package]] 3134 | name = "typenum" 3135 | version = "1.17.0" 3136 | source = "registry+https://github.com/rust-lang/crates.io-index" 3137 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 3138 | 3139 | [[package]] 3140 | name = "ucd-trie" 3141 | version = "0.1.7" 3142 | source = "registry+https://github.com/rust-lang/crates.io-index" 3143 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 3144 | 3145 | [[package]] 3146 | name = "uint" 3147 | version = "0.9.5" 3148 | source = "registry+https://github.com/rust-lang/crates.io-index" 3149 | checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" 3150 | dependencies = [ 3151 | "byteorder", 3152 | "crunchy", 3153 | "hex", 3154 | "static_assertions", 3155 | ] 3156 | 3157 | [[package]] 3158 | name = "unarray" 3159 | version = "0.1.4" 3160 | source = "registry+https://github.com/rust-lang/crates.io-index" 3161 | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" 3162 | 3163 | [[package]] 3164 | name = "unicode-bidi" 3165 | version = "0.3.17" 3166 | source = "registry+https://github.com/rust-lang/crates.io-index" 3167 | checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" 3168 | 3169 | [[package]] 3170 | name = "unicode-ident" 3171 | version = "1.0.13" 3172 | source = "registry+https://github.com/rust-lang/crates.io-index" 3173 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 3174 | 3175 | [[package]] 3176 | name = "unicode-normalization" 3177 | version = "0.1.24" 3178 | source = "registry+https://github.com/rust-lang/crates.io-index" 3179 | checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 3180 | dependencies = [ 3181 | "tinyvec", 3182 | ] 3183 | 3184 | [[package]] 3185 | name = "unicode-xid" 3186 | version = "0.2.6" 3187 | source = "registry+https://github.com/rust-lang/crates.io-index" 3188 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 3189 | 3190 | [[package]] 3191 | name = "untrusted" 3192 | version = "0.9.0" 3193 | source = "registry+https://github.com/rust-lang/crates.io-index" 3194 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 3195 | 3196 | [[package]] 3197 | name = "url" 3198 | version = "2.5.2" 3199 | source = "registry+https://github.com/rust-lang/crates.io-index" 3200 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 3201 | dependencies = [ 3202 | "form_urlencoded", 3203 | "idna", 3204 | "percent-encoding", 3205 | ] 3206 | 3207 | [[package]] 3208 | name = "utf-8" 3209 | version = "0.7.6" 3210 | source = "registry+https://github.com/rust-lang/crates.io-index" 3211 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 3212 | 3213 | [[package]] 3214 | name = "v3-rs" 3215 | version = "0.1.0" 3216 | dependencies = [ 3217 | "alloy", 3218 | "anyhow", 3219 | "async-trait", 3220 | "futures", 3221 | "lazy_static", 3222 | "phf", 3223 | "rug", 3224 | "serde", 3225 | "thiserror", 3226 | "tokio", 3227 | "tracing", 3228 | "tracing-subscriber", 3229 | ] 3230 | 3231 | [[package]] 3232 | name = "valuable" 3233 | version = "0.1.0" 3234 | source = "registry+https://github.com/rust-lang/crates.io-index" 3235 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 3236 | 3237 | [[package]] 3238 | name = "vcpkg" 3239 | version = "0.2.15" 3240 | source = "registry+https://github.com/rust-lang/crates.io-index" 3241 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 3242 | 3243 | [[package]] 3244 | name = "version_check" 3245 | version = "0.9.5" 3246 | source = "registry+https://github.com/rust-lang/crates.io-index" 3247 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 3248 | 3249 | [[package]] 3250 | name = "wait-timeout" 3251 | version = "0.2.0" 3252 | source = "registry+https://github.com/rust-lang/crates.io-index" 3253 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 3254 | dependencies = [ 3255 | "libc", 3256 | ] 3257 | 3258 | [[package]] 3259 | name = "want" 3260 | version = "0.3.1" 3261 | source = "registry+https://github.com/rust-lang/crates.io-index" 3262 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 3263 | dependencies = [ 3264 | "try-lock", 3265 | ] 3266 | 3267 | [[package]] 3268 | name = "wasi" 3269 | version = "0.11.0+wasi-snapshot-preview1" 3270 | source = "registry+https://github.com/rust-lang/crates.io-index" 3271 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 3272 | 3273 | [[package]] 3274 | name = "wasm-bindgen" 3275 | version = "0.2.95" 3276 | source = "registry+https://github.com/rust-lang/crates.io-index" 3277 | checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" 3278 | dependencies = [ 3279 | "cfg-if", 3280 | "once_cell", 3281 | "wasm-bindgen-macro", 3282 | ] 3283 | 3284 | [[package]] 3285 | name = "wasm-bindgen-backend" 3286 | version = "0.2.95" 3287 | source = "registry+https://github.com/rust-lang/crates.io-index" 3288 | checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" 3289 | dependencies = [ 3290 | "bumpalo", 3291 | "log", 3292 | "once_cell", 3293 | "proc-macro2", 3294 | "quote", 3295 | "syn 2.0.79", 3296 | "wasm-bindgen-shared", 3297 | ] 3298 | 3299 | [[package]] 3300 | name = "wasm-bindgen-futures" 3301 | version = "0.4.45" 3302 | source = "registry+https://github.com/rust-lang/crates.io-index" 3303 | checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" 3304 | dependencies = [ 3305 | "cfg-if", 3306 | "js-sys", 3307 | "wasm-bindgen", 3308 | "web-sys", 3309 | ] 3310 | 3311 | [[package]] 3312 | name = "wasm-bindgen-macro" 3313 | version = "0.2.95" 3314 | source = "registry+https://github.com/rust-lang/crates.io-index" 3315 | checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" 3316 | dependencies = [ 3317 | "quote", 3318 | "wasm-bindgen-macro-support", 3319 | ] 3320 | 3321 | [[package]] 3322 | name = "wasm-bindgen-macro-support" 3323 | version = "0.2.95" 3324 | source = "registry+https://github.com/rust-lang/crates.io-index" 3325 | checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" 3326 | dependencies = [ 3327 | "proc-macro2", 3328 | "quote", 3329 | "syn 2.0.79", 3330 | "wasm-bindgen-backend", 3331 | "wasm-bindgen-shared", 3332 | ] 3333 | 3334 | [[package]] 3335 | name = "wasm-bindgen-shared" 3336 | version = "0.2.95" 3337 | source = "registry+https://github.com/rust-lang/crates.io-index" 3338 | checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" 3339 | 3340 | [[package]] 3341 | name = "web-sys" 3342 | version = "0.3.72" 3343 | source = "registry+https://github.com/rust-lang/crates.io-index" 3344 | checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" 3345 | dependencies = [ 3346 | "js-sys", 3347 | "wasm-bindgen", 3348 | ] 3349 | 3350 | [[package]] 3351 | name = "webpki-roots" 3352 | version = "0.26.6" 3353 | source = "registry+https://github.com/rust-lang/crates.io-index" 3354 | checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" 3355 | dependencies = [ 3356 | "rustls-pki-types", 3357 | ] 3358 | 3359 | [[package]] 3360 | name = "widestring" 3361 | version = "1.1.0" 3362 | source = "registry+https://github.com/rust-lang/crates.io-index" 3363 | checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" 3364 | 3365 | [[package]] 3366 | name = "winapi" 3367 | version = "0.3.9" 3368 | source = "registry+https://github.com/rust-lang/crates.io-index" 3369 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 3370 | dependencies = [ 3371 | "winapi-i686-pc-windows-gnu", 3372 | "winapi-x86_64-pc-windows-gnu", 3373 | ] 3374 | 3375 | [[package]] 3376 | name = "winapi-i686-pc-windows-gnu" 3377 | version = "0.4.0" 3378 | source = "registry+https://github.com/rust-lang/crates.io-index" 3379 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3380 | 3381 | [[package]] 3382 | name = "winapi-x86_64-pc-windows-gnu" 3383 | version = "0.4.0" 3384 | source = "registry+https://github.com/rust-lang/crates.io-index" 3385 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3386 | 3387 | [[package]] 3388 | name = "windows-registry" 3389 | version = "0.2.0" 3390 | source = "registry+https://github.com/rust-lang/crates.io-index" 3391 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 3392 | dependencies = [ 3393 | "windows-result", 3394 | "windows-strings", 3395 | "windows-targets", 3396 | ] 3397 | 3398 | [[package]] 3399 | name = "windows-result" 3400 | version = "0.2.0" 3401 | source = "registry+https://github.com/rust-lang/crates.io-index" 3402 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 3403 | dependencies = [ 3404 | "windows-targets", 3405 | ] 3406 | 3407 | [[package]] 3408 | name = "windows-strings" 3409 | version = "0.1.0" 3410 | source = "registry+https://github.com/rust-lang/crates.io-index" 3411 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 3412 | dependencies = [ 3413 | "windows-result", 3414 | "windows-targets", 3415 | ] 3416 | 3417 | [[package]] 3418 | name = "windows-sys" 3419 | version = "0.52.0" 3420 | source = "registry+https://github.com/rust-lang/crates.io-index" 3421 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 3422 | dependencies = [ 3423 | "windows-targets", 3424 | ] 3425 | 3426 | [[package]] 3427 | name = "windows-sys" 3428 | version = "0.59.0" 3429 | source = "registry+https://github.com/rust-lang/crates.io-index" 3430 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 3431 | dependencies = [ 3432 | "windows-targets", 3433 | ] 3434 | 3435 | [[package]] 3436 | name = "windows-targets" 3437 | version = "0.52.6" 3438 | source = "registry+https://github.com/rust-lang/crates.io-index" 3439 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 3440 | dependencies = [ 3441 | "windows_aarch64_gnullvm", 3442 | "windows_aarch64_msvc", 3443 | "windows_i686_gnu", 3444 | "windows_i686_gnullvm", 3445 | "windows_i686_msvc", 3446 | "windows_x86_64_gnu", 3447 | "windows_x86_64_gnullvm", 3448 | "windows_x86_64_msvc", 3449 | ] 3450 | 3451 | [[package]] 3452 | name = "windows_aarch64_gnullvm" 3453 | version = "0.52.6" 3454 | source = "registry+https://github.com/rust-lang/crates.io-index" 3455 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 3456 | 3457 | [[package]] 3458 | name = "windows_aarch64_msvc" 3459 | version = "0.52.6" 3460 | source = "registry+https://github.com/rust-lang/crates.io-index" 3461 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 3462 | 3463 | [[package]] 3464 | name = "windows_i686_gnu" 3465 | version = "0.52.6" 3466 | source = "registry+https://github.com/rust-lang/crates.io-index" 3467 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 3468 | 3469 | [[package]] 3470 | name = "windows_i686_gnullvm" 3471 | version = "0.52.6" 3472 | source = "registry+https://github.com/rust-lang/crates.io-index" 3473 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 3474 | 3475 | [[package]] 3476 | name = "windows_i686_msvc" 3477 | version = "0.52.6" 3478 | source = "registry+https://github.com/rust-lang/crates.io-index" 3479 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 3480 | 3481 | [[package]] 3482 | name = "windows_x86_64_gnu" 3483 | version = "0.52.6" 3484 | source = "registry+https://github.com/rust-lang/crates.io-index" 3485 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 3486 | 3487 | [[package]] 3488 | name = "windows_x86_64_gnullvm" 3489 | version = "0.52.6" 3490 | source = "registry+https://github.com/rust-lang/crates.io-index" 3491 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 3492 | 3493 | [[package]] 3494 | name = "windows_x86_64_msvc" 3495 | version = "0.52.6" 3496 | source = "registry+https://github.com/rust-lang/crates.io-index" 3497 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 3498 | 3499 | [[package]] 3500 | name = "winnow" 3501 | version = "0.6.20" 3502 | source = "registry+https://github.com/rust-lang/crates.io-index" 3503 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 3504 | dependencies = [ 3505 | "memchr", 3506 | ] 3507 | 3508 | [[package]] 3509 | name = "ws_stream_wasm" 3510 | version = "0.7.4" 3511 | source = "registry+https://github.com/rust-lang/crates.io-index" 3512 | checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" 3513 | dependencies = [ 3514 | "async_io_stream", 3515 | "futures", 3516 | "js-sys", 3517 | "log", 3518 | "pharos", 3519 | "rustc_version 0.4.1", 3520 | "send_wrapper", 3521 | "thiserror", 3522 | "wasm-bindgen", 3523 | "wasm-bindgen-futures", 3524 | "web-sys", 3525 | ] 3526 | 3527 | [[package]] 3528 | name = "wyz" 3529 | version = "0.5.1" 3530 | source = "registry+https://github.com/rust-lang/crates.io-index" 3531 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 3532 | dependencies = [ 3533 | "tap", 3534 | ] 3535 | 3536 | [[package]] 3537 | name = "zerocopy" 3538 | version = "0.7.35" 3539 | source = "registry+https://github.com/rust-lang/crates.io-index" 3540 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 3541 | dependencies = [ 3542 | "byteorder", 3543 | "zerocopy-derive", 3544 | ] 3545 | 3546 | [[package]] 3547 | name = "zerocopy-derive" 3548 | version = "0.7.35" 3549 | source = "registry+https://github.com/rust-lang/crates.io-index" 3550 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 3551 | dependencies = [ 3552 | "proc-macro2", 3553 | "quote", 3554 | "syn 2.0.79", 3555 | ] 3556 | 3557 | [[package]] 3558 | name = "zeroize" 3559 | version = "1.8.1" 3560 | source = "registry+https://github.com/rust-lang/crates.io-index" 3561 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 3562 | dependencies = [ 3563 | "zeroize_derive", 3564 | ] 3565 | 3566 | [[package]] 3567 | name = "zeroize_derive" 3568 | version = "1.4.2" 3569 | source = "registry+https://github.com/rust-lang/crates.io-index" 3570 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 3571 | dependencies = [ 3572 | "proc-macro2", 3573 | "quote", 3574 | "syn 2.0.79", 3575 | ] 3576 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "v3-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | repository = "https://github.com/nhtyy/v3-rs" 6 | description = "A Rust library for interacting with Uniswap V3 pools." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | rug = "1.10.0" 12 | tokio = { version = "1.16.1", features = ["full"] } 13 | futures = "0.3.17" 14 | lazy_static = "1.4.0" 15 | async-trait = "0.1.74" 16 | tracing = "0.1.40" 17 | serde = {version = "1.0.193", features = ["derive"]} 18 | anyhow = "1.0.75" 19 | thiserror = "1.0.61" 20 | alloy = { version = "0.4.0", features = ["full"] } 21 | phf = { version = "0.11.2", features = ["macros"] } 22 | 23 | [[example]] 24 | name = "get_lp_balance" 25 | path = "examples/get_lp_balance.rs" 26 | 27 | [[example]] 28 | name = "get_pool_price" 29 | path = "examples/get_pool_price.rs" 30 | 31 | [[example]] 32 | name = "optimal_swap_for_price" 33 | path = "examples/optimal_swap_for_price.rs" 34 | 35 | [features] 36 | default = [] 37 | aerodrome = [] 38 | trace_callMany = ["alloy/rpc-types-trace"] 39 | eth_callMany = [] 40 | 41 | [dev-dependencies] 42 | tracing-subscriber = "0.3.18" 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v3-rs 2 | 3 | ### Motivation 4 | 5 | v3-rs is a Rust library for interacting with Uniswap v3 Pools. 6 | 7 | v3-rs currently has high level functionality for: 8 | - computing the optimal swap amount for a given price/pool 9 | - computing the LP balances owned by a given address (NFT positions only) 10 | and implements many low level helpers to make additional functionality easy 11 | 12 | We also expose some useful [crate::types] that can help you seemlessly interact with on chain pools without having to think about token decimals or anything like that. 13 | 14 | Please see the examples in the repo for more information. 15 | 16 | #### Creating Pool prices from human readable prices 17 | To create a pool price, (account for the decimals) you can use [PoolPrice::from_human_readable], which implements `Into` 18 | 19 | #### Pool Price Example 20 | ```rust 21 | use v3_rs::{AlloyFactory, FeeTier, constants::MAINNET, V3Pool}; 22 | use alloy::providers::ProviderBuilder; 23 | use alloy::primitives::{address, Address}; 24 | 25 | const WETH: Address = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); 26 | const DAI: Address = address!("6b175474e89094c44da98b954eedeac495271d0f"); 27 | 28 | #[tokio::main] 29 | async fn main() { 30 | let provider = ProviderBuilder::new().with_recommended_fillers().on_http("https://cloudflare-eth.com".parse().unwrap()); 31 | 32 | let factory = AlloyFactory::new(MAINNET.factory, &provider); 33 | 34 | let pool = factory.pool(WETH, DAI, FeeTier::Mid).await.unwrap(); 35 | 36 | let numeraire_idx = pool.position_of(&DAI).expect("Token should be in the pool"); 37 | 38 | let price = pool.pool_price(numeraire_idx).await.unwrap(); 39 | 40 | println!("Pool Price: {}", price); 41 | } 42 | ``` 43 | 44 | # Note: 45 | v3-rs doesnt actually help you *interact* with pools on chain, only extract useful information from them. 46 | 47 | ### Usage 48 | 49 | see `cargo doc --open` and the examples in the repo. 50 | 51 | ### Plans 52 | - add quoting and path building -------------------------------------------------------------------------------- /examples/get_lp_balance.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::{address, Address}; 2 | use alloy::providers::ProviderBuilder; 3 | use v3_rs::{constants::MAINNET, Factory, FeeTier}; 4 | 5 | const TOKEN_A: Address = address!(); 6 | const TOKEN_B: Address = address!(); 7 | const LP: Address = address!(); 8 | 9 | #[tokio::main] 10 | async fn main() { 11 | let provider = ProviderBuilder::new() 12 | .with_recommended_fillers() 13 | .on_http("https://cloudflare-eth.com".parse().unwrap()); 14 | 15 | let factory = Factory::new(MAINNET.factory, &provider); 16 | 17 | let pool = factory.pool(TOKEN_A, TOKEN_B, FeeTier::Mid).await.unwrap(); 18 | 19 | let balance = pool.lp_balance(LP).await.unwrap(); 20 | 21 | println!("LP Balance: {:?}", balance); 22 | } 23 | -------------------------------------------------------------------------------- /examples/get_pool_price.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::{address, Address}; 2 | use alloy::providers::ProviderBuilder; 3 | use v3_rs::{constants::MAINNET, Factory, FeeTier, V3Pool}; 4 | 5 | const WETH: Address = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); 6 | const DAI: Address = address!("6b175474e89094c44da98b954eedeac495271d0f"); 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | let provider = ProviderBuilder::new() 11 | .with_recommended_fillers() 12 | .on_http("https://cloudflare-eth.com".parse().unwrap()); 13 | 14 | let factory = Factory::new(MAINNET.factory, &provider); 15 | 16 | let pool = factory.pool(WETH, DAI, FeeTier::Mid).await.unwrap(); 17 | 18 | let numeraire_idx = pool.position_of(&DAI).expect("Token should be in the pool"); 19 | 20 | let price = pool.pool_price(numeraire_idx).await.unwrap(); 21 | 22 | println!("Pool Price: {}", price); 23 | } 24 | -------------------------------------------------------------------------------- /examples/optimal_swap_for_price.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::{address, Address}; 2 | use alloy::providers::ProviderBuilder; 3 | use v3_rs::{constants::MAINNET, math::Price, Factory, FeeTier, PriceExt, V3Pool}; 4 | 5 | const WETH: Address = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); 6 | const DAI: Address = address!("6b175474e89094c44da98b954eedeac495271d0f"); 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | let provider = ProviderBuilder::new() 11 | .with_recommended_fillers() 12 | .on_http("https://cloudflare-eth.com".parse().unwrap()); 13 | 14 | let factory = Factory::new(MAINNET.factory, &provider); 15 | 16 | let pool = factory.pool(WETH, DAI, FeeTier::Mid).await.unwrap(); 17 | 18 | let numeraire_idx = pool.position_of(&DAI).expect("Token should be in the pool"); 19 | 20 | let price = pool.pool_price(numeraire_idx).await.unwrap(); 21 | 22 | println!("Pool Price: {}", price); 23 | 24 | // lets scale down the price 5% 25 | let new_price = rug::Float::from(price) * 0.95; 26 | 27 | // lets find the optimal swap for this price 28 | let optimal = pool 29 | .optimal_swap_for_price(Price::new(new_price).unwrap()) 30 | .await 31 | .unwrap(); 32 | 33 | println!("Optimal Swap: {:?}", optimal); 34 | println!("fee needed: {}", optimal.fee_amount()) 35 | } 36 | -------------------------------------------------------------------------------- /src/alloy_pool/factory.rs: -------------------------------------------------------------------------------- 1 | use super::pool::Pool; 2 | use super::pool::V3PoolContract::V3PoolContractInstance; 3 | use crate::{error::V3PoolError, FeeTier}; 4 | use alloy::network::Network; 5 | use alloy::primitives::Address; 6 | use alloy::providers::Provider; 7 | use alloy::transports::Transport; 8 | use FactoryInterface::FactoryInterfaceInstance; 9 | 10 | alloy::sol! { 11 | #[derive(Debug)] 12 | #[sol(rpc)] 13 | interface FactoryInterface { 14 | /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist 15 | /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order 16 | /// @param tokenA The contract address of either token0 or token1 17 | /// @param tokenB The contract address of the other token 18 | /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip 19 | /// @return pool The pool address 20 | function getPool( 21 | address tokenA, 22 | address tokenB, 23 | uint24 fee 24 | ) external view returns (address pool); 25 | } 26 | 27 | #[sol(rpc)] 28 | #[cfg(feature = "aerodrome")] 29 | interface AerodromeInterface { 30 | /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist 31 | /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order 32 | /// @param tokenA The contract address of either token0 or token1 33 | /// @param tokenB The contract address of the other token 34 | /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip 35 | /// @return pool The pool address 36 | function getPool( 37 | address tokenA, 38 | address tokenB, 39 | int24 tickSpacing 40 | ) external view returns (address pool); 41 | } 42 | } 43 | 44 | /// The alloy implementation of an on chain v3 factory. 45 | /// 46 | /// This is useful for getting pool instances from the underlying tokens 47 | pub struct Factory { 48 | instance: FactoryInterfaceInstance, 49 | } 50 | 51 | impl Factory 52 | where 53 | T: Transport + Clone, 54 | P: Provider, 55 | N: Network, 56 | { 57 | pub const fn new(address: Address, provider: P) -> Self { 58 | Self { 59 | instance: FactoryInterfaceInstance::new(address, provider), 60 | } 61 | } 62 | 63 | pub async fn pool_address( 64 | &self, 65 | first_token: Address, 66 | second_token: Address, 67 | fee: FeeTier, 68 | ) -> Result { 69 | self.instance 70 | .getPool(first_token, second_token, fee.as_scaled_bp()) 71 | .call() 72 | .await 73 | .map(|x| x.pool) 74 | } 75 | 76 | /// todo! maybe we spawn a thread here and send the Pool over a channel or use an arc to share 77 | /// the pool between threads. 78 | /// 79 | /// should be ran inside its own thread as it blocks whatever thread it was instantiated on 80 | pub async fn pool( 81 | &self, 82 | first_token: Address, 83 | second_token: Address, 84 | fee: FeeTier, 85 | ) -> Result, V3PoolError> { 86 | self.pool_with_provider(first_token, second_token, fee, self.instance.provider()) 87 | .await 88 | } 89 | 90 | pub async fn pool_with_provider( 91 | &self, 92 | first_token: Address, 93 | second_token: Address, 94 | fee: FeeTier, 95 | provider: P2, 96 | ) -> Result, V3PoolError> 97 | where 98 | P2: Provider, 99 | { 100 | let address = self 101 | .pool_address(first_token, second_token, fee) 102 | .await 103 | .map_err(V3PoolError::backend_error)?; 104 | 105 | if address == Address::ZERO { 106 | return Err(V3PoolError::PoolNotFound); 107 | } 108 | 109 | let bindings = V3PoolContractInstance::new(address, provider); 110 | 111 | Pool::new(bindings) 112 | .await 113 | .map_err(V3PoolError::backend_error) 114 | } 115 | } 116 | 117 | #[cfg(feature = "aerodrome")] 118 | pub use aerodrome::{AerodromeFactory, AERODROME_FACTORY_ADDRESS}; 119 | 120 | #[cfg(feature = "aerodrome")] 121 | mod aerodrome { 122 | 123 | use super::AerodromeInterface::AerodromeInterfaceInstance as IAerodromeFactory; 124 | use super::*; 125 | use alloy::contract::Error as ContractError; 126 | use alloy::primitives::Signed; 127 | 128 | pub const AERODROME_FACTORY_ADDRESS: Address = 129 | alloy::primitives::address!("5e7BB104d84c7CB9B682AaC2F3d509f5F406809A"); 130 | 131 | pub struct AerodromeFactory { 132 | inner: IAerodromeFactory, 133 | } 134 | 135 | impl AerodromeFactory 136 | where 137 | P: Provider, 138 | T: Transport + Clone, 139 | N: Network, 140 | { 141 | pub const fn new(provider: P) -> Self { 142 | Self { 143 | inner: IAerodromeFactory::new(AERODROME_FACTORY_ADDRESS, provider), 144 | } 145 | } 146 | 147 | pub async fn get_pool_address( 148 | &self, 149 | token_a: Address, 150 | token_b: Address, 151 | tick_spacing: Signed<24, 1>, 152 | ) -> Result { 153 | let addr = self 154 | .inner 155 | .getPool(token_a, token_b, tick_spacing) 156 | .call() 157 | .await 158 | .map(|addr| addr.pool)?; 159 | 160 | Ok(addr) 161 | } 162 | 163 | pub async fn get_pool( 164 | &self, 165 | token_a: Address, 166 | token_b: Address, 167 | tick_spacing: Signed<24, 1>, 168 | ) -> anyhow::Result> { 169 | self.get_pool_with_provider(self.inner.provider(), token_a, token_b, tick_spacing) 170 | .await 171 | } 172 | 173 | pub async fn get_pool_with_provider( 174 | &self, 175 | provider: P2, 176 | token_a: Address, 177 | token_b: Address, 178 | tick_spacing: Signed<24, 1>, 179 | ) -> anyhow::Result> 180 | where 181 | P2: Provider, 182 | { 183 | let addr = self 184 | .get_pool_address(token_a, token_b, tick_spacing) 185 | .await?; 186 | 187 | let instance = crate::alloy_pool::pool::V3PoolContract::V3PoolContractInstance::new( 188 | addr, provider, 189 | ); 190 | 191 | Ok(crate::AerodromePool::new(instance).await?) 192 | } 193 | } 194 | } 195 | 196 | #[cfg(test)] 197 | mod test { 198 | #[cfg(feature = "aerodrome")] 199 | #[tokio::test] 200 | async fn test_get_pool() { 201 | use crate::V3Pool; 202 | use alloy::primitives::{address, Address}; 203 | use alloy::providers::ProviderBuilder; 204 | 205 | const WETH: Address = address!("4200000000000000000000000000000000000006"); 206 | const U_SUI: Address = address!("b0505e5a99abd03d94a1169e638B78EDfEd26ea4"); 207 | 208 | let provider = ProviderBuilder::new() 209 | .with_recommended_fillers() 210 | .on_http("https://mainnet.base.org".parse().unwrap()); 211 | 212 | let factory = super::AerodromeFactory::new(provider); 213 | 214 | let pool = factory 215 | .get_pool(U_SUI, WETH, crate::I24::try_from(200).unwrap()) 216 | .await 217 | .unwrap(); 218 | 219 | let _ = pool.price().await.unwrap(); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/alloy_pool/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod factory; 2 | pub mod pool; 3 | -------------------------------------------------------------------------------- /src/alloy_pool/pool.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | use crate::error::V3PoolError; 4 | use crate::math::Tick; 5 | use crate::position::Balances; 6 | use crate::traits::{Batch, IntoFloat}; 7 | // use crate::pool::{FeeTier, Tick, TickSpacing, V3Pool, V3PoolError}; 8 | use crate::{AlloyManager, PoolResult, V3Pool}; 9 | use alloy::contract::Error as ContractError; 10 | use alloy::network::Network; 11 | use alloy::primitives::Signed; 12 | use alloy::primitives::{Address, Uint}; 13 | use alloy::providers::Provider; 14 | use alloy::transports::{Transport, TransportError}; 15 | 16 | use rug::Float; 17 | use V3PoolContract::V3PoolContractInstance; 18 | 19 | pub type Pool = AlloyPool; 20 | 21 | #[cfg(feature = "aerodrome")] 22 | pub type AerodromePool = AlloyPool; 23 | 24 | alloy::sol! { 25 | #[derive(Debug)] 26 | #[sol(rpc)] 27 | interface V3PoolContract { 28 | /// @notice The currently in range liquidity available to the pool 29 | /// @dev This value has no relationship to the total liquidity across all ticks 30 | function liquidity() external view returns (uint128); 31 | 32 | /// @notice The first of the two tokens of the pool, sorted by address 33 | /// @return The token contract address 34 | function token0() external view returns (address); 35 | 36 | /// @notice The second of the two tokens of the pool, sorted by address 37 | /// @return The token contract address 38 | function token1() external view returns (address); 39 | 40 | /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 41 | /// @return The fee 42 | function fee() external view returns (uint24); 43 | 44 | /// @notice The pool tick spacing 45 | /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive 46 | /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... 47 | /// This value is an int24 to avoid casting even though it is always positive. 48 | /// @return The tick spacing 49 | function tickSpacing() external view returns (int24); 50 | } 51 | 52 | #[sol(rpc)] 53 | interface Vanilla { 54 | function slot0() 55 | external 56 | view 57 | returns ( 58 | uint160 sqrtPriceX96, 59 | int24 tick, 60 | uint16 observationIndex, 61 | uint16 observationCardinality, 62 | uint16 observationCardinalityNext, 63 | uint8 feeProtocol, 64 | bool unlocked 65 | ); 66 | 67 | function ticks(int24 tick) 68 | external 69 | view 70 | returns ( 71 | uint128 liquidityGross, 72 | int128 liquidityNet, 73 | uint256 feeGrowthOutside0X128, 74 | uint256 feeGrowthOutside1X128, 75 | int56 tickCumulativeOutside, 76 | uint160 secondsPerLiquidityOutsideX128, 77 | uint32 secondsOutside, 78 | bool initialized 79 | ); 80 | } 81 | 82 | #[sol(rpc)] 83 | #[cfg(feature = "aerodrome")] 84 | interface Aerodrome { 85 | function slot0() 86 | external 87 | view 88 | returns ( 89 | uint160 sqrtPriceX96, 90 | int24 tick, 91 | uint16 observationIndex, 92 | uint16 observationCardinality, 93 | uint16 observationCardinalityNext, 94 | bool unlocked 95 | ); 96 | 97 | function ticks(int24 tick) 98 | external 99 | view 100 | returns ( 101 | uint128 liquidityGross, 102 | int128 liquidityNet, 103 | int128 stakedLiquidityNet, 104 | uint256 feeGrowthOutside0X128, 105 | uint256 feeGrowthOutside1X128, 106 | uint256 rewardGrowthOutsideX128, 107 | int56 tickCumulativeOutside, 108 | uint160 secondsPerLiquidityOutsideX128, 109 | uint32 secondsOutside, 110 | bool initialized 111 | ); 112 | } 113 | } 114 | 115 | /// The alloy implementation of an on chain v3 pool. 116 | /// 117 | /// See the [crate::V3Pool] trait for more information 118 | pub struct AlloyPool { 119 | pool: V3PoolContractInstance, 120 | tick_spacing: Signed<24, 1>, 121 | token0: Address, 122 | token1: Address, 123 | token0_decimals: u8, 124 | token1_decimals: u8, 125 | fee: Uint<24, 1>, 126 | _marker: std::marker::PhantomData, 127 | } 128 | 129 | impl AlloyPool 130 | where 131 | T: Transport + Clone, 132 | P: Provider, 133 | N: Network, 134 | { 135 | pub async fn new( 136 | pool: V3PoolContractInstance, 137 | ) -> Result { 138 | let token0 = pool.token0().call().await?._0; 139 | let token1 = pool.token1().call().await?._0; 140 | 141 | let token0_decimals = crate::utils::decimals(pool.provider(), token0).await?; 142 | let token1_decimals = crate::utils::decimals(pool.provider(), token1).await?; 143 | 144 | let tick_spacing = pool.tickSpacing().call().await?._0; 145 | let fee = pool.fee().call().await?._0; 146 | 147 | Ok(Self { 148 | pool, 149 | tick_spacing, 150 | token0, 151 | token1, 152 | token0_decimals, 153 | token1_decimals, 154 | fee, 155 | _marker: std::marker::PhantomData, 156 | }) 157 | } 158 | } 159 | 160 | impl AlloyPool 161 | where 162 | T: Transport + Clone, 163 | P: Provider, 164 | N: Network, 165 | Self: V3Pool, 166 | { 167 | /// Get the (NFT) LP balance owned by the address 168 | /// 169 | /// # Errors 170 | /// - If the chain constants are not supported (see [crate::constants::NETWORKS] & [Self::lp_balance_with_manager]) 171 | pub async fn lp_balance( 172 | &self, 173 | who: Address, 174 | ) -> Result, V3PoolError> { 175 | let chain_id = self 176 | .pool 177 | .provider() 178 | .get_chain_id() 179 | .await 180 | .map_err(TransportError::from) 181 | .map_err(alloy::contract::Error::from) 182 | .map_err(V3PoolError::backend_error)?; 183 | 184 | let manager = AlloyManager::new( 185 | crate::constants::NETWORKS 186 | .get(&chain_id) 187 | .ok_or(V3PoolError::UnsupportedChain)? 188 | .manager, 189 | self.pool.provider(), 190 | ); 191 | 192 | manager.total_positions_balance(self, who).await 193 | } 194 | 195 | /// Returns all the NFT liquidty positions for this manager 196 | /// 197 | /// Manager: The nft position manager contract to query 198 | pub async fn lp_balance_with_manager( 199 | &self, 200 | manager: &AlloyManager, 201 | who: Address, 202 | ) -> Result, V3PoolError> 203 | where 204 | P2: Provider, 205 | { 206 | manager.total_positions_balance(self, who).await 207 | } 208 | } 209 | 210 | #[async_trait::async_trait] 211 | impl V3Pool for AlloyPool 212 | where 213 | T: Transport + Clone, 214 | P: Provider, 215 | N: Network, 216 | M: ForkMarker, 217 | { 218 | type BackendError = alloy::contract::Error; 219 | 220 | /// will error if the ticks arent n * spacing apart 221 | async fn tick_range( 222 | &self, 223 | starting: Tick, 224 | ending: Tick, 225 | ) -> PoolResult, Self::BackendError> { 226 | let spacing: i32 = self.tick_spacing.unchecked_into(); 227 | let mut down: bool = false; 228 | 229 | let differnce = starting - ending; 230 | let differnce = differnce.abs(); 231 | let capactiy = differnce / spacing + 1; 232 | 233 | if capactiy > 500 { 234 | // todo should we just maxx out? 235 | return Err(V3PoolError::TooManyTicks); 236 | } 237 | 238 | tracing::trace!("getting tick range"); 239 | tracing::trace!( 240 | "starting: {:?}, ending: {:?}, spacing: {:?}", 241 | starting, 242 | ending, 243 | spacing 244 | ); 245 | tracing::trace!("difference: {}, capacity: {}", differnce, capactiy); 246 | 247 | if differnce % spacing != 0 { 248 | let tick_spacing = self.tick_spacing; 249 | 250 | return Err(V3PoolError::BadTickRange(starting, ending, tick_spacing)); 251 | } 252 | 253 | if starting > ending { 254 | down = true; 255 | } 256 | 257 | if starting == ending { 258 | return Ok(vec![]); 259 | } 260 | 261 | Ok(M::liquidity_net(self, starting, ending, down) 262 | .await 263 | .map_err(V3PoolError::backend_error)? 264 | .into_iter() 265 | .map(|x| if down { -x } else { x }) 266 | .collect::>()) 267 | } 268 | 269 | fn tick_spacing(&self) -> crate::I24 { 270 | self.tick_spacing 271 | } 272 | 273 | async fn current_liquidity(&self) -> Result> { 274 | let liquidity = self 275 | .pool 276 | .liquidity() 277 | .call() 278 | .await 279 | .map_err(V3PoolError::backend_error)?; 280 | 281 | tracing::trace!("current liquidity: {}", liquidity._0); 282 | 283 | Ok(Float::with_val(100, liquidity._0)) 284 | } 285 | 286 | async fn sqrt_price_x96(&self) -> Result> { 287 | M::sqrt_price_x96(self) 288 | .await 289 | .map_err(V3PoolError::backend_error) 290 | } 291 | 292 | async fn tick(&self, tick: Tick) -> Result> { 293 | M::tick(self, tick) 294 | .await 295 | .map_err(V3PoolError::backend_error) 296 | } 297 | 298 | fn token0(&self) -> &Address { 299 | &self.token0 300 | } 301 | 302 | fn token1(&self) -> &Address { 303 | &self.token1 304 | } 305 | 306 | fn token0_decimals(&self) -> &u8 { 307 | &self.token0_decimals 308 | } 309 | 310 | fn token1_decimals(&self) -> &u8 { 311 | &self.token1_decimals 312 | } 313 | 314 | fn fee(&self) -> alloy::primitives::Uint<24, 1> { 315 | self.fee 316 | } 317 | 318 | fn address(&self) -> Address { 319 | *self.pool.address() 320 | } 321 | } 322 | 323 | /// The vanilla implementation of an on chain v3 pool. 324 | pub struct VanillaMarker; 325 | 326 | /// The aerodrome implementation of an on chain v3 pool. 327 | #[cfg(feature = "aerodrome")] 328 | pub struct AerodromeMarker; 329 | 330 | trait ForkMarker: Sized + Send + Sync + 'static { 331 | fn liquidity_net( 332 | instance: &AlloyPool, 333 | start: Tick, 334 | end: Tick, 335 | down: bool, 336 | ) -> impl Future, ContractError>> + Send; 337 | 338 | fn tick( 339 | instance: &AlloyPool, 340 | tick: Tick, 341 | ) -> impl Future> + Send; 342 | 343 | fn sqrt_price_x96( 344 | instance: &AlloyPool, 345 | ) -> impl Future> + Send; 346 | } 347 | 348 | impl ForkMarker for VanillaMarker 349 | where 350 | T: Transport + Clone, 351 | P: Provider, 352 | N: Network, 353 | { 354 | async fn liquidity_net( 355 | instance: &AlloyPool, 356 | start: Tick, 357 | end: Tick, 358 | down: bool, 359 | ) -> Result, ContractError> { 360 | let pool = 361 | Vanilla::VanillaInstance::new(*instance.pool.address(), instance.pool.provider()); 362 | 363 | let mut calls = Vec::new(); 364 | let mut current = start; 365 | // we know this should happen because we check that the diff is a multiple of the spacing 366 | while current != end { 367 | calls.push(pool.ticks(current.into())); 368 | 369 | if down { 370 | current = current.down(instance.tick_spacing); 371 | } else { 372 | current = current.up(instance.tick_spacing); 373 | } 374 | } 375 | 376 | Ok(calls 377 | .batch() 378 | .call() 379 | .await? 380 | .into_iter() 381 | .map(|x| x.liquidityNet) 382 | .collect()) 383 | } 384 | 385 | async fn tick(instance: &AlloyPool, tick: Tick) -> Result { 386 | let pool = 387 | Vanilla::VanillaInstance::new(*instance.pool.address(), instance.pool.provider()); 388 | 389 | pool.ticks(tick.into()) 390 | .call() 391 | .await 392 | .map(|x| Float::with_val(100, x.liquidityNet)) 393 | } 394 | 395 | async fn sqrt_price_x96(instance: &AlloyPool) -> Result { 396 | let pool = 397 | Vanilla::VanillaInstance::new(*instance.pool.address(), instance.pool.provider()); 398 | 399 | pool.slot0() 400 | .call() 401 | .await 402 | .map(|x| x.sqrtPriceX96.into_float()) 403 | } 404 | } 405 | 406 | #[cfg(feature = "aerodrome")] 407 | impl ForkMarker for AerodromeMarker 408 | where 409 | T: Transport + Clone, 410 | P: Provider, 411 | N: Network, 412 | { 413 | async fn liquidity_net( 414 | instance: &AlloyPool, 415 | start: Tick, 416 | end: Tick, 417 | down: bool, 418 | ) -> Result, ContractError> { 419 | let pool = 420 | Aerodrome::AerodromeInstance::new(*instance.pool.address(), instance.pool.provider()); 421 | 422 | let mut calls = Vec::new(); 423 | let mut current = start; 424 | // we know this should happen because we check that the diff is a multiple of the spacing 425 | while current != end { 426 | calls.push(pool.ticks(current.into())); 427 | 428 | if down { 429 | current = current.down(instance.tick_spacing); 430 | } else { 431 | current = current.up(instance.tick_spacing); 432 | } 433 | } 434 | 435 | Ok(calls 436 | .batch() 437 | .call() 438 | .await? 439 | .into_iter() 440 | .map(|x| x.liquidityNet) 441 | .collect()) 442 | } 443 | 444 | async fn tick(instance: &AlloyPool, tick: Tick) -> Result { 445 | let pool = 446 | Aerodrome::AerodromeInstance::new(*instance.pool.address(), instance.pool.provider()); 447 | 448 | pool.ticks(tick.into()) 449 | .call() 450 | .await 451 | .map(|x| Float::with_val(100, x.liquidityNet)) 452 | } 453 | 454 | async fn sqrt_price_x96(instance: &AlloyPool) -> Result { 455 | let pool = 456 | Aerodrome::AerodromeInstance::new(*instance.pool.address(), instance.pool.provider()); 457 | 458 | pool.slot0() 459 | .call() 460 | .await 461 | .map(|x| x.sqrtPriceX96.into_float()) 462 | } 463 | } 464 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::{address, Address}; 2 | 3 | pub const MULTICALL3: Address = address!("cA11bde05977b3631167028862bE2a173976CA11"); 4 | 5 | pub struct ChainConstants { 6 | pub factory: Address, 7 | pub manager: Address, 8 | pub quoter_v2: Address, 9 | pub supports_multicall: bool, 10 | } 11 | 12 | pub const MAINNET: ChainConstants = ChainConstants { 13 | factory: address!("1F98431c8aD98523631AE4a59f267346ea31F984"), 14 | manager: address!("C36442b4a4522E871399CD717aBDD847Ab11FE88"), 15 | quoter_v2: address!("61fFE014bA17989E743c5F6cB21bF9697530B21e"), 16 | supports_multicall: true, 17 | }; 18 | 19 | pub const ARBITRUM: ChainConstants = ChainConstants { 20 | factory: address!("1F98431c8aD98523631AE4a59f267346ea31F984"), 21 | manager: address!("C36442b4a4522E871399CD717aBDD847Ab11FE88"), 22 | quoter_v2: address!("61fFE014bA17989E743c5F6cB21bF9697530B21e"), 23 | supports_multicall: true, 24 | }; 25 | 26 | pub const OPTIMISM: ChainConstants = ChainConstants { 27 | factory: address!("1F98431c8aD98523631AE4a59f267346ea31F984"), 28 | manager: address!("C36442b4a4522E871399CD717aBDD847Ab11FE88"), 29 | quoter_v2: address!("61fFE014bA17989E743c5F6cB21bF9697530B21e"), 30 | supports_multicall: true, 31 | }; 32 | 33 | pub const POLYGON: ChainConstants = ChainConstants { 34 | factory: address!("1F98431c8aD98523631AE4a59f267346ea31F984"), 35 | manager: address!("C36442b4a4522E871399CD717aBDD847Ab11FE88"), 36 | quoter_v2: address!("61fFE014bA17989E743c5F6cB21bF9697530B21e"), 37 | supports_multicall: true, 38 | }; 39 | 40 | pub const BASE: ChainConstants = ChainConstants { 41 | factory: address!("33128a8fC17869897dcE68Ed026d694621f6FDfD"), 42 | manager: address!("03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1"), 43 | quoter_v2: address!("3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), 44 | supports_multicall: true, 45 | }; 46 | 47 | // todo check multicall 48 | pub const BNB: ChainConstants = ChainConstants { 49 | factory: address!("dB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7"), 50 | manager: address!("7b8A01B39D58278b5DE7e48c8449c9f4F5170613"), 51 | quoter_v2: address!("78D78E420Da98ad378D7799bE8f4AF69033EB077"), 52 | supports_multicall: false, 53 | }; 54 | 55 | // todo check multicall 56 | pub const AVAX: ChainConstants = ChainConstants { 57 | factory: address!("740b1c1de25031C31FF4fC9A62f554A55cdC1baD"), 58 | manager: address!("655C406EBFa14EE2006250925e54ec43AD184f8B"), 59 | quoter_v2: address!("be0F5544EC67e9B3b2D979aaA43f18Fd87E6257F"), 60 | supports_multicall: false, 61 | }; 62 | 63 | // todo check multicall 64 | pub const CELO: ChainConstants = ChainConstants { 65 | factory: address!("AfE208a311B21f13EF87E33A90049fC17A7acDEc"), 66 | manager: address!("3d79EdAaBC0EaB6F08ED885C05Fc0B014290D95A"), 67 | quoter_v2: address!("82825d0554fA07f7FC52Ab63c961F330fdEFa8E8"), 68 | supports_multicall: false, 69 | }; 70 | 71 | pub static NETWORKS: phf::Map = phf::phf_map! { 72 | 1_u64 => MAINNET, 73 | 42161_u64 => ARBITRUM, 74 | 10_u64 => OPTIMISM, 75 | 137_u64 => POLYGON, 76 | 8453_u64 => BASE, 77 | 56_u64 => BNB, 78 | 43114_u64 => AVAX, 79 | 42220_u64 => CELO, 80 | }; 81 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::math::Tick; 2 | use alloy::primitives::Signed; 3 | use rug::float::ParseFloatError; 4 | use std::error::Error; 5 | 6 | use crate::math::BoundsError; 7 | 8 | #[derive(Debug, thiserror::Error)] 9 | pub enum V3PoolError { 10 | #[error("Error parsing float: {0}")] 11 | ParseError(#[from] ParseFloatError), 12 | #[error("Backend error: {0}")] 13 | BackendError(E), 14 | #[error("Bounds error: {0}")] 15 | BoundsError(#[from] BoundsError), 16 | #[error("Pool not found")] 17 | PoolNotFound, 18 | #[error("Bad tick range: {0:?} {1:?} {2:?}")] 19 | BadTickRange(Tick, Tick, Signed<24, 1>), 20 | #[error("Too many ticks")] 21 | TooManyTicks, 22 | #[error("Unsupported Chain")] 23 | UnsupportedChain, 24 | } 25 | 26 | impl V3PoolError { 27 | pub fn backend_error(e: E) -> Self { 28 | V3PoolError::BackendError(e) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | 3 | #[macro_use] 4 | mod macros; 5 | 6 | pub mod traits; 7 | 8 | /// Addresses from Uniswap and things like that 9 | pub mod constants; 10 | 11 | /// The Alloy Implementation of the [crate::V3Pool] trait 12 | pub mod alloy_pool; 13 | #[doc(inline)] 14 | pub use alloy_pool::{ 15 | factory::Factory, 16 | pool::Pool, 17 | }; 18 | 19 | #[cfg(feature = "aerodrome")] 20 | pub use alloy_pool::{pool::AerodromePool, factory::AerodromeFactory}; 21 | 22 | pub mod pool; 23 | #[doc(inline)] 24 | pub use pool::{price::PriceExt, PoolResult, V3Pool}; 25 | 26 | mod position; 27 | #[doc(inline)] 28 | pub use position::{Manager as AlloyManager, PositionsReturn}; 29 | 30 | /// The error type that is returned from interacting with a [crate::V3Pool] 31 | pub mod error; 32 | 33 | /// The math module contains all the math functions that are used in the library 34 | pub mod math; 35 | 36 | /// Some useful types that are used in the library 37 | pub mod types; 38 | #[doc(inline)] 39 | pub use types::{FeeTier, PoolPrice, TickSpacing, Token as TokenIdx, TokenAmount}; 40 | 41 | pub type I24 = alloy::primitives::Signed<24, 1>; 42 | 43 | mod utils { 44 | use alloy::contract::Error; 45 | use alloy::network::Network; 46 | use alloy::primitives::Address; 47 | use alloy::providers::Provider; 48 | use alloy::transports::Transport; 49 | use ERC20::ERC20Instance; 50 | 51 | alloy::sol! { 52 | #[derive(Debug)] 53 | #[sol(rpc)] 54 | interface ERC20 { 55 | function decimals() external view returns (uint8); 56 | } 57 | } 58 | 59 | pub async fn decimals(provider: P, address: Address) -> Result 60 | where 61 | T: Transport + Clone, 62 | P: Provider, 63 | N: Network, 64 | { 65 | let instance = ERC20Instance::new(address, provider); 66 | 67 | instance.decimals().call().await.map(|v| v._0) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod token_amount; 3 | 4 | #[macro_use] 5 | mod wrappers; 6 | -------------------------------------------------------------------------------- /src/macros/token_amount.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_token_amount_cmp_eq_inner { 2 | ($token_amount:ident, $($native:ty),* $(,)?) => { 3 | $( 4 | impl<'a, P: V3Pool> PartialEq<$native> for $token_amount<'a, P> { 5 | fn eq(&self, other: &$native) -> bool { 6 | let scaled = ::rug::Float::with_val(100, *other) * ::rug::Float::with_val(100, 10).pow(*self.decimals()); 7 | 8 | self.amount.eq(&scaled.floor()) 9 | } 10 | } 11 | 12 | impl<'a, P: V3Pool> PartialOrd<$native> for $token_amount<'a, P> { 13 | fn partial_cmp(&self, other: &$native) -> Option { 14 | let scaled = ::rug::Float::with_val(100, *other) * ::rug::Float::with_val(100, 10).pow(*self.decimals()); 15 | 16 | self.amount.partial_cmp(&scaled.floor()) 17 | } 18 | } 19 | 20 | impl<'a, P: V3Pool> PartialEq<$token_amount<'a, P>> for $native { 21 | fn eq(&self, other: &$token_amount<'a, P>) -> bool { 22 | let scaled = ::rug::Float::with_val(100, *self) * ::rug::Float::with_val(100, 10).pow(*other.decimals()); 23 | 24 | scaled.floor().eq(&other.amount) 25 | } 26 | } 27 | 28 | impl<'a, P: V3Pool> PartialOrd<$token_amount<'a, P>> for $native { 29 | fn partial_cmp(&self, other: &$token_amount<'a, P>) -> Option { 30 | let scaled = ::rug::Float::with_val(100, *self) * ::rug::Float::with_val(100, 10).pow(*other.decimals()); 31 | 32 | scaled.floor().partial_cmp(&other.amount) 33 | } 34 | } 35 | 36 | impl<'a, P: V3Pool> IntoTokenAmount<'a, P> for $native { 37 | fn into_token_amount(self, pool: &'a P, token: TokenIdx) -> $token_amount<'a, P> { 38 | let decimals = match token { 39 | TokenIdx::Zero => pool.token0_decimals(), 40 | TokenIdx::One => pool.token1_decimals(), 41 | }; 42 | 43 | let scaled = rug::Float::with_val(100, self) * rug::Float::with_val(100, 10).pow(decimals); 44 | 45 | $token_amount::from_scaled(pool, token, scaled.floor()) 46 | } 47 | } 48 | )* 49 | } 50 | } 51 | 52 | /// Implement token amount comparison and equality for native types 53 | /// 54 | /// Native types will be scaled to match the token amount's decimals 55 | macro_rules! impl_token_amount_cmp_eq_native { 56 | ($name:ident) => { 57 | impl_token_amount_cmp_eq_inner! { 58 | $name, 59 | usize, 60 | u8, 61 | u16, 62 | u32, 63 | u64, 64 | f32, 65 | f64, 66 | i8, 67 | i16, 68 | i32, 69 | i64, 70 | } 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /src/macros/wrappers.rs: -------------------------------------------------------------------------------- 1 | /// Implements conversions and operations on the type 2 | /// 3 | /// The type must impl `Add`, `Sub`, `Mul`, `Div` 4 | macro_rules! impl_wrappers { 5 | ( 6 | $( 7 | $(#[$attrs:meta])* 8 | pub struct $name:ident($vis:vis $inner:ty); 9 | )* 10 | ) => { 11 | $( 12 | $(#[$attrs])* 13 | pub struct $name($vis $inner); 14 | 15 | impl $name { 16 | #[inline] 17 | /// Get the wrapped value by consuming the wrapper 18 | pub fn into_inner(self) -> $inner { 19 | self.0 20 | } 21 | } 22 | 23 | impl From<$name> for $inner { 24 | fn from(inner: $name) -> Self { 25 | inner.0 26 | } 27 | } 28 | 29 | impl ::std::ops::Deref for $name { 30 | type Target = $inner; 31 | 32 | fn deref(&self) -> &Self::Target { 33 | &self.0 34 | } 35 | } 36 | 37 | impl ::std::ops::DerefMut for $name { 38 | fn deref_mut(&mut self) -> &mut Self::Target { 39 | &mut self.0 40 | } 41 | } 42 | 43 | impl ::std::ops::Add for $name { 44 | type Output = $inner; 45 | 46 | fn add(self, rhs: Self) -> Self::Output { 47 | self.0 + rhs.0 48 | } 49 | } 50 | 51 | impl ::std::ops::Add<$inner> for $name { 52 | type Output = $inner; 53 | 54 | fn add(self, rhs: $inner) -> Self::Output { 55 | self.0 + rhs 56 | } 57 | } 58 | 59 | impl ::std::ops::Add<$name> for $inner { 60 | type Output = $inner; 61 | 62 | fn add(self, rhs: $name) -> Self::Output { 63 | self + rhs.0 64 | } 65 | } 66 | 67 | impl ::std::ops::Sub for $name { 68 | type Output = $inner; 69 | 70 | fn sub(self, rhs: Self) -> Self::Output { 71 | self.0 - rhs.0 72 | } 73 | } 74 | 75 | impl ::std::ops::Sub<$inner> for $name { 76 | type Output = $inner; 77 | 78 | fn sub(self, rhs: $inner) -> Self::Output { 79 | self.0 - rhs 80 | } 81 | } 82 | 83 | impl ::std::ops::Sub<$name> for $inner { 84 | type Output = $inner; 85 | 86 | fn sub(self, rhs: $name) -> Self::Output { 87 | self - rhs.0 88 | } 89 | } 90 | 91 | impl ::std::ops::Mul for $name { 92 | type Output = $inner; 93 | 94 | fn mul(self, rhs: Self) -> Self::Output { 95 | self.0 * rhs.0 96 | } 97 | } 98 | 99 | impl ::std::ops::Mul<$inner> for $name { 100 | type Output = $inner; 101 | 102 | fn mul(self, rhs: $inner) -> Self::Output { 103 | self.0 * rhs 104 | } 105 | } 106 | 107 | impl ::std::ops::Mul<$name> for $inner { 108 | type Output = $inner; 109 | 110 | fn mul(self, rhs: $name) -> Self::Output { 111 | self * rhs.0 112 | } 113 | } 114 | 115 | impl ::std::ops::Div for $name { 116 | type Output = $inner; 117 | 118 | fn div(self, rhs: Self) -> Self::Output { 119 | self.0 / rhs.0 120 | } 121 | } 122 | 123 | impl ::std::ops::Div<$inner> for $name { 124 | type Output = $inner; 125 | 126 | fn div(self, rhs: $inner) -> Self::Output { 127 | self.0 / rhs 128 | } 129 | } 130 | 131 | impl ::std::ops::Div<$name> for $inner { 132 | type Output = $inner; 133 | 134 | fn div(self, rhs: $name) -> Self::Output { 135 | self / rhs.0 136 | } 137 | } 138 | )* 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /src/math.rs: -------------------------------------------------------------------------------- 1 | pub mod liquidity; 2 | pub mod swap; 3 | pub mod tick; 4 | 5 | mod wrappers; 6 | #[doc(inline)] 7 | pub use wrappers::{BoundsError, Price, SqrtPrice, Tick}; 8 | -------------------------------------------------------------------------------- /src/math/liquidity.rs: -------------------------------------------------------------------------------- 1 | use rug::Float; 2 | 3 | use super::wrappers::SqrtPrice; 4 | 5 | /// How much token0 is in the pool reserves given a price range and liquidity 6 | pub fn real_token0_from_l(sqrt_current: SqrtPrice, sqrt_upper: SqrtPrice, l: Float) -> Float { 7 | let inverse_current = sqrt_current.into_inner().recip(); 8 | let inverse_upper = sqrt_upper.into_inner().recip(); 9 | 10 | let real: Float = l * (inverse_current - inverse_upper); 11 | 12 | if real.is_sign_negative() { 13 | // return 0 14 | Float::with_val(256, 0) 15 | } else { 16 | real.floor() 17 | } 18 | } 19 | 20 | /// How much token1 is in the pool reserves given a price range and liquidity 21 | pub fn real_token1_from_l(sqrt_currnet: SqrtPrice, sqrt_lower: SqrtPrice, l: Float) -> Float { 22 | let real = l * (sqrt_currnet - sqrt_lower); 23 | 24 | if real.is_sign_negative() { 25 | // return 0 26 | Float::with_val(256, 0) 27 | } else { 28 | real.floor() 29 | } 30 | } 31 | 32 | /// the `L` value of the pool given the amount of token0 33 | pub fn liqudity_from_real_token1( 34 | sqrt_current: SqrtPrice, 35 | sqrt_lower: SqrtPrice, 36 | token1: Float, 37 | ) -> Float { 38 | let l = token1 / (sqrt_current - sqrt_lower); 39 | 40 | l.floor() 41 | } 42 | 43 | /// the `L` value of the pool given the amount of token1 44 | pub fn liqudity_from_real_token0( 45 | sqrt_current: SqrtPrice, 46 | sqrt_upper: SqrtPrice, 47 | token0: Float, 48 | ) -> Float { 49 | let inverse_current = sqrt_current.into_inner().recip(); 50 | let inverse_upper = sqrt_upper.into_inner().recip(); 51 | 52 | let l = token0 / (inverse_current - inverse_upper); 53 | 54 | l.floor() 55 | } 56 | -------------------------------------------------------------------------------- /src/math/swap.rs: -------------------------------------------------------------------------------- 1 | use rug::Float; 2 | 3 | use super::wrappers::SqrtPrice; 4 | 5 | /// How much token0 reserves will change given a change in price and a fixed amount of liquidity 6 | pub fn token0_delta(sqrt_price: SqrtPrice, target_price: SqrtPrice, liquidity: Float) -> Float { 7 | let invert_target = target_price.into_inner().recip(); 8 | let invert_price = sqrt_price.into_inner().recip(); 9 | 10 | let d0 = liquidity * (invert_target - invert_price); 11 | 12 | d0.floor() 13 | } 14 | 15 | /// How much token1 reserves will change given a change in price and a fixed amount of liquidity 16 | pub fn token1_delta(sqrt_price: SqrtPrice, target_price: SqrtPrice, liquidity: Float) -> Float { 17 | let d1 = liquidity * (target_price - sqrt_price); 18 | 19 | d1.floor() 20 | } 21 | -------------------------------------------------------------------------------- /src/math/tick.rs: -------------------------------------------------------------------------------- 1 | use rug::ops::Pow; 2 | use rug::Float; 3 | 4 | use super::wrappers::{Price, Tick}; 5 | 6 | lazy_static::lazy_static! { 7 | pub static ref TICK_BASE: Float = Float::with_val(100, 1.0001); 8 | 9 | pub static ref LN_TICK_BASE: Float = TICK_BASE.clone().ln(); 10 | } 11 | 12 | /// the tick corresponding to this price 13 | /// 14 | /// # Caution 15 | /// this tick is not guaranteed to be initializable 16 | /// use [price_to_initializable_tick] if you need an initializable tick 17 | pub fn price_to_tick(price: Price) -> Tick { 18 | // saftey: Price is assumed to be in range to produce a valid tick 19 | unsafe { 20 | Tick::new_unchecked( 21 | // change of base log[1.0001](price) 22 | (price.into_inner().ln() / &*LN_TICK_BASE) 23 | .to_i32_saturating_round(rug::float::Round::Down) 24 | .expect("Can create a valid i32 from a valid price"), 25 | ) 26 | } 27 | } 28 | 29 | /// the *initializable lower* tick corresponding to this price 30 | pub fn price_to_initializable_tick(price: Price, tick_spacing: crate::I24) -> Tick { 31 | let spacing: i32 = tick_spacing.unchecked_into(); 32 | 33 | // change of base log[1.0001](price) 34 | let tick = price.into_inner().ln() / &*LN_TICK_BASE; 35 | // our tick must be of the form spacing * n where n is an integer 36 | let spacing_scalar = tick / spacing; 37 | 38 | // get the interger part of n and turn it back into the tick 39 | // saftey: price is assumed to be in range to produce a valid tick 40 | unsafe { 41 | Tick::new_unchecked( 42 | (spacing_scalar.floor() * spacing) 43 | .to_i32_saturating_round(rug::float::Round::Down) 44 | .expect("Can create a valid i32 from a valid price"), 45 | ) 46 | } 47 | } 48 | 49 | /// 1.0001^tick 50 | pub fn tick_to_price(tick: Tick) -> Price { 51 | // saftey: tick is assumed to be in range to produce a valid price 52 | unsafe { Price::new_unchecked(TICK_BASE.clone().pow(*tick)) } 53 | } 54 | -------------------------------------------------------------------------------- /src/math/wrappers.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use alloy::primitives::{Signed, U256}; 4 | use lazy_static::lazy_static; 5 | use rug::ops::Pow; 6 | use rug::Float; 7 | 8 | use crate::traits::IntoU256; 9 | 10 | lazy_static! { 11 | pub static ref MAX_PRICE: Float = Float::with_val(100, 1.0001).pow(887272); 12 | pub static ref MIN_PRICE: Float = Float::with_val(100, 1.0001).pow(-887272); 13 | pub static ref MAX_SQRT_PRICE: Float = MAX_PRICE.clone().sqrt(); 14 | pub static ref MIN_SQRT_PRICE: Float = MIN_PRICE.clone().sqrt(); 15 | } 16 | 17 | #[derive(Clone, Debug)] 18 | /// An error that occurs when a value is out of bounds for a type 19 | /// checked at compile time 20 | pub struct BoundsError(&'static str, String); 21 | 22 | impl std::fmt::Display for BoundsError { 23 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 24 | write!( 25 | f, 26 | "Bounds error on type {}, given value: {}", 27 | self.0, self.1 28 | ) 29 | } 30 | } 31 | 32 | impl std::error::Error for BoundsError {} 33 | 34 | impl_wrappers! { 35 | /// A *valid* tick in the range [-887272, 887272] 36 | #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq)] 37 | pub struct Tick(i32); 38 | 39 | /// A raw in-range pool price 40 | #[derive(Clone, Debug, PartialEq, PartialOrd)] 41 | pub struct Price(Float); 42 | 43 | /// A raw in range sqrt pool sqrt price 44 | #[derive(Clone, Debug, PartialEq, PartialOrd)] 45 | pub struct SqrtPrice(Float); 46 | } 47 | 48 | impl Tick { 49 | /// Creates a new *valid* tick from an i32 50 | /// 51 | /// # Errors: 52 | /// - if the tick is less than -887272 53 | /// - if the tick is greater than 887272 54 | pub fn new(tick: i32) -> Result { 55 | if tick.abs() <= 887272 { 56 | Ok(Self(tick)) 57 | } else { 58 | Err(BoundsError("Tick", tick.to_string())) 59 | } 60 | } 61 | 62 | /// Creates a new tick from an i32 without checking if it is valid 63 | /// useful for when youre reading directly from the pool 64 | /// 65 | /// # Safey: The tick should be in the range [-887272, 887272] 66 | pub unsafe fn new_unchecked(tick: i32) -> Self { 67 | Self(tick) 68 | } 69 | 70 | /// Returns the next initializable tick 71 | /// 72 | /// # Panics: 73 | /// - if the next tick is out of bounds 74 | pub fn up(self, spacing: crate::I24) -> Self { 75 | let spacing: i32 = spacing.unchecked_into(); 76 | let scalar = self.0 / spacing + 1; 77 | let next_tick = scalar * spacing; 78 | 79 | if next_tick > 887272 { 80 | panic!("Up Tick OOB") 81 | } else { 82 | unsafe { Self::new_unchecked(next_tick) } 83 | } 84 | } 85 | 86 | /// Returns the previous initializable tick 87 | /// 88 | /// # Panics: 89 | /// - if the next tick is out of bounds 90 | pub fn down(self, spacing: crate::I24) -> Self { 91 | let spacing: i32 = spacing.unchecked_into(); 92 | let scalar = self.0 / spacing - 1; 93 | let prev_tick = scalar * spacing; 94 | 95 | if prev_tick < -887272 { 96 | panic!("Down Tick OOB") 97 | } else { 98 | unsafe { Self::new_unchecked(prev_tick) } 99 | } 100 | } 101 | } 102 | 103 | impl Price { 104 | /// Creates a new sqrt price from a float 105 | /// 106 | /// # Errors: 107 | /// - if the price is less than the minimum price 108 | /// - if the price is greater than the maximum price 109 | pub fn new(float: Float) -> Result { 110 | if float >= *MIN_PRICE && float <= *MAX_PRICE { 111 | Ok(Self(float)) 112 | } else { 113 | Err(BoundsError("Price", float.to_string())) 114 | } 115 | } 116 | 117 | pub fn invert(self) -> Self { 118 | Self(self.0.recip()) 119 | } 120 | 121 | /// Creates a new price from a float without checking if it is valid 122 | /// useful for when youre reading directly from the pool 123 | /// 124 | /// # Safety: The price should be in the range [MIN_PRICE, MAX_PRICE] 125 | pub unsafe fn new_unchecked(float: Float) -> Self { 126 | Self(float) 127 | } 128 | } 129 | 130 | impl SqrtPrice { 131 | /// Creates a new sqrt price from a float 132 | /// 133 | /// # Errors: 134 | /// - if the sqrt price is less than the minimum sqrt price 135 | /// - if the sqrt price is greater than the maximum sqrt price 136 | pub fn new(float: Float) -> Result { 137 | if float >= *MIN_SQRT_PRICE && float <= *MAX_SQRT_PRICE { 138 | Ok(Self(float)) 139 | } else { 140 | Err(BoundsError("SqrtPrice", float.to_string())) 141 | } 142 | } 143 | 144 | /// Creates a new sqrt price from a float without checking if it is valid 145 | /// useful for when youre reading directly from the pool 146 | /// 147 | /// # Safety: The sqrt price should be in the range [MIN_SQRT_PRICE, MAX_SQRT_PRICE] 148 | pub unsafe fn new_unchecked(float: Float) -> Self { 149 | Self(float) 150 | } 151 | } 152 | 153 | impl PartialOrd for Price { 154 | fn partial_cmp(&self, other: &Float) -> Option { 155 | self.0.partial_cmp(other) 156 | } 157 | } 158 | 159 | impl PartialOrd for SqrtPrice { 160 | fn partial_cmp(&self, other: &Float) -> Option { 161 | self.0.partial_cmp(other) 162 | } 163 | } 164 | 165 | impl PartialEq for Price { 166 | fn eq(&self, other: &Float) -> bool { 167 | self.0.eq(other) 168 | } 169 | } 170 | 171 | impl PartialEq for SqrtPrice { 172 | fn eq(&self, other: &Float) -> bool { 173 | self.0.eq(other) 174 | } 175 | } 176 | 177 | impl From for U256 { 178 | fn from(price: Price) -> Self { 179 | price 180 | .0 181 | .into_u256() 182 | .expect("To convert a valid price wrapper to a u256") 183 | } 184 | } 185 | 186 | impl From for SqrtPrice { 187 | fn from(price: Price) -> Self { 188 | SqrtPrice(price.0.sqrt()) 189 | } 190 | } 191 | 192 | impl From for Price { 193 | fn from(sqrt_price: SqrtPrice) -> Self { 194 | Price(sqrt_price.0.pow(2)) 195 | } 196 | } 197 | 198 | impl std::fmt::Display for Price { 199 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 200 | write!(f, "{}", self.0) 201 | } 202 | } 203 | 204 | impl std::fmt::Display for SqrtPrice { 205 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 206 | write!(f, "{}", self.0) 207 | } 208 | } 209 | 210 | impl From for Signed<24, 1> { 211 | fn from(tick: Tick) -> Self { 212 | Signed::from_str(&tick.0.to_string()).expect("To convert a valid tick to a i24") 213 | } 214 | } 215 | 216 | #[cfg(test)] 217 | mod test { 218 | use super::*; 219 | 220 | #[test] 221 | fn test_cant_make_oob_tick() { 222 | let tick = Tick::new(887273); 223 | assert!(tick.is_err()); 224 | } 225 | 226 | #[test] 227 | fn test_cant_make_oob_price() { 228 | let price = Price::new(Float::with_val(100, 1.0001).pow(887273)); 229 | assert!(price.is_err()); 230 | } 231 | 232 | #[test] 233 | fn test_cant_make_oob_sqrt_price() { 234 | let sqrt_price = SqrtPrice::new(Float::with_val(100, 1.0001).pow(887273)); 235 | assert!(sqrt_price.is_err()); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/pool.rs: -------------------------------------------------------------------------------- 1 | pub mod price; 2 | pub mod swap; 3 | 4 | use std::error::Error; 5 | 6 | use crate::error::V3PoolError; 7 | use crate::math::{Price, SqrtPrice, Tick}; 8 | 9 | use crate::PoolPrice; 10 | use crate::TokenIdx; 11 | use alloy::primitives::Address; 12 | use alloy::primitives::{Signed, Uint}; 13 | use lazy_static::lazy_static; 14 | use rug::Float; 15 | 16 | pub type PoolResult = std::result::Result>; 17 | 18 | lazy_static! { 19 | pub static ref X96: Float = Float::with_val(100, 2u128.pow(96)); 20 | } 21 | 22 | /// [V3Pool] is the main trait of this library. It encompasses all the low level functions of a uniswapv3 pool 23 | #[async_trait::async_trait] 24 | pub trait V3Pool: Send + Sync + Sized { 25 | type BackendError: Error + Send + Sync; 26 | 27 | /// The fee tier of the pool 28 | fn fee(&self) -> Uint<24, 1>; 29 | fn token0(&self) -> &Address; 30 | fn token0_decimals(&self) -> &u8; 31 | fn token1(&self) -> &Address; 32 | fn token1_decimals(&self) -> &u8; 33 | fn address(&self) -> Address; 34 | 35 | // The current in range liquidity of the pool 36 | async fn current_liquidity(&self) -> PoolResult; 37 | 38 | /// The sqrt price of the pool scaled by 2^96 39 | async fn sqrt_price_x96(&self) -> PoolResult; 40 | 41 | /// Returns the liqudity delta to be added if youre were crossing 42 | /// into this tick as price is increasing 43 | async fn tick(&self, tick: Tick) -> PoolResult; 44 | 45 | /// returns the deltas (accounting for direction) for ticks `[starting, ending)` 46 | /// if starting == ending, returns [] 47 | /// ### Notice: 48 | /// implementors should ensure that the returned amount is correct for the direction 49 | /// Since tick delta should be added as price increase, a tick range can account for the opposite case 50 | /// if ending < starting, you can flip the signs of the deltas 51 | async fn tick_range( 52 | &self, 53 | starting: Tick, 54 | ending: Tick, 55 | ) -> PoolResult, Self::BackendError>; 56 | 57 | /// Returns the position of the token in the pool 58 | fn position_of(&self, token: &Address) -> Option { 59 | if token == self.token0() { 60 | Some(TokenIdx::Zero) 61 | } else if token == self.token1() { 62 | Some(TokenIdx::One) 63 | } else { 64 | None 65 | } 66 | } 67 | 68 | /// Returns the tick spacing of the pool 69 | fn tick_spacing(&self) -> Signed<24, 1>; 70 | 71 | /// The price of the pool (with decimals) 72 | async fn price(&self) -> PoolResult { 73 | Ok(self.sqrt_price().await?.into()) 74 | } 75 | 76 | /// The sqrt price of the pool (with decimals) 77 | async fn sqrt_price(&self) -> PoolResult { 78 | // saftey: sqrt price comes from pool 79 | Ok(unsafe { SqrtPrice::new_unchecked(self.sqrt_price_x96().await? / &*X96) }) 80 | } 81 | 82 | /// Returns the current [crate::PoolPrice] in terms of the numeraire 83 | async fn pool_price( 84 | &self, 85 | numeraire: TokenIdx, 86 | ) -> PoolResult, Self::BackendError> { 87 | Ok(PoolPrice::from_price(self, self.price().await?, numeraire)) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/pool/price.rs: -------------------------------------------------------------------------------- 1 | use crate::error::V3PoolError; 2 | use crate::math::tick::{price_to_initializable_tick, tick_to_price}; 3 | use crate::math::{Price, SqrtPrice, Tick}; 4 | use crate::types::Deltas; 5 | use crate::V3Pool; 6 | 7 | #[async_trait::async_trait] 8 | pub trait PriceExt: V3Pool { 9 | /// Returns the amount of token0 and token1 needed to move the pool price to the target price 10 | /// price_of_0_in_1 should not include the underlying nominal units 11 | async fn optimal_swap_for_price( 12 | &self, 13 | new_price: Price, 14 | ) -> Result, V3PoolError> { 15 | let mut current_liquidity = self.current_liquidity().await?; 16 | 17 | tracing::debug!("current L: {:?}", current_liquidity); 18 | 19 | let mut current_sqrt_price = self.sqrt_price().await?; 20 | let target_sqrt_price: SqrtPrice = new_price.into(); 21 | 22 | tracing::debug!("current sqrt price: {:?}", current_sqrt_price); 23 | tracing::debug!("target sqrt price: {:?}", target_sqrt_price); 24 | 25 | // at this point we dont know if were going up or down 26 | // but either way these are always the "lower" prices but 27 | let starting_lower_tick = 28 | price_to_initializable_tick(current_sqrt_price.clone().into(), self.tick_spacing()); 29 | 30 | let target_lower_tick: Tick = 31 | price_to_initializable_tick(target_sqrt_price.clone().into(), self.tick_spacing()); 32 | 33 | tracing::trace!("starting_lower_tick {:?}", starting_lower_tick); 34 | tracing::trace!("target_lower_tick {:?}", target_lower_tick); 35 | 36 | let mut deltas = Deltas::new(self); 37 | let mut next_tick: Tick; 38 | let up = starting_lower_tick < target_lower_tick; 39 | let neq = starting_lower_tick != target_lower_tick; 40 | 41 | // if were in the same tick we want to just move to the price and exit from there 42 | // if were going up lets move to the boundry, include that boundry and then move into the loop 43 | // if were going down lets move to the boundry, include that boundry and then move into the loop 44 | let ticks = if up { 45 | tracing::debug!("current lower tick is less than target lower tick"); 46 | tracing::debug!("were moving the price up"); 47 | next_tick = starting_lower_tick.up(self.tick_spacing()); 48 | 49 | // move the price to the next tick 50 | deltas.update( 51 | current_liquidity.clone(), 52 | current_sqrt_price, 53 | tick_to_price(next_tick).into(), 54 | ); 55 | 56 | // get the tick range from the current tick to the target tick 57 | self.tick_range(next_tick, target_lower_tick.up(self.tick_spacing())) 58 | .await? 59 | } else if neq { 60 | tracing::debug!("current lower tick is greater than target lower tick"); 61 | tracing::debug!("were moving the price down"); 62 | next_tick = starting_lower_tick; 63 | 64 | // move the price to the next tick 65 | deltas.update( 66 | current_liquidity.clone(), 67 | current_sqrt_price, 68 | tick_to_price(next_tick).into(), 69 | ); 70 | 71 | // get the tick range from the current tick to the target tick 72 | self.tick_range(next_tick, target_lower_tick.down(self.tick_spacing())) 73 | .await? 74 | } else { 75 | tracing::debug!("current lower tick is equal to target lower tick"); 76 | 77 | deltas.update(current_liquidity, current_sqrt_price, target_sqrt_price); 78 | 79 | return Ok(deltas); 80 | }; 81 | 82 | // todo we could make this faster with swapping and avoiding clones 83 | tracing::trace!("starting tick loop"); 84 | let ticks = ticks.into_iter(); 85 | for delta in ticks { 86 | current_liquidity += delta; 87 | if up { 88 | next_tick = next_tick.up(self.tick_spacing()); 89 | current_sqrt_price = tick_to_price(next_tick).into(); 90 | 91 | let next_tick_price: SqrtPrice = tick_to_price(next_tick).into(); 92 | if next_tick_price > target_sqrt_price { 93 | deltas.update(current_liquidity, current_sqrt_price, target_sqrt_price); 94 | 95 | tracing::trace!(?up, "exiting tick loop"); 96 | 97 | break; 98 | } 99 | } else { 100 | next_tick = next_tick.down(self.tick_spacing()); 101 | current_sqrt_price = tick_to_price(next_tick).into(); 102 | 103 | let next_tick_price: SqrtPrice = tick_to_price(next_tick).into(); 104 | if next_tick_price < target_sqrt_price { 105 | deltas.update(current_liquidity, current_sqrt_price, target_sqrt_price); 106 | 107 | tracing::trace!(?up, "exiting tick loop"); 108 | 109 | break; 110 | } 111 | } 112 | 113 | deltas.update( 114 | current_liquidity.clone(), 115 | current_sqrt_price, 116 | tick_to_price(next_tick).into(), 117 | ); 118 | } 119 | 120 | Ok(deltas) 121 | } 122 | } 123 | 124 | impl PriceExt for P {} 125 | -------------------------------------------------------------------------------- /src/pool/swap.rs: -------------------------------------------------------------------------------- 1 | use crate::{types::IntoTokenAmount, TokenAmount, TokenIdx, V3Pool}; 2 | 3 | alloy::sol! { 4 | #[derive(Debug)] 5 | #[sol(rpc)] 6 | /// @title QuoterV2 Interface 7 | /// @notice Supports quoting the calculated amounts from exact input or exact output swaps. 8 | /// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. 9 | /// @dev These functions are not marked view because they rely on calling non-view functions and reverting 10 | /// to compute the result. They are also not gas efficient and should not be called on-chain. 11 | interface IQuoterV2 { 12 | /// @notice Returns the amount out received for a given exact input swap without executing the swap 13 | /// @param path The path of the swap, i.e. each token pair and the pool fee 14 | /// @param amountIn The amount of the first token to swap 15 | /// @return amountOut The amount of the last token that would be received 16 | /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path 17 | /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path 18 | /// @return gasEstimate The estimate of the gas that the swap consumes 19 | function quoteExactInput(bytes memory path, uint256 amountIn) 20 | external 21 | returns ( 22 | uint256 amountOut, 23 | uint160[] memory sqrtPriceX96AfterList, 24 | uint32[] memory initializedTicksCrossedList, 25 | uint256 gasEstimate 26 | ); 27 | 28 | struct QuoteExactInputSingleParams { 29 | address tokenIn; 30 | address tokenOut; 31 | uint256 amountIn; 32 | uint24 fee; 33 | uint160 sqrtPriceLimitX96; 34 | } 35 | 36 | /// @notice Returns the amount out received for a given exact input but for a swap of a single pool 37 | /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` 38 | /// tokenIn The token being swapped in 39 | /// tokenOut The token being swapped out 40 | /// fee The fee of the token pool to consider for the pair 41 | /// amountIn The desired input amount 42 | /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap 43 | /// @return amountOut The amount of `tokenOut` that would be received 44 | /// @return sqrtPriceX96After The sqrt price of the pool after the swap 45 | /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed 46 | /// @return gasEstimate The estimate of the gas that the swap consumes 47 | function quoteExactInputSingle(QuoteExactInputSingleParams memory params) 48 | external 49 | returns ( 50 | uint256 amountOut, 51 | uint160 sqrtPriceX96After, 52 | uint32 initializedTicksCrossed, 53 | uint256 gasEstimate 54 | ); 55 | 56 | /// @notice Returns the amount in required for a given exact output swap without executing the swap 57 | /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order 58 | /// @param amountOut The amount of the last token to receive 59 | /// @return amountIn The amount of first token required to be paid 60 | /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path 61 | /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path 62 | /// @return gasEstimate The estimate of the gas that the swap consumes 63 | function quoteExactOutput(bytes memory path, uint256 amountOut) 64 | external 65 | returns ( 66 | uint256 amountIn, 67 | uint160[] memory sqrtPriceX96AfterList, 68 | uint32[] memory initializedTicksCrossedList, 69 | uint256 gasEstimate 70 | ); 71 | 72 | struct QuoteExactOutputSingleParams { 73 | address tokenIn; 74 | address tokenOut; 75 | uint256 amount; 76 | uint24 fee; 77 | uint160 sqrtPriceLimitX96; 78 | } 79 | 80 | /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool 81 | /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` 82 | /// tokenIn The token being swapped in 83 | /// tokenOut The token being swapped out 84 | /// fee The fee of the token pool to consider for the pair 85 | /// amountOut The desired output amount 86 | /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap 87 | /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` 88 | /// @return sqrtPriceX96After The sqrt price of the pool after the swap 89 | /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed 90 | /// @return gasEstimate The estimate of the gas that the swap consumes 91 | function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) 92 | external 93 | returns ( 94 | uint256 amountIn, 95 | uint160 sqrtPriceX96After, 96 | uint32 initializedTicksCrossed, 97 | uint256 gasEstimate 98 | ); 99 | } 100 | } 101 | 102 | // todo lookup for the quoter v2 103 | #[async_trait::async_trait] 104 | #[allow(unused)] 105 | trait SwapExt: V3Pool { 106 | async fn amount_in<'a, T>( 107 | &'a self, 108 | amount_out: T, 109 | token_idx: TokenIdx, 110 | ) -> Result, Self::BackendError> 111 | where 112 | T: IntoTokenAmount<'a, Self> + Send, 113 | { 114 | todo!() 115 | } 116 | 117 | async fn amount_out<'a, T>( 118 | &'a self, 119 | amount_in: T, 120 | token_idx: TokenIdx, 121 | ) -> Result, Self::BackendError> 122 | where 123 | T: IntoTokenAmount<'a, Self> + Send, 124 | { 125 | todo!() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/position.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use crate::{ 4 | error::V3PoolError, 5 | math::{SqrtPrice, Tick}, 6 | traits::Batch, 7 | TokenAmount, 8 | }; 9 | use alloy::{ 10 | network::Network, 11 | primitives::{uint, Address, U256}, 12 | providers::Provider, 13 | transports::Transport, 14 | }; 15 | use rug::Float; 16 | 17 | use crate::math::liquidity::{real_token0_from_l, real_token1_from_l}; 18 | use crate::math::tick::{price_to_tick, tick_to_price}; 19 | use crate::pool::V3Pool; 20 | 21 | alloy::sol! { 22 | #[derive(Debug)] 23 | #[sol(rpc)] 24 | interface PositionManager { 25 | function positions(uint256 tokenId) 26 | external 27 | view 28 | returns ( 29 | uint96 nonce, 30 | address operator, 31 | address token0, 32 | address token1, 33 | uint24 fee, 34 | int24 tickLower, 35 | int24 tickUpper, 36 | uint128 liquidity, 37 | uint256 feeGrowthInside0LastX128, 38 | uint256 feeGrowthInside1LastX128, 39 | uint128 tokensOwed0, 40 | uint128 tokensOwed1 41 | ); 42 | 43 | function balanceOf(address owner) external view returns (uint256); 44 | 45 | function tokenOfOwnerByIndex(address owner, uint256 idx) returns (uint256); 46 | } 47 | } 48 | 49 | pub use PositionManager::positionsReturn as PositionsReturn; 50 | 51 | /// A read only wrapper around the NFT position manager contract 52 | pub struct Manager { 53 | instance: PositionManager::PositionManagerInstance, 54 | } 55 | 56 | #[derive(Clone)] 57 | pub struct Balances<'a, P: V3Pool> { 58 | tokens: [TokenAmount<'a, P>; 2], 59 | } 60 | 61 | impl<'a, P: V3Pool> Debug for Balances<'a, P> { 62 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 63 | f.debug_struct("Balances") 64 | .field("token0", &self.tokens[0]) 65 | .field("token1", &self.tokens[1]) 66 | .finish() 67 | } 68 | } 69 | 70 | impl<'a, P: V3Pool> Balances<'a, P> { 71 | pub fn new(token0: TokenAmount<'a, P>, token1: TokenAmount<'a, P>) -> Self { 72 | Self { 73 | tokens: [token0, token1], 74 | } 75 | } 76 | 77 | pub fn token0(&self) -> &TokenAmount<'a, P> { 78 | &self.tokens[0] 79 | } 80 | 81 | pub fn token1(&self) -> &TokenAmount<'a, P> { 82 | &self.tokens[1] 83 | } 84 | } 85 | 86 | impl Manager 87 | where 88 | T: Transport + Clone, 89 | P: Provider + Clone, 90 | N: Network, 91 | { 92 | pub fn new(address: Address, provider: P) -> Self { 93 | Self { 94 | instance: PositionManager::PositionManagerInstance::new(address, provider), 95 | } 96 | } 97 | } 98 | 99 | impl Manager 100 | where 101 | T: Transport + Clone, 102 | P: Provider, 103 | N: Network, 104 | { 105 | pub async fn all_positions( 106 | &self, 107 | owner: Address, 108 | ) -> Result, alloy::contract::Error> { 109 | let balance = self.instance.balanceOf(owner).call().await?._0; 110 | 111 | let mut calls = Vec::with_capacity(balance.saturating_to()); 112 | let mut i = U256::ZERO; 113 | while i < balance { 114 | calls.push(self.instance.tokenOfOwnerByIndex(owner, i)); 115 | i += uint!(1_U256); 116 | } 117 | 118 | let ids = calls.batch().call().await?; 119 | Ok(ids 120 | .into_iter() 121 | .map(|id| self.instance.positions(id._0)) 122 | .collect::>() 123 | .batch() 124 | .call() 125 | .await?) 126 | } 127 | 128 | pub async fn total_positions_balance<'p, Pool>( 129 | &self, 130 | pool: &'p Pool, 131 | owner: Address, 132 | ) -> Result, V3PoolError> 133 | where 134 | Pool: V3Pool, 135 | { 136 | let positions = self 137 | .all_positions(owner) 138 | .await 139 | .map_err(V3PoolError::backend_error)? 140 | .into_iter() 141 | .filter(|pos| { 142 | pos.token0 == *pool.token0() 143 | && pos.token1 == *pool.token1() 144 | && pos.fee == pool.fee() 145 | }) 146 | .collect::>(); 147 | 148 | tracing::debug!("Positions for {:#?}:\n {:#?}", owner, positions); 149 | 150 | let sqrt_price = pool.sqrt_price().await?; 151 | 152 | let init = Balances { 153 | tokens: [ 154 | TokenAmount::zero(pool, crate::TokenIdx::Zero), 155 | TokenAmount::zero(pool, crate::TokenIdx::One), 156 | ], 157 | }; 158 | 159 | Ok(positions 160 | .iter() 161 | .map(|pos| pos.token_balances(pool, sqrt_price.clone())) 162 | .collect::>() 163 | .into_iter() 164 | .fold(init, |mut acc, balance| { 165 | acc.tokens[0] += balance.token0().as_float(); 166 | acc.tokens[1] += balance.token1().as_float(); 167 | 168 | acc 169 | })) 170 | } 171 | } 172 | 173 | impl PositionsReturn { 174 | pub fn token_balances<'a, P: V3Pool>( 175 | &self, 176 | pool: &'a P, 177 | sqrt_price: SqrtPrice, 178 | ) -> Balances<'a, P> { 179 | let current_tick = price_to_tick(sqrt_price.clone().into()); 180 | 181 | // saftey: comes from pool 182 | let tick_upper = unsafe { Tick::new_unchecked(self.tickUpper.as_i32()) }; 183 | let tick_lower = unsafe { Tick::new_unchecked(self.tickLower.as_i32()) }; 184 | 185 | let upper_price: SqrtPrice = tick_to_price(tick_upper).into(); 186 | let lower_price: SqrtPrice = tick_to_price(tick_lower).into(); 187 | 188 | let l = Float::with_val(100, self.liquidity); 189 | 190 | let token0_amount = if current_tick >= tick_lower && current_tick < tick_upper { 191 | real_token0_from_l(sqrt_price.clone(), upper_price.clone(), l.clone()) 192 | } else if current_tick < tick_lower { 193 | real_token0_from_l(lower_price.clone(), upper_price.clone(), l.clone()) 194 | } else { 195 | Float::with_val(18, 0) 196 | }; 197 | 198 | let token1_amount = if current_tick >= tick_lower && current_tick < tick_upper { 199 | real_token1_from_l(sqrt_price, lower_price, l) 200 | } else if current_tick > tick_upper { 201 | real_token1_from_l(upper_price, lower_price, l) 202 | } else { 203 | Float::with_val(18, 0) 204 | }; 205 | 206 | Balances::new( 207 | TokenAmount::from_scaled(pool, crate::TokenIdx::Zero, token0_amount), 208 | TokenAmount::from_scaled(pool, crate::TokenIdx::One, token1_amount), 209 | ) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/traits/basis_points.rs: -------------------------------------------------------------------------------- 1 | pub trait ApplyBps { 2 | /// Scale value by 1 + bps / 10_000 3 | /// 4 | /// # Panics 5 | /// If bps > 10_000 6 | fn apply_bps_up(&self, bps: u16) -> Self; 7 | 8 | /// Scale value by 1 - bps / 10_000 9 | /// 10 | /// # Panics 11 | /// If bps > 10_000 12 | fn apply_bps_down(&self, bps: u16) -> Self; 13 | } 14 | 15 | impl ApplyBps for T 16 | where 17 | T: std::ops::Mul 18 | + std::ops::Div 19 | + std::ops::Mul 20 | + Clone, 21 | { 22 | fn apply_bps_down(&self, bps: u16) -> Self { 23 | assert!(bps <= 10_000, "bps must be <= 10_000"); 24 | 25 | self.clone() * (10_000 - bps) / 10_000 26 | } 27 | 28 | fn apply_bps_up(&self, bps: u16) -> Self { 29 | assert!(bps <= 10_000, "bps must be <= 10_000"); 30 | 31 | self.clone() * (10_000 + bps) / 10_000 32 | } 33 | } 34 | 35 | #[cfg(test)] 36 | mod test { 37 | use super::ApplyBps; 38 | use rug::Float; 39 | 40 | #[test] 41 | fn test_apply_bps_up_float() { 42 | let value = Float::with_val(100, 100); 43 | // 100 bps = 1% 44 | let result = value.apply_bps_up(100); 45 | 46 | assert_eq!(result, Float::with_val(100, 101)); 47 | } 48 | 49 | #[test] 50 | fn test_apply_bps_down_float() { 51 | let value = Float::with_val(100, 100); 52 | // 100 bps = 1% 53 | let result = value.apply_bps_down(100); 54 | 55 | assert_eq!(result, Float::with_val(100, 99)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/traits/batch.rs: -------------------------------------------------------------------------------- 1 | use alloy::contract::{CallBuilder, SolCallBuilder}; 2 | use alloy::network::Network; 3 | use alloy::providers::Provider; 4 | use alloy::sol; 5 | use alloy::sol_types::SolCall; 6 | use alloy::transports::Transport; 7 | use alloy::network::TransactionBuilder; 8 | 9 | pub trait Batch: Sized { 10 | /// Batch a collection of calls using one of the available batching strategies. 11 | fn batch(self) -> BatchCall; 12 | } 13 | 14 | impl Batch for I 15 | where 16 | P: Provider, 17 | I: IntoIterator>, 18 | SC: SolCall, 19 | T: Transport + Clone, 20 | N: Network, 21 | { 22 | fn batch(self) -> BatchCall { 23 | BatchCall { calls: self } 24 | } 25 | } 26 | 27 | pub struct BatchCall { 28 | calls: I, 29 | } 30 | 31 | impl BatchCall 32 | where 33 | P: Provider, 34 | I: IntoIterator>, 35 | SC: SolCall, 36 | T: Transport + Clone, 37 | N: Network, 38 | { 39 | /// Note: https://github.com/rust-lang/rust/issues/110338 40 | /// 41 | /// You may need to collect your iterator before calling this function 42 | pub async fn call(self) -> Result, alloy::contract::Error> { 43 | let mut iter = self.calls.into_iter(); 44 | 45 | let Some(call) = iter.next() else { 46 | return Ok(vec![]); 47 | }; 48 | 49 | // todo: Clone because upstream stops us from taking both the provideer and the tx_req 50 | let tx_req = call.as_ref().clone(); 51 | 52 | let CallBuilder { provider, .. } = call; 53 | 54 | #[cfg(not(any(feature = "trace_callMany", feature = "eth_callMany")))] 55 | { 56 | use Multicall::{Call, MulticallInstance}; 57 | 58 | #[cfg(debug_assertions)] 59 | { 60 | let chain_id = provider.get_chain_id().await?; 61 | 62 | if !crate::constants::NETWORKS 63 | .get(&chain_id) 64 | .map(|c| c.supports_multicall) 65 | .unwrap_or(false) 66 | { 67 | tracing::error!("Chain does not support multicall, this call will fail"); 68 | } 69 | } 70 | 71 | let calls = std::iter::once(tx_req) 72 | .chain(iter.map(|c| c.into_transaction_request())) 73 | .map(|call| Call { 74 | target: call.to().unwrap_or_default(), 75 | callData: call.input().cloned().unwrap_or_default(), 76 | }) 77 | .collect::>(); 78 | 79 | let multicall = MulticallInstance::new(crate::constants::MULTICALL3, provider); 80 | 81 | let data = multicall.aggregate(calls).call().await?.returnData; 82 | 83 | return data 84 | .into_iter() 85 | .map(|d| SC::abi_decode_returns(&d, true).map_err(alloy::contract::Error::from)) 86 | .collect(); 87 | } 88 | 89 | #[cfg(feature = "trace_callMany")] 90 | { 91 | use alloy::providers::ext::TraceApi; 92 | use alloy::rpc::types::trace::parity::TraceType; 93 | 94 | let tt = vec![TraceType::Trace]; 95 | return provider 96 | .trace_call_many( 97 | std::iter::once(tx_req) 98 | .chain(iter.map(|call| call.into_transaction_request())) 99 | .map(|call| (call, tt.as_slice())) 100 | .collect::>() 101 | .as_slice(), 102 | ) 103 | .await 104 | .map_err(alloy::contract::Error::from)? 105 | .into_iter() 106 | .filter_map(|r| match SC::abi_decode_returns(&r.output, true).ok() { 107 | Some(o) => Some(Ok(o)), 108 | None => { 109 | tracing::error!("Failed to decode return value: {:?}", r.output); 110 | None 111 | } 112 | }) 113 | .collect(); 114 | } 115 | 116 | // todo: bundle is concrete over Eth::TxRequest 117 | // #[cfg(feature = "eth_callMany")] 118 | // { 119 | // use alloy::rpc::types::Bundle; 120 | // let bundle = Bundle { 121 | // transactions: std::iter::once(call) 122 | // .chain(iter.map(|call| call.into_transaction_request())) 123 | // .map(|call| call.into()) 124 | // .collect::>(), 125 | // block_override: None, 126 | // }; 127 | 128 | // return provider 129 | // .raw_request( 130 | // "eth_callMany".into(), 131 | // bundle 132 | // ) 133 | // .await 134 | // .map_err(alloy::contract::Error::from)? 135 | // .into_iter() 136 | // .map(|r| { 137 | // SC::abi_decode_returns(&r.output, true).map_err(alloy::contract::Error::from) 138 | // }) 139 | // .collect(); 140 | // } 141 | } 142 | 143 | pub fn map(self, f: F) -> MapCall 144 | where 145 | F: FnMut(SC::Return) -> R, 146 | { 147 | MapCall { batch: self, f } 148 | } 149 | } 150 | 151 | pub struct MapCall { 152 | batch: BatchCall, 153 | f: F, 154 | } 155 | 156 | impl MapCall 157 | where 158 | P: Provider, 159 | SC: SolCall, 160 | T: Transport + Clone, 161 | N: Network, 162 | I: IntoIterator>, 163 | F: FnMut(SC::Return) -> R, 164 | { 165 | pub async fn call(mut self) -> Result, alloy::contract::Error> { 166 | Ok(self 167 | .batch 168 | .call() 169 | .await? 170 | .into_iter() 171 | .map(|r| (self.f)(r)) 172 | .collect()) 173 | } 174 | } 175 | 176 | sol! { 177 | #[sol(rpc)] 178 | interface Multicall { 179 | struct Call { 180 | address target; 181 | bytes callData; 182 | } 183 | 184 | function aggregate(Call[] memory calls) external returns (uint256 blockNumber, bytes[] returnData); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/traits/float.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::Uint; 2 | use alloy::primitives::U256; 3 | use rug::ops::Pow; 4 | use rug::Float; 5 | 6 | lazy_static::lazy_static! { 7 | pub static ref U256_MAX: Float = Float::with_val(100, 2).pow(256); 8 | } 9 | 10 | pub trait IntoFloat { 11 | fn into_float(&self) -> Float; 12 | } 13 | 14 | impl IntoFloat for Uint { 15 | fn into_float(&self) -> Float { 16 | // safey: U256 is always a valid float 17 | let parse = Float::parse(self.to_string()).expect("Failed to parse U256 to Float"); 18 | 19 | Float::with_val(100, parse) 20 | } 21 | } 22 | 23 | impl IntoFloat for f64 { 24 | fn into_float(&self) -> Float { 25 | Float::with_val(100, *self) 26 | } 27 | } 28 | 29 | #[derive(Debug, thiserror::Error)] 30 | pub enum ConversionError { 31 | #[error("Value is negative")] 32 | ValueNegative, 33 | #[error("Value is too large")] 34 | ValueTooLarge, 35 | #[error("Value is NaN")] 36 | NaN, 37 | #[error("Value is infinite")] 38 | IsInfinte, 39 | } 40 | 41 | #[doc(hidden)] 42 | /// We want to impl TryFrom for U256 but orphan rule 43 | /// 44 | /// Makes the bounds nicer anyway 45 | pub trait IntoU256 { 46 | /// Converts a Float to a U256 47 | /// 48 | /// # Errors: 49 | /// - If the float is not a valid U256 50 | fn into_u256(&self) -> Result; 51 | } 52 | 53 | impl IntoU256 for Float { 54 | #[inline] 55 | fn into_u256(&self) -> Result { 56 | if self.is_infinite() { 57 | return Err(ConversionError::IsInfinte); 58 | } 59 | 60 | if self.is_nan() { 61 | return Err(ConversionError::NaN); 62 | } 63 | 64 | if self.is_sign_negative() { 65 | return Err(ConversionError::ValueNegative); 66 | } 67 | 68 | if self > &U256_MAX.clone() { 69 | return Err(ConversionError::ValueTooLarge); 70 | } 71 | 72 | // rounds floor 73 | let i = self 74 | .to_integer() 75 | .expect("Failed to convert Float to integer even though done our checks, this is a bug") 76 | .to_string(); 77 | 78 | Ok(U256::from_str_radix(&i, 10).expect( 79 | "Failed to convert Float to U256 even though weve done our checks, this is a bug", 80 | )) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | mod basis_points; 2 | pub use basis_points::ApplyBps; 3 | 4 | mod float; 5 | pub use float::IntoFloat; 6 | 7 | pub use float::{ConversionError, IntoU256}; 8 | 9 | mod batch; 10 | pub use batch::Batch; 11 | -------------------------------------------------------------------------------- /src/types/amount.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Add; 2 | use std::ops::AddAssign; 3 | 4 | use alloy::primitives::Address; 5 | use alloy::primitives::U256; 6 | use rug::ops::Pow; 7 | use rug::Float; 8 | 9 | use crate::traits::ApplyBps; 10 | use crate::traits::{ConversionError, IntoFloat, IntoU256}; 11 | use crate::TokenIdx; 12 | use crate::V3Pool; 13 | 14 | /// A token amount that belongs to a pool, with helpful display and conversion impls 15 | /// 16 | /// There are helpers for converting between human readable amounts and scaled amounts 17 | /// and display and debug implementations return the human readable amount 18 | /// 19 | /// # Scaling Assumption 20 | /// - PartialOrd & PartialEq with Self, [Float] and [U256] assuming theyre scaled 21 | /// - `Into` returns the scaled amounts 22 | /// - Add with [U256] and [rug::Float] are assumed to be scaled 23 | /// 24 | /// - PartialOrd & PartialEq with native types will scale the the values (u8, u16, u32, f16, f32) 25 | /// - Add and Sub with native types will scale the native types (u8, u16, u32, f16, f32) 26 | /// 27 | /// No guarntees the amount is in range 28 | pub struct TokenAmount<'a, P> { 29 | pool: &'a P, 30 | token: TokenIdx, 31 | amount: Float, 32 | } 33 | 34 | impl<'a, P> Clone for TokenAmount<'a, P> { 35 | fn clone(&self) -> Self { 36 | Self { 37 | pool: self.pool, 38 | token: self.token, 39 | amount: self.amount.clone(), 40 | } 41 | } 42 | } 43 | 44 | impl<'a, P: V3Pool> TokenAmount<'a, P> { 45 | #[inline] 46 | pub fn decimals(&self) -> &u8 { 47 | match self.token { 48 | TokenIdx::Zero => self.pool.token0_decimals(), 49 | TokenIdx::One => self.pool.token1_decimals(), 50 | } 51 | } 52 | 53 | #[inline] 54 | pub fn token(&self) -> &TokenIdx { 55 | &self.token 56 | } 57 | 58 | #[inline] 59 | pub fn token_address(&self) -> &Address { 60 | match self.token { 61 | TokenIdx::Zero => self.pool.token0(), 62 | TokenIdx::One => self.pool.token1(), 63 | } 64 | } 65 | 66 | #[inline] 67 | pub fn as_float(&self) -> &Float { 68 | &self.amount 69 | } 70 | 71 | #[inline] 72 | pub fn human_readable(&self) -> Float { 73 | Self::scale_down(self.pool, self.token, self.amount.clone()) 74 | } 75 | 76 | #[inline] 77 | /// Create a new TokenAmount with a zero amount 78 | pub fn zero(pool: &'a P, token: TokenIdx) -> Self { 79 | Self { 80 | pool, 81 | token, 82 | amount: Float::with_val(100, 0), 83 | } 84 | } 85 | 86 | #[inline] 87 | /// Create a token amount from a human readable amount 88 | pub fn from_human_readable(pool: &'a P, token: TokenIdx, amount: f64) -> Self { 89 | Self { 90 | pool, 91 | token, 92 | amount: Self::scale_up(pool, token, amount), 93 | } 94 | } 95 | 96 | /// Create a token amount from a scaled amount 97 | #[inline] 98 | pub fn from_scaled(pool: &'a P, token: TokenIdx, amount: Float) -> Self { 99 | Self { 100 | pool, 101 | token, 102 | amount, 103 | } 104 | } 105 | 106 | /// Scale up a human readable amount to a scaled amount 107 | #[inline] 108 | fn scale_up(pool: &P, token: TokenIdx, amount: f64) -> Float { 109 | let exp = match token { 110 | TokenIdx::Zero => pool.token0_decimals(), 111 | TokenIdx::One => pool.token1_decimals(), 112 | }; 113 | 114 | amount * Float::with_val(100, 10).pow(exp) 115 | } 116 | 117 | #[inline] 118 | fn scale_down(pool: &P, token: TokenIdx, amount: Float) -> Float { 119 | let exp = match token { 120 | TokenIdx::Zero => pool.token0_decimals(), 121 | TokenIdx::One => pool.token1_decimals(), 122 | }; 123 | 124 | amount / Float::with_val(100, 10).pow(exp) 125 | } 126 | } 127 | 128 | impl<'a, P> ApplyBps for TokenAmount<'a, P> { 129 | fn apply_bps_down(&self, bps: u16) -> Self { 130 | Self { 131 | amount: self.amount.apply_bps_down(bps), 132 | token: self.token, 133 | pool: self.pool, 134 | } 135 | } 136 | 137 | fn apply_bps_up(&self, bps: u16) -> Self { 138 | Self { 139 | amount: self.amount.apply_bps_up(bps), 140 | token: self.token, 141 | pool: self.pool, 142 | } 143 | } 144 | } 145 | 146 | impl<'a, P> IntoU256 for TokenAmount<'a, P> { 147 | fn into_u256(&self) -> Result { 148 | self.amount.into_u256() 149 | } 150 | } 151 | 152 | impl<'a, P> From> for Float { 153 | fn from(amount: TokenAmount<'a, P>) -> Self { 154 | amount.amount 155 | } 156 | } 157 | 158 | impl<'a, P> Add for TokenAmount<'a, P> { 159 | type Output = Self; 160 | 161 | fn add(self, rhs: Float) -> Self::Output { 162 | Self { 163 | amount: self.amount + rhs, 164 | token: self.token, 165 | pool: self.pool, 166 | } 167 | } 168 | } 169 | 170 | impl<'a, P> Add> for Float { 171 | type Output = TokenAmount<'a, P>; 172 | 173 | fn add(self, rhs: TokenAmount<'a, P>) -> Self::Output { 174 | rhs + self 175 | } 176 | } 177 | 178 | impl<'a, P> Add for TokenAmount<'a, P> { 179 | type Output = Self; 180 | 181 | fn add(self, rhs: U256) -> Self::Output { 182 | Self { 183 | amount: self.amount + rhs.into_float(), 184 | token: self.token, 185 | pool: self.pool, 186 | } 187 | } 188 | } 189 | 190 | impl<'a, P> Add> for U256 { 191 | type Output = TokenAmount<'a, P>; 192 | 193 | fn add(self, rhs: TokenAmount<'a, P>) -> Self::Output { 194 | TokenAmount { 195 | amount: self.into_float() + rhs.amount, 196 | token: rhs.token, 197 | pool: rhs.pool, 198 | } 199 | } 200 | } 201 | 202 | impl<'a, P> AddAssign for TokenAmount<'a, P> { 203 | fn add_assign(&mut self, rhs: Float) { 204 | self.amount += rhs; 205 | } 206 | } 207 | 208 | impl<'a, P> AddAssign<&Float> for TokenAmount<'a, P> { 209 | fn add_assign(&mut self, rhs: &Float) { 210 | self.amount += rhs; 211 | } 212 | } 213 | 214 | impl<'a, P> AddAssign for TokenAmount<'a, P> { 215 | fn add_assign(&mut self, rhs: U256) { 216 | self.amount += rhs.into_float(); 217 | } 218 | } 219 | 220 | // Float and U256 implementations 221 | 222 | impl<'a, P> PartialEq for TokenAmount<'a, P> { 223 | fn eq(&self, other: &Float) -> bool { 224 | self.amount.eq(other) 225 | } 226 | } 227 | 228 | impl<'a, P> PartialEq> for Float { 229 | fn eq(&self, other: &TokenAmount<'a, P>) -> bool { 230 | self.eq(&other.amount) 231 | } 232 | } 233 | 234 | impl<'a, P> PartialOrd for TokenAmount<'a, P> { 235 | fn partial_cmp(&self, other: &Float) -> Option { 236 | self.amount.partial_cmp(other) 237 | } 238 | } 239 | 240 | impl<'a, P> PartialOrd> for Float { 241 | fn partial_cmp(&self, other: &TokenAmount<'a, P>) -> Option { 242 | self.partial_cmp(&other.amount) 243 | } 244 | } 245 | 246 | impl<'a, P> PartialEq for TokenAmount<'a, P> { 247 | fn eq(&self, other: &U256) -> bool { 248 | self.amount.eq(&other.into_float()) 249 | } 250 | } 251 | 252 | impl<'a, P> PartialEq> for U256 { 253 | fn eq(&self, other: &TokenAmount<'a, P>) -> bool { 254 | self.into_float().eq(&other.amount) 255 | } 256 | } 257 | 258 | impl<'a, P> PartialOrd for TokenAmount<'a, P> { 259 | fn partial_cmp(&self, other: &U256) -> Option { 260 | self.amount.partial_cmp(&other.into_float()) 261 | } 262 | } 263 | 264 | impl<'a, P> PartialOrd> for U256 { 265 | fn partial_cmp(&self, other: &TokenAmount<'a, P>) -> Option { 266 | self.into_float().partial_cmp(&other.amount) 267 | } 268 | } 269 | 270 | pub trait IntoTokenAmount<'a, P: V3Pool> { 271 | fn into_token_amount(self, pool: &'a P, token: TokenIdx) -> TokenAmount<'a, P>; 272 | } 273 | 274 | impl<'a, P: V3Pool> IntoTokenAmount<'a, P> for TokenAmount<'a, P> { 275 | #[inline] 276 | fn into_token_amount(self, _pool: &'a P, _token: TokenIdx) -> TokenAmount<'a, P> { 277 | self 278 | } 279 | } 280 | 281 | impl<'a, P: V3Pool> IntoTokenAmount<'a, P> for Float { 282 | fn into_token_amount(self, pool: &'a P, token: TokenIdx) -> TokenAmount<'a, P> { 283 | TokenAmount::from_scaled(pool, token, self) 284 | } 285 | } 286 | 287 | impl<'a, P: V3Pool> IntoTokenAmount<'a, P> for U256 { 288 | fn into_token_amount(self, pool: &'a P, token: TokenIdx) -> TokenAmount<'a, P> { 289 | TokenAmount::from_scaled(pool, token, self.into_float()) 290 | } 291 | } 292 | 293 | // Implementations for native types that scales them during ops 294 | impl_token_amount_cmp_eq_native!(TokenAmount); 295 | 296 | impl<'a, P: V3Pool> std::fmt::Display for TokenAmount<'a, P> { 297 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 298 | write!(f, "{}", self.human_readable()) 299 | } 300 | } 301 | 302 | impl<'a, P: V3Pool> std::fmt::Debug for TokenAmount<'a, P> { 303 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 304 | let token = match self.token { 305 | TokenIdx::Zero => self.pool.token0(), 306 | TokenIdx::One => self.pool.token1(), 307 | }; 308 | 309 | f.debug_struct("TokenAmount") 310 | .field("raw", self.as_float()) 311 | .field("human_readable", &self.human_readable()) 312 | .field("token", token) 313 | .finish() 314 | } 315 | } 316 | 317 | #[cfg(test)] 318 | mod test { 319 | use super::TokenAmount; 320 | use crate::TokenIdx; 321 | use alloy::primitives::Address; 322 | use alloy::primitives::U256; 323 | use rug::ops::Pow; 324 | use rug::Float; 325 | 326 | use crate::types::tests::MockPool; 327 | 328 | #[test] 329 | fn test_eq_float() { 330 | let pool = MockPool { 331 | token0: Address::ZERO, 332 | token1: Address::ZERO, 333 | token0_decimals: 18, 334 | token1_decimals: 18, 335 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 336 | }; 337 | 338 | let amount = TokenAmount::from_scaled(&pool, TokenIdx::Zero, Float::with_val(100, 100)); 339 | let amount2 = Float::with_val(100, 100); 340 | 341 | assert_eq!(amount, amount2); 342 | } 343 | 344 | #[test] 345 | fn test_eq_u256() { 346 | let pool = MockPool { 347 | token0: Address::ZERO, 348 | token1: Address::ZERO, 349 | token0_decimals: 18, 350 | token1_decimals: 18, 351 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 352 | }; 353 | 354 | let amount = TokenAmount::from_scaled(&pool, TokenIdx::Zero, Float::with_val(100, 100)); 355 | let amount2 = U256::from(100); 356 | 357 | assert_eq!(amount, amount2); 358 | } 359 | 360 | #[test] 361 | fn test_cmp_float() { 362 | let pool = MockPool { 363 | token0: Address::ZERO, 364 | token1: Address::ZERO, 365 | token0_decimals: 18, 366 | token1_decimals: 18, 367 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 368 | }; 369 | 370 | let amount = TokenAmount::from_scaled(&pool, TokenIdx::Zero, Float::with_val(100, 100)); 371 | let amount2 = Float::with_val(100, 99); 372 | 373 | assert!(amount > amount2); 374 | assert!(amount2 < amount); 375 | } 376 | 377 | #[test] 378 | fn test_cmp_u256() { 379 | let pool = MockPool { 380 | token0: Address::ZERO, 381 | token1: Address::ZERO, 382 | token0_decimals: 18, 383 | token1_decimals: 18, 384 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 385 | }; 386 | 387 | let amount = TokenAmount::from_scaled(&pool, TokenIdx::Zero, Float::with_val(100, 100)); 388 | let amount2 = U256::from(99); 389 | 390 | assert!(amount > amount2); 391 | assert!(amount2 < amount); 392 | } 393 | 394 | #[test] 395 | fn test_eq_native_u8() { 396 | let pool = MockPool { 397 | token0: Address::ZERO, 398 | token1: Address::ZERO, 399 | token0_decimals: 18, 400 | token1_decimals: 18, 401 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 402 | }; 403 | 404 | let amount = 100_u8; 405 | let token_amount = TokenAmount::from_human_readable(&pool, TokenIdx::Zero, amount.into()); 406 | 407 | assert_eq!(amount, token_amount); 408 | } 409 | 410 | #[test] 411 | fn test_eq_native_f64() { 412 | let pool = MockPool { 413 | token0: Address::ZERO, 414 | token1: Address::ZERO, 415 | token0_decimals: 18, 416 | token1_decimals: 18, 417 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 418 | }; 419 | 420 | let amount = 100.0; 421 | let token_amount = TokenAmount::from_human_readable(&pool, TokenIdx::Zero, amount); 422 | 423 | assert_eq!(amount, token_amount); 424 | } 425 | 426 | #[test] 427 | fn test_returns_scaled_version() { 428 | let pool = MockPool { 429 | token0: Address::ZERO, 430 | token1: Address::ZERO, 431 | token0_decimals: 18, 432 | token1_decimals: 18, 433 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 434 | }; 435 | 436 | let scalar = Float::with_val(100, 10).pow(18); 437 | 438 | let amount = TokenAmount::from_human_readable(&pool, TokenIdx::Zero, 100.0); 439 | let scaled = amount.as_float(); 440 | 441 | assert_eq!(*scaled, Float::with_val(100, 100) * scalar); 442 | } 443 | 444 | #[test] 445 | fn test_add_float() { 446 | let pool = MockPool { 447 | token0: Address::ZERO, 448 | token1: Address::ZERO, 449 | token0_decimals: 18, 450 | token1_decimals: 18, 451 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 452 | }; 453 | 454 | let amount = TokenAmount::from_scaled(&pool, TokenIdx::Zero, Float::with_val(100, 100)); 455 | let result = amount + Float::with_val(100, 100); 456 | 457 | assert_eq!(result, Float::with_val(10, 200)); 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /src/types/deltas.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Formatter; 2 | 3 | use rug::Float; 4 | 5 | use crate::math::swap::{token0_delta, token1_delta}; 6 | use crate::math::SqrtPrice; 7 | use crate::types::amount::TokenAmount; 8 | use crate::V3Pool; 9 | 10 | /// The change change in token of a pool because of some operation 11 | #[derive(Clone)] 12 | pub struct Deltas<'a, P: V3Pool> { 13 | pool: &'a P, 14 | pub token0_amount: TokenAmount<'a, P>, 15 | pub token1_amount: TokenAmount<'a, P>, 16 | } 17 | 18 | impl<'a, P: V3Pool> std::fmt::Debug for Deltas<'a, P> { 19 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 20 | f.debug_struct("Deltas") 21 | .field("token0_amount", &self.token0_amount) 22 | .field("token1_amount", &self.token1_amount) 23 | .finish() 24 | } 25 | } 26 | 27 | impl<'a, P: V3Pool> Deltas<'a, P> { 28 | pub fn token0_amount(&self) -> &TokenAmount

{ 29 | &self.token0_amount 30 | } 31 | 32 | pub fn token1_amount(&self) -> &TokenAmount

{ 33 | &self.token1_amount 34 | } 35 | 36 | pub fn new(pool: &'a P) -> Self { 37 | Self { 38 | pool, 39 | token0_amount: TokenAmount::zero(pool, super::Token::Zero), 40 | token1_amount: TokenAmount::zero(pool, super::Token::One), 41 | } 42 | } 43 | 44 | pub fn update(&mut self, liquidity: Float, sqrt_price: SqrtPrice, target_price: SqrtPrice) { 45 | tracing::trace!( 46 | "updating deltas with liquidity: {}, sqrt_price: {}, target_price: {}", 47 | liquidity, 48 | sqrt_price, 49 | target_price 50 | ); 51 | 52 | self.token0_amount += 53 | token0_delta(sqrt_price.clone(), target_price.clone(), liquidity.clone()); 54 | 55 | self.token1_amount += token1_delta(sqrt_price, target_price, liquidity); 56 | } 57 | 58 | /// Returns the additional amount of tokens you would need to add to your swap to cover the fee 59 | /// 60 | /// Returns None if any amount is zero 61 | pub fn fee_amount(&self) -> TokenAmount

{ 62 | let token1_amount = self.token1_amount.as_float(); 63 | let token0_amount = self.token0_amount.as_float(); 64 | 65 | if token0_amount.is_zero() || token1_amount.is_zero() { 66 | tracing::warn!("got a zero token trade"); 67 | return TokenAmount::zero(self.pool, super::Token::Zero); 68 | } 69 | 70 | let fee = Float::with_val(100, self.pool.fee().to::()); 71 | let fee = fee / 1e6; 72 | let decay = 1 - fee; 73 | 74 | // The positive amount is the amount coming into the pool 75 | match ( 76 | token0_amount.is_sign_negative(), 77 | token1_amount.is_sign_negative(), 78 | ) { 79 | (true, false) => TokenAmount::from_scaled( 80 | self.pool, 81 | super::Token::One, 82 | token1_amount.clone() / decay, 83 | ), 84 | (false, true) => TokenAmount::from_scaled( 85 | self.pool, 86 | super::Token::Zero, 87 | token0_amount.clone() / decay, 88 | ), 89 | (_, _) => unreachable!("Got two non zero same sign deltas, this is a bug"), 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::{uint, Uint}; 2 | 3 | mod amount; 4 | mod deltas; 5 | mod price; 6 | 7 | pub use amount::*; 8 | pub use deltas::*; 9 | pub use price::*; 10 | 11 | /// The index of the token in the pool 12 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 13 | pub enum Token { 14 | Zero, 15 | One, 16 | } 17 | 18 | /// The fee tier for the pool 19 | #[derive(Debug, Clone, Copy)] 20 | pub enum FeeTier { 21 | /// Added after by governance = 1 bps 22 | Lowest, 23 | Min, 24 | Mid, 25 | Max, 26 | } 27 | 28 | impl FeeTier { 29 | /// Big endian representation of the fee tier 30 | /// used for encoding paths 31 | pub const fn as_u24_bytes(&self) -> [u8; 3] { 32 | self.as_scaled_bp().to_be_bytes() 33 | } 34 | 35 | pub const fn as_spacing(&self) -> TickSpacing { 36 | match self { 37 | FeeTier::Lowest => TickSpacing::Lowest, 38 | FeeTier::Min => TickSpacing::Min, 39 | FeeTier::Mid => TickSpacing::Mid, 40 | FeeTier::Max => TickSpacing::Max, 41 | } 42 | } 43 | 44 | pub const fn as_bp(&self) -> u16 { 45 | match self { 46 | FeeTier::Lowest => 1, 47 | FeeTier::Min => 5, 48 | FeeTier::Mid => 30, 49 | FeeTier::Max => 100, 50 | } 51 | } 52 | 53 | pub const fn as_scaled_bp(&self) -> Uint<24, 1> { 54 | match self { 55 | FeeTier::Lowest => uint!(100_U24), 56 | FeeTier::Min => uint!(500_U24), 57 | FeeTier::Mid => uint!(3000_U24), 58 | FeeTier::Max => uint!(10000_U24), 59 | } 60 | } 61 | } 62 | 63 | #[derive(Debug, Clone, Copy)] 64 | pub enum TickSpacing { 65 | /// Added after by governance = 1 bps 66 | Lowest = 1, 67 | Min = 10, 68 | Mid = 60, 69 | Max = 200, 70 | } 71 | 72 | impl TickSpacing { 73 | pub const fn as_fee(tick_spacing: TickSpacing) -> FeeTier { 74 | match tick_spacing { 75 | TickSpacing::Lowest => FeeTier::Lowest, 76 | TickSpacing::Min => FeeTier::Min, 77 | TickSpacing::Mid => FeeTier::Mid, 78 | TickSpacing::Max => FeeTier::Max, 79 | } 80 | } 81 | } 82 | 83 | #[cfg(test)] 84 | mod tests { 85 | use crate::{math::Tick, PoolResult}; 86 | use alloy::primitives::Address; 87 | use rug::Float; 88 | use std::convert::Infallible; 89 | 90 | pub(crate) struct MockPool { 91 | pub token0: Address, 92 | pub token1: Address, 93 | pub token0_decimals: u8, 94 | pub token1_decimals: u8, 95 | pub fee: alloy::primitives::Uint<24, 1>, 96 | } 97 | 98 | #[async_trait::async_trait] 99 | impl crate::V3Pool for MockPool { 100 | type BackendError = Infallible; 101 | 102 | fn token0(&self) -> &Address { 103 | &self.token0 104 | } 105 | 106 | fn token0_decimals(&self) -> &u8 { 107 | &self.token0_decimals 108 | } 109 | 110 | fn token1(&self) -> &Address { 111 | &self.token1 112 | } 113 | 114 | fn token1_decimals(&self) -> &u8 { 115 | &self.token1_decimals 116 | } 117 | 118 | fn fee(&self) -> alloy::primitives::Uint<24, 1> { 119 | self.fee 120 | } 121 | 122 | fn tick_spacing(&self) -> alloy::primitives::Signed<24, 1> { 123 | alloy::primitives::Signed::<24, 1>::ZERO 124 | } 125 | 126 | fn address(&self) -> Address { 127 | Address::ZERO 128 | } 129 | 130 | async fn current_liquidity(&self) -> PoolResult { 131 | Ok(Float::with_val(100, 100)) 132 | } 133 | 134 | async fn sqrt_price_x96(&self) -> PoolResult { 135 | Ok(Float::with_val(100, 100)) 136 | } 137 | 138 | async fn tick(&self, _tick: Tick) -> PoolResult { 139 | Ok(Float::with_val(100, 100)) 140 | } 141 | 142 | async fn tick_range( 143 | &self, 144 | _starting: Tick, 145 | _ending: Tick, 146 | ) -> PoolResult, Self::BackendError> { 147 | Ok(vec![]) 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/types/price.rs: -------------------------------------------------------------------------------- 1 | use rug::ops::Pow; 2 | use rug::Float; 3 | 4 | use super::Token; 5 | use crate::math::BoundsError; 6 | use crate::math::Price; 7 | use crate::V3Pool; 8 | use alloy::primitives::U256; 9 | 10 | /// Display and Debug implementations return the human readable price in the form the user selected at creation 11 | /// and there are helpers for converting between human readable prices and scaled prices 12 | /// 13 | /// ## Comparions 14 | /// A pool price should be [Self::human_readble] to remove the decimals and this will be the human readable price 15 | /// 16 | /// ## Conversions 17 | /// - all Into implementations will return the scaled price accounting for the internal decimals of the pool 18 | /// - if you want the human readable price use [PoolPrice::human_readble] 19 | pub struct PoolPrice<'a, P> { 20 | /// The token you want the price to be formatted as 21 | numeraire: Token, 22 | 23 | /// the price of token0 in terms of token1, accounting for the decimals of the pool 24 | price: Price, 25 | 26 | /// the pool that this price is for 27 | pool: &'a P, 28 | } 29 | 30 | impl<'a, P> Clone for PoolPrice<'a, P> { 31 | fn clone(&self) -> Self { 32 | Self { 33 | price: self.price.clone(), 34 | pool: self.pool, 35 | numeraire: self.numeraire, 36 | } 37 | } 38 | } 39 | 40 | impl<'a, P: V3Pool> PoolPrice<'a, P> { 41 | /// Create a new pool price from this Price wrapper. 42 | /// 43 | /// # Arguments 44 | /// The price of token0 in terms of token1, and the denomination to format the price in 45 | pub(crate) fn from_price(pool: &'a P, price: Price, numeraire: Token) -> Self { 46 | Self { 47 | price, 48 | pool, 49 | numeraire, 50 | } 51 | } 52 | 53 | /// The quote token (numeraire) of this price 54 | pub fn quote(&self) -> &Token { 55 | &self.numeraire 56 | } 57 | 58 | /// Converts a (normalized) human readable price into a pool price 59 | pub fn from_human_readable( 60 | pool: &'a P, 61 | price: Float, 62 | numeraire: Token, 63 | ) -> Result { 64 | match numeraire { 65 | Token::One => Ok(Self { 66 | price: Price::new(scale_up(pool, price))?, 67 | pool, 68 | numeraire, 69 | }), 70 | Token::Zero => Ok(Self { 71 | price: Price::new(scale_up(pool, price.recip()))?, 72 | pool, 73 | numeraire, 74 | }), 75 | } 76 | } 77 | 78 | /// Remove scalar decimals from the price 79 | /// 80 | /// In other words this is the human readable price 81 | pub fn human_readable(&self) -> Float { 82 | match self.numeraire { 83 | Token::One => self.scale_down(), 84 | Token::Zero => self.scale_down().recip(), 85 | } 86 | } 87 | } 88 | 89 | impl<'a, P: V3Pool> PoolPrice<'a, P> { 90 | /// Probaly only useful for formatting 91 | /// 92 | /// Remove the internal decimals from the price 93 | fn scale_down(&self) -> Float { 94 | scale_down(self.pool, self.price.clone().into()) 95 | } 96 | } 97 | 98 | fn scale_up(pool: &P, val: Float) -> Float { 99 | let exp = *pool.token1_decimals() as i16 - *pool.token0_decimals() as i16; 100 | 101 | val * Float::with_val(100, 10).pow(exp) 102 | } 103 | 104 | fn scale_down(pool: &P, val: Float) -> Float { 105 | let exp = *pool.token0_decimals() as i16 - *pool.token1_decimals() as i16; 106 | 107 | val * Float::with_val(100, 10).pow(exp) 108 | } 109 | 110 | impl<'a, P> From> for Price { 111 | fn from(price: PoolPrice<'a, P>) -> Self { 112 | price.price 113 | } 114 | } 115 | 116 | impl<'a, P> From> for Float { 117 | fn from(price: PoolPrice<'a, P>) -> Self { 118 | price.price.into() 119 | } 120 | } 121 | 122 | impl<'a, P> From> for U256 { 123 | fn from(price: PoolPrice<'a, P>) -> Self { 124 | price.price.into() 125 | } 126 | } 127 | 128 | impl<'a, P: V3Pool> std::fmt::Display for PoolPrice<'a, P> { 129 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 130 | write!(f, "{}", self.human_readable()) 131 | } 132 | } 133 | 134 | impl<'a, P: V3Pool> std::fmt::Debug for PoolPrice<'a, P> { 135 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 136 | f.debug_struct("PoolPrice") 137 | .field("raw", &self.price) 138 | .field("human_readable", &self.human_readable()) 139 | .field("token0", &self.pool.token0()) 140 | .field("token1", &self.pool.token1()) 141 | .field("token0_decimals", &self.pool.token0_decimals()) 142 | .field("token1_decimals", &self.pool.token1_decimals()) 143 | .field("numeraire", &self.numeraire) 144 | .finish() 145 | } 146 | } 147 | 148 | #[cfg(test)] 149 | mod test { 150 | use crate::types::tests::MockPool; 151 | use rug::ops::Pow; 152 | 153 | #[test] 154 | fn test_price_scaled_as_expected() { 155 | let pool = MockPool { 156 | token0: Default::default(), 157 | token1: Default::default(), 158 | token0_decimals: 4, 159 | token1_decimals: 10, 160 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 161 | }; 162 | 163 | let price = rug::Float::with_val(100, 100); 164 | let pool_price = crate::types::price::PoolPrice::from_human_readable( 165 | &pool, 166 | price.clone(), 167 | crate::types::Token::One, 168 | ) 169 | .unwrap(); 170 | 171 | println!("{:?}", rug::Float::from(pool_price.clone()).to_string()); 172 | assert_eq!( 173 | rug::Float::from(pool_price), 174 | price * rug::Float::with_val(100, 10).pow(6) 175 | ); 176 | } 177 | 178 | #[test] 179 | fn test_price_round_trip() { 180 | let pool = MockPool { 181 | token0: Default::default(), 182 | token1: Default::default(), 183 | token0_decimals: 5, 184 | token1_decimals: 10, 185 | fee: alloy::primitives::Uint::<24, 1>::from(3000), 186 | }; 187 | 188 | let price = rug::Float::with_val(100, 100); 189 | let pool_price = crate::types::price::PoolPrice::from_human_readable( 190 | &pool, 191 | price.clone(), 192 | crate::types::Token::One, 193 | ) 194 | .unwrap(); 195 | 196 | assert_eq!(pool_price.human_readable(), price); 197 | } 198 | } 199 | --------------------------------------------------------------------------------