feat: Implement UniswapV4 Native integration (#125)

* feat: initial data structure + ABI & buf models

* feat: initial modules: identify new pools and events

* feat: map liquidity and balance changes, introduce balance delta calculation from liquidity

* feat: map tick deltas

* chore: undo weird formatting

* chore: undo weird formatting

* feat: map fee changes and aggregate data to final block structure

* feat: reimplement math natively, remove alloy and univ3sdk dependencies

* chore: make clippy happy + misc improvements

* chore: add rust generated files from buf & ABI

* chore: make clippy happy

* feat: add all modules to ethereum-uniswap-v4.yaml

* chore: update yaml file to skip unnecessary buf paths

* fix: update pb mod.rs

* fix: fix hex / utf-8 encoding. working version

* fix: simplify error handling, rename yaml file to match chain & formatting

* fix: fix ChangeType for sqrt_price_x96 on Initialization

* fix: make fee a non-static attribute

* fix: add balance_owner to univ4 pool

* feat: add uniswap-v4 mainnet yaml

* fix(uniswap-v4): miscellaneous fixes for UniswapV4 (#147)

* fix(uniswap-v4): correctly decode swap event deltas.

Deltas are given from a user debt perspective by the event (negative if received by the pool, positive if sent by the pool). In our usecase we need the opposite of this. This commit uses `.neg()` on the amount to apply them correctly.

* fix(uniswap-v4): correctly compute token amounts.

We were using `get_sqrt_ratio_at_tick` at the current tick to compute the amounts. This was incorrect because it provides the price at the tick boundary, but we might be mid-tick, which could lead to erroneous balances.

We now track the current price (updated by `initialization` and `swap` events) and use it when calculating the amounts.

* fix(uniswapv4): do not account for fees in swaps.

Previously we were adding fees as balances. But they are actually not part of the TVL and we aren't accounting for fees in the position changes (withdrawals). This commit addresses this and remove the fees from the token balances.

* refactor: fix pb mod.rs

* refactor: bump version and update sepolia config

* ci: make clippy happy

* refactor: clean unimath tests

* refactor: make logic clearer and improve docstrings

---------

Co-authored-by: zizou <111426680+flopell@users.noreply.github.com>

---------

Co-authored-by: Zizou <111426680+zizou0x@users.noreply.github.com>
Co-authored-by: zizou <111426680+flopell@users.noreply.github.com>
This commit is contained in:
tvinagre
2025-02-05 10:19:09 -03:00
committed by GitHub
parent e413284017
commit af8643ecb4
27 changed files with 9544 additions and 151 deletions

495
substreams/Cargo.lock generated
View File

@@ -4,30 +4,30 @@ version = 4
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.81" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.4" version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "base64" name = "base64"
@@ -48,9 +48,9 @@ dependencies = [
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.2" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "bitvec" name = "bitvec"
@@ -87,9 +87,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.5.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -99,9 +99,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.12" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -140,9 +140,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]] [[package]]
name = "either" name = "either"
version = "1.10.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
@@ -152,9 +152,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.8" version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys",
@@ -173,7 +173,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha3", "sha3",
"thiserror", "thiserror 1.0.69",
"uint", "uint",
] ]
@@ -190,7 +190,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha3", "sha3",
"thiserror", "thiserror 1.0.69",
"uint", "uint",
] ]
@@ -367,11 +367,32 @@ dependencies = [
"tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)",
] ]
[[package]]
name = "ethereum-uniswap-v4"
version = "0.1.1"
dependencies = [
"anyhow",
"ethabi 18.0.0",
"getrandom",
"hex",
"hex-literal 0.4.1",
"itertools 0.13.0",
"num-bigint",
"prost 0.11.9",
"rstest",
"substreams",
"substreams-entity-change",
"substreams-ethereum",
"substreams-helper 0.0.2 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)",
"tiny-keccak",
"tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)",
]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.0.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]] [[package]]
name = "fixed-hash" name = "fixed-hash"
@@ -409,6 +430,49 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-timer"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@@ -421,9 +485,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.12" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -431,10 +495,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "hashbrown" name = "glob"
version = "0.14.3" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -462,9 +532,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
[[package]] [[package]]
name = "home" name = "home"
version = "0.5.9" version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [ dependencies = [
"windows-sys", "windows-sys",
] ]
@@ -507,20 +577,20 @@ dependencies = [
[[package]] [[package]]
name = "impl-trait-for-tuples" name = "impl-trait-for-tuples"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.90",
] ]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.2.5" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@@ -555,9 +625,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]] [[package]]
name = "keccak" name = "keccak"
@@ -570,33 +640,33 @@ dependencies = [
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.13" version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.21" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.1" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "multimap" name = "multimap"
@@ -606,11 +676,10 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.4" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [ dependencies = [
"autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
@@ -626,18 +695,18 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.18" version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "pad" name = "pad"
@@ -650,9 +719,9 @@ dependencies = [
[[package]] [[package]]
name = "parity-scale-codec" name = "parity-scale-codec"
version = "3.6.9" version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitvec", "bitvec",
@@ -664,9 +733,9 @@ dependencies = [
[[package]] [[package]]
name = "parity-scale-codec-derive" name = "parity-scale-codec-derive"
version = "3.6.9" version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@@ -682,20 +751,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.7.14" version = "2.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
dependencies = [ dependencies = [
"memchr", "memchr",
"thiserror", "thiserror 2.0.7",
"ucd-trie", "ucd-trie",
] ]
[[package]] [[package]]
name = "pest_derive" name = "pest_derive"
version = "2.7.14" version = "2.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
dependencies = [ dependencies = [
"pest", "pest",
"pest_generator", "pest_generator",
@@ -703,22 +772,22 @@ dependencies = [
[[package]] [[package]]
name = "pest_generator" name = "pest_generator"
version = "2.7.14" version = "2.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.52", "syn 2.0.90",
] ]
[[package]] [[package]]
name = "pest_meta" name = "pest_meta"
version = "2.7.14" version = "2.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"pest", "pest",
@@ -727,19 +796,34 @@ dependencies = [
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.6.4" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [ dependencies = [
"fixedbitset", "fixedbitset",
"indexmap", "indexmap",
] ]
[[package]] [[package]]
name = "ppv-lite86" name = "pin-project-lite"
version = "0.2.17" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "prettyplease" name = "prettyplease"
@@ -779,19 +863,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "2.0.2" version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
dependencies = [ dependencies = [
"toml_datetime",
"toml_edit", "toml_edit",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.79" version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -861,7 +944,7 @@ dependencies = [
"itertools 0.12.1", "itertools 0.12.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.52", "syn 2.0.90",
] ]
[[package]] [[package]]
@@ -884,9 +967,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -929,9 +1012,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.4" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -941,9 +1024,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.6" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -952,9 +1035,15 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.2" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "relative-path"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
[[package]] [[package]]
name = "rlp" name = "rlp"
@@ -966,6 +1055,36 @@ dependencies = [
"rustc-hex", "rustc-hex",
] ]
[[package]]
name = "rstest"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e905296805ab93e13c1ec3a03f4b6c4f35e9498a3d5fa96dc626d22c03cd89"
dependencies = [
"futures-timer",
"futures-util",
"rstest_macros",
"rustc_version",
]
[[package]]
name = "rstest_macros"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef0053bbffce09062bee4bcc499b0fbe7a57b879f1efe088d6d8d4c7adcdef9b"
dependencies = [
"cfg-if",
"glob",
"proc-macro-crate",
"proc-macro2",
"quote",
"regex",
"relative-path",
"rustc_version",
"syn 2.0.90",
"unicode-ident",
]
[[package]] [[package]]
name = "rustc-hex" name = "rustc-hex"
version = "2.1.0" version = "2.1.0"
@@ -973,10 +1092,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
[[package]] [[package]]
name = "rustix" name = "rustc_version"
version = "0.38.31" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@@ -987,37 +1115,44 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "semver"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.204" version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.204" version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.52", "syn 2.0.90",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.120" version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr",
"ryu", "ryu",
"serde", "serde",
] ]
@@ -1030,7 +1165,7 @@ checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6"
dependencies = [ dependencies = [
"percent-encoding", "percent-encoding",
"serde", "serde",
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@@ -1054,6 +1189,15 @@ dependencies = [
"keccak", "keccak",
] ]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@@ -1080,7 +1224,7 @@ dependencies = [
"prost-build", "prost-build",
"prost-types 0.11.9", "prost-types 0.11.9",
"substreams-macro", "substreams-macro",
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@@ -1097,9 +1241,9 @@ dependencies = [
[[package]] [[package]]
name = "substreams-ethereum" name = "substreams-ethereum"
version = "0.9.9" version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" checksum = "3d033738be190ad9c9a63712cf121e4f33ae9c57845c64021e421c45aac688b5"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"num-bigint", "num-bigint",
@@ -1111,9 +1255,9 @@ dependencies = [
[[package]] [[package]]
name = "substreams-ethereum-abigen" name = "substreams-ethereum-abigen"
version = "0.9.9" version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" checksum = "27ef0adda971fbbd085545e73ccd7efbc12e31139cd301252f478e6b9743ff65"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ethabi 17.2.0", "ethabi 17.2.0",
@@ -1146,9 +1290,9 @@ dependencies = [
[[package]] [[package]]
name = "substreams-ethereum-core" name = "substreams-ethereum-core"
version = "0.9.9" version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" checksum = "0a38e740018de8c2453f08621bab84ac55b0f1bfd42d56cf8b43ad340e670862"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"ethabi 17.2.0", "ethabi 17.2.0",
@@ -1162,9 +1306,9 @@ dependencies = [
[[package]] [[package]]
name = "substreams-ethereum-derive" name = "substreams-ethereum-derive"
version = "0.9.9" version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" checksum = "55c934c70e6ab1fe11a89f401f36e7d9be3fe087687395767a4c13ab3d6bd055"
dependencies = [ dependencies = [
"ethabi 17.2.0", "ethabi 17.2.0",
"heck", "heck",
@@ -1213,7 +1357,7 @@ dependencies = [
"substreams", "substreams",
"substreams-entity-change", "substreams-entity-change",
"substreams-ethereum", "substreams-ethereum",
"thiserror", "thiserror 1.0.69",
"tiny-keccak", "tiny-keccak",
] ]
@@ -1236,7 +1380,7 @@ dependencies = [
"substreams", "substreams",
"substreams-entity-change", "substreams-entity-change",
"substreams-ethereum", "substreams-ethereum",
"thiserror", "thiserror 1.0.69",
"tiny-keccak", "tiny-keccak",
] ]
@@ -1249,7 +1393,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@@ -1265,9 +1409,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.52" version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1282,34 +1426,55 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.1" version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"once_cell",
"rustix", "rustix",
"windows-sys", "windows-sys",
] ]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.58" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767"
dependencies = [
"thiserror-impl 2.0.7",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.58" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.52", "syn 2.0.90",
]
[[package]]
name = "thiserror-impl"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
] ]
[[package]] [[package]]
@@ -1323,15 +1488,15 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.3" version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.20.2" version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"toml_datetime", "toml_datetime",
@@ -1411,21 +1576,21 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.11" version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasi" name = "wasi"
@@ -1447,22 +1612,23 @@ dependencies = [
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
"windows_i686_gnu", "windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc",
"windows_x86_64_gnu", "windows_x86_64_gnu",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm",
@@ -1471,51 +1637,57 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.4" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.40" version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@@ -1528,3 +1700,24 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [ dependencies = [
"tap", "tap",
] ]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]

View File

@@ -10,6 +10,7 @@ members = [
"ethereum-sfrax", "ethereum-sfrax",
"ethereum-sfraxeth", "ethereum-sfraxeth",
"ethereum-uniswap-v3-logs-only", "ethereum-uniswap-v3-logs-only",
"ethereum-uniswap-v4"
] ]
resolver = "2" resolver = "2"

View File

@@ -0,0 +1,33 @@
[package]
name = "ethereum-uniswap-v4"
version = "0.1.1"
edition = "2021"
[lib]
name = "ethereum_uniswap_v4"
crate-type = ["cdylib"]
[dependencies]
substreams = "0.5.22"
substreams-ethereum = "0.9.9"
prost = "0.11"
ethabi = "18.0.0"
anyhow = "1.0.75"
hex-literal = "0.4.1"
substreams-helper = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "b8aeaa3" }
tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "b8aeaa3" }
num-bigint = "0.4.4"
hex = "0.4.3"
tiny-keccak = "2.0"
substreams-entity-change = "1.3"
itertools = "0.13.0"
[dev-dependencies]
rstest = "0.24.0"
[target.wasm32-unknown-unknown.dependencies]
getrandom = { version = "0.2", features = ["custom"] }
[build-dependencies]
anyhow = "1.0.75"
substreams-ethereum = "0.9.9"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
version: v1
plugins:
- plugin: buf.build/community/neoeinstein-prost:v0.2.2
out: src/pb
opt:
- file_descriptor_set=false
- plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1
out: src/pb
opt:
- no_features

