diff --git a/Cargo.lock b/Cargo.lock index 53aec90..1521502 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 eedf6a7..9392ff7 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 0000000..7414b18 --- /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 0000000..49f147c --- /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 0000000..7874ac8 --- /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 0000000..e69de29 diff --git a/sql/dbt/uniswap_v2/dbt_project.yml b/sql/dbt/uniswap_v2/dbt_project.yml new file mode 100644 index 0000000..3091927 --- /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 0000000..e69de29 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 0000000..0e4d8a5 --- /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 0000000..39638e6 --- /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 0000000..39638e6 --- /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 0000000..1342a80 --- /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 0000000..308f75a --- /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 0000000..e69de29 diff --git a/sql/dbt/uniswap_v2/snapshots/.gitkeep b/sql/dbt/uniswap_v2/snapshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/dbt/uniswap_v2/tests/.gitkeep b/sql/dbt/uniswap_v2/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/uniswap_v2/Cargo.toml b/sql/uniswap_v2/Cargo.toml new file mode 100644 index 0000000..4926dc4 --- /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 0000000..5fca602 --- /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 0000000..6eb1eaa --- /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 0000000..c0a354a --- /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 0000000..7a7a2f1 --- /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 0000000..ec334c0 --- /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 0000000..18a0347 --- /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 0000000..a27f20e --- /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 0000000..f4f1948 --- /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 0000000..fb99a2d --- /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 0000000..2943dbb --- /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 0000000..9f60c6a --- /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 0000000..5f3140a --- /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 0000000..611ea83 --- /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 0000000..a8d2b56 --- /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 0000000..1c79388 --- /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 0000000..af7b8bf --- /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 0000000..0ee78f4 --- /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 0000000..7b1d10c --- /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