diff --git a/.gitignore b/.gitignore index e12b4ca..f78c572 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ Reference/ **/target/ **/build/ **/data/ +**/logs/dbt.log +**/logs/ **/*.spkg **/buf.gen.yaml replay.log diff --git a/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/.gitignore b/sql/dbt/.gitignore new file mode 100644 index 0000000..49f147c --- /dev/null +++ b/sql/dbt/.gitignore @@ -0,0 +1,4 @@ + +target/ +dbt_packages/ +logs/ diff --git a/sql/dbt/README.md b/sql/dbt/README.md new file mode 100644 index 0000000..7874ac8 --- /dev/null +++ b/sql/dbt/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/analyses/.gitkeep b/sql/dbt/analyses/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/dbt/dbt_project.yml b/sql/dbt/dbt_project.yml new file mode 100644 index 0000000..86e8407 --- /dev/null +++ b/sql/dbt/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: 'messari_substreams' +version: '1.0.0' +config-version: 2 + +# This setting configures which "profile" dbt uses for this project. +profile: 'messari_substreams' + +# These configurations specify where dbt should look for different types of files. +# The `model-paths` config, for example, states that models in this project can be +# 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: + messari_substreams: + # Config indicated by + and applies to all files under models/example/ + example: + +materialized: view diff --git a/sql/dbt/macros/.gitkeep b/sql/dbt/macros/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql new file mode 100644 index 0000000..83f81b3 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_input_token_balances.sql @@ -0,0 +1,48 @@ +{{ + config( + materialized = 'view', + alias = 'COMPILED_METRICS_DELTAS_LIQUIDITY_POOL_INPUT_TOKEN_BALANCES', + unique_key='id', + ) +}} + +{% set deltas_input_token_balances = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances') %} + +WITH + incremental_deltas AS (SELECT * FROM {{ deltas_input_token_balances }}) + + , final AS ( + SELECT + id.id + , id.pool__id + , id.token__id + , DATE_TRUNC('hour', id.block_timestamp) AS hour + + -- Delta Calculations + , id.delta + , COALESCE(id.delta / POWER(10, token.decimals) * token.price_usd, 0) AS delta_usd + + -- Cumulative Sum Delta Calculations + , SUM(id.delta) OVER (PARTITION BY id.pool__id, id.token__id ORDER BY id.block_number, id.transaction_index, id.log_index) AS cumulative_sum + + -- Cumulative Sum Delta Calculations (Current Timestamp Price) + , COALESCE(cumulative_sum / POWER(10, token.decimals) * token.price_usd, 0) AS cumulative_sum_usd_current_timestamp_price + + , id.transaction_hash + , id.block_number + , id.block_timestamp + , id.transaction_index + , id.log_index + FROM incremental_deltas id + LEFT JOIN {{ token_prices_usd_hour }} token + ON id.token__id = token.contract_address + AND DATE_TRUNC('hour', id.block_timestamp) = token.time + ORDER BY + pool__id + , token__id + , block_number + , transaction_index + , log_index + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql new file mode 100644 index 0000000..d6b3868 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__compiled_metrics_deltas_liquidity_pool_volumes.sql @@ -0,0 +1,57 @@ +{{ + config( + materialized = 'view', + alias = 'COMPILED_METRICS_DELTAS_LIQUIDITY_POOL_VOLUMES', + unique_key='id', + ) +}} + +{% set deltas_volumes = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes') %} + +WITH + incremental_deltas AS (SELECT * FROM {{ deltas_volumes }}) + + , prepared_incremental_deltas AS ( + SELECT + id.* + , id.delta_in AS delta + , token_in__id AS token__id + , DATE_TRUNC('hour', id.block_timestamp) AS hour + , 0 AS delta_usd + FROM incremental_deltas id + ) + + , final AS ( + SELECT + pid.id + , pid.pool__id + , pid.token__id + , pid.hour + + -- Delta Calculations + , pid.delta + , pid.delta_usd + + -- Cumulative Sum Delta Calculations + , SUM(pid.delta) OVER (PARTITION BY pid.pool__id, pid.token__id ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS cumulative_sum + , SUM(pid.delta_usd) OVER (PARTITION BY pid.pool__id, pid.token__id ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS cumulative_sum_usd + + -- Hourly Delta Calculations + , SUM(pid.delta) OVER (PARTITION BY pid.pool__id, pid.token__id, pid.hour ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS hour_sum + , SUM(pid.delta_usd) OVER (PARTITION BY pid.pool__id, pid.token__id, pid.hour ORDER BY pid.block_number, pid.transaction_index, pid.log_index) AS hour_sum_usd + + , pid.transaction_hash + , pid.block_number + , pid.block_timestamp + , pid.transaction_index + , pid.log_index + FROM prepared_incremental_deltas pid + ORDER BY + pool__id + , pid.token__id + , block_number + , transaction_index + , log_index + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql new file mode 100644 index 0000000..6428cfc --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_input_token_balances.sql @@ -0,0 +1,120 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_DELTAS_INPUT_TOKEN_BALANCES', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} +{% set initialized_deposits = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits') %} +{% set initialized_withdraws = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws') %} + +WITH + incremental_initialized_swaps AS (SELECT * FROM {{ initialized_swaps }}) + , incremental_initialized_deposits AS (SELECT * FROM {{ initialized_deposits }}) + , incremental_initialized_withdraws AS (SELECT * FROM {{ initialized_withdraws }}) + + , deposit_withdraws AS ( + SELECT + id + + , protocol__id + , pool__id + + , input_token_amounts + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_deposits + + UNION ALL + + SELECT + iiw.id + + , iiw.protocol__id + , iiw.pool__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, iiw.input_token_amounts -> ilp.input_tokens[1]::VARCHAR, + ilp.input_tokens[2]::VARCHAR, iiw.input_token_amounts -> ilp.input_tokens[2]::VARCHAR + ) AS input_token_amounts + + , iiw.block_number + , iiw.transaction_index + , iiw.transaction_hash + , iiw.log_index + , iiw.block_timestamp + FROM incremental_initialized_withdraws iiw + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON iiw.pool__id = ilp.id + ) + + , flattened_deposit_withdraw_deltas AS ( + SELECT + dw.id + + , dw.protocol__id + , dw.pool__id + , f.key::VARCHAR AS token__id + + , (f.value)::TEXT::FLOAT AS delta + + , dw.block_number + , dw.transaction_index + , dw.transaction_hash + , dw.log_index + , dw.block_timestamp + FROM deposit_withdraws dw, + LATERAL JSON_EACH(input_token_amounts) AS f + ) + + , swap_in_deltas AS ( + SELECT + id + + , protocol__id + , pool__id + , token_in__id AS token__id + + , amount_in AS delta + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_swaps + ) + + , swap_out_deltas AS ( + SELECT + id + + , protocol__id + , pool__id + , token_out__id AS token__id + + , -amount_out AS delta + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM incremental_initialized_swaps + ) + + , final AS ( + SELECT * FROM flattened_deposit_withdraw_deltas + UNION ALL + SELECT * FROM swap_in_deltas + UNION ALL + SELECT * FROM swap_out_deltas + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql new file mode 100644 index 0000000..0c78820 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_deltas_volumes.sql @@ -0,0 +1,32 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_DELTAS_VOLUMES', + unique_key='id', + ) +}} + +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} + +WITH + final AS ( + SELECT + id + + , amount_in AS delta_in + , amount_out AS delta_out + + , protocol__id + , pool__id + , token_in__id + , token_out__id + + , block_number + , transaction_index + , transaction_hash + , log_index + , block_timestamp + FROM {{ initialized_swaps }} iis + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql new file mode 100644 index 0000000..5c4350e --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits.sql @@ -0,0 +1,65 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_DEPOSITS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} + +WITH + incremental_mint_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0 AS param_amount0 + , amount1 AS param_amount1 + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_mint + ), + + incremental_transfer_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , evt_index AS log_index + , "from" AS param_from + , "to" AS param_to + , value AS param_value + FROM pools_transfer + ) + + , final AS ( + SELECT + 'DEPOSIT-' || ime.transaction_hash || '-' || ime.log_index AS id + + , idap.id AS protocol__id + , ime.contract_address AS pool__id + , ime.param_sender AS user__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, ime.param_amount0, + ilp.input_tokens[2]::VARCHAR, ime.param_amount1 + ) AS input_token_amounts + + , t.param_value AS output_token_amount + + , ime.block_number + , ime.transaction_index + , ime.transaction_hash + , ime.log_index + , ime.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_mint_events ime + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ime.contract_address = ilp.id + INNER JOIN incremental_transfer_events t + ON ime.transaction_hash = t.transaction_hash + AND ime.log_index = t.log_index + 2 + AND t.param_from = '0000000000000000000000000000000000000000' + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql new file mode 100644 index 0000000..1ed3882 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols.sql @@ -0,0 +1,22 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_DEX_AMM_PROTOCOLS', + unique_key='id', + ) +}} + +WITH + final as ( + SELECT + '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f' AS id + , 'Uniswap V2' AS name + , 'uniswap_v2' AS slug + , '1.3.2' AS schema_version + , '1.0.0' AS subgraph_version + , '1.0.0' AS methodology_version + , 'MAINNET' AS network + , 'EXCHANGE' AS type + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql new file mode 100644 index 0000000..ef66801 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_interactions.sql @@ -0,0 +1,82 @@ +{# {{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_INTERACTIONS', + unique_key='id', + ) +}} + +{% set initialized_swaps = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps') %} +{% set initialized_deposits = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_deposits') %} +{% set initialized_withdraws = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws') %} +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + user_interactions AS ( + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_DEPOSIT' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_deposits }} + UNION ALL + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_WITHDRAW' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_withdraws }} + UNION ALL + SELECT + id + , user__id + , pool__id + , protocol__id + , 'DEX_SWAP' AS type + , block_number + , transaction_hash + , transaction_index + , log_index + , block_timestamp + , _load_timestamp_utc + , _last_run_timestamp_utc + FROM {{ initialized_swaps }} + ) + + , final AS ( + SELECT + ui.id + + , ui.user__id + , ui.pool__id + , ui.protocol__id + + , ui.type + + , ui.block_number + , ui.transaction_hash + , ui.transaction_index + , ui.log_index + , ui.block_timestamp + , ui._load_timestamp_utc + , ui._last_run_timestamp_utc + FROM user_interactions ui + ) + +SELECT * FROM final #} \ No newline at end of file diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql new file mode 100644 index 0000000..4f4659b --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools.sql @@ -0,0 +1,43 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_LIQUIDITY_POOLS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + incremental_pool_created_events AS ( + SELECT * FROM factory_pair_created + ) + + , name_and_symbol AS ( + SELECT + ipce.pair AS pool + , 'token0' || '/' || 'token1' AS _symbol + , 'Uniswap V2 Pool: null' AS name + FROM incremental_pool_created_events ipce + ) + + , final AS ( + SELECT + ipce.pair AS id + + , idap.id AS protocol__id + + , nas.name + , nas._symbol AS symbol + , ARRAY[token0, token1] AS input_tokens + + , evt_block_number as block_number + , evt_tx_hash as transaction_hash + , null as transaction_index + , evt_index as log_index + , evt_block_time as block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_pool_created_events ipce + LEFT JOIN name_and_symbol nas ON ipce.pair = nas.pool + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql new file mode 100644 index 0000000..e21f0f0 --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_swaps.sql @@ -0,0 +1,64 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_SWAPS', + unique_key='id', + ) +}} + +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} + +WITH + incremental_swap_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0_in AS param_amount0_in + , amount0_out AS param_amount0_out + , amount1_in AS param_amount1_in + , amount1_out AS param_amount1_out + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_swap + ) + + , final AS ( + SELECT + 'SWAP-' || ise.transaction_hash || '-' || ise.log_index AS id + + , idap.id AS protocol__id + , ise.contract_address AS pool__id + , ise.param_sender AS user__id + + , CASE + WHEN ise.param_amount0_in > 0 THEN ise.param_amount0_in + ELSE ise.param_amount1_in + END AS amount_in + , CASE + WHEN ise.param_amount0_in > 0 THEN ABS(ise.param_amount1_out) + ELSE ABS(ise.param_amount0_out) + END AS amount_out + + , CASE + WHEN ise.param_amount0_in > 0 THEN ilp.input_tokens[1]::VARCHAR + ELSE ilp.input_tokens[2]::VARCHAR + END AS token_in__id + , CASE + WHEN ise.param_amount0_in > 0 THEN ilp.input_tokens[2]::VARCHAR + ELSE ilp.input_tokens[1]::VARCHAR + END AS token_out__id + + , ise.block_number + , ise.transaction_index + , ise.transaction_hash + , ise.log_index + , ise.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_swap_events ise + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ise.contract_address = ilp.id + ) + +SELECT * FROM final diff --git a/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql new file mode 100644 index 0000000..d89712b --- /dev/null +++ b/sql/dbt/models/protocol_uniswap_v2_ethereum_mainnet/analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_withdraws.sql @@ -0,0 +1,67 @@ +{{ + config( + materialized = 'view', + alias = 'ENTITY_MODIFICATIONS_INITIALIZATIONS_WITHDRAWS', + unique_key='id', + ) +}} + +{% set initialized_dex_amm_protocols = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_dex_amm_protocols') %} +{% set initialized_liquidity_pools = ref('analytics__protocol_uniswap_v2_ethereum_mainnet__entity_modifications_initializations_liquidity_pools') %} + +WITH + incremental_burn_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , null AS transaction_index + , evt_index AS log_index + , evt_address AS contract_address + , sender AS param_sender + , amount0 AS param_amount0 + , amount1 AS param_amount1 + , evt_block_number AS block_number + , evt_block_time AS block_timestamp + FROM pools_burn + ), + + incremental_transfer_events AS ( + SELECT + evt_tx_hash AS transaction_hash + , evt_index AS log_index + , evt_address AS contract_address + , "from" AS param_from + , "to" AS param_to + , value AS param_value + FROM pools_transfer + ) + + , final AS ( + SELECT + 'WITHDRAW-' || ibe.transaction_hash || '-' || ibe.log_index AS id + + , idap.id AS protocol__id + , ibe.contract_address AS pool__id + , ibe.param_sender AS user__id + + , JSON_BUILD_OBJECT( + ilp.input_tokens[1]::VARCHAR, ibe.param_amount0, + ilp.input_tokens[2]::VARCHAR, ibe.param_amount1 + ) AS input_token_amounts + + , t.param_value AS output_token_amount + + , ibe.block_number + , ibe.transaction_index + , ibe.transaction_hash + , ibe.log_index + , ibe.block_timestamp + FROM {{ initialized_dex_amm_protocols }} idap, incremental_burn_events ibe + LEFT JOIN {{ initialized_liquidity_pools }} ilp ON ibe.contract_address = ilp.id + INNER JOIN incremental_transfer_events t + ON ibe.transaction_hash = t.transaction_hash + AND ibe.log_index > t.log_index + AND ibe.contract_address = t.contract_address + AND t.param_to = '0000000000000000000000000000000000000000' + ) + +SELECT * FROM final diff --git a/sql/dbt/seeds/.gitkeep b/sql/dbt/seeds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/dbt/snapshots/.gitkeep b/sql/dbt/snapshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sql/dbt/tests/.gitkeep b/sql/dbt/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..168d701 --- /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 $(if $(MODULE),$(MODULE),map_events) $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK)) + +.PHONY: gui +gui: build + substreams gui substreams.yaml $(if $(MODULE),$(MODULE),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/factory_contract.abi.json b/sql/uniswap_v2/abi/factory_contract.abi.json new file mode 100644 index 0000000..7063b1f --- /dev/null +++ b/sql/uniswap_v2/abi/factory_contract.abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/sql/uniswap_v2/abi/pools_contract.abi.json b/sql/uniswap_v2/abi/pools_contract.abi.json new file mode 100644 index 0000000..6eb1eaa --- /dev/null +++ b/sql/uniswap_v2/abi/pools_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..723bc22 --- /dev/null +++ b/sql/uniswap_v2/build.rs @@ -0,0 +1,33 @@ +use anyhow::{Ok, Result}; +use regex::Regex; +use substreams_ethereum::Abigen; +use std::fs; + +fn main() -> Result<(), anyhow::Error> { + let file_names = [ + "abi/factory_contract.abi.json", + "abi/pools_contract.abi.json", + ]; + let file_output_names = [ + "src/abi/factory_contract.rs", + "src/abi/pools_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..3c1f8de --- /dev/null +++ b/sql/uniswap_v2/proto/contract.proto @@ -0,0 +1,95 @@ +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package contract.v1; + +message Events { + repeated factory_PairCreated factory_pair_createds = 1; + repeated pools_Approval pools_approvals = 2; + repeated pools_Burn pools_burns = 3; + repeated pools_Mint pools_mints = 4; + repeated pools_Swap pools_swaps = 5; + repeated pools_Sync pools_syncs = 6; + repeated pools_Transfer pools_transfers = 7; +} + +message factory_PairCreated { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + bytes token0 = 5; + bytes token1 = 6; + bytes pair = 7; + string param3 = 8; +} + +message pools_Approval { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes owner = 6; + bytes spender = 7; + string value = 8; +} + +message pools_Burn { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes sender = 6; + string amount0 = 7; + string amount1 = 8; + bytes to = 9; +} + +message pools_Mint { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes sender = 6; + string amount0 = 7; + string amount1 = 8; +} + +message pools_Swap { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes sender = 6; + string amount0_in = 7; + string amount1_in = 8; + string amount0_out = 9; + string amount1_out = 10; + bytes to = 11; +} + +message pools_Sync { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + string reserve0 = 6; + string reserve1 = 7; +} + +message pools_Transfer { + string evt_tx_hash = 1; + uint32 evt_index = 2; + google.protobuf.Timestamp evt_block_time = 3; + uint64 evt_block_number = 4; + string evt_address = 5; + bytes from = 6; + bytes to = 7; + string value = 8; +} diff --git a/sql/uniswap_v2/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..67c8296 --- /dev/null +++ b/sql/uniswap_v2/schema.clickhouse.sql @@ -0,0 +1,75 @@ +CREATE TABLE IF NOT EXISTS factory_pair_created ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "pair" VARCHAR(40), + "param3" UInt256, + "token0" VARCHAR(40), + "token1" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "owner" VARCHAR(40), + "spender" VARCHAR(40), + "value" UInt256 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_burn ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "amount0" UInt256, + "amount1" UInt256, + "sender" VARCHAR(40), + "to" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_mint ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "amount0" UInt256, + "amount1" UInt256, + "sender" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_swap ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "amount0_in" UInt256, + "amount0_out" UInt256, + "amount1_in" UInt256, + "amount1_out" UInt256, + "sender" VARCHAR(40), + "to" VARCHAR(40) +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_sync ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "reserve0" UInt128, + "reserve1" UInt128 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); +CREATE TABLE IF NOT EXISTS pools_transfer ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" UInt64, + "evt_address" VARCHAR(40), + "from" VARCHAR(40), + "to" VARCHAR(40), + "value" UInt256 +) ENGINE = MergeTree PRIMARY KEY ("evt_tx_hash","evt_index"); + + diff --git a/sql/uniswap_v2/schema.graphql b/sql/uniswap_v2/schema.graphql new file mode 100644 index 0000000..44066e7 --- /dev/null +++ b/sql/uniswap_v2/schema.graphql @@ -0,0 +1,81 @@ +type factory_pair_created @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + pair: String! + param3: BigDecimal! + token0: String! + token1: String! +} + +type pools_approval @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + owner: String! + spender: String! + value: BigDecimal! +} +type pools_burn @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + amount0: BigDecimal! + amount1: BigDecimal! + sender: String! + to: String! +} +type pools_mint @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + amount0: BigDecimal! + amount1: BigDecimal! + sender: String! +} +type pools_swap @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + amount0_in: BigDecimal! + amount0_out: BigDecimal! + amount1_in: BigDecimal! + amount1_out: BigDecimal! + sender: String! + to: String! +} +type pools_sync @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + reserve0: BigDecimal! + reserve1: BigDecimal! +} +type pools_transfer @entity { + id: ID! + evt_tx_hash: String! + evt_index: BigInt! + evt_block_time: String! + evt_block_number: BigInt! + evt_address: String! + from: String! + to: String! + value: BigDecimal! +} \ No newline at end of file diff --git a/sql/uniswap_v2/schema.sql b/sql/uniswap_v2/schema.sql new file mode 100644 index 0000000..f830f43 --- /dev/null +++ b/sql/uniswap_v2/schema.sql @@ -0,0 +1,81 @@ +CREATE TABLE IF NOT EXISTS factory_pair_created ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "pair" VARCHAR(40), + "param3" DECIMAL, + "token0" VARCHAR(40), + "token1" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); + +CREATE TABLE IF NOT EXISTS pools_approval ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "owner" VARCHAR(40), + "spender" VARCHAR(40), + "value" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS pools_burn ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "amount0" DECIMAL, + "amount1" DECIMAL, + "sender" VARCHAR(40), + "to" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS pools_mint ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "amount0" DECIMAL, + "amount1" DECIMAL, + "sender" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS pools_swap ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "amount0_in" DECIMAL, + "amount0_out" DECIMAL, + "amount1_in" DECIMAL, + "amount1_out" DECIMAL, + "sender" VARCHAR(40), + "to" VARCHAR(40), + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS pools_sync ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "reserve0" DECIMAL, + "reserve1" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); +CREATE TABLE IF NOT EXISTS pools_transfer ( + "evt_tx_hash" VARCHAR(64), + "evt_index" INT, + "evt_block_time" TIMESTAMP, + "evt_block_number" DECIMAL, + "evt_address" VARCHAR(40), + "from" VARCHAR(40), + "to" VARCHAR(40), + "value" DECIMAL, + PRIMARY KEY(evt_tx_hash,evt_index) +); diff --git a/sql/uniswap_v2/src/abi/factory_contract.rs b/sql/uniswap_v2/src/abi/factory_contract.rs new file mode 100644 index 0000000..9c82b94 --- /dev/null +++ b/sql/uniswap_v2/src/abi/factory_contract.rs @@ -0,0 +1,908 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct AllPairs { + pub param0: substreams::scalar::BigInt, + } + impl AllPairs { + const METHOD_ID: [u8; 4] = [30u8, 61u8, 209u8, 139u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.param0.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for AllPairs { + const NAME: &'static str = "allPairs"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for AllPairs { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct AllPairsLength {} + impl AllPairsLength { + const METHOD_ID: [u8; 4] = [87u8, 79u8, 43u8, 163u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for AllPairsLength { + const NAME: &'static str = "allPairsLength"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for AllPairsLength { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CreatePair { + pub token_a: Vec, + pub token_b: Vec, + } + impl CreatePair { + const METHOD_ID: [u8; 4] = [201u8, 198u8, 83u8, 150u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token_a: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token_b: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_a), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_b), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for CreatePair { + const NAME: &'static str = "createPair"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for CreatePair { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeTo {} + impl FeeTo { + const METHOD_ID: [u8; 4] = [1u8, 126u8, 126u8, 88u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeTo { + const NAME: &'static str = "feeTo"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for FeeTo { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeToSetter {} + impl FeeToSetter { + const METHOD_ID: [u8; 4] = [9u8, 75u8, 116u8, 21u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeToSetter { + const NAME: &'static str = "feeToSetter"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for FeeToSetter { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPair { + pub param0: Vec, + pub param1: Vec, + } + impl GetPair { + const METHOD_ID: [u8; 4] = [230u8, 164u8, 57u8, 5u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.param1)), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPair { + const NAME: &'static str = "getPair"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetPair { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeTo { + pub u_fee_to: Vec, + } + impl SetFeeTo { + const METHOD_ID: [u8; 4] = [244u8, 105u8, 1u8, 237u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + u_fee_to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_fee_to), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetFeeTo { + const NAME: &'static str = "setFeeTo"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeToSetter { + pub u_fee_to_setter: Vec, + } + impl SetFeeToSetter { + const METHOD_ID: [u8; 4] = [162u8, 231u8, 74u8, 246u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + u_fee_to_setter: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.u_fee_to_setter), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetFeeToSetter { + const NAME: &'static str = "setFeeToSetter"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct PairCreated { + pub token0: Vec, + pub token1: Vec, + pub pair: Vec, + pub param3: substreams::scalar::BigInt, + } + impl PairCreated { + const TOPIC_ID: [u8; 32] = [ + 13u8, + 54u8, + 72u8, + 189u8, + 15u8, + 107u8, + 168u8, + 1u8, + 52u8, + 163u8, + 59u8, + 169u8, + 39u8, + 90u8, + 197u8, + 133u8, + 217u8, + 211u8, + 21u8, + 240u8, + 173u8, + 131u8, + 85u8, + 205u8, + 222u8, + 253u8, + 227u8, + 26u8, + 250u8, + 40u8, + 208u8, + 233u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + token0: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token0' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token1: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token1' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pair: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param3: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for PairCreated { + const NAME: &'static str = "PairCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/sql/uniswap_v2/src/abi/mod.rs b/sql/uniswap_v2/src/abi/mod.rs new file mode 100644 index 0000000..65b37e3 --- /dev/null +++ b/sql/uniswap_v2/src/abi/mod.rs @@ -0,0 +1,3 @@ + +pub mod factory_contract; +pub mod pools_contract; \ No newline at end of file diff --git a/sql/uniswap_v2/src/abi/pools_contract.rs b/sql/uniswap_v2/src/abi/pools_contract.rs new file mode 100644 index 0000000..fb99a2d --- /dev/null +++ b/sql/uniswap_v2/src/abi/pools_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/lib.rs b/sql/uniswap_v2/src/lib.rs new file mode 100644 index 0000000..777ec7f --- /dev/null +++ b/sql/uniswap_v2/src/lib.rs @@ -0,0 +1,430 @@ +mod abi; +mod pb; +use hex_literal::hex; +use pb::contract::v1 as contract; +use substreams::prelude::*; +use substreams::store; +use substreams::Hex; +use substreams_database_change::pb::database::DatabaseChanges; +use substreams_database_change::tables::Tables as DatabaseChangeTables; +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; + +substreams_ethereum::init!(); + +const FACTORY_TRACKED_CONTRACT: [u8; 20] = hex!("5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f"); + +fn map_factory_events(blk: ð::Block, events: &mut contract::Events) { + events.factory_pair_createds.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::factory_contract::events::PairCreated::match_and_decode(log) { + return Some(contract::FactoryPairCreated { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + pair: event.pair, + param3: event.param3.to_string(), + token0: event.token0, + token1: event.token1, + }); + } + + None + }) + }) + .collect()); +} + +fn is_declared_dds_address(addr: &Vec, ordinal: u64, dds_store: &store::StoreGetInt64) -> bool { + // substreams::log::info!("Checking if address {} is declared dds address", Hex(addr).to_string()); + if dds_store.get_at(ordinal, Hex(addr).to_string()).is_some() { + return true; + } + return false; +} + +fn map_pools_events( + blk: ð::Block, + dds_store: &store::StoreGetInt64, + events: &mut contract::Events, +) { + + events.pools_approvals.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Approval::match_and_decode(log) { + return Some(contract::PoolsApproval { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + owner: event.owner, + spender: event.spender, + value: event.value.to_string(), + }); + } + + None + }) + }) + .collect()); + + events.pools_burns.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Burn::match_and_decode(log) { + return Some(contract::PoolsBurn { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + to: event.to, + }); + } + + None + }) + }) + .collect()); + + events.pools_mints.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Mint::match_and_decode(log) { + return Some(contract::PoolsMint { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + sender: event.sender, + }); + } + + None + }) + }) + .collect()); + + events.pools_swaps.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Swap::match_and_decode(log) { + return Some(contract::PoolsSwap { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0_in: event.amount0_in.to_string(), + amount0_out: event.amount0_out.to_string(), + amount1_in: event.amount1_in.to_string(), + amount1_out: event.amount1_out.to_string(), + sender: event.sender, + to: event.to, + }); + } + + None + }) + }) + .collect()); + + events.pools_syncs.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Sync::match_and_decode(log) { + return Some(contract::PoolsSync { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + reserve0: event.reserve0.to_string(), + reserve1: event.reserve1.to_string(), + }); + } + + None + }) + }) + .collect()); + + events.pools_transfers.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Transfer::match_and_decode(log) { + return Some(contract::PoolsTransfer { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + from: event.from, + to: event.to, + value: event.value.to_string(), + }); + } + + None + }) + }) + .collect()); +} + + +fn db_factory_out(events: &contract::Events, tables: &mut DatabaseChangeTables) { + // Loop over all the abis events to create table changes + events.factory_pair_createds.iter().for_each(|evt| { + tables + .create_row("factory_pair_created", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("pair", Hex(&evt.pair).to_string()) + .set("param3", BigDecimal::from_str(&evt.param3).unwrap()) + .set("token0", Hex(&evt.token0).to_string()) + .set("token1", Hex(&evt.token1).to_string()); + }); +} +fn db_pools_out(events: &contract::Events, tables: &mut DatabaseChangeTables) { + // Loop over all the abis events to create table changes + events.pools_approvals.iter().for_each(|evt| { + tables + .create_row("pools_approval", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("owner", Hex(&evt.owner).to_string()) + .set("spender", Hex(&evt.spender).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + events.pools_burns.iter().for_each(|evt| { + tables + .create_row("pools_burn", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.pools_mints.iter().for_each(|evt| { + tables + .create_row("pools_mint", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()); + }); + events.pools_swaps.iter().for_each(|evt| { + tables + .create_row("pools_swap", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) + .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) + .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) + .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.pools_syncs.iter().for_each(|evt| { + tables + .create_row("pools_sync", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("reserve0", BigDecimal::from_str(&evt.reserve0).unwrap()) + .set("reserve1", BigDecimal::from_str(&evt.reserve1).unwrap()); + }); + events.pools_transfers.iter().for_each(|evt| { + tables + .create_row("pools_transfer", [("evt_tx_hash", evt.evt_tx_hash.to_string()),("evt_index", evt.evt_index.to_string())]) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("from", Hex(&evt.from).to_string()) + .set("to", Hex(&evt.to).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); +} + + +fn graph_factory_out(events: &contract::Events, tables: &mut EntityChangesTables) { + // Loop over all the abis events to create table changes + events.factory_pair_createds.iter().for_each(|evt| { + tables + .create_row("factory_pair_created", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("pair", Hex(&evt.pair).to_string()) + .set("param3", BigDecimal::from_str(&evt.param3).unwrap()) + .set("token0", Hex(&evt.token0).to_string()) + .set("token1", Hex(&evt.token1).to_string()); + }); +} +fn graph_pools_out(events: &contract::Events, tables: &mut EntityChangesTables) { + // Loop over all the abis events to create table changes + events.pools_approvals.iter().for_each(|evt| { + tables + .create_row("pools_approval", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("owner", Hex(&evt.owner).to_string()) + .set("spender", Hex(&evt.spender).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); + events.pools_burns.iter().for_each(|evt| { + tables + .create_row("pools_burn", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()) + .set("to", Hex(&evt.to).to_string()); + }); + events.pools_mints.iter().for_each(|evt| { + tables + .create_row("pools_mint", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0", BigDecimal::from_str(&evt.amount0).unwrap()) + .set("amount1", BigDecimal::from_str(&evt.amount1).unwrap()) + .set("sender", Hex(&evt.sender).to_string()); + }); + events.pools_swaps.iter().for_each(|evt| { + tables + .create_row("pools_swap", format!("{}-{}", evt.evt_tx_hash, evt.evt_index)) + .set("evt_tx_hash", &evt.evt_tx_hash) + .set("evt_index", evt.evt_index) + .set("evt_block_time", evt.evt_block_time.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("amount0_in", BigDecimal::from_str(&evt.amount0_in).unwrap()) + .set("amount0_out", BigDecimal::from_str(&evt.amount0_out).unwrap()) + .set("amount1_in", BigDecimal::from_str(&evt.amount1_in).unwrap()) + .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.pools_syncs.iter().for_each(|evt| { + tables + .create_row("pools_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.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("reserve0", BigDecimal::from_str(&evt.reserve0).unwrap()) + .set("reserve1", BigDecimal::from_str(&evt.reserve1).unwrap()); + }); + events.pools_transfers.iter().for_each(|evt| { + tables + .create_row("pools_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.as_ref().unwrap()) + .set("evt_block_number", evt.evt_block_number) + .set("evt_address", &evt.evt_address) + .set("from", Hex(&evt.from).to_string()) + .set("to", Hex(&evt.to).to_string()) + .set("value", BigDecimal::from_str(&evt.value).unwrap()); + }); +} +#[substreams::handlers::store] +fn store_factory_pools_created(blk: eth::Block, store: StoreSetInt64) { + for rcpt in blk.receipts() { + for log in rcpt + .receipt + .logs + .iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + { + if let Some(event) = abi::factory_contract::events::PairCreated::match_and_decode(log) { + store.set(log.ordinal, Hex(event.pair).to_string(), &1); + } + } + } +} + +#[substreams::handlers::map] +fn map_events( + blk: eth::Block, + store_pools: StoreGetInt64, +) -> Result { + let mut events = contract::Events::default(); + map_factory_events(&blk, &mut events); + map_pools_events(&blk, &store_pools, &mut events); + Ok(events) +} + +#[substreams::handlers::map] +fn db_out(events: contract::Events) -> Result { + // Initialize Database Changes container + let mut tables = DatabaseChangeTables::new(); + db_factory_out(&events, &mut tables); + db_pools_out(&events, &mut tables); + Ok(tables.to_database_changes()) +} + +#[substreams::handlers::map] +fn graph_out(events: contract::Events) -> Result { + // Initialize Database Changes container + let mut tables = EntityChangesTables::new(); + graph_factory_out(&events, &mut tables); + graph_pools_out(&events, &mut tables); + Ok(tables.to_entity_changes()) +} diff --git a/sql/uniswap_v2/src/pb/contract.v1.rs b/sql/uniswap_v2/src/pb/contract.v1.rs new file mode 100644 index 0000000..97d05f6 --- /dev/null +++ b/sql/uniswap_v2/src/pb/contract.v1.rs @@ -0,0 +1,166 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Events { + #[prost(message, repeated, tag="1")] + pub factory_pair_createds: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub pools_approvals: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="3")] + pub pools_burns: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="4")] + pub pools_mints: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="5")] + pub pools_swaps: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="6")] + pub pools_syncs: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="7")] + pub pools_transfers: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FactoryPairCreated { + #[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 token0: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="6")] + pub token1: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] + pub pair: ::prost::alloc::vec::Vec, + #[prost(string, tag="8")] + pub param3: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsApproval { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] + pub owner: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] + pub spender: ::prost::alloc::vec::Vec, + #[prost(string, tag="8")] + pub value: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsBurn { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="7")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub amount1: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="9")] + pub to: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsMint { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="7")] + pub amount0: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub amount1: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsSwap { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(string, tag="7")] + pub amount0_in: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub amount1_in: ::prost::alloc::string::String, + #[prost(string, tag="9")] + pub amount0_out: ::prost::alloc::string::String, + #[prost(string, tag="10")] + pub amount1_out: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="11")] + pub to: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsSync { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub reserve0: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub reserve1: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolsTransfer { + #[prost(string, tag="1")] + pub evt_tx_hash: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub evt_index: u32, + #[prost(message, optional, tag="3")] + pub evt_block_time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(uint64, tag="4")] + pub evt_block_number: u64, + #[prost(string, tag="5")] + pub evt_address: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="6")] + pub from: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="7")] + pub to: ::prost::alloc::vec::Vec, + #[prost(string, tag="8")] + 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..a2998db --- /dev/null +++ b/sql/uniswap_v2/substreams.clickhouse.yaml @@ -0,0 +1,68 @@ +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: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + + - name: map_events + kind: map + initialBlock: 10000835 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10000835 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10000835 + 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..2a72bb0 --- /dev/null +++ b/sql/uniswap_v2/substreams.sql.yaml @@ -0,0 +1,66 @@ +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: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + + - name: map_events + kind: map + initialBlock: 10000835 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10000835 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10000835 + 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..d82b566 --- /dev/null +++ b/sql/uniswap_v2/substreams.subgraph.yaml @@ -0,0 +1,65 @@ +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: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + + - name: map_events + kind: map + initialBlock: 10000835 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10000835 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10000835 + 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..14212bd --- /dev/null +++ b/sql/uniswap_v2/substreams.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: store_factory_pools_created + kind: store + initialBlock: 10000835 + updatePolicy: set + valueType: proto:dynamic_datasource + inputs: + - source: sf.ethereum.type.v2.Block + + - name: map_events + kind: map + initialBlock: 10000835 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_factory_pools_created + output: + type: proto:contract.v1.Events + + - name: db_out + kind: map + initialBlock: 10000835 + inputs: + - map: map_events + output: + type: proto:sf.substreams.sink.database.v1.DatabaseChanges + + - name: graph_out + kind: map + initialBlock: 10000835 + inputs: + - map: map_events + output: + type: proto:sf.substreams.entity.v1.EntityChanges + +network: mainnet