View File

@@ -0,0 +1,9 @@
use anyhow::{Ok, Result};
use substreams_ethereum::Abigen;
fn main() -> Result<(), anyhow::Error> {
Abigen::new("Factory", "abi/PoolManager.json")?
.generate()?
.write_to_file("src/abi/pool_manager.rs")?;
Ok(())
}

View File

@@ -0,0 +1,138 @@
specVersion: v0.1.0
package:
name: "ethereum_uniswap_v4"
version: v0.1.1
protobuf:
files:
- tycho/evm/v1/entity.proto
- tycho/evm/v1/common.proto
- tycho/evm/v1/utils.proto
- uniswap.proto
importPaths:
- ../../proto
- ./proto
excludePaths:
- sf/ethereum
- sf/substreams
- google
binaries:
default:
type: wasm/rust-v1
file: ../target/wasm32-unknown-unknown/release/ethereum_uniswap_v4.wasm
modules:
- name: map_pools_created
kind: map
initialBlock: 21688329
inputs:
- params: string
- source: sf.ethereum.type.v2.Block
output:
type: proto:tycho.evm.v1.BlockEntityChanges
- name: store_pools
kind: store
initialBlock: 21688329
updatePolicy: set_if_not_exists
valueType: proto:uniswap.v4.Pool
inputs:
- map: map_pools_created
- name: map_events
kind: map
initialBlock: 21688329
inputs:
- source: sf.ethereum.type.v2.Block
- store: store_pools
output:
type: proto:uniswap.v4.Events
- name: store_pool_current_tick
kind: store
initialBlock: 21688329
updatePolicy: set
valueType: int64
inputs:
- map: map_events
- name: store_pool_current_sqrt_price
kind: store
initialBlock: 21688329
updatePolicy: set
valueType: bigint
inputs:
- map: map_events
- name: map_balance_changes
kind: map
initialBlock: 21688329
inputs:
- map: map_events
- store: store_pool_current_sqrt_price
output:
type: proto:tycho.evm.v1.BlockBalanceDeltas
- name: store_pools_balances
kind: store
initialBlock: 21688329
updatePolicy: add
valueType: bigint
inputs:
- map: map_balance_changes
- name: map_ticks_changes
kind: map
initialBlock: 21688329
inputs:
- map: map_events
output:
type: proto:uniswap.v4.TickDeltas
- name: store_ticks_liquidity
kind: store
initialBlock: 21688329
updatePolicy: add
valueType: bigint
inputs:
- map: map_ticks_changes
- name: map_liquidity_changes
kind: map
initialBlock: 21688329
inputs:
- map: map_events
- store: store_pool_current_tick
output:
type: proto:uniswap.v4.LiquidityChanges
- name: store_liquidity
kind: store
initialBlock: 21688329
updatePolicy: set_sum
valueType: bigint
inputs:
- map: map_liquidity_changes
- name: map_protocol_changes
kind: map
initialBlock: 21688329
inputs:
- source: sf.ethereum.type.v2.Block
- map: map_pools_created
- map: map_events
- map: map_balance_changes
- store: store_pools_balances
mode: deltas
- map: map_ticks_changes
- store: store_ticks_liquidity
mode: deltas
- map: map_liquidity_changes
- store: store_liquidity
mode: deltas
output:
type: proto:tycho.evm.v1.BlockChanges
params:
map_pools_created: "000000000004444c5dc75cB358380D2e3dE08A90"

View File

@@ -0,0 +1,124 @@
syntax = "proto3";
package uniswap.v4;
message Pool {
// // The pool address.
bytes id = 1;
// The token0 address.
bytes currency0 = 2;
// The token1 address.
bytes currency1 = 3;
// The transaction where the pool was created.
bytes created_tx_hash = 4;
}
// A struct describing a transaction.
message Transaction {
// The transaction hash.
bytes hash = 1;
// The sender of the transaction.
bytes from = 2;
// The receiver of the transaction.
bytes to = 3;
// The transactions index within the block.
uint64 index = 4;
}
// A change to a pool's tick.
message TickDelta {
// The address of the pool.
bytes pool_address = 1;
// The index of the tick.
int32 tick_index = 2;
// The liquidity net delta of this tick. Bigint encoded as signed little endian bytes.
bytes liquidity_net_delta = 3;
// Used to determine the order of the balance changes. Necessary for the balance store.
uint64 ordinal = 4;
Transaction transaction = 5;
}
// A group of TickDelta
message TickDeltas {
repeated TickDelta deltas = 1;
}
// A change to a pool's liquidity.
message LiquidityChange {
// The address of the pool.
bytes pool_address = 1;
// The liquidity changed amount. Bigint encoded as signed little endian bytes.
bytes value = 2;
// The type of update, can be absolute or delta.
LiquidityChangeType change_type = 3;
// Used to determine the order of the balance changes. Necessary for the balance store.
uint64 ordinal = 4;
Transaction transaction = 5;
}
// A group of LiquidityChange
message LiquidityChanges {
repeated LiquidityChange changes = 1;
}
enum LiquidityChangeType {
DELTA = 0;
ABSOLUTE = 1;
}
message Events {
repeated PoolEvent pool_events = 3;
message PoolEvent {
oneof type {
Initialize initialize = 1;
ModifyLiquidity modify_liquidity = 2;
Swap swap = 3;
Donate donate = 4;
ProtocolFeeUpdated protocol_fee_updated = 5;
}
uint64 log_ordinal = 100;
string pool_id = 102; // Changed from pool_address to pool_id as V4 uses PoolId
string currency0 = 103; // Changed from token0 to currency0
string currency1 = 104; // Changed from token1 to currency1
Transaction transaction = 105;
message Initialize {
string sqrt_price_x96 = 1;
int32 tick = 2;
uint32 fee = 3;
int32 tick_spacing = 4;
string hooks = 5; // Address of the hooks contract
}
message ModifyLiquidity {
string sender = 1;
int32 tick_lower = 2;
int32 tick_upper = 3;
string liquidity_delta = 4; // Changed to support signed integers
string salt = 5; // Added salt field
}
message Swap {
string sender = 1;
string amount0 = 2; // Signed int128
string amount1 = 3; // Signed int128
string sqrt_price_x96 = 4;
string liquidity = 5;
int32 tick = 6;
uint32 fee = 7; // Added fee field
}
message Donate {
string sender = 1;
string amount0 = 2;
string amount1 = 3;
}
message ProtocolFeeUpdated {
string pool_id = 1;
uint32 protocol_fee = 2;
}
}
}

