From d7bc94e529b48b402490c64b8eed71d0e1b22c9f Mon Sep 17 00:00:00 2001 From: Harsh Date: Wed, 24 Jan 2024 19:31:24 +0530 Subject: [PATCH 1/6] Add uniswap-v2-sql --- Cargo.lock | 131 +- Cargo.toml | 1 + sql/dbt/logs/dbt.log | 29 + sql/dbt/uniswap_v2/.gitignore | 4 + sql/dbt/uniswap_v2/README.md | 15 + sql/dbt/uniswap_v2/analyses/.gitkeep | 0 sql/dbt/uniswap_v2/dbt_project.yml | 37 + sql/dbt/uniswap_v2/macros/.gitkeep | 0 .../analytics/uniswap_v2_ethereum__burn.sql | 13 + .../analytics/uniswap_v2_ethereum__mint.sql | 13 + .../analytics/uniswap_v2_ethereum__pool.sql | 13 + .../analytics/uniswap_v2_ethereum__swaps.sql | 13 + .../analytics/uniswap_v2_ethereum__sync.sql | 12 + sql/dbt/uniswap_v2/seeds/.gitkeep | 0 sql/dbt/uniswap_v2/snapshots/.gitkeep | 0 sql/dbt/uniswap_v2/tests/.gitkeep | 0 sql/uniswap_v2/Cargo.toml | 34 + sql/uniswap_v2/Makefile | 26 + sql/uniswap_v2/abi/contract.abi.json | 1 + sql/uniswap_v2/build.rs | 31 + sql/uniswap_v2/proto/contract.proto | 77 + sql/uniswap_v2/rust-toolchain.toml | 4 + sql/uniswap_v2/schema.clickhouse.sql | 58 + sql/uniswap_v2/schema.graphql | 63 + sql/uniswap_v2/schema.sql | 64 + sql/uniswap_v2/src/abi/contract.rs | 3556 +++++++++++++++++ sql/uniswap_v2/src/abi/mod.rs | 1 + sql/uniswap_v2/src/lib.rs | 307 ++ sql/uniswap_v2/src/pb/contract.v1.rs | 132 + sql/uniswap_v2/src/pb/mod.rs | 8 + sql/uniswap_v2/subgraph.yaml | 17 + sql/uniswap_v2/substreams.clickhouse.yaml | 59 + sql/uniswap_v2/substreams.sql.yaml | 57 + sql/uniswap_v2/substreams.subgraph.yaml | 56 + sql/uniswap_v2/substreams.yaml | 48 + 35 files changed, 4861 insertions(+), 19 deletions(-) create mode 100644 sql/dbt/logs/dbt.log create mode 100644 sql/dbt/uniswap_v2/.gitignore create mode 100644 sql/dbt/uniswap_v2/README.md create mode 100644 sql/dbt/uniswap_v2/analyses/.gitkeep create mode 100644 sql/dbt/uniswap_v2/dbt_project.yml create mode 100644 sql/dbt/uniswap_v2/macros/.gitkeep create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql create mode 100644 sql/dbt/uniswap_v2/seeds/.gitkeep create mode 100644 sql/dbt/uniswap_v2/snapshots/.gitkeep create mode 100644 sql/dbt/uniswap_v2/tests/.gitkeep create mode 100644 sql/uniswap_v2/Cargo.toml create mode 100644 sql/uniswap_v2/Makefile create mode 100644 sql/uniswap_v2/abi/contract.abi.json create mode 100644 sql/uniswap_v2/build.rs create mode 100644 sql/uniswap_v2/proto/contract.proto create mode 100644 sql/uniswap_v2/rust-toolchain.toml create mode 100644 sql/uniswap_v2/schema.clickhouse.sql create mode 100644 sql/uniswap_v2/schema.graphql create mode 100644 sql/uniswap_v2/schema.sql create mode 100644 sql/uniswap_v2/src/abi/contract.rs create mode 100644 sql/uniswap_v2/src/abi/mod.rs create mode 100644 sql/uniswap_v2/src/lib.rs create mode 100644 sql/uniswap_v2/src/pb/contract.v1.rs create mode 100644 sql/uniswap_v2/src/pb/mod.rs create mode 100644 sql/uniswap_v2/subgraph.yaml create mode 100644 sql/uniswap_v2/substreams.clickhouse.yaml create mode 100644 sql/uniswap_v2/substreams.sql.yaml create mode 100644 sql/uniswap_v2/substreams.subgraph.yaml create mode 100644 sql/uniswap_v2/substreams.yaml diff --git a/Cargo.lock b/Cargo.lock index 53aec903..15215024 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -181,7 +181,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "tiny-keccak", ] @@ -249,7 +249,7 @@ dependencies = [ "serde_json", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", "tiny-keccak", ] @@ -271,7 +271,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -285,7 +285,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -321,7 +321,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -338,7 +338,7 @@ dependencies = [ "substreams 0.5.10", "substreams-common", "substreams-entity-change 0.3.0", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -625,7 +625,7 @@ dependencies = [ "prost-types 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", "thiserror", ] @@ -1114,10 +1114,21 @@ dependencies = [ "prost 0.11.9", "regex", "substreams 0.5.10", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "thiserror", ] +[[package]] +name = "substreams-database-change" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea09c700498fea3e50eb9aab5b0637d8bfce888be899aa68f987132923e46cc" +dependencies = [ + "prost 0.11.9", + "prost-types 0.11.9", + "substreams 0.5.10", +] + [[package]] name = "substreams-entity-change" version = "0.3.0" @@ -1153,7 +1164,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -1167,7 +1178,7 @@ dependencies = [ "prost 0.11.9", "substreams 0.5.10", "substreams-common", - "substreams-ethereum", + "substreams-ethereum 0.8.0", ] [[package]] @@ -1178,9 +1189,23 @@ checksum = "03a426822f6032fa28145cb2cb7661e70554da839a40ee08b6348f1479a44e1b" dependencies = [ "getrandom", "substreams 0.5.10", - "substreams-ethereum-abigen", - "substreams-ethereum-core", - "substreams-ethereum-derive", + "substreams-ethereum-abigen 0.8.0", + "substreams-ethereum-core 0.8.0", + "substreams-ethereum-derive 0.8.0", +] + +[[package]] +name = "substreams-ethereum" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" +dependencies = [ + "getrandom", + "num-bigint", + "substreams 0.5.10", + "substreams-ethereum-abigen 0.9.9", + "substreams-ethereum-core 0.9.9", + "substreams-ethereum-derive 0.9.9", ] [[package]] @@ -1196,7 +1221,24 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "substreams-ethereum-core", + "substreams-ethereum-core 0.8.0", + "syn 1.0.109", +] + +[[package]] +name = "substreams-ethereum-abigen" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" +dependencies = [ + "anyhow", + "ethabi", + "heck", + "hex", + "prettyplease", + "proc-macro2", + "quote", + "substreams-ethereum-core 0.9.9", "syn 1.0.109", ] @@ -1216,6 +1258,22 @@ dependencies = [ "substreams 0.5.10", ] +[[package]] +name = "substreams-ethereum-core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" +dependencies = [ + "bigdecimal", + "ethabi", + "getrandom", + "num-bigint", + "prost 0.11.9", + "prost-build 0.11.9", + "prost-types 0.11.9", + "substreams 0.5.10", +] + [[package]] name = "substreams-ethereum-derive" version = "0.8.0" @@ -1227,7 +1285,23 @@ dependencies = [ "hex", "proc-macro2", "quote", - "substreams-ethereum-abigen", + "substreams-ethereum-abigen 0.8.0", + "syn 1.0.109", +] + +[[package]] +name = "substreams-ethereum-derive" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" +dependencies = [ + "ethabi", + "heck", + "hex", + "num-bigint", + "proc-macro2", + "quote", + "substreams-ethereum-abigen 0.9.9", "syn 1.0.109", ] @@ -1249,7 +1323,7 @@ dependencies = [ "substreams 0.5.10", "substreams-common", "substreams-entity-change 1.3.0", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "thiserror", "tiny-keccak", ] @@ -1315,7 +1389,7 @@ dependencies = [ "substreams 0.5.10", "substreams-common", "substreams-entity-change 1.3.0", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -1354,7 +1428,7 @@ dependencies = [ "substreams 0.5.10", "substreams-common", "substreams-entity-change 1.3.0", - "substreams-ethereum", + "substreams-ethereum 0.8.0", "substreams-helper", ] @@ -1464,6 +1538,25 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "uniswap_v2" +version = "0.0.1" +dependencies = [ + "anyhow", + "ethabi", + "getrandom", + "hex-literal", + "num-bigint", + "num-traits", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "substreams 0.5.10", + "substreams-database-change", + "substreams-entity-change 1.3.0", + "substreams-ethereum 0.9.9", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index eedf6a7e..9392ff71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "eth-supply", "synthetix", "aave-v2", + "sql/uniswap_v2", ] exclude = ["messari-cli"] diff --git a/sql/dbt/logs/dbt.log b/sql/dbt/logs/dbt.log new file mode 100644 index 00000000..7414b18d --- /dev/null +++ b/sql/dbt/logs/dbt.log @@ -0,0 +1,29 @@ +19:23:45.911835 [debug] [MainThread]: Sending event: {'category': 'dbt', 'action': 'invocation', 'label': 'start', 'context': [, , ]} + + +============================== 19:23:45.953718 | 8f48e584-280b-4320-a367-b327ed9233a0 ============================== +19:23:45.953718 [info ] [MainThread]: Running with dbt=1.7.4 +19:23:45.955099 [debug] [MainThread]: running dbt with arguments {'printer_width': '80', 'indirect_selection': 'eager', 'write_json': 'True', 'log_cache_events': 'False', 'partial_parse': 'True', 'cache_selected_only': 'False', 'warn_error': 'None', 'debug': 'False', 'profiles_dir': '/home/harsh9200/.dbt', 'log_path': 'logs', 'fail_fast': 'False', 'version_check': 'True', 'use_colors': 'True', 'use_experimental_parser': 'False', 'no_print': 'None', 'quiet': 'False', 'warn_error_options': 'WarnErrorOptions(include=[], exclude=[])', 'introspect': 'True', 'invocation_command': 'dbt init uniswap_v2', 'log_format': 'default', 'target_path': 'None', 'static_parser': 'True', 'send_anonymous_usage_stats': 'True'} +19:23:45.996959 [debug] [MainThread]: Starter project path: /home/harsh9200/.local/lib/python3.8/site-packages/dbt/include/starter_project +19:23:46.287730 [info ] [MainThread]: +Your new dbt project "uniswap_v2" was created! + +For more information on how to configure the profiles.yml file, +please consult the dbt documentation here: + + https://docs.getdbt.com/docs/configure-your-profile + +One more thing: + +Need help? Don't hesitate to reach out to us via GitHub issues or on Slack: + + https://community.getdbt.com/ + +Happy modeling! + +19:23:46.289001 [info ] [MainThread]: Setting up your profile. +19:24:46.788765 [info ] [MainThread]: Profile uniswap_v2 written to /home/harsh9200/.dbt/profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection. +19:24:46.793541 [debug] [MainThread]: Resource report: {"command_name": "init", "command_success": true, "command_wall_clock_time": 61.000103, "process_user_time": 3.309072, "process_kernel_time": 0.40499, "process_mem_max_rss": "93412", "process_in_blocks": "68528", "process_out_blocks": "8"} +19:24:46.794838 [debug] [MainThread]: Command `dbt init` succeeded at 19:24:46.794585 after 61.00 seconds +19:24:46.795981 [debug] [MainThread]: Sending event: {'category': 'dbt', 'action': 'invocation', 'label': 'end', 'context': [, , ]} +19:24:46.797016 [debug] [MainThread]: Flushing usage events diff --git a/sql/dbt/uniswap_v2/.gitignore b/sql/dbt/uniswap_v2/.gitignore new file mode 100644 index 00000000..49f147cb --- /dev/null +++ b/sql/dbt/uniswap_v2/.gitignore @@ -0,0 +1,4 @@ + +target/ +dbt_packages/ +logs/ diff --git a/sql/dbt/uniswap_v2/README.md b/sql/dbt/uniswap_v2/README.md new file mode 100644 index 00000000..7874ac84 --- /dev/null +++ b/sql/dbt/uniswap_v2/README.md @@ -0,0 +1,15 @@ +Welcome to your new dbt project! + +### Using the starter project + +Try running the following commands: +- dbt run +- dbt test + + +### Resources: +- Learn more about dbt [in the docs](https://docs.getdbt.com/docs/introduction) +- Check out [Discourse](https://discourse.getdbt.com/) for commonly asked questions and answers +- Join the [chat](https://community.getdbt.com/) on Slack for live discussions and support +- Find [dbt events](https://events.getdbt.com) near you +- Check out [the blog](https://blog.getdbt.com/) for the latest news on dbt's development and best practices diff --git a/sql/dbt/uniswap_v2/analyses/.gitkeep b/sql/dbt/uniswap_v2/analyses/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/sql/dbt/uniswap_v2/dbt_project.yml b/sql/dbt/uniswap_v2/dbt_project.yml new file mode 100644 index 00000000..30919275 --- /dev/null +++ b/sql/dbt/uniswap_v2/dbt_project.yml @@ -0,0 +1,37 @@ + +# Name your project! Project names should contain only lowercase characters +# and underscores. A good package name should reflect your organization's +# name or the intended use of these models +name: 'uniswap_v2' +version: '1.0.0' +config-version: 2 + +# This setting configures which "profile" dbt uses for this project. +profile: 'uniswap_v2' + +# These configurations specify where dbt should look for different types of files. +# The `model-paths` config, for example, states that models in this project can be +# found in the "models/" directory. You probably won't need to change these! +model-paths: ["models"] +analysis-paths: ["analyses"] +test-paths: ["tests"] +seed-paths: ["seeds"] +macro-paths: ["macros"] +snapshot-paths: ["snapshots"] + +clean-targets: # directories to be removed by `dbt clean` + - "target" + - "dbt_packages" + + +# Configuring models +# Full documentation: https://docs.getdbt.com/docs/configuring-models + +# In this example config, we tell dbt to build all models in the example/ +# directory as views. These settings can be overridden in the individual model +# files using the `{{ config(...) }}` macro. +models: + uniswap_v2: + # Config indicated by + and applies to all files under models/example/ + example: + +materialized: view diff --git a/sql/dbt/uniswap_v2/macros/.gitkeep b/sql/dbt/uniswap_v2/macros/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql new file mode 100644 index 00000000..0e4d8a5f --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql @@ -0,0 +1,13 @@ + +with final as ( + select + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_block_time as block_time + , evt_block_number as block_number + , amount0 + , amount1 + from burn +) + +select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql new file mode 100644 index 00000000..39638e63 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql @@ -0,0 +1,13 @@ + +with final as ( + select + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_block_time as block_time + , evt_block_number as block_number + , amount0 + , amount1 + from mint +) + +select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql new file mode 100644 index 00000000..39638e63 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql @@ -0,0 +1,13 @@ + +with final as ( + select + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_block_time as block_time + , evt_block_number as block_number + , amount0 + , amount1 + from mint +) + +select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql new file mode 100644 index 00000000..1342a803 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql @@ -0,0 +1,13 @@ + +with final as ( + select + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_block_time as block_time + , evt_block_number as block_number + , amount0_in - amount0_out as amount0 + , amount1_in - amount1_out as amount1 + from swap +) + +select * from final diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql new file mode 100644 index 00000000..308f75a6 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql @@ -0,0 +1,12 @@ +with final as ( + select + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_block_time as block_time + , evt_block_number as block_number + , reserve0 + , reserve1 + from sync +) + +select * from final diff --git a/sql/dbt/uniswap_v2/seeds/.gitkeep b/sql/dbt/uniswap_v2/seeds/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/sql/dbt/uniswap_v2/snapshots/.gitkeep b/sql/dbt/uniswap_v2/snapshots/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/sql/dbt/uniswap_v2/tests/.gitkeep b/sql/dbt/uniswap_v2/tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/sql/uniswap_v2/Cargo.toml b/sql/uniswap_v2/Cargo.toml new file mode 100644 index 00000000..4926dc44 --- /dev/null +++ b/sql/uniswap_v2/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "uniswap_v2" +version = "0.0.1" +edition = "2021" + +[lib] +name = "substreams" +crate-type = ["cdylib"] + +[dependencies] +ethabi = "17" +hex-literal = "0.3.4" +num-bigint = "0.4" +num-traits = "0.2.15" +prost = "0.11" +prost-types = "0.11" +substreams = "0.5" +substreams-ethereum = "0.9" +substreams-database-change = "1" +substreams-entity-change = "1" + +# Required so that ethabi > ethereum-types build correctly under wasm32-unknown-unknown +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["custom"] } + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9" +regex = "1.8" + +[profile.release] +lto = true +opt-level = 's' +strip = "debuginfo" diff --git a/sql/uniswap_v2/Makefile b/sql/uniswap_v2/Makefile new file mode 100644 index 00000000..5fca602e --- /dev/null +++ b/sql/uniswap_v2/Makefile @@ -0,0 +1,26 @@ +CARGO_VERSION := $(shell cargo version 2>/dev/null) + +.PHONY: build +build: +ifdef CARGO_VERSION + cargo build --target wasm32-unknown-unknown --release +else + @echo "Building substreams target using Docker. To speed up this step, install a Rust development environment." + docker run --rm -ti --init -v ${PWD}:/usr/src --workdir /usr/src/ rust:bullseye cargo build --target wasm32-unknown-unknown --release +endif + +.PHONY: run +run: build + substreams run substreams.yaml map_events $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) + +.PHONY: gui +gui: build + substreams gui substreams.yaml map_events $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) + +.PHONY: protogen +protogen: + substreams protogen ./substreams.yaml --exclude-paths="sf/substreams,google" + +.PHONY: pack +pack: build + substreams pack substreams.yaml diff --git a/sql/uniswap_v2/abi/contract.abi.json b/sql/uniswap_v2/abi/contract.abi.json new file mode 100644 index 00000000..6eb1eaa5 --- /dev/null +++ b/sql/uniswap_v2/abi/contract.abi.json @@ -0,0 +1 @@ +[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/sql/uniswap_v2/build.rs b/sql/uniswap_v2/build.rs new file mode 100644 index 00000000..c0a354a3 --- /dev/null +++ b/sql/uniswap_v2/build.rs @@ -0,0 +1,31 @@ +use anyhow::{Ok, Result}; +use regex::Regex; +use substreams_ethereum::Abigen; +use std::fs; + +fn main() -> Result<(), anyhow::Error> { + let file_names = [ + "abi/contract.abi.json", + ]; + let file_output_names = [ + "src/abi/contract.rs", + ]; + + let mut i = 0; + for f in file_names { + let contents = fs::read_to_string(f) + .expect("Should have been able to read the file"); + + // sanitize fields and attributes starting with an underscore + let regex = Regex::new(r#"("\w+"\s?:\s?")_(\w+")"#).unwrap(); + let sanitized_abi_file = regex.replace_all(contents.as_str(), "${1}u_${2}"); + + Abigen::from_bytes("Contract", sanitized_abi_file.as_bytes())? + .generate()? + .write_to_file(file_output_names[i])?; + + i = i+1; + } + + Ok(()) +} diff --git a/sql/uniswap_v2/proto/contract.proto b/sql/uniswap_v2/proto/contract.proto new file mode 100644 index 00000000..7a7a2f1b --- /dev/null +++ b/sql/uniswap_v2/proto/contract.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package contract.v1; + +message Events { + repeated Approval approvals = 1; + repeated Burn burns = 2; + repeated Mint mints = 3; + repeated Swap swaps = 4; + repeated Sync syncs = 5; + repeated Transfer transfers = 6; +} + +message Approval { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes owner = 5; + bytes spender = 6; + string value = 7; +} + +message Burn { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes sender = 5; + string amount0 = 6; + string amount1 = 7; + bytes to = 8; +} + +message Mint { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes sender = 5; + string amount0 = 6; + string amount1 = 7; +} + +message Swap { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes sender = 5; + string amount0_in = 6; + string amount1_in = 7; + string amount0_out = 8; + string amount1_out = 9; + bytes to = 10; +} + +message Sync { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string reserve0 = 5; + string reserve1 = 6; +} + +message Transfer { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes from = 5; + bytes to = 6; + string value = 7; +} diff --git a/sql/uniswap_v2/rust-toolchain.toml b/sql/uniswap_v2/rust-toolchain.toml new file mode 100644 index 00000000..ec334c0b --- /dev/null +++ b/sql/uniswap_v2/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.65" +components = [ "rustfmt" ] +targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/sql/uniswap_v2/schema.clickhouse.sql b/sql/uniswap_v2/schema.clickhouse.sql new file mode 100644 index 00000000..18a0347e --- /dev/null +++ b/sql/uniswap_v2/schema.clickhouse.sql @@ -0,0 +1,58 @@ +CREATE TABLE IF NOT EXISTS approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "owner" VARCHAR(40), + "spender" VARCHAR(40), + "value" UInt256 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS burn ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "amount0" UInt256, + "amount1" UInt256, + "sender" VARCHAR(40), + "to" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS mint ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "amount0" UInt256, + "amount1" UInt256, + "sender" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS swap ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "amount0_in" UInt256, + "amount0_out" UInt256, + "amount1_in" UInt256, + "amount1_out" UInt256, + "sender" VARCHAR(40), + "to" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS sync ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "reserve0" UInt128, + "reserve1" UInt128 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS transfer ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "from" VARCHAR(40), + "to" VARCHAR(40), + "value" UInt256 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); + diff --git a/sql/uniswap_v2/schema.graphql b/sql/uniswap_v2/schema.graphql new file mode 100644 index 00000000..a27f20e4 --- /dev/null +++ b/sql/uniswap_v2/schema.graphql @@ -0,0 +1,63 @@ +type approval @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + owner: String! + spender: String! + value: BigDecimal! +} +type burn @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + amount0: BigDecimal! + amount1: BigDecimal! + sender: String! + to: String! +} +type mint @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + amount0: BigDecimal! + amount1: BigDecimal! + sender: String! +} +type swap @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + amount0_in: BigDecimal! + amount0_out: BigDecimal! + amount1_in: BigDecimal! + amount1_out: BigDecimal! + sender: String! + to: String! +} +type sync @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + reserve0: BigDecimal! + reserve1: BigDecimal! +} +type transfer @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + from: String! + to: String! + value: BigDecimal! +} diff --git a/sql/uniswap_v2/schema.sql b/sql/uniswap_v2/schema.sql new file mode 100644 index 00000000..f4f19483 --- /dev/null +++ b/sql/uniswap_v2/schema.sql @@ -0,0 +1,64 @@ +CREATE TABLE IF NOT EXISTS approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "owner" VARCHAR(40), + "spender" VARCHAR(40), + "value" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS burn ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "amount0" DECIMAL, + "amount1" DECIMAL, + "sender" VARCHAR(40), + "to" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS mint ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "amount0" DECIMAL, + "amount1" DECIMAL, + "sender" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS swap ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "amount0_in" DECIMAL, + "amount0_out" DECIMAL, + "amount1_in" DECIMAL, + "amount1_out" DECIMAL, + "sender" VARCHAR(40), + "to" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS sync ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "reserve0" DECIMAL, + "reserve1" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS transfer ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "from" VARCHAR(40), + "to" VARCHAR(40), + "value" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); + diff --git a/sql/uniswap_v2/src/abi/contract.rs b/sql/uniswap_v2/src/abi/contract.rs new file mode 100644 index 00000000..fb99a2db --- /dev/null +++ b/sql/uniswap_v2/src/abi/contract.rs @@ -0,0 +1,3556 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct DomainSeparator {} + impl DomainSeparator { + const METHOD_ID: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for DomainSeparator { + const NAME: &'static str = "DOMAIN_SEPARATOR"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for DomainSeparator { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct MinimumLiquidity {} + impl MinimumLiquidity { + const METHOD_ID: [u8; 4] = [186u8, 154u8, 122u8, 86u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for MinimumLiquidity { + const NAME: &'static str = "MINIMUM_LIQUIDITY"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for MinimumLiquidity { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PermitTypehash {} + impl PermitTypehash { + const METHOD_ID: [u8; 4] = [48u8, 173u8, 248u8, 31u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for PermitTypehash { + const NAME: &'static str = "PERMIT_TYPEHASH"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for PermitTypehash { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Allowance { + pub param0: Vec, + pub param1: Vec, + } + impl Allowance { + const METHOD_ID: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.param1)), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Allowance { + const NAME: &'static str = "allowance"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Allowance { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Approve { + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approve { + const METHOD_ID: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + spender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.spender), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Approve { + const NAME: &'static str = "approve"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Approve { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct BalanceOf { + pub param0: Vec, + } + impl BalanceOf { + const METHOD_ID: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.param0))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for BalanceOf { + const NAME: &'static str = "balanceOf"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for BalanceOf { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Burn { + pub to: Vec, + } + impl Burn { + const METHOD_ID: [u8; 4] = [137u8, 175u8, 203u8, 68u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.to))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Burn { + const NAME: &'static str = "burn"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for Burn { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Decimals {} + impl Decimals { + const METHOD_ID: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(8usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Decimals { + const NAME: &'static str = "decimals"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Decimals { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Factory {} + impl Factory { + const METHOD_ID: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Factory { + const NAME: &'static str = "factory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Factory { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetReserves {} + impl GetReserves { + const METHOD_ID: [u8; 4] = [9u8, 2u8, 241u8, 172u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(112usize), + ethabi::ParamType::Uint(112usize), + ethabi::ParamType::Uint(32usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetReserves { + const NAME: &'static str = "getReserves"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > for GetReserves { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Initialize { + pub u_token0: Vec, + pub u_token1: Vec, + } + impl Initialize { + const METHOD_ID: [u8; 4] = [72u8, 92u8, 201u8, 85u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + u_token0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + u_token1: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_token0), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_token1), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Initialize { + const NAME: &'static str = "initialize"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct KLast {} + impl KLast { + const METHOD_ID: [u8; 4] = [116u8, 100u8, 252u8, 61u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for KLast { + const NAME: &'static str = "kLast"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for KLast { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Mint { + pub to: Vec, + } + impl Mint { + const METHOD_ID: [u8; 4] = [106u8, 98u8, 120u8, 66u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.to))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Mint { + const NAME: &'static str = "mint"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Mint { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Name {} + impl Name { + const METHOD_ID: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Name { + const NAME: &'static str = "name"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Name { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Nonces { + pub param0: Vec, + } + impl Nonces { + const METHOD_ID: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.param0))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Nonces { + const NAME: &'static str = "nonces"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Nonces { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Permit { + pub owner: Vec, + pub spender: Vec, + pub value: substreams::scalar::BigInt, + pub deadline: substreams::scalar::BigInt, + pub v: substreams::scalar::BigInt, + pub r: [u8; 32usize], + pub s: [u8; 32usize], + } + impl Permit { + const METHOD_ID: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + spender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + deadline: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + v: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + r: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + s: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.spender), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.deadline.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.v.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::FixedBytes(self.r.as_ref().to_vec()), + ethabi::Token::FixedBytes(self.s.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Permit { + const NAME: &'static str = "permit"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Price0CumulativeLast {} + impl Price0CumulativeLast { + const METHOD_ID: [u8; 4] = [89u8, 9u8, 192u8, 213u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Price0CumulativeLast { + const NAME: &'static str = "price0CumulativeLast"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Price0CumulativeLast { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Price1CumulativeLast {} + impl Price1CumulativeLast { + const METHOD_ID: [u8; 4] = [90u8, 61u8, 84u8, 147u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Price1CumulativeLast { + const NAME: &'static str = "price1CumulativeLast"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Price1CumulativeLast { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Skim { + pub to: Vec, + } + impl Skim { + const METHOD_ID: [u8; 4] = [188u8, 37u8, 207u8, 119u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.to))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Skim { + const NAME: &'static str = "skim"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub amount0_out: substreams::scalar::BigInt, + pub amount1_out: substreams::scalar::BigInt, + pub to: Vec, + pub data: Vec, + } + impl Swap { + const METHOD_ID: [u8; 4] = [2u8, 44u8, 13u8, 159u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + amount0_out: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1_out: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount0_out.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount1_out.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Bytes(self.data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Swap { + const NAME: &'static str = "swap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Symbol {} + impl Symbol { + const METHOD_ID: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Symbol { + const NAME: &'static str = "symbol"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Symbol { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Sync {} + impl Sync { + const METHOD_ID: [u8; 4] = [255u8, 246u8, 202u8, 233u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Sync { + const NAME: &'static str = "sync"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Token0 {} + impl Token0 { + const METHOD_ID: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Token0 { + const NAME: &'static str = "token0"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Token0 { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Token1 {} + impl Token1 { + const METHOD_ID: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Token1 { + const NAME: &'static str = "token1"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Token1 { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TotalSupply {} + impl TotalSupply { + const METHOD_ID: [u8; 4] = [24u8, 22u8, 13u8, 221u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for TotalSupply { + const NAME: &'static str = "totalSupply"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for TotalSupply { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Transfer { + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const METHOD_ID: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Transfer { + const NAME: &'static str = "transfer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Transfer { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TransferFrom { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl TransferFrom { + const METHOD_ID: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + from: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.from)), + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for TransferFrom { + const NAME: &'static str = "transferFrom"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for TransferFrom { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Approval { + pub owner: Vec, + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approval { + const TOPIC_ID: [u8; 32] = [ + 140u8, + 91u8, + 225u8, + 229u8, + 235u8, + 236u8, + 125u8, + 91u8, + 209u8, + 79u8, + 113u8, + 66u8, + 125u8, + 30u8, + 132u8, + 243u8, + 221u8, + 3u8, + 20u8, + 192u8, + 247u8, + 178u8, + 41u8, + 30u8, + 91u8, + 32u8, + 10u8, + 200u8, + 199u8, + 195u8, + 185u8, + 37u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + spender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'spender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Approval { + const NAME: &'static str = "Approval"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Burn { + pub sender: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + pub to: Vec, + } + impl Burn { + const TOPIC_ID: [u8; 32] = [ + 220u8, + 205u8, + 65u8, + 47u8, + 11u8, + 18u8, + 82u8, + 129u8, + 156u8, + 177u8, + 253u8, + 51u8, + 11u8, + 147u8, + 34u8, + 76u8, + 164u8, + 38u8, + 18u8, + 137u8, + 43u8, + 179u8, + 244u8, + 247u8, + 137u8, + 151u8, + 110u8, + 109u8, + 129u8, + 147u8, + 100u8, + 150u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Burn { + const NAME: &'static str = "Burn"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Mint { + pub sender: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl Mint { + const TOPIC_ID: [u8; 32] = [ + 76u8, + 32u8, + 155u8, + 95u8, + 200u8, + 173u8, + 80u8, + 117u8, + 143u8, + 19u8, + 226u8, + 225u8, + 8u8, + 139u8, + 165u8, + 106u8, + 86u8, + 13u8, + 255u8, + 105u8, + 10u8, + 28u8, + 111u8, + 239u8, + 38u8, + 57u8, + 79u8, + 76u8, + 3u8, + 130u8, + 28u8, + 79u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Mint { + const NAME: &'static str = "Mint"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub sender: Vec, + pub amount0_in: substreams::scalar::BigInt, + pub amount1_in: substreams::scalar::BigInt, + pub amount0_out: substreams::scalar::BigInt, + pub amount1_out: substreams::scalar::BigInt, + pub to: Vec, + } + impl Swap { + const TOPIC_ID: [u8; 32] = [ + 215u8, + 138u8, + 217u8, + 95u8, + 164u8, + 108u8, + 153u8, + 75u8, + 101u8, + 81u8, + 208u8, + 218u8, + 133u8, + 252u8, + 39u8, + 95u8, + 230u8, + 19u8, + 206u8, + 55u8, + 101u8, + 127u8, + 184u8, + 213u8, + 227u8, + 209u8, + 48u8, + 132u8, + 1u8, + 89u8, + 216u8, + 34u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 128usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0_in: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1_in: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount0_out: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1_out: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Swap { + const NAME: &'static str = "Swap"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Sync { + pub reserve0: substreams::scalar::BigInt, + pub reserve1: substreams::scalar::BigInt, + } + impl Sync { + const TOPIC_ID: [u8; 32] = [ + 28u8, + 65u8, + 30u8, + 154u8, + 150u8, + 224u8, + 113u8, + 36u8, + 28u8, + 47u8, + 33u8, + 247u8, + 114u8, + 107u8, + 23u8, + 174u8, + 137u8, + 227u8, + 202u8, + 180u8, + 199u8, + 139u8, + 229u8, + 14u8, + 6u8, + 43u8, + 3u8, + 169u8, + 255u8, + 251u8, + 186u8, + 209u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(112usize), + ethabi::ParamType::Uint(112usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + reserve0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + reserve1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Sync { + const NAME: &'static str = "Sync"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Transfer { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const TOPIC_ID: [u8; 32] = [ + 221u8, + 242u8, + 82u8, + 173u8, + 27u8, + 226u8, + 200u8, + 155u8, + 105u8, + 194u8, + 176u8, + 104u8, + 252u8, + 55u8, + 141u8, + 170u8, + 149u8, + 43u8, + 167u8, + 241u8, + 99u8, + 196u8, + 161u8, + 22u8, + 40u8, + 245u8, + 90u8, + 77u8, + 245u8, + 35u8, + 179u8, + 239u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + from: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'from' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Transfer { + const NAME: &'static str = "Transfer"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/sql/uniswap_v2/src/abi/mod.rs b/sql/uniswap_v2/src/abi/mod.rs new file mode 100644 index 00000000..2943dbb5 --- /dev/null +++ b/sql/uniswap_v2/src/abi/mod.rs @@ -0,0 +1 @@ +pub mod contract; diff --git a/sql/uniswap_v2/src/lib.rs b/sql/uniswap_v2/src/lib.rs new file mode 100644 index 00000000..9f60c6a9 --- /dev/null +++ b/sql/uniswap_v2/src/lib.rs @@ -0,0 +1,307 @@ +mod abi; +mod pb; +use hex_literal::hex; +use pb::contract::v1 as contract; +use substreams::Hex; +use substreams_database_change::pb::database::DatabaseChanges; +use substreams_database_change::tables::Tables as DatabaseChangeTables; +use substreams_entity_change::pb::entity::EntityChanges; +use substreams_entity_change::tables::Tables as EntityChangesTables; +use substreams_ethereum::pb::eth::v2 as eth; +use substreams_ethereum::Event; + +#[allow(unused_imports)] +use num_traits::cast::ToPrimitive; +use std::str::FromStr; +use substreams::scalar::BigDecimal; + +const TRACKED_CONTRACT: [u8; 20] = hex!("0d4a11d5eeaac28ec3f61d100daf4d40471f1852"); + +substreams_ethereum::init!(); + +#[substreams::handlers::map] +fn map_events(blk: eth::Block) -> Result { + Ok(contract::Events { + approvals: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Approval::match_and_decode(log) { + return Some(contract::Approval { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + owner: event.owner, + spender: event.spender, + value: event.value.to_string(), + }); + } + + None + }) + }) + .collect(), + burns: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Burn::match_and_decode(log) { + return Some(contract::Burn { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + to: event.to, + }); + } + + None + }) + }) + .collect(), + mints: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Mint::match_and_decode(log) { + return Some(contract::Mint { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + }); + } + + None + }) + }) + .collect(), + swaps: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Swap::match_and_decode(log) { + return Some(contract::Swap { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + amount0_in: event.amount0_in.to_string(), + amount0_out: event.amount0_out.to_string(), + amount1_in: event.amount1_in.to_string(), + amount1_out: event.amount1_out.to_string(), + sender: event.sender, + to: event.to, + }); + } + + None + }) + }) + .collect(), + syncs: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Sync::match_and_decode(log) { + return Some(contract::Sync { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + reserve0: event.reserve0.to_string(), + reserve1: event.reserve1.to_string(), + }); + } + + None + }) + }) + .collect(), + transfers: blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::contract::events::Transfer::match_and_decode(log) { + return Some(contract::Transfer { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + from: event.from, + to: event.to, + value: event.value.to_string(), + }); + } + + None + }) + }) + .collect(), + }) +} + +#[substreams::handlers::map] +fn db_out(events: contract::Events) -> Result { + // Initialize changes container + let mut tables = DatabaseChangeTables::new(); + + // Loop over all the abis events to create changes + events.approvals.into_iter().for_each(|evt| { + tables + .create_row("approval", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("owner", Hex(&evt.owner).to_string()) + .set("spender", Hex(&evt.spender).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + events.burns.into_iter().for_each(|evt| { + tables + .create_row("burn", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.mints.into_iter().for_each(|evt| { + tables + .create_row("mint", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()); + }); + events.swaps.into_iter().for_each(|evt| { + tables + .create_row("swap", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) + .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) + .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) + .set("amount1_out", BigDecimal::from_str(&evt.amount1_out).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.syncs.into_iter().for_each(|evt| { + tables + .create_row("sync", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("reserve0", BigDecimal::from_str(&evt.reserve0).unwrap()) + .set("reserve1", BigDecimal::from_str(&evt.reserve1).unwrap()); + }); + events.transfers.into_iter().for_each(|evt| { + tables + .create_row("transfer", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("from", Hex(&evt.from).to_string()) + .set("to", Hex(&evt.to).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + + Ok(tables.to_database_changes()) +} + +#[substreams::handlers::map] +fn graph_out(events: contract::Events) -> Result { + // Initialize changes container + let mut tables = EntityChangesTables::new(); + + // Loop over all the abis events to create changes + events.approvals.into_iter().for_each(|evt| { + tables + .create_row("approval", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("owner", Hex(&evt.owner).to_string()) + .set("spender", Hex(&evt.spender).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + events.burns.into_iter().for_each(|evt| { + tables + .create_row("burn", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.mints.into_iter().for_each(|evt| { + tables + .create_row("mint", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()); + }); + events.swaps.into_iter().for_each(|evt| { + tables + .create_row("swap", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) + .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) + .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) + .set("amount1_out", BigDecimal::from_str(&evt.amount1_out).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.syncs.into_iter().for_each(|evt| { + tables + .create_row("sync", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("reserve0", BigDecimal::from_str(&evt.reserve0).unwrap()) + .set("reserve1", BigDecimal::from_str(&evt.reserve1).unwrap()); + }); + events.transfers.into_iter().for_each(|evt| { + tables + .create_row("transfer", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("from", Hex(&evt.from).to_string()) + .set("to", Hex(&evt.to).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + + Ok(tables.to_entity_changes()) +} diff --git a/sql/uniswap_v2/src/pb/contract.v1.rs b/sql/uniswap_v2/src/pb/contract.v1.rs new file mode 100644 index 00000000..5f3140ae --- /dev/null +++ b/sql/uniswap_v2/src/pb/contract.v1.rs @@ -0,0 +1,132 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Events { + #[prost(message, repeated, tag="1")] + pub approvals: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub burns: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="3")] + pub mints: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="4")] + pub swaps: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="5")] + pub syncs: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="6")] + pub transfers: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Approval { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(bytes="vec", tag="5")] + pub owner: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="6")] + pub spender: ::prost::alloc::vec::Vec, + #[prost(string, tag="7")] + pub value: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Burn { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(bytes="vec", tag="5")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="6")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub amount1: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="8")] + pub to: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Mint { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(bytes="vec", tag="5")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="6")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub amount1: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Swap { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(bytes="vec", tag="5")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="6")] + pub amount0_in: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub amount1_in: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub amount0_out: ::prost::alloc::string::String, + #[prost(string, tag="9")] + pub amount1_out: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="10")] + pub to: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Sync { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub reserve0: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub reserve1: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfer { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(bytes="vec", tag="5")] + pub from: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="6")] + pub to: ::prost::alloc::vec::Vec, + #[prost(string, tag="7")] + pub value: ::prost::alloc::string::String, +} +// @@protoc_insertion_point(module) diff --git a/sql/uniswap_v2/src/pb/mod.rs b/sql/uniswap_v2/src/pb/mod.rs new file mode 100644 index 00000000..611ea83c --- /dev/null +++ b/sql/uniswap_v2/src/pb/mod.rs @@ -0,0 +1,8 @@ +// @generated +pub mod contract { + // @@protoc_insertion_point(attribute:contract.v1) + pub mod v1 { + include!("contract.v1.rs"); + // @@protoc_insertion_point(contract.v1) + } +} diff --git a/sql/uniswap_v2/subgraph.yaml b/sql/uniswap_v2/subgraph.yaml new file mode 100644 index 00000000..a8d2b569 --- /dev/null +++ b/sql/uniswap_v2/subgraph.yaml @@ -0,0 +1,17 @@ +specVersion: 0.0.6 +description: uniswap-v2 substreams based subgraph +repository: # fill in with git remote url +schema: + file: ./schema.graphql + +dataSources: + - kind: substreams + name: uniswap-v2 + network: mainnet + source: + package: + moduleName: graph_out + file: uniswap-v2-v0.1.0.spkg + mapping: + kind: substreams/graph-entities + apiVersion: 0.0.5 diff --git a/sql/uniswap_v2/substreams.clickhouse.yaml b/sql/uniswap_v2/substreams.clickhouse.yaml new file mode 100644 index 00000000..1c793883 --- /dev/null +++ b/sql/uniswap_v2/substreams.clickhouse.yaml @@ -0,0 +1,59 @@ +specVersion: v0.1.0 +package: + name: uniswap_v2 + version: v0.1.0 + +imports: + sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.7/substreams-sink-sql-protodefs-v1.0.7.spkg + graph: https://github.com/streamingfast/substreams-sink-subgraph/releases/download/v0.1.0/substreams-sink-subgraph-protodefs-v0.1.0.spkg + database_change: https://github.com/streamingfast/substreams-sink-database-changes/releases/download/v1.2.1/substreams-database-change-v1.2.1.spkg + entity: https://github.com/streamingfast/substreams-entity-change/releases/download/v1.1.0/substreams-entity-change-v1.1.0.spkg + +protobuf: + files: + - contract.proto + importPaths: + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: ./target/wasm32-unknown-unknown/release/substreams.wasm + +modules: + - name: map_events + kind: map + initialBlock: 10110528 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.entity.v1.EntityChanges + +network: mainnet + +sink: + module: db_out + type: sf.substreams.sink.sql.v1.Service + config: + schema: "./schema.clickhouse.sql" + engine: clickhouse + postgraphile_frontend: + enabled: false + rest_frontend: + enabled: false diff --git a/sql/uniswap_v2/substreams.sql.yaml b/sql/uniswap_v2/substreams.sql.yaml new file mode 100644 index 00000000..af7b8bf4 --- /dev/null +++ b/sql/uniswap_v2/substreams.sql.yaml @@ -0,0 +1,57 @@ +specVersion: v0.1.0 +package: + name: uniswap_v2 + version: v0.1.0 + +imports: + sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.7/substreams-sink-sql-protodefs-v1.0.7.spkg + graph: https://github.com/streamingfast/substreams-sink-subgraph/releases/download/v0.1.0/substreams-sink-subgraph-protodefs-v0.1.0.spkg + database_change: https://github.com/streamingfast/substreams-sink-database-changes/releases/download/v1.2.1/substreams-database-change-v1.2.1.spkg + entity: https://github.com/streamingfast/substreams-entity-change/releases/download/v1.1.0/substreams-entity-change-v1.1.0.spkg + +protobuf: + files: + - contract.proto + importPaths: + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: ../../target/wasm32-unknown-unknown/release/substreams.wasm + +modules: + - name: map_events + kind: map + initialBlock: 10110528 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.entity.v1.EntityChanges + +network: mainnet + +sink: + module: db_out + type: sf.substreams.sink.sql.v1.Service + config: + schema: "./schema.sql" + engine: postgres + postgraphile_frontend: + enabled: true diff --git a/sql/uniswap_v2/substreams.subgraph.yaml b/sql/uniswap_v2/substreams.subgraph.yaml new file mode 100644 index 00000000..0ee78f4e --- /dev/null +++ b/sql/uniswap_v2/substreams.subgraph.yaml @@ -0,0 +1,56 @@ +specVersion: v0.1.0 +package: + name: uniswap_v2 + version: v0.1.0 + +imports: + sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.7/substreams-sink-sql-protodefs-v1.0.7.spkg + graph: https://github.com/streamingfast/substreams-sink-subgraph/releases/download/v0.1.0/substreams-sink-subgraph-protodefs-v0.1.0.spkg + database_change: https://github.com/streamingfast/substreams-sink-database-changes/releases/download/v1.2.1/substreams-database-change-v1.2.1.spkg + entity: https://github.com/streamingfast/substreams-entity-change/releases/download/v1.1.0/substreams-entity-change-v1.1.0.spkg + +protobuf: + files: + - contract.proto + importPaths: + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: ./target/wasm32-unknown-unknown/release/substreams.wasm + +modules: + - name: map_events + kind: map + initialBlock: 10110528 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.entity.v1.EntityChanges + +network: mainnet + +sink: + module: graph_out + type: sf.substreams.sink.subgraph.v1.Service + config: + schema: "./schema.graphql" + subgraph_yaml: "./subgraph.yaml" + postgres_direct_protocol_access: true diff --git a/sql/uniswap_v2/substreams.yaml b/sql/uniswap_v2/substreams.yaml new file mode 100644 index 00000000..7b1d10cf --- /dev/null +++ b/sql/uniswap_v2/substreams.yaml @@ -0,0 +1,48 @@ +specVersion: v0.1.0 +package: + name: uniswap_v2 + version: v0.1.0 + +imports: + sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.7/substreams-sink-sql-protodefs-v1.0.7.spkg + graph: https://github.com/streamingfast/substreams-sink-subgraph/releases/download/v0.1.0/substreams-sink-subgraph-protodefs-v0.1.0.spkg + database_change: https://github.com/streamingfast/substreams-sink-database-changes/releases/download/v1.2.1/substreams-database-change-v1.2.1.spkg + entity: https://github.com/streamingfast/substreams-entity-change/releases/download/v1.1.0/substreams-entity-change-v1.1.0.spkg + +protobuf: + files: + - contract.proto + importPaths: + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: ./target/wasm32-unknown-unknown/release/substreams.wasm + +modules: + - name: map_events + kind: map + initialBlock: 10110528 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10110528 + inputs: + - map: map_events + output: + type: proto:sf.substreams.entity.v1.EntityChanges + +network: mainnet From 8f39307fff4c12912287f702df08dbdbe0da47f9 Mon Sep 17 00:00:00 2001 From: Harsh Date: Thu, 25 Jan 2024 01:37:03 +0530 Subject: [PATCH 2/6] Add dbt models --- .../analytics/uniswap_v2_ethereum__pool.sql | 16 +++++---- .../analytics/uniswap_v2_ethereum__swaps.sql | 16 +++++++-- .../uniswap_v2_ethereum__token_prices.sql | 26 +++++++++++++++ .../analytics/uniswap_v2_ethereum__tvl.sql | 33 +++++++++++++++++++ .../analytics/uniswap_v2_ethereum__volume.sql | 32 ++++++++++++++++++ 5 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql create mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql index 39638e63..d1c2738c 100644 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql @@ -1,13 +1,15 @@ with final as ( select - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_block_time as block_time - , evt_block_number as block_number - , amount0 - , amount1 - from mint + '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' as pool_address + , '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' as token0__id + , 'Wrapped ETH' as token0__name + , 'WETH' as token0__symbol + , '18' as token0__decimals + , '0xdAC17F958D2ee523a2206206994597C13D831ec7' as token1__id + , 'Tether USD' as token1__name + , 'USDT' as token1__symbol + , '6' as token1__decimals ) select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql index 1342a803..26e49bc8 100644 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql @@ -1,3 +1,4 @@ +{% set pool = ref("uniswap_v2_ethereum__pool") %} with final as ( select @@ -5,9 +6,20 @@ with final as ( , evt_index as log_index , evt_block_time as block_time , evt_block_number as block_number - , amount0_in - amount0_out as amount0 - , amount1_in - amount1_out as amount1 + , case + when amount0_in > 0 then p.token0__id else p.token1__id + end as token_in__id + , case + when amount0_in > 0 then amount0_in else amount1_in + end as amount_in + , case + when amount0_in > 0 then p.token1__id else p.token0__id + end as token_out__id + , case + when amount0_in > 0 then amount1_out else amount0_out + end as amount_out from swap + cross join {{ pool }} p ) select * from final diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql new file mode 100644 index 00000000..96b7a118 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql @@ -0,0 +1,26 @@ +{% set swaps = ref("uniswap_v2_ethereum__swaps") %} + +with final as ( + select + transaction_hash + , log_index + , amount_in + , amount_out + , token_in__id + , case + when token_in__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 6 else 18 + end as token_in__decimals + , case + when token_in__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 1 else (amount_out / pow(10, 6)) / (amount_in / pow(10, 18)) + end as token_in__price + , token_out__id + , case + when token_out__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 6 else 18 + end as token_out__decimals + , case + when token_out__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 1 else (amount_in / pow(10, 6)) / (amount_out / pow(10, 18)) + end as token_out__price + from {{ swaps }} +) + +select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql new file mode 100644 index 00000000..b5e1b2aa --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql @@ -0,0 +1,33 @@ +{% set sync = ref("uniswap_v2_ethereum__sync") %} +{% set prices = ref("uniswap_v2_ethereum__token_prices") %} + +with tvl as ( + select + s.transaction_hash + , s.log_index + , s.block_number + , s.block_time + , case + when sw.token_in__id = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' then (s.reserve0 / pow(10, 18)) * sw.token_in__price + when sw.token_out__id = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' then (s.reserve0 / pow(10, 18)) * sw.token_out__price + end as token0_balance_usd + , s.reserve1 / pow(10, 6) as token1_balance_usd + from {{ sync }} s + left join {{ prices }} sw + on s.transaction_hash = sw.transaction_hash + and s.log_index = sw.log_index - 1 +) + +, final as ( + select + transaction_hash + , log_index + , block_number + , block_time + , token0_balance_usd + , token1_balance_usd + , (token0_balance_usd + token1_balance_usd) as tvl + from tvl +) + +select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql new file mode 100644 index 00000000..a3a11651 --- /dev/null +++ b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql @@ -0,0 +1,32 @@ +{% set swaps = ref("uniswap_v2_ethereum__swaps") %} +{% set prices = ref("uniswap_v2_ethereum__token_prices") %} + +with swap_volume as ( + select + s.transaction_hash + , s.log_index + , s.block_number + , s.block_time + , s.token_in__id + , (s.amount_in * p.token_in__price) / pow(10, p.token_in__decimals) as amount_in_usd + , s.token_out__id + , (s.amount_out * p.token_out__price) / pow(10, p.token_out__decimals) as amount_out_usd + from {{ swaps }} s + left join {{ prices }} p + on s.transaction_hash = p.transaction_hash + and s.log_index = p.log_index +) + +, final as ( + select + transaction_hash + , log_index + , block_number + , block_time + , amount_in_usd + , amount_out_usd + , (amount_in_usd + amount_out_usd) / 2 as volume + from swap_volume +) + +select * from final \ No newline at end of file From 892b0188118a5dc99f02e1602032de965fee1769 Mon Sep 17 00:00:00 2001 From: Harsh Date: Fri, 26 Jan 2024 22:19:18 +0530 Subject: [PATCH 3/6] update clickhouse yaml --- sql/uniswap_v2/substreams.clickhouse.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/uniswap_v2/substreams.clickhouse.yaml b/sql/uniswap_v2/substreams.clickhouse.yaml index 1c793883..c56b6ca5 100644 --- a/sql/uniswap_v2/substreams.clickhouse.yaml +++ b/sql/uniswap_v2/substreams.clickhouse.yaml @@ -18,7 +18,7 @@ protobuf: binaries: default: type: wasm/rust-v1 - file: ./target/wasm32-unknown-unknown/release/substreams.wasm + file: ../../target/wasm32-unknown-unknown/release/substreams.wasm modules: - name: map_events From 767a02c956c2a028c398433fe87a20d01b06474d Mon Sep 17 00:00:00 2001 From: Harsh Date: Mon, 12 Feb 2024 16:28:46 +0530 Subject: [PATCH 4/6] Add support for multiple datasources --- .gitignore | 2 + sql/dbt/logs/dbt.log | 29 - .../.gitignore | 0 .../README.md | 0 .../analyses/.gitkeep | 0 .../dbt_project.yml | 6 +- .../macros/.gitkeep | 0 .../models/example/my_first_dbt_model.sql | 27 + .../models/example/my_second_dbt_model.sql | 6 + .../models/example/schema.yml | 21 + .../seeds/.gitkeep | 0 .../snapshots/.gitkeep | 0 .../tests/.gitkeep | 0 .../analytics/uniswap_v2_ethereum__burn.sql | 13 - .../analytics/uniswap_v2_ethereum__mint.sql | 13 - .../analytics/uniswap_v2_ethereum__pool.sql | 15 - .../analytics/uniswap_v2_ethereum__swaps.sql | 25 - .../analytics/uniswap_v2_ethereum__sync.sql | 12 - .../uniswap_v2_ethereum__token_prices.sql | 26 - .../analytics/uniswap_v2_ethereum__tvl.sql | 33 - .../analytics/uniswap_v2_ethereum__volume.sql | 32 - sql/uniswap_v2/Makefile | 4 +- sql/uniswap_v2/abi/factory_contract.abi.json | 1 + ...tract.abi.json => pools_contract.abi.json} | 0 sql/uniswap_v2/build.rs | 6 +- sql/uniswap_v2/proto/contract.proto | 84 +- sql/uniswap_v2/schema.clickhouse.sql | 29 +- sql/uniswap_v2/schema.graphql | 32 +- sql/uniswap_v2/schema.sql | 31 +- sql/uniswap_v2/src/abi/factory_contract.rs | 908 ++++++++++++++++++ sql/uniswap_v2/src/abi/mod.rs | 4 +- .../abi/{contract.rs => pools_contract.rs} | 0 sql/uniswap_v2/src/lib.rs | 489 ++++++---- sql/uniswap_v2/src/pb/contract.v1.rs | 96 +- sql/uniswap_v2/substreams.clickhouse.yaml | 17 +- sql/uniswap_v2/substreams.sql.yaml | 15 +- sql/uniswap_v2/substreams.subgraph.yaml | 15 +- sql/uniswap_v2/substreams.yaml | 15 +- 38 files changed, 1520 insertions(+), 486 deletions(-) delete mode 100644 sql/dbt/logs/dbt.log rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/.gitignore (100%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/README.md (100%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/analyses/.gitkeep (100%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/dbt_project.yml (90%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/macros/.gitkeep (100%) create mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql create mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql create mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/seeds/.gitkeep (100%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/snapshots/.gitkeep (100%) rename sql/dbt/{uniswap_v2 => projects/protocol_uniswap_v2_ethereum_mainnet}/tests/.gitkeep (100%) delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql delete mode 100644 sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql create mode 100644 sql/uniswap_v2/abi/factory_contract.abi.json rename sql/uniswap_v2/abi/{contract.abi.json => pools_contract.abi.json} (100%) create mode 100644 sql/uniswap_v2/src/abi/factory_contract.rs rename sql/uniswap_v2/src/abi/{contract.rs => pools_contract.rs} (100%) diff --git a/.gitignore b/.gitignore index e12b4ca6..f78c5729 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ Reference/ **/target/ **/build/ **/data/ +**/logs/dbt.log +**/logs/ **/*.spkg **/buf.gen.yaml replay.log diff --git a/sql/dbt/logs/dbt.log b/sql/dbt/logs/dbt.log deleted file mode 100644 index 7414b18d..00000000 --- a/sql/dbt/logs/dbt.log +++ /dev/null @@ -1,29 +0,0 @@ -19:23:45.911835 [debug] [MainThread]: Sending event: {'category': 'dbt', 'action': 'invocation', 'label': 'start', 'context': [, , ]} - - -============================== 19:23:45.953718 | 8f48e584-280b-4320-a367-b327ed9233a0 ============================== -19:23:45.953718 [info ] [MainThread]: Running with dbt=1.7.4 -19:23:45.955099 [debug] [MainThread]: running dbt with arguments {'printer_width': '80', 'indirect_selection': 'eager', 'write_json': 'True', 'log_cache_events': 'False', 'partial_parse': 'True', 'cache_selected_only': 'False', 'warn_error': 'None', 'debug': 'False', 'profiles_dir': '/home/harsh9200/.dbt', 'log_path': 'logs', 'fail_fast': 'False', 'version_check': 'True', 'use_colors': 'True', 'use_experimental_parser': 'False', 'no_print': 'None', 'quiet': 'False', 'warn_error_options': 'WarnErrorOptions(include=[], exclude=[])', 'introspect': 'True', 'invocation_command': 'dbt init uniswap_v2', 'log_format': 'default', 'target_path': 'None', 'static_parser': 'True', 'send_anonymous_usage_stats': 'True'} -19:23:45.996959 [debug] [MainThread]: Starter project path: /home/harsh9200/.local/lib/python3.8/site-packages/dbt/include/starter_project -19:23:46.287730 [info ] [MainThread]: -Your new dbt project "uniswap_v2" was created! - -For more information on how to configure the profiles.yml file, -please consult the dbt documentation here: - - https://docs.getdbt.com/docs/configure-your-profile - -One more thing: - -Need help? Don't hesitate to reach out to us via GitHub issues or on Slack: - - https://community.getdbt.com/ - -Happy modeling! - -19:23:46.289001 [info ] [MainThread]: Setting up your profile. -19:24:46.788765 [info ] [MainThread]: Profile uniswap_v2 written to /home/harsh9200/.dbt/profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection. -19:24:46.793541 [debug] [MainThread]: Resource report: {"command_name": "init", "command_success": true, "command_wall_clock_time": 61.000103, "process_user_time": 3.309072, "process_kernel_time": 0.40499, "process_mem_max_rss": "93412", "process_in_blocks": "68528", "process_out_blocks": "8"} -19:24:46.794838 [debug] [MainThread]: Command `dbt init` succeeded at 19:24:46.794585 after 61.00 seconds -19:24:46.795981 [debug] [MainThread]: Sending event: {'category': 'dbt', 'action': 'invocation', 'label': 'end', 'context': [, , ]} -19:24:46.797016 [debug] [MainThread]: Flushing usage events diff --git a/sql/dbt/uniswap_v2/.gitignore b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/.gitignore similarity index 100% rename from sql/dbt/uniswap_v2/.gitignore rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/.gitignore diff --git a/sql/dbt/uniswap_v2/README.md b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/README.md similarity index 100% rename from sql/dbt/uniswap_v2/README.md rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/README.md diff --git a/sql/dbt/uniswap_v2/analyses/.gitkeep b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/analyses/.gitkeep similarity index 100% rename from sql/dbt/uniswap_v2/analyses/.gitkeep rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/analyses/.gitkeep diff --git a/sql/dbt/uniswap_v2/dbt_project.yml b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/dbt_project.yml similarity index 90% rename from sql/dbt/uniswap_v2/dbt_project.yml rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/dbt_project.yml index 30919275..abf7d0a4 100644 --- a/sql/dbt/uniswap_v2/dbt_project.yml +++ b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/dbt_project.yml @@ -2,12 +2,12 @@ # Name your project! Project names should contain only lowercase characters # and underscores. A good package name should reflect your organization's # name or the intended use of these models -name: 'uniswap_v2' +name: 'protocol_uniswap_v2_ethereum_mainnet' version: '1.0.0' config-version: 2 # This setting configures which "profile" dbt uses for this project. -profile: 'uniswap_v2' +profile: 'protocol_uniswap_v2_ethereum_mainnet' # These configurations specify where dbt should look for different types of files. # The `model-paths` config, for example, states that models in this project can be @@ -31,7 +31,7 @@ clean-targets: # directories to be removed by `dbt clean` # directory as views. These settings can be overridden in the individual model # files using the `{{ config(...) }}` macro. models: - uniswap_v2: + protocol_uniswap_v2_ethereum_mainnet: # Config indicated by + and applies to all files under models/example/ example: +materialized: view diff --git a/sql/dbt/uniswap_v2/macros/.gitkeep b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/macros/.gitkeep similarity index 100% rename from sql/dbt/uniswap_v2/macros/.gitkeep rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/macros/.gitkeep diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql new file mode 100644 index 00000000..f31a12d9 --- /dev/null +++ b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql @@ -0,0 +1,27 @@ + +/* + Welcome to your first dbt model! + Did you know that you can also configure models directly within SQL files? + This will override configurations stated in dbt_project.yml + + Try changing "table" to "view" below +*/ + +{{ config(materialized='table') }} + +with source_data as ( + + select 1 as id + union all + select null as id + +) + +select * +from source_data + +/* + Uncomment the line below to remove records with null `id` values +*/ + +-- where id is not null diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql new file mode 100644 index 00000000..c91f8793 --- /dev/null +++ b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql @@ -0,0 +1,6 @@ + +-- Use the `ref` function to select from other models + +select * +from {{ ref('my_first_dbt_model') }} +where id = 1 diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml new file mode 100644 index 00000000..2a530817 --- /dev/null +++ b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml @@ -0,0 +1,21 @@ + +version: 2 + +models: + - name: my_first_dbt_model + description: "A starter dbt model" + columns: + - name: id + description: "The primary key for this table" + tests: + - unique + - not_null + + - name: my_second_dbt_model + description: "A starter dbt model" + columns: + - name: id + description: "The primary key for this table" + tests: + - unique + - not_null diff --git a/sql/dbt/uniswap_v2/seeds/.gitkeep b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/seeds/.gitkeep similarity index 100% rename from sql/dbt/uniswap_v2/seeds/.gitkeep rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/seeds/.gitkeep diff --git a/sql/dbt/uniswap_v2/snapshots/.gitkeep b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/snapshots/.gitkeep similarity index 100% rename from sql/dbt/uniswap_v2/snapshots/.gitkeep rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/snapshots/.gitkeep diff --git a/sql/dbt/uniswap_v2/tests/.gitkeep b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/tests/.gitkeep similarity index 100% rename from sql/dbt/uniswap_v2/tests/.gitkeep rename to sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/tests/.gitkeep diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql deleted file mode 100644 index 0e4d8a5f..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__burn.sql +++ /dev/null @@ -1,13 +0,0 @@ - -with final as ( - select - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_block_time as block_time - , evt_block_number as block_number - , amount0 - , amount1 - from burn -) - -select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql deleted file mode 100644 index 39638e63..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__mint.sql +++ /dev/null @@ -1,13 +0,0 @@ - -with final as ( - select - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_block_time as block_time - , evt_block_number as block_number - , amount0 - , amount1 - from mint -) - -select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql deleted file mode 100644 index d1c2738c..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__pool.sql +++ /dev/null @@ -1,15 +0,0 @@ - -with final as ( - select - '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' as pool_address - , '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' as token0__id - , 'Wrapped ETH' as token0__name - , 'WETH' as token0__symbol - , '18' as token0__decimals - , '0xdAC17F958D2ee523a2206206994597C13D831ec7' as token1__id - , 'Tether USD' as token1__name - , 'USDT' as token1__symbol - , '6' as token1__decimals -) - -select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql deleted file mode 100644 index 26e49bc8..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__swaps.sql +++ /dev/null @@ -1,25 +0,0 @@ -{% set pool = ref("uniswap_v2_ethereum__pool") %} - -with final as ( - select - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_block_time as block_time - , evt_block_number as block_number - , case - when amount0_in > 0 then p.token0__id else p.token1__id - end as token_in__id - , case - when amount0_in > 0 then amount0_in else amount1_in - end as amount_in - , case - when amount0_in > 0 then p.token1__id else p.token0__id - end as token_out__id - , case - when amount0_in > 0 then amount1_out else amount0_out - end as amount_out - from swap - cross join {{ pool }} p -) - -select * from final diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql deleted file mode 100644 index 308f75a6..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__sync.sql +++ /dev/null @@ -1,12 +0,0 @@ -with final as ( - select - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_block_time as block_time - , evt_block_number as block_number - , reserve0 - , reserve1 - from sync -) - -select * from final diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql deleted file mode 100644 index 96b7a118..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__token_prices.sql +++ /dev/null @@ -1,26 +0,0 @@ -{% set swaps = ref("uniswap_v2_ethereum__swaps") %} - -with final as ( - select - transaction_hash - , log_index - , amount_in - , amount_out - , token_in__id - , case - when token_in__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 6 else 18 - end as token_in__decimals - , case - when token_in__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 1 else (amount_out / pow(10, 6)) / (amount_in / pow(10, 18)) - end as token_in__price - , token_out__id - , case - when token_out__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 6 else 18 - end as token_out__decimals - , case - when token_out__id = '0xdAC17F958D2ee523a2206206994597C13D831ec7' then 1 else (amount_in / pow(10, 6)) / (amount_out / pow(10, 18)) - end as token_out__price - from {{ swaps }} -) - -select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql deleted file mode 100644 index b5e1b2aa..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__tvl.sql +++ /dev/null @@ -1,33 +0,0 @@ -{% set sync = ref("uniswap_v2_ethereum__sync") %} -{% set prices = ref("uniswap_v2_ethereum__token_prices") %} - -with tvl as ( - select - s.transaction_hash - , s.log_index - , s.block_number - , s.block_time - , case - when sw.token_in__id = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' then (s.reserve0 / pow(10, 18)) * sw.token_in__price - when sw.token_out__id = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' then (s.reserve0 / pow(10, 18)) * sw.token_out__price - end as token0_balance_usd - , s.reserve1 / pow(10, 6) as token1_balance_usd - from {{ sync }} s - left join {{ prices }} sw - on s.transaction_hash = sw.transaction_hash - and s.log_index = sw.log_index - 1 -) - -, final as ( - select - transaction_hash - , log_index - , block_number - , block_time - , token0_balance_usd - , token1_balance_usd - , (token0_balance_usd + token1_balance_usd) as tvl - from tvl -) - -select * from final \ No newline at end of file diff --git a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql b/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql deleted file mode 100644 index a3a11651..00000000 --- a/sql/dbt/uniswap_v2/models/analytics/uniswap_v2_ethereum__volume.sql +++ /dev/null @@ -1,32 +0,0 @@ -{% set swaps = ref("uniswap_v2_ethereum__swaps") %} -{% set prices = ref("uniswap_v2_ethereum__token_prices") %} - -with swap_volume as ( - select - s.transaction_hash - , s.log_index - , s.block_number - , s.block_time - , s.token_in__id - , (s.amount_in * p.token_in__price) / pow(10, p.token_in__decimals) as amount_in_usd - , s.token_out__id - , (s.amount_out * p.token_out__price) / pow(10, p.token_out__decimals) as amount_out_usd - from {{ swaps }} s - left join {{ prices }} p - on s.transaction_hash = p.transaction_hash - and s.log_index = p.log_index -) - -, final as ( - select - transaction_hash - , log_index - , block_number - , block_time - , amount_in_usd - , amount_out_usd - , (amount_in_usd + amount_out_usd) / 2 as volume - from swap_volume -) - -select * from final \ No newline at end of file diff --git a/sql/uniswap_v2/Makefile b/sql/uniswap_v2/Makefile index 5fca602e..168d7012 100644 --- a/sql/uniswap_v2/Makefile +++ b/sql/uniswap_v2/Makefile @@ -11,11 +11,11 @@ endif .PHONY: run run: build - substreams run substreams.yaml map_events $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) + substreams run substreams.yaml $(if $(MODULE),$(MODULE),map_events) $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) .PHONY: gui gui: build - substreams gui substreams.yaml map_events $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) + substreams gui substreams.yaml $(if $(MODULE),$(MODULE),map_events) $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) .PHONY: protogen protogen: diff --git a/sql/uniswap_v2/abi/factory_contract.abi.json b/sql/uniswap_v2/abi/factory_contract.abi.json new file mode 100644 index 00000000..7063b1fe --- /dev/null +++ b/sql/uniswap_v2/abi/factory_contract.abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/sql/uniswap_v2/abi/contract.abi.json b/sql/uniswap_v2/abi/pools_contract.abi.json similarity index 100% rename from sql/uniswap_v2/abi/contract.abi.json rename to sql/uniswap_v2/abi/pools_contract.abi.json diff --git a/sql/uniswap_v2/build.rs b/sql/uniswap_v2/build.rs index c0a354a3..723bc223 100644 --- a/sql/uniswap_v2/build.rs +++ b/sql/uniswap_v2/build.rs @@ -5,10 +5,12 @@ use std::fs; fn main() -> Result<(), anyhow::Error> { let file_names = [ - "abi/contract.abi.json", + "abi/factory_contract.abi.json", + "abi/pools_contract.abi.json", ]; let file_output_names = [ - "src/abi/contract.rs", + "src/abi/factory_contract.rs", + "src/abi/pools_contract.rs", ]; let mut i = 0; diff --git a/sql/uniswap_v2/proto/contract.proto b/sql/uniswap_v2/proto/contract.proto index 7a7a2f1b..3c1f8dee 100644 --- a/sql/uniswap_v2/proto/contract.proto +++ b/sql/uniswap_v2/proto/contract.proto @@ -5,73 +5,91 @@ import "google/protobuf/timestamp.proto"; package contract.v1; message Events { - repeated Approval approvals = 1; - repeated Burn burns = 2; - repeated Mint mints = 3; - repeated Swap swaps = 4; - repeated Sync syncs = 5; - repeated Transfer transfers = 6; + repeated factory_PairCreated factory_pair_createds = 1; + repeated pools_Approval pools_approvals = 2; + repeated pools_Burn pools_burns = 3; + repeated pools_Mint pools_mints = 4; + repeated pools_Swap pools_swaps = 5; + repeated pools_Sync pools_syncs = 6; + repeated pools_Transfer pools_transfers = 7; } -message Approval { +message factory_PairCreated { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - bytes owner = 5; - bytes spender = 6; - string value = 7; + bytes token0 = 5; + bytes token1 = 6; + bytes pair = 7; + string param3 = 8; } -message Burn { +message pools_Approval { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - bytes sender = 5; - string amount0 = 6; - string amount1 = 7; - bytes to = 8; + string evt_address = 5; + bytes owner = 6; + bytes spender = 7; + string value = 8; } -message Mint { +message pools_Burn { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - bytes sender = 5; - string amount0 = 6; - string amount1 = 7; + string evt_address = 5; + bytes sender = 6; + string amount0 = 7; + string amount1 = 8; + bytes to = 9; } -message Swap { +message pools_Mint { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - bytes sender = 5; - string amount0_in = 6; - string amount1_in = 7; - string amount0_out = 8; - string amount1_out = 9; - bytes to = 10; + string evt_address = 5; + bytes sender = 6; + string amount0 = 7; + string amount1 = 8; } -message Sync { +message pools_Swap { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - string reserve0 = 5; - string reserve1 = 6; + string evt_address = 5; + bytes sender = 6; + string amount0_in = 7; + string amount1_in = 8; + string amount0_out = 9; + string amount1_out = 10; + bytes to = 11; } -message Transfer { +message pools_Sync { string evt_tx_hash = 1; uint32 evt_index = 2; google.protobuf.Timestamp evt_block_time = 3; uint64 evt_block_number = 4; - bytes from = 5; - bytes to = 6; - string value = 7; + string evt_address = 5; + string reserve0 = 6; + string reserve1 = 7; +} + +message pools_Transfer { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes from = 6; + bytes to = 7; + string value = 8; } diff --git a/sql/uniswap_v2/schema.clickhouse.sql b/sql/uniswap_v2/schema.clickhouse.sql index 18a0347e..67c8296c 100644 --- a/sql/uniswap_v2/schema.clickhouse.sql +++ b/sql/uniswap_v2/schema.clickhouse.sql @@ -1,36 +1,50 @@ -CREATE TABLE IF NOT EXISTS approval ( +CREATE TABLE IF NOT EXISTS factory_pair_created ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "pair" VARCHAR(40), + "param3" UInt256, + "token0" VARCHAR(40), + "token1" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "owner" VARCHAR(40), "spender" VARCHAR(40), "value" UInt256 ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); -CREATE TABLE IF NOT EXISTS burn ( +CREATE TABLE IF NOT EXISTS pools_burn ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "amount0" UInt256, "amount1" UInt256, "sender" VARCHAR(40), "to" VARCHAR(40) ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); -CREATE TABLE IF NOT EXISTS mint ( +CREATE TABLE IF NOT EXISTS pools_mint ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "amount0" UInt256, "amount1" UInt256, "sender" VARCHAR(40) ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); -CREATE TABLE IF NOT EXISTS swap ( +CREATE TABLE IF NOT EXISTS pools_swap ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "amount0_in" UInt256, "amount0_out" UInt256, "amount1_in" UInt256, @@ -38,21 +52,24 @@ CREATE TABLE IF NOT EXISTS swap ( "sender" VARCHAR(40), "to" VARCHAR(40) ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); -CREATE TABLE IF NOT EXISTS sync ( +CREATE TABLE IF NOT EXISTS pools_sync ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "reserve0" UInt128, "reserve1" UInt128 ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); -CREATE TABLE IF NOT EXISTS transfer ( +CREATE TABLE IF NOT EXISTS pools_transfer ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" UInt64, + "evt_address" VARCHAR(40), "from" VARCHAR(40), "to" VARCHAR(40), "value" UInt256 ) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); + diff --git a/sql/uniswap_v2/schema.graphql b/sql/uniswap_v2/schema.graphql index a27f20e4..44066e70 100644 --- a/sql/uniswap_v2/schema.graphql +++ b/sql/uniswap_v2/schema.graphql @@ -1,40 +1,56 @@ -type approval @entity { +type factory_pair_created @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + pair: String! + param3: BigDecimal! + token0: String! + token1: String! +} + +type pools_approval @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! owner: String! spender: String! value: BigDecimal! } -type burn @entity { +type pools_burn @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + evt_address: String! amount0: BigDecimal! amount1: BigDecimal! sender: String! to: String! } -type mint @entity { +type pools_mint @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + evt_address: String! amount0: BigDecimal! amount1: BigDecimal! sender: String! } -type swap @entity { +type pools_swap @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + evt_address: String! amount0_in: BigDecimal! amount0_out: BigDecimal! amount1_in: BigDecimal! @@ -42,22 +58,24 @@ type swap @entity { sender: String! to: String! } -type sync @entity { +type pools_sync @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + evt_address: String! reserve0: BigDecimal! reserve1: BigDecimal! } -type transfer @entity { +type pools_transfer @entity { id: ID! evt_tx_hash: String! evt_index: BigInt! evt_block_time: String! evt_block_number: BigInt! + evt_address: String! from: String! to: String! value: BigDecimal! -} +} \ No newline at end of file diff --git a/sql/uniswap_v2/schema.sql b/sql/uniswap_v2/schema.sql index f4f19483..f830f43c 100644 --- a/sql/uniswap_v2/schema.sql +++ b/sql/uniswap_v2/schema.sql @@ -1,39 +1,55 @@ -CREATE TABLE IF NOT EXISTS approval ( +CREATE TABLE IF NOT EXISTS factory_pair_created ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "pair" VARCHAR(40), + "param3" DECIMAL, + "token0" VARCHAR(40), + "token1" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); + +CREATE TABLE IF NOT EXISTS pools_approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "owner" VARCHAR(40), "spender" VARCHAR(40), "value" DECIMAL, PRIMARY KEY(evt_tx_hash,evt_index) ); -CREATE TABLE IF NOT EXISTS burn ( +CREATE TABLE IF NOT EXISTS pools_burn ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "amount0" DECIMAL, "amount1" DECIMAL, "sender" VARCHAR(40), "to" VARCHAR(40), PRIMARY KEY(evt_tx_hash,evt_index) ); -CREATE TABLE IF NOT EXISTS mint ( +CREATE TABLE IF NOT EXISTS pools_mint ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "amount0" DECIMAL, "amount1" DECIMAL, "sender" VARCHAR(40), PRIMARY KEY(evt_tx_hash,evt_index) ); -CREATE TABLE IF NOT EXISTS swap ( +CREATE TABLE IF NOT EXISTS pools_swap ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "amount0_in" DECIMAL, "amount0_out" DECIMAL, "amount1_in" DECIMAL, @@ -42,23 +58,24 @@ CREATE TABLE IF NOT EXISTS swap ( "to" VARCHAR(40), PRIMARY KEY(evt_tx_hash,evt_index) ); -CREATE TABLE IF NOT EXISTS sync ( +CREATE TABLE IF NOT EXISTS pools_sync ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "reserve0" DECIMAL, "reserve1" DECIMAL, PRIMARY KEY(evt_tx_hash,evt_index) ); -CREATE TABLE IF NOT EXISTS transfer ( +CREATE TABLE IF NOT EXISTS pools_transfer ( "evt_tx_hash" VARCHAR(64), "evt_index" INT, "evt_block_time" TIMESTAMP, "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), "from" VARCHAR(40), "to" VARCHAR(40), "value" DECIMAL, PRIMARY KEY(evt_tx_hash,evt_index) ); - diff --git a/sql/uniswap_v2/src/abi/factory_contract.rs b/sql/uniswap_v2/src/abi/factory_contract.rs new file mode 100644 index 00000000..9c82b949 --- /dev/null +++ b/sql/uniswap_v2/src/abi/factory_contract.rs @@ -0,0 +1,908 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct AllPairs { + pub param0: substreams::scalar::BigInt, + } + impl AllPairs { + const METHOD_ID: [u8; 4] = [30u8, 61u8, 209u8, 139u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.param0.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for AllPairs { + const NAME: &'static str = "allPairs"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for AllPairs { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct AllPairsLength {} + impl AllPairsLength { + const METHOD_ID: [u8; 4] = [87u8, 79u8, 43u8, 163u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for AllPairsLength { + const NAME: &'static str = "allPairsLength"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for AllPairsLength { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CreatePair { + pub token_a: Vec, + pub token_b: Vec, + } + impl CreatePair { + const METHOD_ID: [u8; 4] = [201u8, 198u8, 83u8, 150u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token_a: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token_b: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_a), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_b), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for CreatePair { + const NAME: &'static str = "createPair"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for CreatePair { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeTo {} + impl FeeTo { + const METHOD_ID: [u8; 4] = [1u8, 126u8, 126u8, 88u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeTo { + const NAME: &'static str = "feeTo"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for FeeTo { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeToSetter {} + impl FeeToSetter { + const METHOD_ID: [u8; 4] = [9u8, 75u8, 116u8, 21u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeToSetter { + const NAME: &'static str = "feeToSetter"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for FeeToSetter { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPair { + pub param0: Vec, + pub param1: Vec, + } + impl GetPair { + const METHOD_ID: [u8; 4] = [230u8, 164u8, 57u8, 5u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.param1)), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPair { + const NAME: &'static str = "getPair"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetPair { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeTo { + pub u_fee_to: Vec, + } + impl SetFeeTo { + const METHOD_ID: [u8; 4] = [244u8, 105u8, 1u8, 237u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + u_fee_to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_fee_to), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetFeeTo { + const NAME: &'static str = "setFeeTo"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeToSetter { + pub u_fee_to_setter: Vec, + } + impl SetFeeToSetter { + const METHOD_ID: [u8; 4] = [162u8, 231u8, 74u8, 246u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + u_fee_to_setter: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_fee_to_setter), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetFeeToSetter { + const NAME: &'static str = "setFeeToSetter"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct PairCreated { + pub token0: Vec, + pub token1: Vec, + pub pair: Vec, + pub param3: substreams::scalar::BigInt, + } + impl PairCreated { + const TOPIC_ID: [u8; 32] = [ + 13u8, + 54u8, + 72u8, + 189u8, + 15u8, + 107u8, + 168u8, + 1u8, + 52u8, + 163u8, + 59u8, + 169u8, + 39u8, + 90u8, + 197u8, + 133u8, + 217u8, + 211u8, + 21u8, + 240u8, + 173u8, + 131u8, + 85u8, + 205u8, + 222u8, + 253u8, + 227u8, + 26u8, + 250u8, + 40u8, + 208u8, + 233u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + token0: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token0' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token1: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token1' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pair: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param3: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for PairCreated { + const NAME: &'static str = "PairCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/sql/uniswap_v2/src/abi/mod.rs b/sql/uniswap_v2/src/abi/mod.rs index 2943dbb5..65b37e3c 100644 --- a/sql/uniswap_v2/src/abi/mod.rs +++ b/sql/uniswap_v2/src/abi/mod.rs @@ -1 +1,3 @@ -pub mod contract; + +pub mod factory_contract; +pub mod pools_contract; \ No newline at end of file diff --git a/sql/uniswap_v2/src/abi/contract.rs b/sql/uniswap_v2/src/abi/pools_contract.rs similarity index 100% rename from sql/uniswap_v2/src/abi/contract.rs rename to sql/uniswap_v2/src/abi/pools_contract.rs diff --git a/sql/uniswap_v2/src/lib.rs b/sql/uniswap_v2/src/lib.rs index 9f60c6a9..777ec7f7 100644 --- a/sql/uniswap_v2/src/lib.rs +++ b/sql/uniswap_v2/src/lib.rs @@ -2,6 +2,8 @@ mod abi; mod pb; use hex_literal::hex; use pb::contract::v1 as contract; +use substreams::prelude::*; +use substreams::store; use substreams::Hex; use substreams_database_change::pb::database::DatabaseChanges; use substreams_database_change::tables::Tables as DatabaseChangeTables; @@ -15,190 +17,251 @@ use num_traits::cast::ToPrimitive; use std::str::FromStr; use substreams::scalar::BigDecimal; -const TRACKED_CONTRACT: [u8; 20] = hex!("0d4a11d5eeaac28ec3f61d100daf4d40471f1852"); - substreams_ethereum::init!(); -#[substreams::handlers::map] -fn map_events(blk: eth::Block) -> Result { - Ok(contract::Events { - approvals: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Approval::match_and_decode(log) { - return Some(contract::Approval { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - owner: event.owner, - spender: event.spender, - value: event.value.to_string(), - }); - } +const FACTORY_TRACKED_CONTRACT: [u8; 20] = hex!("5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f"); + +fn map_factory_events(blk: ð::Block, events: &mut contract::Events) { + events.factory_pair_createds.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::factory_contract::events::PairCreated::match_and_decode(log) { + return Some(contract::FactoryPairCreated { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + pair: event.pair, + param3: event.param3.to_string(), + token0: event.token0, + token1: event.token1, + }); + } - None + None }) - }) - .collect(), - burns: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Burn::match_and_decode(log) { - return Some(contract::Burn { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - amount0: event.amount0.to_string(), - amount1: event.amount1.to_string(), - sender: event.sender, - to: event.to, - }); - } + }) + .collect()); +} + +fn is_declared_dds_address(addr: &Vec, ordinal: u64, dds_store: &store::StoreGetInt64) -> bool { + // substreams::log::info!("Checking if address {} is declared dds address", Hex(addr).to_string()); + if dds_store.get_at(ordinal, Hex(addr).to_string()).is_some() { + return true; + } + return false; +} - None +fn map_pools_events( + blk: ð::Block, + dds_store: &store::StoreGetInt64, + events: &mut contract::Events, +) { + + events.pools_approvals.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Approval::match_and_decode(log) { + return Some(contract::PoolsApproval { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + owner: event.owner, + spender: event.spender, + value: event.value.to_string(), + }); + } + + None }) - }) - .collect(), - mints: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Mint::match_and_decode(log) { - return Some(contract::Mint { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - amount0: event.amount0.to_string(), - amount1: event.amount1.to_string(), - sender: event.sender, - }); - } + }) + .collect()); + + events.pools_burns.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Burn::match_and_decode(log) { + return Some(contract::PoolsBurn { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + to: event.to, + }); + } - None + None }) - }) - .collect(), - swaps: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Swap::match_and_decode(log) { - return Some(contract::Swap { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - amount0_in: event.amount0_in.to_string(), - amount0_out: event.amount0_out.to_string(), - amount1_in: event.amount1_in.to_string(), - amount1_out: event.amount1_out.to_string(), - sender: event.sender, - to: event.to, - }); - } + }) + .collect()); - None + events.pools_mints.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Mint::match_and_decode(log) { + return Some(contract::PoolsMint { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + }); + } + + None }) - }) - .collect(), - syncs: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Sync::match_and_decode(log) { - return Some(contract::Sync { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - reserve0: event.reserve0.to_string(), - reserve1: event.reserve1.to_string(), - }); - } + }) + .collect()); + + events.pools_swaps.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Swap::match_and_decode(log) { + return Some(contract::PoolsSwap { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0_in: event.amount0_in.to_string(), + amount0_out: event.amount0_out.to_string(), + amount1_in: event.amount1_in.to_string(), + amount1_out: event.amount1_out.to_string(), + sender: event.sender, + to: event.to, + }); + } - None + None }) - }) - .collect(), - transfers: blk - .receipts() - .flat_map(|view| { - view.receipt.logs.iter() - .filter(|log| log.address == TRACKED_CONTRACT) - .filter_map(|log| { - if let Some(event) = abi::contract::events::Transfer::match_and_decode(log) { - return Some(contract::Transfer { - evt_tx_hash: Hex(&view.transaction.hash).to_string(), - evt_index: log.block_index, - evt_block_time: Some(blk.timestamp().to_owned()), - evt_block_number: blk.number, - from: event.from, - to: event.to, - value: event.value.to_string(), - }); - } + }) + .collect()); + + events.pools_syncs.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Sync::match_and_decode(log) { + return Some(contract::PoolsSync { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + reserve0: event.reserve0.to_string(), + reserve1: event.reserve1.to_string(), + }); + } - None + None }) - }) - .collect(), - }) + }) + .collect()); + + events.pools_transfers.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Transfer::match_and_decode(log) { + return Some(contract::PoolsTransfer { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + from: event.from, + to: event.to, + value: event.value.to_string(), + }); + } + + None + }) + }) + .collect()); } -#[substreams::handlers::map] -fn db_out(events: contract::Events) -> Result { - // Initialize changes container - let mut tables = DatabaseChangeTables::new(); - // Loop over all the abis events to create changes - events.approvals.into_iter().for_each(|evt| { +fn db_factory_out(events: &contract::Events, tables: &mut DatabaseChangeTables) { + // Loop over all the abis events to create table changes + events.factory_pair_createds.iter().for_each(|evt| { tables - .create_row("approval", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .create_row("factory_pair_created", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("pair", Hex(&evt.pair).to_string()) + .set("param3", BigDecimal::from_str(&evt.param3).unwrap()) + .set("token0", Hex(&evt.token0).to_string()) + .set("token1", Hex(&evt.token1).to_string()); + }); +} +fn db_pools_out(events: &contract::Events, tables: &mut DatabaseChangeTables) { + // Loop over all the abis events to create table changes + events.pools_approvals.iter().for_each(|evt| { + tables + .create_row("pools_approval", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("owner", Hex(&evt.owner).to_string()) .set("spender", Hex(&evt.spender).to_string()) .set("value", BigDecimal::from_str(&evt.value).unwrap()); }); - events.burns.into_iter().for_each(|evt| { + events.pools_burns.iter().for_each(|evt| { tables - .create_row("burn", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .create_row("pools_burn", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) .set("sender", Hex(&evt.sender).to_string()) .set("to", Hex(&evt.to).to_string()); }); - events.mints.into_iter().for_each(|evt| { + events.pools_mints.iter().for_each(|evt| { tables - .create_row("mint", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .create_row("pools_mint", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) .set("sender", Hex(&evt.sender).to_string()); }); - events.swaps.into_iter().for_each(|evt| { + events.pools_swaps.iter().for_each(|evt| { tables - .create_row("swap", [("evt_tx_hash", evt.evt_tx_hash),("evt_index", evt.evt_index.to_string())]) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .create_row("pools_swap", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) @@ -206,74 +269,90 @@ fn db_out(events: contract::Events) -> Result Result { - // Initialize changes container - let mut tables = EntityChangesTables::new(); - // Loop over all the abis events to create changes - events.approvals.into_iter().for_each(|evt| { +fn graph_factory_out(events: &contract::Events, tables: &mut EntityChangesTables) { + // Loop over all the abis events to create table changes + events.factory_pair_createds.iter().for_each(|evt| { + tables + .create_row("factory_pair_created", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("pair", Hex(&evt.pair).to_string()) + .set("param3", BigDecimal::from_str(&evt.param3).unwrap()) + .set("token0", Hex(&evt.token0).to_string()) + .set("token1", Hex(&evt.token1).to_string()); + }); +} +fn graph_pools_out(events: &contract::Events, tables: &mut EntityChangesTables) { + // Loop over all the abis events to create table changes + events.pools_approvals.iter().for_each(|evt| { tables - .create_row("approval", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) - .set("evt_tx_hash", evt.evt_tx_hash) + .create_row("pools_approval", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) .set("evt_index", evt.evt_index) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("owner", Hex(&evt.owner).to_string()) .set("spender", Hex(&evt.spender).to_string()) .set("value", BigDecimal::from_str(&evt.value).unwrap()); }); - events.burns.into_iter().for_each(|evt| { + events.pools_burns.iter().for_each(|evt| { tables - .create_row("burn", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) - .set("evt_tx_hash", evt.evt_tx_hash) + .create_row("pools_burn", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) .set("evt_index", evt.evt_index) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) .set("sender", Hex(&evt.sender).to_string()) .set("to", Hex(&evt.to).to_string()); }); - events.mints.into_iter().for_each(|evt| { + events.pools_mints.iter().for_each(|evt| { tables - .create_row("mint", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) - .set("evt_tx_hash", evt.evt_tx_hash) + .create_row("pools_mint", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) .set("evt_index", evt.evt_index) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) .set("sender", Hex(&evt.sender).to_string()); }); - events.swaps.into_iter().for_each(|evt| { + events.pools_swaps.iter().for_each(|evt| { tables - .create_row("swap", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) - .set("evt_tx_hash", evt.evt_tx_hash) + .create_row("pools_swap", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) .set("evt_index", evt.evt_index) - .set("evt_block_time", evt.evt_block_time.unwrap()) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) @@ -281,27 +360,71 @@ fn graph_out(events: contract::Events) -> Result Result { + let mut events = contract::Events::default(); + map_factory_events(&blk, &mut events); + map_pools_events(&blk, &store_pools, &mut events); + Ok(events) +} + +#[substreams::handlers::map] +fn db_out(events: contract::Events) -> Result { + // Initialize Database Changes container + let mut tables = DatabaseChangeTables::new(); + db_factory_out(&events, &mut tables); + db_pools_out(&events, &mut tables); + Ok(tables.to_database_changes()) +} + +#[substreams::handlers::map] +fn graph_out(events: contract::Events) -> Result { + // Initialize Database Changes container + let mut tables = EntityChangesTables::new(); + graph_factory_out(&events, &mut tables); + graph_pools_out(&events, &mut tables); Ok(tables.to_entity_changes()) } diff --git a/sql/uniswap_v2/src/pb/contract.v1.rs b/sql/uniswap_v2/src/pb/contract.v1.rs index 5f3140ae..97d05f6f 100644 --- a/sql/uniswap_v2/src/pb/contract.v1.rs +++ b/sql/uniswap_v2/src/pb/contract.v1.rs @@ -3,21 +3,23 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct Events { #[prost(message, repeated, tag="1")] - pub approvals: ::prost::alloc::vec::Vec, + pub factory_pair_createds: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="2")] - pub burns: ::prost::alloc::vec::Vec, + pub pools_approvals: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="3")] - pub mints: ::prost::alloc::vec::Vec, + pub pools_burns: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="4")] - pub swaps: ::prost::alloc::vec::Vec, + pub pools_mints: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="5")] - pub syncs: ::prost::alloc::vec::Vec, + pub pools_swaps: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="6")] - pub transfers: ::prost::alloc::vec::Vec, + pub pools_syncs: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="7")] + pub pools_transfers: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Approval { +pub struct FactoryPairCreated { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -27,15 +29,37 @@ pub struct Approval { #[prost(uint64, tag="4")] pub evt_block_number: u64, #[prost(bytes="vec", tag="5")] - pub owner: ::prost::alloc::vec::Vec, + pub token0: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="6")] + pub token1: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] + pub pair: ::prost::alloc::vec::Vec, + #[prost(string, tag="8")] + pub param3: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsApproval { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, #[prost(bytes="vec", tag="6")] + pub owner: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] pub spender: ::prost::alloc::vec::Vec, - #[prost(string, tag="7")] + #[prost(string, tag="8")] pub value: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Burn { +pub struct PoolsBurn { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -44,18 +68,20 @@ pub struct Burn { pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, #[prost(uint64, tag="4")] pub evt_block_number: u64, - #[prost(bytes="vec", tag="5")] + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] pub sender: ::prost::alloc::vec::Vec, - #[prost(string, tag="6")] - pub amount0: ::prost::alloc::string::String, #[prost(string, tag="7")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="8")] pub amount1: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="8")] + #[prost(bytes="vec", tag="9")] pub to: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Mint { +pub struct PoolsMint { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -64,16 +90,18 @@ pub struct Mint { pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, #[prost(uint64, tag="4")] pub evt_block_number: u64, - #[prost(bytes="vec", tag="5")] + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] pub sender: ::prost::alloc::vec::Vec, - #[prost(string, tag="6")] - pub amount0: ::prost::alloc::string::String, #[prost(string, tag="7")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="8")] pub amount1: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Swap { +pub struct PoolsSwap { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -82,22 +110,24 @@ pub struct Swap { pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, #[prost(uint64, tag="4")] pub evt_block_number: u64, - #[prost(bytes="vec", tag="5")] + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] pub sender: ::prost::alloc::vec::Vec, - #[prost(string, tag="6")] - pub amount0_in: ::prost::alloc::string::String, #[prost(string, tag="7")] - pub amount1_in: ::prost::alloc::string::String, + pub amount0_in: ::prost::alloc::string::String, #[prost(string, tag="8")] - pub amount0_out: ::prost::alloc::string::String, + pub amount1_in: ::prost::alloc::string::String, #[prost(string, tag="9")] + pub amount0_out: ::prost::alloc::string::String, + #[prost(string, tag="10")] pub amount1_out: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="10")] + #[prost(bytes="vec", tag="11")] pub to: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Sync { +pub struct PoolsSync { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -107,13 +137,15 @@ pub struct Sync { #[prost(uint64, tag="4")] pub evt_block_number: u64, #[prost(string, tag="5")] - pub reserve0: ::prost::alloc::string::String, + pub evt_address: ::prost::alloc::string::String, #[prost(string, tag="6")] + pub reserve0: ::prost::alloc::string::String, + #[prost(string, tag="7")] pub reserve1: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transfer { +pub struct PoolsTransfer { #[prost(string, tag="1")] pub evt_tx_hash: ::prost::alloc::string::String, #[prost(uint32, tag="2")] @@ -122,11 +154,13 @@ pub struct Transfer { pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, #[prost(uint64, tag="4")] pub evt_block_number: u64, - #[prost(bytes="vec", tag="5")] - pub from: ::prost::alloc::vec::Vec, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, #[prost(bytes="vec", tag="6")] + pub from: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] pub to: ::prost::alloc::vec::Vec, - #[prost(string, tag="7")] + #[prost(string, tag="8")] pub value: ::prost::alloc::string::String, } // @@protoc_insertion_point(module) diff --git a/sql/uniswap_v2/substreams.clickhouse.yaml b/sql/uniswap_v2/substreams.clickhouse.yaml index c56b6ca5..a2998dbe 100644 --- a/sql/uniswap_v2/substreams.clickhouse.yaml +++ b/sql/uniswap_v2/substreams.clickhouse.yaml @@ -18,20 +18,29 @@ protobuf: binaries: default: type: wasm/rust-v1 - file: ../../target/wasm32-unknown-unknown/release/substreams.wasm + file: ./target/wasm32-unknown-unknown/release/substreams.wasm modules: + - name: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + - name: map_events kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created output: type: proto:contract.v1.Events - name: db_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: @@ -39,7 +48,7 @@ modules: - name: graph_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: diff --git a/sql/uniswap_v2/substreams.sql.yaml b/sql/uniswap_v2/substreams.sql.yaml index af7b8bf4..2a72bb06 100644 --- a/sql/uniswap_v2/substreams.sql.yaml +++ b/sql/uniswap_v2/substreams.sql.yaml @@ -21,17 +21,26 @@ binaries: file: ../../target/wasm32-unknown-unknown/release/substreams.wasm modules: + - name: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + - name: map_events kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created output: type: proto:contract.v1.Events - name: db_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: @@ -39,7 +48,7 @@ modules: - name: graph_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: diff --git a/sql/uniswap_v2/substreams.subgraph.yaml b/sql/uniswap_v2/substreams.subgraph.yaml index 0ee78f4e..d82b566b 100644 --- a/sql/uniswap_v2/substreams.subgraph.yaml +++ b/sql/uniswap_v2/substreams.subgraph.yaml @@ -21,17 +21,26 @@ binaries: file: ./target/wasm32-unknown-unknown/release/substreams.wasm modules: + - name: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + - name: map_events kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created output: type: proto:contract.v1.Events - name: db_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: @@ -39,7 +48,7 @@ modules: - name: graph_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: diff --git a/sql/uniswap_v2/substreams.yaml b/sql/uniswap_v2/substreams.yaml index 7b1d10cf..14212bd6 100644 --- a/sql/uniswap_v2/substreams.yaml +++ b/sql/uniswap_v2/substreams.yaml @@ -21,17 +21,26 @@ binaries: file: ./target/wasm32-unknown-unknown/release/substreams.wasm modules: + - name: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + - name: map_events kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created output: type: proto:contract.v1.Events - name: db_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: @@ -39,7 +48,7 @@ modules: - name: graph_out kind: map - initialBlock: 10110528 + initialBlock: 10000835 inputs: - map: map_events output: From 96391ac97be210037e22984ff28f06e01700f7ad Mon Sep 17 00:00:00 2001 From: Harsh Date: Mon, 12 Feb 2024 21:01:14 +0530 Subject: [PATCH 5/6] wip --- .../.gitignore | 0 .../README.md | 0 .../analyses/.gitkeep | 0 .../dbt_project.yml | 0 .../macros/.gitkeep | 0 ..._uniswap_v2_ethereum_mainnet__deposits.sql | 102 ++++++++++++++++ ...col_uniswap_v2_ethereum_mainnet__swaps.sql | 86 +++++++++++++ ...uniswap_v2_ethereum_mainnet__withdraws.sql | 115 ++++++++++++++++++ .../models/example/my_first_dbt_model.sql | 27 ---- .../models/example/my_second_dbt_model.sql | 6 - .../models/example/schema.yml | 21 ---- .../seeds/.gitkeep | 0 .../snapshots/.gitkeep | 0 .../tests/.gitkeep | 0 14 files changed, 303 insertions(+), 54 deletions(-) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/.gitignore (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/README.md (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/analyses/.gitkeep (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/dbt_project.yml (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/macros/.gitkeep (100%) create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql delete mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql delete mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql delete mode 100644 sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/seeds/.gitkeep (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/snapshots/.gitkeep (100%) rename sql/dbt/{projects/protocol_uniswap_v2_ethereum_mainnet => }/tests/.gitkeep (100%) diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/.gitignore b/sql/dbt/.gitignore similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/.gitignore rename to sql/dbt/.gitignore diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/README.md b/sql/dbt/README.md similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/README.md rename to sql/dbt/README.md diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/analyses/.gitkeep b/sql/dbt/analyses/.gitkeep similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/analyses/.gitkeep rename to sql/dbt/analyses/.gitkeep diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/dbt_project.yml b/sql/dbt/dbt_project.yml similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/dbt_project.yml rename to sql/dbt/dbt_project.yml diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/macros/.gitkeep b/sql/dbt/macros/.gitkeep similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/macros/.gitkeep rename to sql/dbt/macros/.gitkeep diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql new file mode 100644 index 00000000..1023d203 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql @@ -0,0 +1,102 @@ +{{ + config( + materialized = 'incremental', + alias = 'DEPOSITS', + unique_key='ID', + ) +}} + +WITH pools as ( + SELECT + pair AS id + , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id + , token0 + , token1 + FROM factory_pair_created +) + +, mint_evts AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_address as contract_address + , pools.protocol__id + , pools.token0 + , pools.token1 + , sender + , amount0 + , amount1 + , evt_block_number as block_number + , evt_block_time as block_timestamp + , DATE_TRUNC('hour', evt_block_time) AS HOUR + FROM pools_mint mint + INNER JOIN pools ON mint.evt_address = pools.id +) + +, sync AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , reserve0 + , reserve1 + FROM pools_sync sync +) + +, mint_transfers AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , "to" + , value as liquidity + FROM pools_transfer t + WHERE "from" = '0000000000000000000000000000000000000000' +) + +, most_cols AS ( + SELECT + 'DEPOSIT-' || m.transaction_hash || '-' || m.log_index AS id + , m.transaction_hash as hash + , m.log_index + , p.protocol__id + , t."to" as "to" + , sender AS "from" + , m.block_number + , m.block_timestamp AS timestamp + , m.contract_address AS pool__id + , ARRAY[p.token0, p.token1] AS input_tokens + , m.contract_address as output_token__id + , ARRAY[amount0, amount1] AS input_token_amounts + , t.liquidity AS output_token_amount + , ARRAY[s.reserve0, s.reserve1] as reserve_amounts + + -- TODO: + , 0 AS _amount0_usd + , 0 AS _amount1_usd + , 0 AS amount_usd + FROM mint_evts m + INNER JOIN pools p ON m.contract_address = p.id + LEFT JOIN sync s ON m.transaction_hash = s.transaction_hash AND m.log_index = s.log_index + 1 + LEFT JOIN mint_transfers t ON m.transaction_hash = t.transaction_hash AND m.log_index = t.log_index + 2 +) + +, final AS ( + SELECT + id + , hash + , log_index + , protocol__id + , "to" + , "from" + , block_number + , timestamp + , input_tokens + , output_token__id + , input_token_amounts + , output_token_amount + , reserve_amounts + , amount_usd + , pool__id + FROM most_cols +) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql new file mode 100644 index 00000000..6972efa5 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql @@ -0,0 +1,86 @@ +{{ + config( + materialized = 'incremental', + alias = 'SWAPS', + unique_key='ID', + ) +}} + +WITH pools as ( + SELECT + pair AS id + , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id + , token0 + , token1 + FROM factory_pair_created +) + +, swap_evts AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_address as contract_address + , pools.protocol__id + , pools.token0 + , pools.token1 + , "to" + , sender + , amount0_in + , amount0_out + , amount1_in + , amount1_out + , evt_block_number as block_number + , evt_block_time as block_timestamp + , DATE_TRUNC('hour', evt_block_time) AS HOUR + FROM pools_swap swap + INNER JOIN pools ON swap.evt_address = pools.id +) + +, sync AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , reserve0 + , reserve1 + FROM pools_sync sync +) + +, final AS ( + SELECT + 'SWAP-' || s.transaction_hash || '-' || s.log_index AS id + , s.transaction_hash as hash + , s.log_index + , p.protocol__id + , s."to" AS "to" + , sender AS "from" + , s.block_number + , s.block_timestamp AS timestamp + + , CASE + WHEN amount0_in > 0 THEN p.token0 + ELSE p.token1 + END AS token_in__id + , CASE + WHEN amount0_in > 0 THEN amount0_in + ELSE amount1_in + END AS amount_in + , 0 AS amount_in_usd + + , CASE + WHEN amount0_in > 0 THEN p.token1 + ELSE p.token0 + END AS token_out__id + , CASE + WHEN amount0_in > 0 THEN amount1_out + ELSE amount0_out + END AS amount_out + , 0 AS amount_out_usd + + , ARRAY[sync.reserve0, sync.reserve1] as reserve_amounts + , s.contract_address AS pool__id + FROM swap_evts s + INNER JOIN pools p ON s.contract_address = p.id + LEFT JOIN sync ON s.transaction_hash = sync.transaction_hash AND s.log_index = sync.log_index + 1 +) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql new file mode 100644 index 00000000..b88b150a --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql @@ -0,0 +1,115 @@ +{{ + config( + materialized = 'incremental', + alias = 'WITHDRAWS', + unique_key='ID', + ) +}} + +WITH pools as ( + SELECT + pair AS id + , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id + , token0 + , token1 + FROM factory_pair_created +) + +, burn_evts AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_address as contract_address + , pools.protocol__id + , pools.token0 + , pools.token1 + , sender + , amount0 + , amount1 + , evt_block_number as block_number + , evt_block_time as block_timestamp + , DATE_TRUNC('hour', evt_block_time) AS HOUR + FROM pools_burn burn + INNER JOIN pools ON burn.evt_address = pools.id +) + +, sync AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , reserve0 + , reserve1 + FROM pools_sync sync +) + +, transfers AS ( + SELECT + evt_tx_hash as transaction_hash + , evt_index as log_index + , evt_address as contract_address + , "from" + , value as liquidity + FROM pools_transfer t + WHERE "to" = '0000000000000000000000000000000000000000' +) + +, burn_transfer AS ( + SELECT + b.transaction_hash, + b.log_index, + t.liquidity + FROM burn_evts b + INNER JOIN transfers t + ON b.transaction_hash = t.transaction_hash + AND b.log_index > t.log_index + AND b.contract_address = t.contract_address +) + +, most_cols AS ( + SELECT + 'WITHDRAW-' || b.transaction_hash || '-' || b.log_index AS id + , b.transaction_hash as hash + , b.log_index + , p.protocol__id + , b.sender AS "to" + , b.contract_address as "from" + , b.block_number + , b.block_timestamp AS timestamp + , b.contract_address AS pool__id + , ARRAY[p.token0, p.token1] AS input_tokens + , b.contract_address as output_token__id + , ARRAY[amount0, amount1] AS input_token_amounts + , t.liquidity AS output_token_amount + , ARRAY[s.reserve0, s.reserve1] as reserve_amounts + + -- TODO: + , 0 AS _amount0_usd + , 0 AS _amount1_usd + , 0 AS amount_usd + FROM burn_evts b + INNER JOIN pools p ON b.contract_address = p.id + LEFT JOIN sync s ON b.transaction_hash = s.transaction_hash AND b.log_index = s.log_index + 1 + LEFT JOIN burn_transfer t ON b.transaction_hash = t.transaction_hash AND b.log_index = t.log_index +) + +, final AS ( + SELECT + id + , hash + , log_index + , protocol__id + , "to" + , "from" + , block_number + , timestamp + , input_tokens + , output_token__id + , input_token_amounts + , output_token_amount + , reserve_amounts + , amount_usd + , pool__id + FROM most_cols +) + +SELECT * FROM final diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql deleted file mode 100644 index f31a12d9..00000000 --- a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_first_dbt_model.sql +++ /dev/null @@ -1,27 +0,0 @@ - -/* - Welcome to your first dbt model! - Did you know that you can also configure models directly within SQL files? - This will override configurations stated in dbt_project.yml - - Try changing "table" to "view" below -*/ - -{{ config(materialized='table') }} - -with source_data as ( - - select 1 as id - union all - select null as id - -) - -select * -from source_data - -/* - Uncomment the line below to remove records with null `id` values -*/ - --- where id is not null diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql deleted file mode 100644 index c91f8793..00000000 --- a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/my_second_dbt_model.sql +++ /dev/null @@ -1,6 +0,0 @@ - --- Use the `ref` function to select from other models - -select * -from {{ ref('my_first_dbt_model') }} -where id = 1 diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml b/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml deleted file mode 100644 index 2a530817..00000000 --- a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/models/example/schema.yml +++ /dev/null @@ -1,21 +0,0 @@ - -version: 2 - -models: - - name: my_first_dbt_model - description: "A starter dbt model" - columns: - - name: id - description: "The primary key for this table" - tests: - - unique - - not_null - - - name: my_second_dbt_model - description: "A starter dbt model" - columns: - - name: id - description: "The primary key for this table" - tests: - - unique - - not_null diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/seeds/.gitkeep b/sql/dbt/seeds/.gitkeep similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/seeds/.gitkeep rename to sql/dbt/seeds/.gitkeep diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/snapshots/.gitkeep b/sql/dbt/snapshots/.gitkeep similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/snapshots/.gitkeep rename to sql/dbt/snapshots/.gitkeep diff --git a/sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/tests/.gitkeep b/sql/dbt/tests/.gitkeep similarity index 100% rename from sql/dbt/projects/protocol_uniswap_v2_ethereum_mainnet/tests/.gitkeep rename to sql/dbt/tests/.gitkeep From 11fd490e4460237d80ff01df04284b140762b377 Mon Sep 17 00:00:00 2001 From: Harsh Date: Tue, 13 Feb 2024 17:33:25 +0530 Subject: [PATCH 6/6] update models --- sql/dbt/dbt_project.yml | 6 +- ...as_liquidity_pool_input_token_balances.sql | 48 +++++++ ..._metrics_deltas_liquidity_pool_volumes.sql | 57 +++++++++ ..._uniswap_v2_ethereum_mainnet__deposits.sql | 102 --------------- ...ifications_deltas_input_token_balances.sql | 120 ++++++++++++++++++ ...t__entity_modifications_deltas_volumes.sql | 32 +++++ ...modifications_initializations_deposits.sql | 65 ++++++++++ ...ions_initializations_dex_amm_protocols.sql | 22 ++++ ...fications_initializations_interactions.sql | 82 ++++++++++++ ...ations_initializations_liquidity_pools.sql | 43 +++++++ ...ty_modifications_initializations_swaps.sql | 64 ++++++++++ ...odifications_initializations_withdraws.sql | 67 ++++++++++ ...col_uniswap_v2_ethereum_mainnet__swaps.sql | 86 ------------- ...uniswap_v2_ethereum_mainnet__withdraws.sql | 115 ----------------- 14 files changed, 603 insertions(+), 306 deletions(-) create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql delete mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql create mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql delete mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql delete mode 100644 sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql diff --git a/sql/dbt/dbt_project.yml b/sql/dbt/dbt_project.yml index abf7d0a4..86e8407b 100644 --- a/sql/dbt/dbt_project.yml +++ b/sql/dbt/dbt_project.yml @@ -2,12 +2,12 @@ # Name your project! Project names should contain only lowercase characters # and underscores. A good package name should reflect your organization's # name or the intended use of these models -name: 'protocol_uniswap_v2_ethereum_mainnet' +name: 'messari_substreams' version: '1.0.0' config-version: 2 # This setting configures which "profile" dbt uses for this project. -profile: 'protocol_uniswap_v2_ethereum_mainnet' +profile: 'messari_substreams' # These configurations specify where dbt should look for different types of files. # The `model-paths` config, for example, states that models in this project can be @@ -31,7 +31,7 @@ clean-targets: # directories to be removed by `dbt clean` # directory as views. These settings can be overridden in the individual model # files using the `{{ config(...) }}` macro. models: - protocol_uniswap_v2_ethereum_mainnet: + messari_substreams: # Config indicated by + and applies to all files under models/example/ example: +materialized: view diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql new file mode 100644 index 00000000..83f81b3f --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql @@ -0,0 +1,48 @@ +{{ + config( + materialized = 'view', + alias = 'COMPILED_METRICS_DELTAS_LIQUIDITY_POOL_INPUT_TOKEN_BALANCES', + unique_key='id', + ) +}} + +{% set deltas_input_token_balances = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances') %} + +WITH + incremental_deltas AS (SELECT * FROM {{ deltas_input_token_balances }}) + + , final AS ( + SELECT + id.id + , id.pool__id + , id.token__id + , DATE_TRUNC('hour', id.block_timestamp) AS hour + + -- Delta Calculations + , id.delta + , COALESCE(id.delta / POWER(10, token.decimals) * token.price_usd, 0) AS delta_usd + + -- Cumulative Sum Delta Calculations + , SUM(id.delta) OVER (PARTITION BY id.pool__id, id.token__id ORDER BY id.block_number, id.transaction_index, id.log_index) AS cumulative_sum + + -- Cumulative Sum Delta Calculations (Current Timestamp Price) + , COALESCE(cumulative_sum / POWER(10, token.decimals) * token.price_usd, 0) AS cumulative_sum_usd_current_timestamp_price + + , id.transaction_hash + , id.block_number + , id.block_timestamp + , id.transaction_index + , id.log_index + FROM incremental_deltas id + LEFT JOIN {{ token_prices_usd_hour }} token + ON id.token__id = token.contract_address + AND DATE_TRUNC('hour', id.block_timestamp) = token.time + ORDER BY + pool__id + , token__id + , block_number + , transaction_index + , log_index + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql new file mode 100644 index 00000000..d6b3868d --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql @@ -0,0 +1,57 @@ +{{ + config( + materialized = 'view', + alias = 'COMPILED_METRICS_DELTAS_LIQUIDITY_POOL_VOLUMES', + unique_key='id', + ) +}} + +{% set deltas_volumes = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes') %} + +WITH + incremental_deltas AS (SELECT * FROM {{ deltas_volumes }}) + + , prepared_incremental_deltas AS ( + SELECT + id.* + , id.delta_in AS delta + , token_in__id AS token__id + , DATE_TRUNC('hour', id.block_timestamp) AS hour + , 0 AS delta_usd + FROM incremental_deltas id + ) + + , final AS ( + SELECT + pid.id + , pid.pool__id + , pid.token__id + , pid.hour + + -- Delta Calculations + , pid.delta + , pid.delta_usd + + -- Cumulative Sum Delta Calculations + , SUM(pid.delta) OVER (PARTITION BY pid.pool__id, pid.token__id ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS cumulative_sum + , SUM(pid.delta_usd) OVER (PARTITION BY pid.pool__id, pid.token__id ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS cumulative_sum_usd + + -- Hourly Delta Calculations + , SUM(pid.delta) OVER (PARTITION BY pid.pool__id, pid.token__id, pid.hour ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS hour_sum + , SUM(pid.delta_usd) OVER (PARTITION BY pid.pool__id, pid.token__id, pid.hour ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS hour_sum_usd + + , pid.transaction_hash + , pid.block_number + , pid.block_timestamp + , pid.transaction_index + , pid.log_index + FROM prepared_incremental_deltas pid + ORDER BY + pool__id + , pid.token__id + , block_number + , transaction_index + , log_index + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql deleted file mode 100644 index 1023d203..00000000 --- a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__deposits.sql +++ /dev/null @@ -1,102 +0,0 @@ -{{ - config( - materialized = 'incremental', - alias = 'DEPOSITS', - unique_key='ID', - ) -}} - -WITH pools as ( - SELECT - pair AS id - , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id - , token0 - , token1 - FROM factory_pair_created -) - -, mint_evts AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_address as contract_address - , pools.protocol__id - , pools.token0 - , pools.token1 - , sender - , amount0 - , amount1 - , evt_block_number as block_number - , evt_block_time as block_timestamp - , DATE_TRUNC('hour', evt_block_time) AS HOUR - FROM pools_mint mint - INNER JOIN pools ON mint.evt_address = pools.id -) - -, sync AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , reserve0 - , reserve1 - FROM pools_sync sync -) - -, mint_transfers AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , "to" - , value as liquidity - FROM pools_transfer t - WHERE "from" = '0000000000000000000000000000000000000000' -) - -, most_cols AS ( - SELECT - 'DEPOSIT-' || m.transaction_hash || '-' || m.log_index AS id - , m.transaction_hash as hash - , m.log_index - , p.protocol__id - , t."to" as "to" - , sender AS "from" - , m.block_number - , m.block_timestamp AS timestamp - , m.contract_address AS pool__id - , ARRAY[p.token0, p.token1] AS input_tokens - , m.contract_address as output_token__id - , ARRAY[amount0, amount1] AS input_token_amounts - , t.liquidity AS output_token_amount - , ARRAY[s.reserve0, s.reserve1] as reserve_amounts - - -- TODO: - , 0 AS _amount0_usd - , 0 AS _amount1_usd - , 0 AS amount_usd - FROM mint_evts m - INNER JOIN pools p ON m.contract_address = p.id - LEFT JOIN sync s ON m.transaction_hash = s.transaction_hash AND m.log_index = s.log_index + 1 - LEFT JOIN mint_transfers t ON m.transaction_hash = t.transaction_hash AND m.log_index = t.log_index + 2 -) - -, final AS ( - SELECT - id - , hash - , log_index - , protocol__id - , "to" - , "from" - , block_number - , timestamp - , input_tokens - , output_token__id - , input_token_amounts - , output_token_amount - , reserve_amounts - , amount_usd - , pool__id - FROM most_cols -) - -SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql new file mode 100644 index 00000000..6428cfc3 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql @@ -0,0 +1,120 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_DELTAS_INPUT_TOKEN_BALANCES', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} +{% set initialized_deposits = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits') %} +{% set initialized_withdraws = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws') %} + +WITH + incremental_initialized_swaps AS (SELECT * FROM {{ initialized_swaps }}) + , incremental_initialized_deposits AS (SELECT * FROM {{ initialized_deposits }}) + , incremental_initialized_withdraws AS (SELECT * FROM {{ initialized_withdraws }}) + + , deposit_withdraws AS ( + SELECT + id + + , protocol__id + , pool__id + + , input_token_amounts + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_deposits + + UNION ALL + + SELECT + iiw.id + + , iiw.protocol__id + , iiw.pool__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, iiw.input_token_amounts -> ilp.input_tokens[1]::VARCHAR, + ilp.input_tokens[2]::VARCHAR, iiw.input_token_amounts -> ilp.input_tokens[2]::VARCHAR + ) AS input_token_amounts + + , iiw.block_number + , iiw.transaction_index + , iiw.transaction_hash + , iiw.log_index + , iiw.block_timestamp + FROM incremental_initialized_withdraws iiw + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON iiw.pool__id = ilp.id + ) + + , flattened_deposit_withdraw_deltas AS ( + SELECT + dw.id + + , dw.protocol__id + , dw.pool__id + , f.key::VARCHAR AS token__id + + , (f.value)::TEXT::FLOAT AS delta + + , dw.block_number + , dw.transaction_index + , dw.transaction_hash + , dw.log_index + , dw.block_timestamp + FROM deposit_withdraws dw, + LATERAL JSON_EACH(input_token_amounts) AS f + ) + + , swap_in_deltas AS ( + SELECT + id + + , protocol__id + , pool__id + , token_in__id AS token__id + + , amount_in AS delta + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_swaps + ) + + , swap_out_deltas AS ( + SELECT + id + + , protocol__id + , pool__id + , token_out__id AS token__id + + , -amount_out AS delta + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_swaps + ) + + , final AS ( + SELECT * FROM flattened_deposit_withdraw_deltas + UNION ALL + SELECT * FROM swap_in_deltas + UNION ALL + SELECT * FROM swap_out_deltas + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql new file mode 100644 index 00000000..0c78820f --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql @@ -0,0 +1,32 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_DELTAS_VOLUMES', + unique_key='id', + ) +}} + +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} + +WITH + final AS ( + SELECT + id + + , amount_in AS delta_in + , amount_out AS delta_out + + , protocol__id + , pool__id + , token_in__id + , token_out__id + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM {{ initialized_swaps }} iis + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql new file mode 100644 index 00000000..5c4350e9 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql @@ -0,0 +1,65 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_DEPOSITS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} + +WITH + incremental_mint_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0 AS param_amount0 + , amount1 AS param_amount1 + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_mint + ), + + incremental_transfer_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , evt_index AS log_index + , "from" AS param_from + , "to" AS param_to + , value AS param_value + FROM pools_transfer + ) + + , final AS ( + SELECT + 'DEPOSIT-' || ime.transaction_hash || '-' || ime.log_index AS id + + , idap.id AS protocol__id + , ime.contract_address AS pool__id + , ime.param_sender AS user__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, ime.param_amount0, + ilp.input_tokens[2]::VARCHAR, ime.param_amount1 + ) AS input_token_amounts + + , t.param_value AS output_token_amount + + , ime.block_number + , ime.transaction_index + , ime.transaction_hash + , ime.log_index + , ime.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_mint_events ime + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ime.contract_address = ilp.id + INNER JOIN incremental_transfer_events t + ON ime.transaction_hash = t.transaction_hash + AND ime.log_index = t.log_index + 2 + AND t.param_from = '0000000000000000000000000000000000000000' + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql new file mode 100644 index 00000000..1ed38827 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql @@ -0,0 +1,22 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_DEX_AMM_PROTOCOLS', + unique_key='id', + ) +}} + +WITH + final as ( + SELECT + '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS id + , 'Uniswap V2' AS name + , 'uniswap_v2' AS slug + , '1.3.2' AS schema_version + , '1.0.0' AS subgraph_version + , '1.0.0' AS methodology_version + , 'MAINNET' AS network + , 'EXCHANGE' AS type + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql new file mode 100644 index 00000000..ef668019 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql @@ -0,0 +1,82 @@ +{# {{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_INTERACTIONS', + unique_key='id', + ) +}} + +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} +{% set initialized_deposits = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits') %} +{% set initialized_withdraws = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws') %} +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + user_interactions AS ( + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_DEPOSIT' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_deposits }} + UNION ALL + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_WITHDRAW' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_withdraws }} + UNION ALL + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_SWAP' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_swaps }} + ) + + , final AS ( + SELECT + ui.id + + , ui.user__id + , ui.pool__id + , ui.protocol__id + + , ui.type + + , ui.block_number + , ui.transaction_hash + , ui.transaction_index + , ui.log_index + , ui.block_timestamp + , ui._load_timestamp_utc + , ui._last_run_timestamp_utc + FROM user_interactions ui + ) + +SELECT * FROM final #} \ No newline at end of file diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql new file mode 100644 index 00000000..4f4659bf --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql @@ -0,0 +1,43 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_LIQUIDITY_POOLS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + incremental_pool_created_events AS ( + SELECT * FROM factory_pair_created + ) + + , name_and_symbol AS ( + SELECT + ipce.pair AS pool + , 'token0' || '/' || 'token1' AS _symbol + , 'Uniswap V2 Pool: null' AS name + FROM incremental_pool_created_events ipce + ) + + , final AS ( + SELECT + ipce.pair AS id + + , idap.id AS protocol__id + + , nas.name + , nas._symbol AS symbol + , ARRAY[token0, token1] AS input_tokens + + , evt_block_number as block_number + , evt_tx_hash as transaction_hash + , null as transaction_index + , evt_index as log_index + , evt_block_time as block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_pool_created_events ipce + LEFT JOIN name_and_symbol nas ON ipce.pair = nas.pool + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql new file mode 100644 index 00000000..e21f0f07 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql @@ -0,0 +1,64 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_SWAPS', + unique_key='id', + ) +}} + +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + incremental_swap_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0_in AS param_amount0_in + , amount0_out AS param_amount0_out + , amount1_in AS param_amount1_in + , amount1_out AS param_amount1_out + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_swap + ) + + , final AS ( + SELECT + 'SWAP-' || ise.transaction_hash || '-' || ise.log_index AS id + + , idap.id AS protocol__id + , ise.contract_address AS pool__id + , ise.param_sender AS user__id + + , CASE + WHEN ise.param_amount0_in > 0 THEN ise.param_amount0_in + ELSE ise.param_amount1_in + END AS amount_in + , CASE + WHEN ise.param_amount0_in > 0 THEN ABS(ise.param_amount1_out) + ELSE ABS(ise.param_amount0_out) + END AS amount_out + + , CASE + WHEN ise.param_amount0_in > 0 THEN ilp.input_tokens[1]::VARCHAR + ELSE ilp.input_tokens[2]::VARCHAR + END AS token_in__id + , CASE + WHEN ise.param_amount0_in > 0 THEN ilp.input_tokens[2]::VARCHAR + ELSE ilp.input_tokens[1]::VARCHAR + END AS token_out__id + + , ise.block_number + , ise.transaction_index + , ise.transaction_hash + , ise.log_index + , ise.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_swap_events ise + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ise.contract_address = ilp.id + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql new file mode 100644 index 00000000..d89712bd --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql @@ -0,0 +1,67 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_WITHDRAWS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} + +WITH + incremental_burn_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0 AS param_amount0 + , amount1 AS param_amount1 + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_burn + ), + + incremental_transfer_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , evt_index AS log_index + , evt_address AS contract_address + , "from" AS param_from + , "to" AS param_to + , value AS param_value + FROM pools_transfer + ) + + , final AS ( + SELECT + 'WITHDRAW-' || ibe.transaction_hash || '-' || ibe.log_index AS id + + , idap.id AS protocol__id + , ibe.contract_address AS pool__id + , ibe.param_sender AS user__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, ibe.param_amount0, + ilp.input_tokens[2]::VARCHAR, ibe.param_amount1 + ) AS input_token_amounts + + , t.param_value AS output_token_amount + + , ibe.block_number + , ibe.transaction_index + , ibe.transaction_hash + , ibe.log_index + , ibe.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_burn_events ibe + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ibe.contract_address = ilp.id + INNER JOIN incremental_transfer_events t + ON ibe.transaction_hash = t.transaction_hash + AND ibe.log_index > t.log_index + AND ibe.contract_address = t.contract_address + AND t.param_to = '0000000000000000000000000000000000000000' + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql deleted file mode 100644 index 6972efa5..00000000 --- a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__swaps.sql +++ /dev/null @@ -1,86 +0,0 @@ -{{ - config( - materialized = 'incremental', - alias = 'SWAPS', - unique_key='ID', - ) -}} - -WITH pools as ( - SELECT - pair AS id - , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id - , token0 - , token1 - FROM factory_pair_created -) - -, swap_evts AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_address as contract_address - , pools.protocol__id - , pools.token0 - , pools.token1 - , "to" - , sender - , amount0_in - , amount0_out - , amount1_in - , amount1_out - , evt_block_number as block_number - , evt_block_time as block_timestamp - , DATE_TRUNC('hour', evt_block_time) AS HOUR - FROM pools_swap swap - INNER JOIN pools ON swap.evt_address = pools.id -) - -, sync AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , reserve0 - , reserve1 - FROM pools_sync sync -) - -, final AS ( - SELECT - 'SWAP-' || s.transaction_hash || '-' || s.log_index AS id - , s.transaction_hash as hash - , s.log_index - , p.protocol__id - , s."to" AS "to" - , sender AS "from" - , s.block_number - , s.block_timestamp AS timestamp - - , CASE - WHEN amount0_in > 0 THEN p.token0 - ELSE p.token1 - END AS token_in__id - , CASE - WHEN amount0_in > 0 THEN amount0_in - ELSE amount1_in - END AS amount_in - , 0 AS amount_in_usd - - , CASE - WHEN amount0_in > 0 THEN p.token1 - ELSE p.token0 - END AS token_out__id - , CASE - WHEN amount0_in > 0 THEN amount1_out - ELSE amount0_out - END AS amount_out - , 0 AS amount_out_usd - - , ARRAY[sync.reserve0, sync.reserve1] as reserve_amounts - , s.contract_address AS pool__id - FROM swap_evts s - INNER JOIN pools p ON s.contract_address = p.id - LEFT JOIN sync ON s.transaction_hash = sync.transaction_hash AND s.log_index = sync.log_index + 1 -) - -SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql deleted file mode 100644 index b88b150a..00000000 --- a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__withdraws.sql +++ /dev/null @@ -1,115 +0,0 @@ -{{ - config( - materialized = 'incremental', - alias = 'WITHDRAWS', - unique_key='ID', - ) -}} - -WITH pools as ( - SELECT - pair AS id - , '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS protocol__id - , token0 - , token1 - FROM factory_pair_created -) - -, burn_evts AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_address as contract_address - , pools.protocol__id - , pools.token0 - , pools.token1 - , sender - , amount0 - , amount1 - , evt_block_number as block_number - , evt_block_time as block_timestamp - , DATE_TRUNC('hour', evt_block_time) AS HOUR - FROM pools_burn burn - INNER JOIN pools ON burn.evt_address = pools.id -) - -, sync AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , reserve0 - , reserve1 - FROM pools_sync sync -) - -, transfers AS ( - SELECT - evt_tx_hash as transaction_hash - , evt_index as log_index - , evt_address as contract_address - , "from" - , value as liquidity - FROM pools_transfer t - WHERE "to" = '0000000000000000000000000000000000000000' -) - -, burn_transfer AS ( - SELECT - b.transaction_hash, - b.log_index, - t.liquidity - FROM burn_evts b - INNER JOIN transfers t - ON b.transaction_hash = t.transaction_hash - AND b.log_index > t.log_index - AND b.contract_address = t.contract_address -) - -, most_cols AS ( - SELECT - 'WITHDRAW-' || b.transaction_hash || '-' || b.log_index AS id - , b.transaction_hash as hash - , b.log_index - , p.protocol__id - , b.sender AS "to" - , b.contract_address as "from" - , b.block_number - , b.block_timestamp AS timestamp - , b.contract_address AS pool__id - , ARRAY[p.token0, p.token1] AS input_tokens - , b.contract_address as output_token__id - , ARRAY[amount0, amount1] AS input_token_amounts - , t.liquidity AS output_token_amount - , ARRAY[s.reserve0, s.reserve1] as reserve_amounts - - -- TODO: - , 0 AS _amount0_usd - , 0 AS _amount1_usd - , 0 AS amount_usd - FROM burn_evts b - INNER JOIN pools p ON b.contract_address = p.id - LEFT JOIN sync s ON b.transaction_hash = s.transaction_hash AND b.log_index = s.log_index + 1 - LEFT JOIN burn_transfer t ON b.transaction_hash = t.transaction_hash AND b.log_index = t.log_index -) - -, final AS ( - SELECT - id - , hash - , log_index - , protocol__id - , "to" - , "from" - , block_number - , timestamp - , input_tokens - , output_token__id - , input_token_amounts - , output_token_amount - , reserve_amounts - , amount_usd - , pool__id - FROM most_cols -) - -SELECT * FROM final