View File

@@ -0,0 +1,138 @@
specVersion: v0.1.0
package:
name: "ethereum_uniswap_v4"
version: v0.1.1
protobuf:
files:
- tycho/evm/v1/entity.proto
- tycho/evm/v1/common.proto
- tycho/evm/v1/utils.proto
- uniswap.proto
importPaths:
- ../../proto
- ./proto
excludePaths:
- sf/ethereum
- sf/substreams
- google
binaries:
default:
type: wasm/rust-v1
file: ../target/wasm32-unknown-unknown/release/ethereum_uniswap_v4.wasm
modules:
- name: map_pools_created
kind: map
initialBlock: 6894393
inputs:
- params: string
- source: sf.ethereum.type.v2.Block
output:
type: proto:tycho.evm.v1.BlockEntityChanges
- name: store_pools
kind: store
initialBlock: 6894393
updatePolicy: set_if_not_exists
valueType: proto:uniswap.v4.Pool
inputs:
- map: map_pools_created
- name: map_events
kind: map
initialBlock: 6894393
inputs:
- source: sf.ethereum.type.v2.Block
- store: store_pools
output:
type: proto:uniswap.v4.Events
- name: store_pool_current_tick
kind: store
initialBlock: 6894393
updatePolicy: set
valueType: int64
inputs:
- map: map_events
- name: store_pool_current_sqrt_price
kind: store
initialBlock: 6894393
updatePolicy: set
valueType: bigint
inputs:
- map: map_events
- name: map_balance_changes
kind: map
initialBlock: 6894393
inputs:
- map: map_events
- store: store_pool_current_sqrt_price
output:
type: proto:tycho.evm.v1.BlockBalanceDeltas
- name: store_pools_balances
kind: store
initialBlock: 6894393
updatePolicy: add
valueType: bigint
inputs:
- map: map_balance_changes
- name: map_ticks_changes
kind: map
initialBlock: 6894393
inputs:
- map: map_events
output:
type: proto:uniswap.v4.TickDeltas
- name: store_ticks_liquidity
kind: store
initialBlock: 6894393
updatePolicy: add
valueType: bigint
inputs:
- map: map_ticks_changes
- name: map_liquidity_changes
kind: map
initialBlock: 6894393
inputs:
- map: map_events
- store: store_pool_current_tick
output:
type: proto:uniswap.v4.LiquidityChanges
- name: store_liquidity
kind: store
initialBlock: 6894393
updatePolicy: set_sum
valueType: bigint
inputs:
- map: map_liquidity_changes
- name: map_protocol_changes
kind: map
initialBlock: 6894393
inputs:
- source: sf.ethereum.type.v2.Block
- map: map_pools_created
- map: map_events
- map: map_balance_changes
- store: store_pools_balances
mode: deltas
- map: map_ticks_changes
- store: store_ticks_liquidity
mode: deltas
- map: map_liquidity_changes
- store: store_liquidity
mode: deltas
output:
type: proto:tycho.evm.v1.BlockChanges
params:
map_pools_created: "8c4bcbe6b9ef47855f97e675296fa3f6fafa5f1a"

View File

@@ -0,0 +1,3 @@
#![allow(clippy::all, clippy::pedantic, clippy::nursery)]
pub mod pool_manager;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
#![allow(clippy::not_unsafe_ptr_arg_deref)]
mod abi;
mod modules;
mod pb;

View File

@@ -0,0 +1,146 @@
use std::str::FromStr;
use ethabi::ethereum_types::Address;
use substreams::scalar::BigInt;
use substreams_ethereum::pb::eth::v2::{self as eth};
use substreams_helper::{event_handler::EventHandler, hex::Hexable};
use crate::abi::pool_manager::events::Initialize;
use tycho_substreams::prelude::*;
#[substreams::handlers::map]
pub fn map_pools_created(
params: String,
block: eth::Block,
) -> Result<BlockEntityChanges, substreams::errors::Error> {
let mut new_pools: Vec<TransactionEntityChanges> = vec![];
let pool_manager = params.as_str();
get_new_pools(&block, &mut new_pools, pool_manager);
Ok(BlockEntityChanges { block: None, changes: new_pools })
}
// Extract new pools initialized on the pool manager contract
fn get_new_pools(
block: &eth::Block,
new_pools: &mut Vec<TransactionEntityChanges>,
pool_manager_address: &str,
) {
// Extract new pools from Initialize events
let mut on_pool_created = |event: Initialize, _tx: &eth::TransactionTrace, _log: &eth::Log| {
let tycho_tx: Transaction = _tx.into();
new_pools.push(TransactionEntityChanges {
tx: Some(tycho_tx.clone()),
entity_changes: vec![EntityChanges {
component_id: event.id.to_vec().to_hex(),
attributes: vec![
// Represents the pool's LP Fee. The fee is either static or dynamic.
// Static fees are represented in hundredths of a bip, and can be set to a
// value between 0 and 1000000 (100%) and are immutable. If
// the value is set to 0x800000 (1 in the most significant bit of uint24) then
// the pool has a dynamic fee. This pool is initialized
// with 0 fee which can be changed later via hooks (dynamic fee).
Attribute {
name: "balance_owner".to_string(),
value: hex::decode(pool_manager_address).unwrap(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "fee".to_string(),
value: event.fee.to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "liquidity".to_string(),
value: BigInt::from(0).to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "tick".to_string(),
value: event.tick.to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "sqrt_price_x96".to_string(),
value: event
.sqrt_price_x96
.to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "protocol_fees/zero2one".to_string(),
value: BigInt::from(0).to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "protocol_fees/one2zero".to_string(),
value: BigInt::from(0).to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
],
}],
component_changes: vec![ProtocolComponent {
id: event.id.to_vec().to_hex(),
tokens: vec![event.currency0.clone(), event.currency1.clone()],
contracts: vec![],
static_att: vec![
Attribute {
name: "tick_spacing".to_string(),
value: event.tick_spacing.to_signed_bytes_be(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "pool_id".to_string(),
value: event.id.to_vec(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "hooks".to_string(),
value: event.hooks.to_vec(),
change: ChangeType::Creation.into(),
},
],
change: i32::from(ChangeType::Creation),
protocol_type: Some(ProtocolType {
name: "uniswap_v4_pool".to_string(),
financial_type: FinancialType::Swap.into(),
attribute_schema: vec![],
implementation_type: ImplementationType::Custom.into(),
}),
tx: Some(tycho_tx),
}],
balance_changes: vec![
BalanceChange {
token: event.currency0,
balance: BigInt::from(0).to_signed_bytes_be(),
component_id: event
.id
.to_vec()
.to_hex()
.as_bytes()
.to_vec(),
},
BalanceChange {
token: event.currency1,
balance: BigInt::from(0).to_signed_bytes_be(),
component_id: event
.id
.to_vec()
.to_hex()
.as_bytes()
.to_vec(),
},
],
})
};
let mut eh = EventHandler::new(block);
eh.filter_by_address(vec![Address::from_str(pool_manager_address).unwrap()]);
eh.on::<Initialize, _>(&mut on_pool_created);
eh.handle_events();
}

View File

@@ -0,0 +1,24 @@
use std::str;
use substreams::store::{StoreNew, StoreSetIfNotExists, StoreSetIfNotExistsProto};
use tycho_substreams::models::BlockEntityChanges;
use crate::pb::uniswap::v4::Pool;
#[substreams::handlers::store]
pub fn store_pools(pools_created: BlockEntityChanges, store: StoreSetIfNotExistsProto<Pool>) {
// Store pools. Required so the next maps can match any event to a known pool by their address
for change in pools_created.changes {
for component_change in &change.component_changes {
let pool_address: &str = &component_change.id;
let pool: Pool = Pool {
id: hex::decode(pool_address.trim_start_matches("0x")).unwrap(),
currency0: component_change.tokens[0].clone(),
currency1: component_change.tokens[1].clone(),
created_tx_hash: change.tx.as_ref().unwrap().hash.clone(),
};
store.set_if_not_exists(0, format!("{}:{}", "pool", pool_address), &pool);
}
}
}

View File

@@ -0,0 +1,138 @@
use crate::{
abi::pool_manager::events::{Initialize, ModifyLiquidity, ProtocolFeeUpdated, Swap},
pb::uniswap::v4::{
events::{pool_event, pool_event::Type, PoolEvent},
Events, Pool,
},
};
use anyhow::Ok;
use substreams::store::{StoreGet, StoreGetProto};
use substreams_ethereum::{
pb::eth::v2::{self as eth, Log, TransactionTrace},
Event,
};
use substreams_helper::hex::Hexable;
#[substreams::handlers::map]
pub fn map_events(
block: eth::Block,
pools_store: StoreGetProto<Pool>,
) -> Result<Events, anyhow::Error> {
let mut pool_manager_events = block
.transaction_traces
.into_iter()
.filter(|tx| tx.status == 1)
.flat_map(|tx| {
tx.clone()
.receipt
.into_iter()
.flat_map(|receipt| receipt.logs)
.filter_map(|log| log_to_event(&log, tx.clone(), &pools_store))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
pool_manager_events.sort_unstable_by_key(|e| e.log_ordinal);
Ok(Events { pool_events: pool_manager_events })
}
fn log_to_event(
event: &Log,
tx: TransactionTrace,
pools_store: &StoreGetProto<Pool>,
) -> Option<PoolEvent> {
if let Some(init) = Initialize::match_and_decode(event) {
// We need to track initialization again to keep track of pool current tick, which is set on
// initialization and changed on swaps.
let pool_id = init.id.to_vec().to_hex();
let pool = pools_store.get_last(format!("{}:{}", "pool", &pool_id))?;
Some(PoolEvent {
log_ordinal: event.ordinal,
pool_id,
currency0: pool.currency0.to_hex(),
currency1: pool.currency1.to_hex(),
transaction: Some(tx.into()),
r#type: Some(Type::Initialize(pool_event::Initialize {
sqrt_price_x96: init.sqrt_price_x96.to_string(),
tick: init.tick.into(),
fee: init.fee.into(),
tick_spacing: init.tick_spacing.into(),
hooks: init.hooks.to_vec().to_hex(),
})),
})
} else if let Some(swap) = Swap::match_and_decode(event) {
let pool_id = swap.id.to_vec().to_hex();
let pool = pools_store.get_last(format!("{}:{}", "pool", &pool_id))?;
Some(PoolEvent {
log_ordinal: event.ordinal,
pool_id,
currency0: pool.currency0.to_hex(),
currency1: pool.currency1.to_hex(),
transaction: Some(tx.into()),
r#type: Some(Type::Swap(pool_event::Swap {
sender: swap.sender.to_hex(),
amount0: swap.amount0.to_string(),
amount1: swap.amount1.to_string(),
sqrt_price_x96: swap.sqrt_price_x96.to_string(),
liquidity: swap.liquidity.to_string(),
tick: swap.tick.into(),
fee: swap.fee.into(),
})),
})
// Skipped because Donate doesn't seem to affect pool liquidity?
// } else if let Some(flash) = Donate::match_and_decode(event) {
// let pool_id = flash.id.to_vec().to_hex();
// let pool = pools_store.get_last(format!("{}:{}", "pool", &pool_id))?;
// Some(PoolEvent {
// log_ordinal: event.ordinal,
// pool_id,
// currency0: pool.currency0.to_hex(),
// currency1: pool.currency1.to_hex(),
// transaction: Some(tx.into()),
// r#type: Some(Type::Donate(pool_event::Donate {
// sender: flash.sender.to_hex(),
// amount0: flash.amount0.to_string(),
// amount1: flash.amount1.to_string(),
// })),
// })
} else if let Some(modify_liquidity) = ModifyLiquidity::match_and_decode(event) {
let pool_id = modify_liquidity.id.to_vec().to_hex();
let pool = pools_store.get_last(format!("{}:{}", "pool", &pool_id))?;
Some(PoolEvent {
log_ordinal: event.ordinal,
pool_id,
currency0: pool.currency0.to_hex(),
currency1: pool.currency1.to_hex(),
transaction: Some(tx.into()),
r#type: Some(Type::ModifyLiquidity(pool_event::ModifyLiquidity {
sender: modify_liquidity.sender.to_hex(),
tick_lower: modify_liquidity.tick_lower.into(),
tick_upper: modify_liquidity.tick_upper.into(),
liquidity_delta: modify_liquidity
.liquidity_delta
.to_string(),
salt: modify_liquidity.salt.to_vec().to_hex(),
})),
})
} else if let Some(protocol_fee_updated) = ProtocolFeeUpdated::match_and_decode(event) {
let pool_id = protocol_fee_updated
.id
.to_vec()
.to_hex();
let pool = pools_store.get_last(format!("{}:{}", "pool", &pool_id))?;
Some(PoolEvent {
log_ordinal: event.ordinal,
pool_id: pool_id.clone(),
currency0: pool.currency0.to_hex(),
currency1: pool.currency1.to_hex(),
transaction: Some(tx.into()),
r#type: Some(Type::ProtocolFeeUpdated(pool_event::ProtocolFeeUpdated {
pool_id,
protocol_fee: protocol_fee_updated.protocol_fee.into(),
})),
})
} else {
None
}
}

View File

@@ -0,0 +1,39 @@
use substreams::{
scalar::BigInt,
store::{StoreSet, StoreSetBigInt},
};
use crate::pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events,
};
use substreams::store::StoreNew;
#[substreams::handlers::store]
pub fn store_pool_current_sqrt_price(events: Events, store: StoreSetBigInt) {
events
.pool_events
.into_iter()
.filter_map(event_to_current_sqrt_price)
.for_each(|(pool, ordinal, new_tick_index)| {
store.set(ordinal, format!("pool:{0}", pool), &new_tick_index)
});
}
fn event_to_current_sqrt_price(event: PoolEvent) -> Option<(String, u64, BigInt)> {
match event.r#type.as_ref().unwrap() {
pool_event::Type::Initialize(initialize) => Some((
event.pool_id,
event.log_ordinal,
BigInt::try_from(&initialize.sqrt_price_x96)
.expect("cannot convert sqrt_price to bigint"),
)),
pool_event::Type::Swap(swap) => Some((
event.pool_id,
event.log_ordinal,
BigInt::try_from(&swap.sqrt_price_x96).expect("cannot convert sqrt_price to bigint"),
)),
_ => None,
}
}

View File

@@ -0,0 +1,28 @@
use substreams::store::{StoreSet, StoreSetInt64};
use crate::pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events,
};
use substreams::store::StoreNew;
#[substreams::handlers::store]
pub fn store_pool_current_tick(events: Events, store: StoreSetInt64) {
events
.pool_events
.into_iter()
.filter_map(event_to_current_tick)
.for_each(|(pool, ordinal, new_tick_index)| {
store.set(ordinal, format!("pool:{0}", pool), &new_tick_index.into())
});
}
fn event_to_current_tick(event: PoolEvent) -> Option<(String, u64, i32)> {
match event.r#type.as_ref().unwrap() {
pool_event::Type::Initialize(initialize) => {
Some((event.pool_id, event.log_ordinal, initialize.tick))
}
pool_event::Type::Swap(swap) => Some((event.pool_id, event.log_ordinal, swap.tick)),
_ => None,
}
}

View File

@@ -0,0 +1,185 @@
use std::str::FromStr;
use anyhow::Ok;
use tycho_substreams::models::{BalanceDelta, BlockBalanceDeltas};
use crate::{
modules::uni_math::calculate_token_amounts,
pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events,
},
};
use substreams::{
prelude::StoreGet,
scalar::BigInt,
store::{StoreAddBigInt, StoreGetBigInt, StoreNew},
};
#[substreams::handlers::map]
pub fn map_balance_changes(
events: Events,
pools_current_sqrt_price_store: StoreGetBigInt,
) -> Result<BlockBalanceDeltas, anyhow::Error> {
let balance_deltas = events
.pool_events
.into_iter()
.filter(PoolEvent::can_introduce_balance_changes)
.map(|e| {
(
pools_current_sqrt_price_store
.get_at(e.log_ordinal, format!("pool:{0}", &e.pool_id))
.unwrap_or(BigInt::zero()),
e,
)
})
.filter_map(|(current_sqrt_price, event)| {
event_to_balance_deltas(current_sqrt_price, event)
})
.flatten()
.collect();
Ok(BlockBalanceDeltas { balance_deltas })
}
#[substreams::handlers::store]
pub fn store_pools_balances(balances_deltas: BlockBalanceDeltas, store: StoreAddBigInt) {
tycho_substreams::balances::store_balance_changes(balances_deltas, store);
}
fn event_to_balance_deltas(
current_sqrt_price: BigInt,
event: PoolEvent,
) -> Option<Vec<BalanceDelta>> {
let address = event.pool_id.as_bytes().to_vec();
match event.r#type.unwrap() {
pool_event::Type::ModifyLiquidity(e) => {
let (delta0, delta1) =
get_amount_delta(current_sqrt_price, e.tick_lower, e.tick_upper, e.liquidity_delta);
Some(vec![
BalanceDelta {
token: hex::decode(
event
.currency0
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
delta: delta0.to_signed_bytes_be(),
component_id: address.clone(),
ord: event.log_ordinal,
tx: event
.transaction
.clone()
.map(Into::into),
},
BalanceDelta {
token: hex::decode(
event
.currency1
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
delta: delta1.to_signed_bytes_be(),
component_id: address,
ord: event.log_ordinal,
tx: event.transaction.map(Into::into),
},
])
}
pool_event::Type::Swap(e) => {
let mut delta0 = BigInt::from_str(&e.amount0)
.unwrap()
.neg();
let mut delta1 = BigInt::from_str(&e.amount1)
.unwrap()
.neg();
// Adjusting deltas to exclude collected fees.
// Collected fees are not considered part of the component balance since they aren't
// accounted for during swaps. Thus, they should be excluded from the Total Value Locked
// (TVL).
// To achieve this, we subtract the fee portion from each delta.
// We perform integer division and round to the nearest integer based on the
// remainder. If the remainder is at least half of the divisor, we
// round up.
let bips_divisor = BigInt::from(1_000_000);
let half_divisor = BigInt::from(500_000);
if delta0 > BigInt::zero() {
let fee_part = delta0.clone() * e.fee;
let (quotient, remainder) = fee_part.div_rem(&bips_divisor);
delta0 =
delta0 - if remainder >= half_divisor { quotient + 1u32 } else { quotient };
}
if delta1 > BigInt::zero() {
let fee_part = delta1.clone() * e.fee;
let (quotient, remainder) = fee_part.div_rem(&bips_divisor);
delta1 =
delta1 - if remainder >= half_divisor { quotient + 1u32 } else { quotient };
}
Some(vec![
BalanceDelta {
token: hex::decode(
event
.currency0
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
delta: delta0.to_signed_bytes_be(),
component_id: address.clone(),
ord: event.log_ordinal,
tx: event
.transaction
.clone()
.map(Into::into),
},
BalanceDelta {
token: hex::decode(
event
.currency1
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
delta: delta1.to_signed_bytes_be(),
component_id: address.clone(),
ord: event.log_ordinal,
tx: event.transaction.map(Into::into),
},
])
}
_ => None,
}
}
impl PoolEvent {
fn can_introduce_balance_changes(&self) -> bool {
matches!(
self.r#type.as_ref().unwrap(),
pool_event::Type::ModifyLiquidity(_) | pool_event::Type::Swap(_)
)
}
}
fn get_amount_delta(
current_sqrt_price: BigInt,
tick_lower: i32,
tick_upper: i32,
liquidity_delta: String,
) -> (BigInt, BigInt) {
// This should never fail because the liquidity delta is a string encoded signed int128 (from
// the contract)
let liquidity_delta: i128 = liquidity_delta
.parse()
.expect("Failed to parse liquidity delta");
let (amount0, amount1) =
calculate_token_amounts(current_sqrt_price.into(), tick_lower, tick_upper, liquidity_delta)
.expect("Failed to calculate token amounts from liquidity delta");
(BigInt::from(amount0), BigInt::from(amount1))
}

View File

@@ -0,0 +1,101 @@
use std::str::FromStr;
use substreams::store::{StoreGet, StoreGetInt64, StoreSetSum, StoreSetSumBigInt};
use crate::pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events, LiquidityChange, LiquidityChangeType, LiquidityChanges,
};
use substreams::scalar::BigInt;
use anyhow::Ok;
use substreams_helper::hex::Hexable;
#[substreams::handlers::map]
pub fn map_liquidity_changes(
events: Events,
pools_current_tick_store: StoreGetInt64,
) -> Result<LiquidityChanges, anyhow::Error> {
let mut changes = events
.pool_events
.into_iter()
.filter(PoolEvent::can_introduce_liquidity_changes)
.map(|e| {
(
pools_current_tick_store
.get_at(e.log_ordinal, format!("pool:{0}", &e.pool_id))
.unwrap_or(0),
e,
)
})
.filter_map(|(current_tick, event)| event_to_liquidity_deltas(current_tick, event))
.collect::<Vec<_>>();
changes.sort_unstable_by_key(|l| l.ordinal);
Ok(LiquidityChanges { changes })
}
#[substreams::handlers::store]
pub fn store_liquidity(ticks_deltas: LiquidityChanges, store: StoreSetSumBigInt) {
ticks_deltas
.changes
.iter()
.for_each(|changes| match changes.change_type() {
LiquidityChangeType::Delta => {
store.sum(
changes.ordinal,
format!("pool:{0}", &changes.pool_address.to_hex()),
BigInt::from_signed_bytes_be(&changes.value),
);
}
LiquidityChangeType::Absolute => {
store.set(
changes.ordinal,
format!("pool:{0}", &changes.pool_address.to_hex()),
BigInt::from_signed_bytes_be(&changes.value),
);
}
});
}
fn event_to_liquidity_deltas(current_tick: i64, event: PoolEvent) -> Option<LiquidityChange> {
match event.r#type.as_ref().unwrap() {
pool_event::Type::ModifyLiquidity(mod_liquidity) => {
if current_tick >= mod_liquidity.tick_lower.into() &&
current_tick < mod_liquidity.tick_upper.into()
{
Some(LiquidityChange {
pool_address: hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
value: BigInt::from_str(&mod_liquidity.liquidity_delta)
.unwrap()
.to_signed_bytes_be(),
change_type: LiquidityChangeType::Delta.into(),
ordinal: event.log_ordinal,
transaction: Some(event.transaction.unwrap()),
})
} else {
None
}
}
pool_event::Type::Swap(swap) => Some(LiquidityChange {
pool_address: hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
value: BigInt::from_str(&swap.liquidity)
.unwrap()
.to_signed_bytes_be(),
change_type: LiquidityChangeType::Absolute.into(),
ordinal: event.log_ordinal,
transaction: Some(event.transaction.unwrap()),
}),
_ => None,
}
}
impl PoolEvent {
fn can_introduce_liquidity_changes(&self) -> bool {
matches!(
self.r#type.as_ref().unwrap(),
pool_event::Type::ModifyLiquidity(_) | pool_event::Type::Swap(_)
)
}
}

View File

@@ -0,0 +1,73 @@
use std::str::FromStr;
use substreams::store::StoreAddBigInt;
use crate::pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events, TickDelta, TickDeltas,
};
use substreams::{
scalar::BigInt,
store::{StoreAdd, StoreNew},
};
use anyhow::Ok;
use substreams_helper::hex::Hexable;
#[substreams::handlers::map]
pub fn map_ticks_changes(events: Events) -> Result<TickDeltas, anyhow::Error> {
let ticks_deltas = events
.pool_events
.into_iter()
.flat_map(event_to_ticks_deltas)
.collect();
Ok(TickDeltas { deltas: ticks_deltas })
}
#[substreams::handlers::store]
pub fn store_ticks_liquidity(ticks_deltas: TickDeltas, store: StoreAddBigInt) {
let mut deltas = ticks_deltas.deltas.clone();
deltas.sort_unstable_by_key(|delta| delta.ordinal);
deltas.iter().for_each(|delta| {
store.add(
delta.ordinal,
format!("pool:{0}:tick:{1}", &delta.pool_address.to_hex(), delta.tick_index,),
BigInt::from_signed_bytes_be(&delta.liquidity_net_delta),
);
});
}
fn event_to_ticks_deltas(event: PoolEvent) -> Vec<TickDelta> {
// On UniswapV4, the only event that changes liquidity is ModifyLiquidity. Liquidity Delta is
// now expressed as a signed int256. A positive number indicates a mint, while a negative
// indicates a burn.
// Mint events will have negative deltas for the upper tick and positive deltas for the lower.
// Burn events will have positive deltas for the upper tick and negative deltas for the lower.
match event.r#type.as_ref().unwrap() {
pool_event::Type::ModifyLiquidity(liq_change) => {
let amount =
BigInt::from_str(&liq_change.liquidity_delta).expect("Failed to parse BigInt");
vec![
TickDelta {
pool_address: hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
tick_index: liq_change.tick_lower,
liquidity_net_delta: amount.to_signed_bytes_be(),
ordinal: event.log_ordinal,
transaction: event.transaction.clone(),
},
TickDelta {
pool_address: hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
tick_index: liq_change.tick_upper,
liquidity_net_delta: amount.neg().to_signed_bytes_be(),
ordinal: event.log_ordinal,
transaction: event.transaction,
},
]
}
_ => vec![],
}
}

View File

@@ -0,0 +1,240 @@
use crate::pb::uniswap::v4::{
events::{pool_event, PoolEvent},
Events, LiquidityChanges, TickDeltas,
};
use itertools::Itertools;
use std::{collections::HashMap, str::FromStr, vec};
use substreams::{pb::substreams::StoreDeltas, scalar::BigInt};
use substreams_ethereum::pb::eth::v2::{self as eth};
use substreams_helper::hex::Hexable;
use tycho_substreams::{balances::aggregate_balances_changes, prelude::*};
type PoolAddress = Vec<u8>;
#[substreams::handlers::map]
pub fn map_protocol_changes(
block: eth::Block,
created_pools: BlockEntityChanges,
events: Events,
balances_map_deltas: BlockBalanceDeltas,
balances_store_deltas: StoreDeltas,
ticks_map_deltas: TickDeltas,
ticks_store_deltas: StoreDeltas,
pool_liquidity_changes: LiquidityChanges,
pool_liquidity_store_deltas: StoreDeltas,
) -> Result<BlockChanges, substreams::errors::Error> {
// We merge contract changes by transaction (identified by transaction index) making it easy to
// sort them at the very end.
let mut transaction_changes: HashMap<_, TransactionChangesBuilder> = HashMap::new();
// Add created pools to the tx_changes_map
for change in created_pools.changes.into_iter() {
let tx = change.tx.as_ref().unwrap();
let builder = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChangesBuilder::new(tx));
change
.component_changes
.iter()
.for_each(|c| {
builder.add_protocol_component(c);
});
change
.entity_changes
.iter()
.for_each(|ec| {
builder.add_entity_change(ec);
});
change
.balance_changes
.iter()
.for_each(|bc| {
builder.add_balance_change(bc);
});
}
// Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating
// `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store`
// this block. Then, these balance changes are merged onto the existing map of tx contract
// changes, inserting a new one if it doesn't exist.
aggregate_balances_changes(balances_store_deltas, balances_map_deltas)
.into_iter()
.for_each(|(_, (tx, balances))| {
let builder = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChangesBuilder::new(&tx));
balances
.values()
.for_each(|token_bc_map| {
token_bc_map
.values()
.for_each(|bc| builder.add_balance_change(bc))
});
});
// Insert ticks net-liquidity changes
ticks_store_deltas
.deltas
.into_iter()
.zip(ticks_map_deltas.deltas)
.for_each(|(store_delta, tick_delta)| {
let new_value_bigint =
BigInt::from_str(&String::from_utf8(store_delta.new_value).unwrap()).unwrap();
// If old value is empty or the int value is 0, it's considered as a creation.
let is_creation = store_delta.old_value.is_empty() ||
BigInt::from_str(&String::from_utf8(store_delta.old_value).unwrap())
.unwrap()
.is_zero();
let attribute_name = format!("ticks/{}/net-liquidity", tick_delta.tick_index);
let attribute = Attribute {
name: attribute_name,
value: new_value_bigint.to_signed_bytes_be(),
change: if is_creation {
ChangeType::Creation.into()
} else if new_value_bigint.is_zero() {
ChangeType::Deletion.into()
} else {
ChangeType::Update.into()
},
};
let tx = tick_delta.transaction.unwrap();
let builder = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChangesBuilder::new(&tx.into()));
builder.add_entity_change(&EntityChanges {
component_id: tick_delta.pool_address.to_hex(),
attributes: vec![attribute],
});
});
// Insert liquidity changes
pool_liquidity_store_deltas
.deltas
.into_iter()
.zip(pool_liquidity_changes.changes)
.for_each(|(store_delta, change)| {
let new_value_bigint = BigInt::from_str(
String::from_utf8(store_delta.new_value)
.unwrap()
.split(':')
.nth(1)
.unwrap(),
)
.unwrap();
let tx = change.transaction.unwrap();
let builder = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChangesBuilder::new(&tx.into()));
builder.add_entity_change(&EntityChanges {
component_id: change.pool_address.to_hex(),
attributes: vec![Attribute {
name: "liquidity".to_string(),
value: new_value_bigint.to_signed_bytes_be(),
change: ChangeType::Update.into(),
}],
});
});
// Insert others changes
events
.pool_events
.into_iter()
.flat_map(event_to_attributes_updates)
.for_each(|(tx, pool_address, attr)| {
let builder = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChangesBuilder::new(&tx));
builder.add_entity_change(&EntityChanges {
component_id: pool_address.to_hex(),
attributes: vec![attr],
});
});
Ok(BlockChanges {
block: Some((&block).into()),
changes: transaction_changes
.drain()
.sorted_unstable_by_key(|(index, _)| *index)
.filter_map(|(_, builder)| builder.build())
.collect::<Vec<_>>(),
})
}
fn event_to_attributes_updates(event: PoolEvent) -> Vec<(Transaction, PoolAddress, Attribute)> {
match event.r#type.as_ref().unwrap() {
pool_event::Type::Swap(swap) => vec![
(
event
.transaction
.clone()
.unwrap()
.into(),
hex::decode(
event
.pool_id
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
Attribute {
name: "sqrt_price_x96".to_string(),
value: BigInt::from_str(&swap.sqrt_price_x96)
.unwrap()
.to_signed_bytes_be(),
change: ChangeType::Update.into(),
},
),
(
event.transaction.unwrap().into(),
hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
Attribute {
name: "tick".to_string(),
value: BigInt::from(swap.tick).to_signed_bytes_be(),
change: ChangeType::Update.into(),
},
),
],
pool_event::Type::ProtocolFeeUpdated(sfp) => {
// Mask to extract the lower 12 bits (0xFFF corresponds to 12 bits set to 1)
let lower_12_bits = sfp.protocol_fee & 0xFFF;
// Shift right by 12 bits and mask again to get the next 12 bits
let upper_12_bits = (sfp.protocol_fee >> 12) & 0xFFF;
vec![
(
event
.transaction
.clone()
.unwrap()
.into(),
hex::decode(
event
.pool_id
.clone()
.trim_start_matches("0x"),
)
.unwrap(),
Attribute {
name: "protocol_fees/zero2one".to_string(),
value: BigInt::from(lower_12_bits).to_signed_bytes_be(),
change: ChangeType::Update.into(),
},
),
(
event.transaction.unwrap().into(),
hex::decode(event.pool_id.trim_start_matches("0x")).unwrap(),
Attribute {
name: "protocol_fees/one2zero".to_string(),
value: BigInt::from(upper_12_bits).to_signed_bytes_be(),
change: ChangeType::Update.into(),
},
),
]
}
_ => vec![],
}
}

View File

@@ -0,0 +1,43 @@
use substreams_ethereum::pb::eth::v2::TransactionTrace;
use crate::pb::uniswap::v4::Transaction;
#[path = "1_map_pool_created.rs"]
mod map_pool_created;
#[path = "2_store_pools.rs"]
mod store_pools;
#[path = "3_map_events.rs"]
mod map_events;
#[path = "4_store_current_tick.rs"]
mod store_current_tick;
#[path = "4_store_current_sqrtprice.rs"]
mod store_current_sqrtprice;
#[path = "5_map_store_balance_changes.rs"]
mod map_store_balance_changes;
#[path = "5_map_store_ticks.rs"]
mod map_store_ticks;
#[path = "5_map_store_liquidity.rs"]
mod map_store_liquidity;
#[path = "6_map_protocol_changes.rs"]
mod map_protocol_changes;
mod uni_math;
impl From<TransactionTrace> for Transaction {
fn from(value: TransactionTrace) -> Self {
Self { hash: value.hash, from: value.from, to: value.to, index: value.index.into() }
}
}
impl From<Transaction> for tycho_substreams::prelude::Transaction {
fn from(value: Transaction) -> Self {
Self { hash: value.hash, from: value.from, to: value.to, index: value.index }
}
}

View File

@@ -0,0 +1,469 @@
use num_bigint::BigInt;
use std::ops::Shr;
/// Calculates the amounts of token0 and token1 for a given position
///
/// Source: https://github.com/Uniswap/v4-core/blob/main/src/libraries/Pool.sol
/// Function: modifyLiquidity
///
/// # Arguments
/// * `current_sqrt_price` - Current square root price
/// * `tick_lower` - Lower tick of the position
/// * `tick_upper` - Upper tick of the position
/// * `liquidity_delta` - Amount of liquidity to add/remove
///
/// # Returns
/// * `Result<(BigInt, BigInt), String>` - Token amounts (amount0, amount1)
pub fn calculate_token_amounts(
current_sqrt_price: BigInt,
tick_lower: i32,
tick_upper: i32,
liquidity_delta: i128,
) -> Result<(BigInt, BigInt), String> {
let sqrt_price_lower_x96: BigInt = get_sqrt_ratio_at_tick(tick_lower)?;
let sqrt_price_upper_x96: BigInt = get_sqrt_ratio_at_tick(tick_upper)?;
// Calculate amounts based on current price relative to the range
let (amount0, amount1) = if current_sqrt_price < sqrt_price_lower_x96 {
// Current price is below the range: position in token0
let amount0 =
get_amount_0_delta_signed(sqrt_price_lower_x96, sqrt_price_upper_x96, liquidity_delta)?;
(amount0, BigInt::from(0))
} else if current_sqrt_price < sqrt_price_upper_x96 {
// Current price is within the range: position in both tokens
let amount0 = get_amount_0_delta_signed(
current_sqrt_price.clone(),
sqrt_price_upper_x96,
liquidity_delta,
)?;
let amount1 =
get_amount_1_delta_signed(sqrt_price_lower_x96, current_sqrt_price, liquidity_delta)?;
(amount0, amount1)
} else {
// Current price is above the range: position in token1
let amount1 =
get_amount_1_delta_signed(sqrt_price_lower_x96, sqrt_price_upper_x96, liquidity_delta)?;
(BigInt::from(0), amount1)
};
Ok((amount0, amount1))
}
const MAX_TICK: i32 = 887272;
/// Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as
/// sqrt(1.0001)^tick
/// Adapted from: https://github.com/shuhuiluo/uniswap-v3-sdk-rs/blob/v2.9.1/src/utils/tick_math.rs#L57
fn get_sqrt_ratio_at_tick(tick: i32) -> Result<BigInt, String> {
let abs_tick = tick.abs();
if abs_tick > MAX_TICK {
return Err("Tick out of bounds".to_string());
}
// Initialize ratio with either 2^128 / sqrt(1.0001) or 2^128
let mut ratio = if abs_tick & 0x1 != 0 {
BigInt::parse_bytes(b"fffcb933bd6fad37aa2d162d1a594001", 16).unwrap()
} else {
BigInt::from(1) << 128
};
if abs_tick & 0x2 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"fff97272373d413259a46990580e213a", 16).unwrap())
.shr(128);
}
if abs_tick & 0x4 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"fff2e50f5f656932ef12357cf3c7fdcc", 16).unwrap())
.shr(128);
}
if abs_tick & 0x8 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"ffe5caca7e10e4e61c3624eaa0941cd0", 16).unwrap())
.shr(128);
}
if abs_tick & 0x10 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"ffcb9843d60f6159c9db58835c926644", 16).unwrap())
.shr(128);
}
if abs_tick & 0x20 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"ff973b41fa98c081472e6896dfb254c0", 16).unwrap())
.shr(128);
}
if abs_tick & 0x40 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"ff2ea16466c96a3843ec78b326b52861", 16).unwrap())
.shr(128);
}
if abs_tick & 0x80 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"fe5dee046a99a2a811c461f1969c3053", 16).unwrap())
.shr(128);
}
if abs_tick & 0x100 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"fcbe86c7900a88aedcffc83b479aa3a4", 16).unwrap())
.shr(128);
}
if abs_tick & 0x200 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"f987a7253ac413176f2b074cf7815e54", 16).unwrap())
.shr(128);
}
if abs_tick & 0x400 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"f3392b0822b70005940c7a398e4b70f3", 16).unwrap())
.shr(128);
}
if abs_tick & 0x800 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"e7159475a2c29b7443b29c7fa6e889d9", 16).unwrap())
.shr(128);
}
if abs_tick & 0x1000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"d097f3bdfd2022b8845ad8f792aa5825", 16).unwrap())
.shr(128);
}
if abs_tick & 0x2000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"a9f746462d870fdf8a65dc1f90e061e5", 16).unwrap())
.shr(128);
}
if abs_tick & 0x4000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"70d869a156d2a1b890bb3df62baf32f7", 16).unwrap())
.shr(128);
}
if abs_tick & 0x8000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"31be135f97d08fd981231505542fcfa6", 16).unwrap())
.shr(128);
}
if abs_tick & 0x10000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"9aa508b5b7a84e1c677de54f3e99bc9", 16).unwrap())
.shr(128);
}
if abs_tick & 0x20000 != 0 {
ratio =
(&ratio * BigInt::parse_bytes(b"5d6af8dedb81196699c329225ee604", 16).unwrap()).shr(128);
}
if abs_tick & 0x40000 != 0 {
ratio =
(&ratio * BigInt::parse_bytes(b"2216e584f5fa1ea926041bedfe98", 16).unwrap()).shr(128);
}
if abs_tick & 0x80000 != 0 {
ratio = (&ratio * BigInt::parse_bytes(b"48a170391f7dc42444e8fa2", 16).unwrap()).shr(128);
}
if tick > 0 {
let max = (BigInt::from(1) << 256) - 1;
ratio = max / ratio;
}
// Add 2^32 - 1 and shift right by 32
ratio = (ratio + ((BigInt::from(1) << 32) - 1)) >> 32;
Ok(ratio)
}
/// Helper that gets signed token0 delta
/// Source: https://github.com/shuhuiluo/uniswap-v3-sdk-rs/blob/v2.9.1/src/utils/sqrt_price_math.rs#L422
///
/// ## Arguments
///
/// * `sqrt_ratio_a_x96`: A sqrt price
/// * `sqrt_ratio_b_x96`: Another sqrt price
/// * `liquidity`: The change in liquidity for which to compute the amount0 delta
///
/// ## Returns
///
/// Amount of token0 corresponding to the passed liquidityDelta between the two prices
fn get_amount_0_delta_signed(
sqrt_ratio_a_x96: BigInt,
sqrt_ratio_b_x96: BigInt,
liquidity: i128,
) -> Result<BigInt, String> {
let sign = !liquidity.is_negative();
// Create mask for negative numbers
let mask = if sign { 0u128 } else { u128::MAX };
// Get absolute value of liquidity using XOR and addition
let liquidity = mask ^ mask.wrapping_add_signed(liquidity);
// Convert mask to BigInt (all 1s or all 0s)
let mask = if sign { BigInt::from(0) } else { -BigInt::from(1) };
let amount_0 = get_amount_0_delta(sqrt_ratio_a_x96, sqrt_ratio_b_x96, liquidity, sign)?;
// Apply the mask using XOR and subtraction to restore the sign
Ok((amount_0 ^ &mask) - mask)
}
/// Gets the amount0 delta between two prices
///
/// Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
/// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
///
/// ## Arguments
///
/// * `sqrt_ratio_a_x96`: A sqrt price assumed to be lower otherwise swapped
/// * `sqrt_ratio_b_x96`: Another sqrt price
/// * `liquidity`: The amount of usable liquidity
/// * `round_up`: Whether to round the amount up or down
///
/// ## Returns
///
/// Amount of token0 required to cover a position of size liquidity between the two passed prices
fn get_amount_0_delta(
sqrt_ratio_a_x96: BigInt,
sqrt_ratio_b_x96: BigInt,
liquidity: u128,
round_up: bool,
) -> Result<BigInt, String> {
let (sqrt_ratio_a_x96, sqrt_ratio_b_x96) = if sqrt_ratio_a_x96 < sqrt_ratio_b_x96 {
(sqrt_ratio_a_x96, sqrt_ratio_b_x96)
} else {
(sqrt_ratio_b_x96, sqrt_ratio_a_x96)
};
if sqrt_ratio_a_x96 == BigInt::from(0) {
return Err("Price cannot be zero".to_string());
}
let numerator_1 = BigInt::from(liquidity) << 96;
let numerator_2 = &sqrt_ratio_b_x96 - &sqrt_ratio_a_x96;
if round_up {
// For rounding up: ceil(ceil(numerator_1 * numerator_2 / sqrt_ratio_b_x96) /
// sqrt_ratio_a_x96)
let temp =
(&numerator_1 * &numerator_2 + &sqrt_ratio_b_x96 - BigInt::from(1)) / &sqrt_ratio_b_x96;
Ok((&temp + &sqrt_ratio_a_x96 - BigInt::from(1)) / sqrt_ratio_a_x96)
} else {
// For rounding down: floor(floor(numerator_1 * numerator_2 / sqrt_ratio_b_x96) /
// sqrt_ratio_a_x96)
Ok((&numerator_1 * &numerator_2) / &sqrt_ratio_b_x96 / sqrt_ratio_a_x96)
}
}
const Q96: u128 = 1 << 96;
/// Helper that gets signed token1 delta
///
/// ## Arguments
///
/// * `sqrt_ratio_a_x96`: A sqrt price
/// * `sqrt_ratio_b_x96`: Another sqrt price
/// * `liquidity`: The change in liquidity for which to compute the amount1 delta
///
/// ## Returns
///
/// Amount of token1 corresponding to the passed liquidityDelta between the two prices
fn get_amount_1_delta_signed(
sqrt_ratio_a_x96: BigInt,
sqrt_ratio_b_x96: BigInt,
liquidity: i128,
) -> Result<BigInt, String> {
let sign = !liquidity.is_negative();
// Create mask for negative numbers
let mask = if sign { 0u128 } else { u128::MAX };
// Get absolute value of liquidity using XOR and addition
let liquidity = mask ^ mask.wrapping_add_signed(liquidity);
// Convert mask to BigInt (all 1s or all 0s)
let mask = if sign { BigInt::from(0) } else { -BigInt::from(1) };
let amount_1 = get_amount_1_delta(sqrt_ratio_a_x96, sqrt_ratio_b_x96, liquidity, sign)?;
// Apply the mask using XOR and subtraction to restore the sign
Ok((amount_1 ^ &mask) - mask)
}
/// Gets the amount1 delta between two prices
///
/// Calculates liquidity * (sqrt(upper) - sqrt(lower))
///
/// ## Arguments
///
/// * `sqrt_ratio_a_x96`: A sqrt price assumed to be lower otherwise swapped
/// * `sqrt_ratio_b_x96`: Another sqrt price
/// * `liquidity`: The amount of usable liquidity
/// * `round_up`: Whether to round the amount up, or down
///
/// ## Returns
///
/// Amount of token1 required to cover a position of size liquidity between the two passed prices
fn get_amount_1_delta(
sqrt_ratio_a_x96: BigInt,
sqrt_ratio_b_x96: BigInt,
liquidity: u128,
round_up: bool,
) -> Result<BigInt, String> {
let (sqrt_ratio_a_x96, sqrt_ratio_b_x96) = if sqrt_ratio_a_x96 < sqrt_ratio_b_x96 {
(sqrt_ratio_a_x96, sqrt_ratio_b_x96)
} else {
(sqrt_ratio_b_x96, sqrt_ratio_a_x96)
};
let numerator = &sqrt_ratio_b_x96 - &sqrt_ratio_a_x96;
let denominator = BigInt::from(Q96);
let liquidity = BigInt::from(liquidity);
let amount_1 = &liquidity * &numerator / &denominator;
// Calculate if there's a remainder
let remainder = (&liquidity * &numerator) % &denominator;
let carry = remainder > BigInt::from(0) && round_up;
Ok(if carry { amount_1 + 1 } else { amount_1 })
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::BigInt;
use rstest::rstest;
use std::str::FromStr;
const MIN_TICK: i32 = -887272;
#[test]
fn test_get_sqrt_ratio_at_tick_is_valid_min_tick() {
assert_eq!(get_sqrt_ratio_at_tick(MIN_TICK).unwrap(), BigInt::from(4295128739_u128));
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_valid_min_tick_add_one() {
assert_eq!(get_sqrt_ratio_at_tick(MIN_TICK + 1).unwrap(), BigInt::from(4295343490_u128));
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_valid_max_tick() {
assert_eq!(
get_sqrt_ratio_at_tick(MAX_TICK).unwrap(),
BigInt::from_str("1461446703485210103287273052203988822378723970342").unwrap()
);
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_valid_max_tick_sub_one() {
assert_eq!(
get_sqrt_ratio_at_tick(MAX_TICK - 1).unwrap(),
BigInt::from_str("1461373636630004318706518188784493106690254656249").unwrap()
);
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_valid_tick_zero() {
assert_eq!(
get_sqrt_ratio_at_tick(0).unwrap(),
BigInt::from_str("79228162514264337593543950336").unwrap()
);
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_less_than_js_impl_min_tick() {
let js_min_sqrt_price = BigInt::from(6085630636u64);
let sol_min_sqrt_price = get_sqrt_ratio_at_tick(MIN_TICK).unwrap();
assert!(sol_min_sqrt_price < js_min_sqrt_price);
}
#[test]
fn test_get_sqrt_ratio_at_tick_is_greater_than_js_impl_max_tick() {
let js_max_sqrt_price =
BigInt::from_str("1033437718471923706666374484006904511252097097914").unwrap();
let sol_max_sqrt_price = get_sqrt_ratio_at_tick(MAX_TICK).unwrap();
assert!(sol_max_sqrt_price > js_max_sqrt_price);
}
#[test]
fn test_get_amount_0_delta_returns_0_if_liquidity_is_0() {
let result = get_amount_0_delta(
BigInt::from_str("79228162514264337593543950336").unwrap(),
BigInt::from_str("112045541949572279837463876454").unwrap(),
0,
true,
)
.unwrap();
assert_eq!(result, BigInt::from(0));
}
#[test]
fn test_get_amount_0_delta_returns_0_if_prices_are_equal() {
let result = get_amount_0_delta(
BigInt::from_str("79228162514264337593543950336").unwrap(),
BigInt::from_str("79228162514264337593543950336").unwrap(),
0,
true,
)
.unwrap();
assert_eq!(result, BigInt::from(0));
}
#[test]
fn test_get_amount_0_delta_reverts_if_price_is_zero() {
let result = get_amount_0_delta(BigInt::from(0), BigInt::from(1), 1, true);
assert!(result.is_err());
}
#[test]
fn test_get_amount_0_delta_1_amount_1_for_price_of_1_to_1_21() {
let sqrt_price_1_1 = BigInt::from_str("79228162514264337593543950336").unwrap();
let sqrt_price_121_100 = BigInt::from_str("87150978765690771352898345369").unwrap();
let amount_0 = get_amount_0_delta(
sqrt_price_1_1.clone(),
sqrt_price_121_100.clone(),
1_000_000_000_000_000_000,
true,
)
.unwrap();
assert_eq!(amount_0, BigInt::from(90_909_090_909_090_910u128));
let amount_0_rounded_down = get_amount_0_delta(
sqrt_price_1_1,
sqrt_price_121_100,
1_000_000_000_000_000_000,
false,
)
.unwrap();
assert_eq!(amount_0_rounded_down, amount_0 - 1);
}
#[test]
fn test_get_amount_0_delta_works_for_prices_that_overflow() {
let sqrt_p_1 = BigInt::from_str("2787593149816327892691964784081045188247552").unwrap();
let sqrt_p_2 = BigInt::from_str("22300745198530623141535718272648361505980416").unwrap();
let amount_0_up =
get_amount_0_delta(sqrt_p_1.clone(), sqrt_p_2.clone(), 1_000_000_000_000_000_000, true)
.unwrap();
let amount_0_down =
get_amount_0_delta(sqrt_p_1, sqrt_p_2, 1_000_000_000_000_000_000, false).unwrap();
assert_eq!(amount_0_up, amount_0_down + 1);
}
#[rstest]
#[case(
BigInt::from(79228162514264337593543950336_i128),
-887270,
887270,
2779504125,
BigInt::from(2779504125_u128),
BigInt::from(2779504125_u128)
)]
#[case(
BigInt::from(17189630842187678489986852982138_i128),
-138200,
107600,
-79381057257465377800177,
BigInt::from(-445577797388351_i128),
BigInt::from(-17222724212376326765220041_i128)
)]
fn test_calculate_token_amounts(
#[case] current_sqrtprice: BigInt,
#[case] tick_lower: i32,
#[case] tick_upper: i32,
#[case] liquidity_delta: i128,
#[case] expected_amount0: BigInt,
#[case] expected_amount1: BigInt,
) {
let (amount0, amount1) =
calculate_token_amounts(current_sqrtprice, tick_lower, tick_upper, liquidity_delta)
.unwrap();
assert_eq!(amount0, expected_amount0);
assert_eq!(amount1, expected_amount1);
}
}

View File

@@ -0,0 +1,8 @@
// @generated
pub mod uniswap {
// @@protoc_insertion_point(attribute:uniswap.v4)
pub mod v4 {
include!("uniswap.v4.rs");
// @@protoc_insertion_point(uniswap.v4)
}
}

View File

@@ -0,0 +1,228 @@
// @generated
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Pool {
/// // The pool address.
#[prost(bytes="vec", tag="1")]
pub id: ::prost::alloc::vec::Vec<u8>,
/// The token0 address.
#[prost(bytes="vec", tag="2")]
pub currency0: ::prost::alloc::vec::Vec<u8>,
/// The token1 address.
#[prost(bytes="vec", tag="3")]
pub currency1: ::prost::alloc::vec::Vec<u8>,
/// The transaction where the pool was created.
#[prost(bytes="vec", tag="4")]
pub created_tx_hash: ::prost::alloc::vec::Vec<u8>,
}
/// A struct describing a transaction.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Transaction {
/// The transaction hash.
#[prost(bytes="vec", tag="1")]
pub hash: ::prost::alloc::vec::Vec<u8>,
/// The sender of the transaction.
#[prost(bytes="vec", tag="2")]
pub from: ::prost::alloc::vec::Vec<u8>,
/// The receiver of the transaction.
#[prost(bytes="vec", tag="3")]
pub to: ::prost::alloc::vec::Vec<u8>,
/// The transactions index within the block.
#[prost(uint64, tag="4")]
pub index: u64,
}
/// A change to a pool's tick.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TickDelta {
/// The address of the pool.
#[prost(bytes="vec", tag="1")]
pub pool_address: ::prost::alloc::vec::Vec<u8>,
/// The index of the tick.
#[prost(int32, tag="2")]
pub tick_index: i32,
/// The liquidity net delta of this tick. Bigint encoded as signed little endian bytes.
#[prost(bytes="vec", tag="3")]
pub liquidity_net_delta: ::prost::alloc::vec::Vec<u8>,
/// Used to determine the order of the balance changes. Necessary for the balance store.
#[prost(uint64, tag="4")]
pub ordinal: u64,
#[prost(message, optional, tag="5")]
pub transaction: ::core::option::Option<Transaction>,
}
/// A group of TickDelta
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TickDeltas {
#[prost(message, repeated, tag="1")]
pub deltas: ::prost::alloc::vec::Vec<TickDelta>,
}
/// A change to a pool's liquidity.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct LiquidityChange {
/// The address of the pool.
#[prost(bytes="vec", tag="1")]
pub pool_address: ::prost::alloc::vec::Vec<u8>,
/// The liquidity changed amount. Bigint encoded as signed little endian bytes.
#[prost(bytes="vec", tag="2")]
pub value: ::prost::alloc::vec::Vec<u8>,
/// The type of update, can be absolute or delta.
#[prost(enumeration="LiquidityChangeType", tag="3")]
pub change_type: i32,
/// Used to determine the order of the balance changes. Necessary for the balance store.
#[prost(uint64, tag="4")]
pub ordinal: u64,
#[prost(message, optional, tag="5")]
pub transaction: ::core::option::Option<Transaction>,
}
/// A group of LiquidityChange
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct LiquidityChanges {
#[prost(message, repeated, tag="1")]
pub changes: ::prost::alloc::vec::Vec<LiquidityChange>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Events {
#[prost(message, repeated, tag="3")]
pub pool_events: ::prost::alloc::vec::Vec<events::PoolEvent>,
}
/// Nested message and enum types in `Events`.
pub mod events {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PoolEvent {
#[prost(uint64, tag="100")]
pub log_ordinal: u64,
/// Changed from pool_address to pool_id as V4 uses PoolId
#[prost(string, tag="102")]
pub pool_id: ::prost::alloc::string::String,
/// Changed from token0 to currency0
#[prost(string, tag="103")]
pub currency0: ::prost::alloc::string::String,
/// Changed from token1 to currency1
#[prost(string, tag="104")]
pub currency1: ::prost::alloc::string::String,
#[prost(message, optional, tag="105")]
pub transaction: ::core::option::Option<super::Transaction>,
#[prost(oneof="pool_event::Type", tags="1, 2, 3, 4, 5")]
pub r#type: ::core::option::Option<pool_event::Type>,
}
/// Nested message and enum types in `PoolEvent`.
pub mod pool_event {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Initialize {
#[prost(string, tag="1")]
pub sqrt_price_x96: ::prost::alloc::string::String,
#[prost(int32, tag="2")]
pub tick: i32,
#[prost(uint32, tag="3")]
pub fee: u32,
#[prost(int32, tag="4")]
pub tick_spacing: i32,
/// Address of the hooks contract
#[prost(string, tag="5")]
pub hooks: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ModifyLiquidity {
#[prost(string, tag="1")]
pub sender: ::prost::alloc::string::String,
#[prost(int32, tag="2")]
pub tick_lower: i32,
#[prost(int32, tag="3")]
pub tick_upper: i32,
/// Changed to support signed integers
#[prost(string, tag="4")]
pub liquidity_delta: ::prost::alloc::string::String,
/// Added salt field
#[prost(string, tag="5")]
pub salt: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Swap {
#[prost(string, tag="1")]
pub sender: ::prost::alloc::string::String,
/// Signed int128
#[prost(string, tag="2")]
pub amount0: ::prost::alloc::string::String,
/// Signed int128
#[prost(string, tag="3")]
pub amount1: ::prost::alloc::string::String,
#[prost(string, tag="4")]
pub sqrt_price_x96: ::prost::alloc::string::String,
#[prost(string, tag="5")]
pub liquidity: ::prost::alloc::string::String,
#[prost(int32, tag="6")]
pub tick: i32,
/// Added fee field
#[prost(uint32, tag="7")]
pub fee: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Donate {
#[prost(string, tag="1")]
pub sender: ::prost::alloc::string::String,
#[prost(string, tag="2")]
pub amount0: ::prost::alloc::string::String,
#[prost(string, tag="3")]
pub amount1: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProtocolFeeUpdated {
#[prost(string, tag="1")]
pub pool_id: ::prost::alloc::string::String,
#[prost(uint32, tag="2")]
pub protocol_fee: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Type {
#[prost(message, tag="1")]
Initialize(Initialize),
#[prost(message, tag="2")]
ModifyLiquidity(ModifyLiquidity),
#[prost(message, tag="3")]
Swap(Swap),
#[prost(message, tag="4")]
Donate(Donate),
#[prost(message, tag="5")]
ProtocolFeeUpdated(ProtocolFeeUpdated),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum LiquidityChangeType {
Delta = 0,
Absolute = 1,
}
impl LiquidityChangeType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
LiquidityChangeType::Delta => "DELTA",
LiquidityChangeType::Absolute => "ABSOLUTE",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"DELTA" => Some(Self::Delta),
"ABSOLUTE" => Some(Self::Absolute),
_ => None,
}
}
}
// @@protoc_insertion_point(module)

View File

@@ -0,0 +1,4 @@
[toolchain]
channel = "1.83.0"
components = [ "rustfmt" ]
targets = [ "wasm32-unknown-unknown" ]

View File

@@ -18,4 +18,5 @@ ignore = [
"ethereum-uniswap-v2/src/abi", "ethereum-uniswap-v2/src/abi",
"ethereum-uniswap-v3/src/abi", "ethereum-uniswap-v3/src/abi",
"ethereum-uniswap-v3-logs-only/src/abi", "ethereum-uniswap-v3-logs-only/src/abi",
"ethereum-uniswap-v4/src/abi",
] ]