An 5719/flow rework (#396)

* core models

* tests

* decoder / abis

* history process

* workflows

* end points

* workflow
This commit is contained in:
Austin 2025-01-30 14:11:04 -05:00 committed by GitHub
parent ecbf09726c
commit e119e85c07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
169 changed files with 6180 additions and 1620 deletions

View File

@ -43,4 +43,4 @@ jobs:
- name: Update evm tables
run: |
dbt run -s tag:evm
dbt run --vars '{"STREAMLINE_INVOKE_STREAMS":True}' -s tag:evm tag:streamline_decoded_logs_realtime tag:streamline_decoded_logs_complete

View File

@ -0,0 +1,46 @@
name: dbt_run_evm_decoded_logs
run-name: dbt_run_evm_decoded_logs
on:
workflow_dispatch:
schedule:
# Every hour on minute 45(see https://crontab.guru)
- cron: "45 * * * *"
env:
USE_VARS: "${{ vars.USE_VARS }}"
DBT_PROFILES_DIR: "${{ vars.DBT_PROFILES_DIR }}"
ACCOUNT: "${{ vars.ACCOUNT }}"
ROLE: "${{ vars.ROLE }}"
USER: "${{ vars.USER }}"
PASSWORD: "${{ secrets.PASSWORD }}"
REGION: "${{ vars.REGION }}"
DATABASE: "${{ vars.DATABASE }}"
WAREHOUSE: "${{ vars.WAREHOUSE }}"
SCHEMA: "${{ vars.SCHEMA }}"
concurrency:
group: ${{ github.workflow }}
jobs:
run_dbt_jobs:
runs-on: ubuntu-latest
environment:
name: workflow_prod
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: "pip"
- name: install dependencies
run: |
pip install -r requirements.txt
dbt deps
- name: Update decoded tables
run: |
dbt run -s tag:evm_decoded_logs

View File

@ -0,0 +1,50 @@
name: dbt_run_scheduled_abis
run-name: dbt_run_scheduled_abis
on:
workflow_dispatch:
schedule:
# Run at 23:27 UTC every day
- cron: "27 23 * * *"
env:
DBT_PROFILES_DIR: ./
ACCOUNT: "${{ vars.ACCOUNT }}"
ROLE: "${{ vars.ROLE }}"
USER: "${{ vars.USER }}"
PASSWORD: "${{ secrets.PASSWORD }}"
REGION: "${{ vars.REGION }}"
DATABASE: "${{ vars.DATABASE }}"
WAREHOUSE: "${{ vars.WAREHOUSE }}"
SCHEMA: "${{ vars.SCHEMA }}"
concurrency:
group: ${{ github.workflow }}
jobs:
run_dbt_jobs:
runs-on: ubuntu-latest
environment:
name: workflow_prod
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: "pip"
- name: install dependencies
run: |
pip install -r requirements.txt
dbt deps
- name: Run ABI Models
run: |
dbt run -m models/evm/silver/abis
- name: Kick off decoded logs history, if there are new ABIs from users
run: |
dbt run-operation run_decoded_logs_history

View File

@ -0,0 +1,50 @@
name: dbt_run_streamline_decoded_logs_history
run-name: dbt_run_streamline_decoded_logs_history
on:
workflow_dispatch:
schedule:
# Run at 22:43 UTC every Saturday
- cron: "43 22 * * 6"
env:
DBT_PROFILES_DIR: ./
ACCOUNT: "${{ vars.ACCOUNT }}"
ROLE: "${{ vars.ROLE }}"
USER: "${{ vars.USER }}"
PASSWORD: "${{ secrets.PASSWORD }}"
REGION: "${{ vars.REGION }}"
DATABASE: "${{ vars.DATABASE }}"
WAREHOUSE: "${{ vars.WAREHOUSE }}"
SCHEMA: "${{ vars.SCHEMA }}"
concurrency:
group: ${{ github.workflow }}
jobs:
run_dbt_jobs:
runs-on: ubuntu-latest
environment:
name: workflow_prod
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: "pip"
- name: install dependencies
run: |
pip install -r requirements.txt
dbt deps
- name: Update complete table
run: |
dbt run -m models/evm/streamline/decoder/streamline__decoded_logs_complete.sql
- name: Decode historical logs
run: |
dbt run-operation decoded_logs_history --vars '{"STREAMLINE_INVOKE_STREAMS":True}'

View File

@ -45,7 +45,7 @@ jobs:
- name: Run DBT Jobs
run: |
dbt test -s "flow_models,models/gold" tag:observability tag:evm tag:evm_gap_test --vars '{"TEST_RANGE": True, "START_HEIGHT": ${{ vars.STREAMLINE_START_BLOCK }}, "END_HEIGHT": 100000000}'
dbt test -s "flow_models,models/gold" tag:observability tag:evm_gap_test --vars '{"TEST_RANGE": True, "START_HEIGHT": ${{ vars.STREAMLINE_START_BLOCK }}, "END_HEIGHT": 100000000}'
continue-on-error: true
- name: Log test results

View File

@ -0,0 +1,50 @@
name: dbt_test_recent_evm
run-name: dbt_test_recent_evm
on:
workflow_dispatch:
schedule:
# Run at 0500 UTC daily (see https://crontab.guru)
- cron: "0 5 * * *"
env:
DBT_PROFILES_DIR: ./
ACCOUNT: "${{ vars.ACCOUNT }}"
ROLE: "${{ vars.ROLE }}"
USER: "${{ vars.USER }}"
PASSWORD: "${{ secrets.PASSWORD }}"
REGION: "${{ vars.REGION }}"
DATABASE: "${{ vars.DATABASE }}"
WAREHOUSE: "${{ vars.WAREHOUSE }}"
SCHEMA: "${{ vars.SCHEMA }}"
concurrency:
group: ${{ github.workflow }}
jobs:
run_dbt_jobs:
runs-on: ubuntu-latest
environment:
name: workflow_prod
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: "pip"
- name: install dependencies
run: |
pip install -r requirements.txt
dbt deps
- name: Build Recent Testing Views
run: |
dbt run -m "flow_models,tag:recent_evm_test"
- name: Run Recent Tests
run: |
dbt test -m "flow_models,tag:recent_evm_test"

View File

@ -0,0 +1,129 @@
{% macro decoded_logs_history(backfill_mode=false) %}
{%- set params = {
"sql_limit": var("DECODED_LOGS_HISTORY_SQL_LIMIT", 8000000),
"producer_batch_size": var("DECODED_LOGS_HISTORY_PRODUCER_BATCH_SIZE", 400000),
"worker_batch_size": var("DECODED_LOGS_HISTORY_WORKER_BATCH_SIZE", 100000)
} -%}
{% set wait_time = var("DECODED_LOGS_HISTORY_WAIT_TIME", 60) %}
{% set find_months_query %}
SELECT
DISTINCT date_trunc('month', block_timestamp)::date as month
FROM {{ ref('core_evm__fact_blocks') }}
ORDER BY month ASC
{% endset %}
{% set results = run_query(find_months_query) %}
{% if execute %}
{% set months = results.columns[0].values() %}
{% for month in months %}
{% set view_name = 'decoded_logs_history_' ~ month.strftime('%Y_%m') %}
{% set create_view_query %}
create or replace view streamline.{{view_name}} as (
WITH target_blocks AS (
SELECT
block_number
FROM {{ ref('core_evm__fact_blocks') }}
WHERE date_trunc('month', block_timestamp) = '{{month}}'::timestamp
),
new_abis AS (
SELECT
abi,
parent_contract_address,
event_signature,
start_block,
end_block
FROM {{ ref('silver_evm__complete_event_abis') }}
{% if not backfill_mode %}
WHERE inserted_timestamp > dateadd('day', -30, sysdate())
{% endif %}
),
existing_logs_to_exclude AS (
SELECT _log_id
FROM {{ ref('streamline__decoded_logs_complete') }} l
INNER JOIN target_blocks b using (block_number)
),
candidate_logs AS (
SELECT
l.block_number,
l.tx_hash,
l.event_index,
l.contract_address,
l.topics,
l.data,
concat(l.tx_hash::string, '-', l.event_index::string) as _log_id
FROM target_blocks b
INNER JOIN {{ ref('core_evm__fact_event_logs') }} l using (block_number)
WHERE l.tx_succeeded and date_trunc('month', l.block_timestamp) = '{{month}}'::timestamp
)
SELECT
l.block_number,
l._log_id,
A.abi,
OBJECT_CONSTRUCT(
'topics', l.topics,
'data', l.data,
'address', l.contract_address
) AS data
FROM candidate_logs l
INNER JOIN new_abis A
ON A.parent_contract_address = l.contract_address
AND A.event_signature = l.topics[0]::STRING
AND l.block_number BETWEEN A.start_block AND A.end_block
WHERE NOT EXISTS (
SELECT 1
FROM existing_logs_to_exclude e
WHERE e._log_id = l._log_id
)
LIMIT {{ params.sql_limit }}
)
{% endset %}
{# Create the view #}
{% do run_query(create_view_query) %}
{{ log("Created view for month " ~ month.strftime('%Y-%m'), info=True) }}
{% if var("STREAMLINE_INVOKE_STREAMS", false) %}
{# Check if rows exist first #}
{% set check_rows_query %}
SELECT EXISTS(SELECT 1 FROM streamline.{{view_name}} LIMIT 1)
{% endset %}
{% set results = run_query(check_rows_query) %}
{% set has_rows = results.columns[0].values()[0] %}
{% if has_rows %}
{# Invoke streamline, if rows exist to decode #}
{% set decode_query %}
SELECT
streamline.udf_bulk_decode_logs_v2(
PARSE_JSON(
$${ "external_table": "decoded_logs",
"producer_batch_size": {{ params.producer_batch_size }},
"sql_limit": {{ params.sql_limit }},
"sql_source": "{{view_name}}",
"worker_batch_size": {{ params.worker_batch_size }} }$$
)
);
{% endset %}
{% do run_query(decode_query) %}
{{ log("Triggered decoding for month " ~ month.strftime('%Y-%m'), info=True) }}
{# Call wait since we actually did some decoding #}
{% do run_query("call system$wait(" ~ wait_time ~ ")") %}
{{ log("Completed wait after decoding for month " ~ month.strftime('%Y-%m'), info=True) }}
{% else %}
{{ log("No rows to decode for month " ~ month.strftime('%Y-%m'), info=True) }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endmacro %}

View File

@ -0,0 +1,31 @@
{% macro run_decoded_logs_history() %}
{% set blockchain = var('GLOBAL_PROD_DB_NAME','').lower() %}
{% set check_for_new_user_abis_query %}
select 1
from {{ ref('silver_evm__user_verified_abis') }}
where _inserted_timestamp::date = sysdate()::date
and dayname(sysdate()) <> 'Sat'
{% endset %}
{% set results = run_query(check_for_new_user_abis_query) %}
{% if execute %}
{% set new_user_abis = results.columns[0].values()[0] %}
{% if new_user_abis %}
{% set invoke_workflow_query %}
SELECT
github_actions.workflow_dispatches(
'FlipsideCrypto',
'flow-models',
'dbt_run_streamline_decoded_logs_history.yml',
NULL
)
{% endset %}
{% do run_query(invoke_workflow_query) %}
{% endif %}
{% endif %}
{% endmacro %}

View File

@ -94,11 +94,11 @@
{% macro create_udf_bulk_decode_logs() %}
CREATE
OR REPLACE EXTERNAL FUNCTION streamline.udf_bulk_decode_logs(
OR REPLACE EXTERNAL FUNCTION streamline.udf_bulk_decode_logs_v2(
json OBJECT
) returns ARRAY api_integration = {% if target.name == "prod" %}
aws_flow_evm_api_prod AS 'https://rajpkbgko9.execute-api.us-east-1.amazonaws.com/prod/bulk_decode_logs'
AWS_FLOW_EVM_API_PROD AS 'https://rajpkbgko9.execute-api.us-east-1.amazonaws.com/prod/bulk_decode_logs'
{% else %}
aws_flow_evm_api_dev AS'https://pfv9lhg3kg.execute-api.us-east-1.amazonaws.com/stg/bulk_decode_logs'
AWS_FLOW_EVM_API_DEV AS'https://pfv9lhg3kg.execute-api.us-east-1.amazonaws.com/stg/bulk_decode_logs'
{%- endif %};
{% endmacro %}

View File

@ -0,0 +1,35 @@
{% test events_match_txs(
model,
transactions_model
) %}
WITH logs AS (
SELECT
DISTINCT block_number,
tx_hash,
tx_position
FROM
{{ model }}
),
missing_transactions AS (
SELECT
logs.block_number,
logs.tx_hash,
logs.tx_position
FROM
logs
LEFT JOIN {{ transactions_model }}
txs USING (
block_number,
tx_hash,
tx_position
)
WHERE
txs.tx_hash IS NULL
OR txs.tx_position IS NULL
OR txs.block_number IS NULL
)
SELECT
*
FROM
missing_transactions
{% endtest %}

View File

@ -0,0 +1,15 @@
{% test find_missing_decoded_logs(model, fact_logs_model, wrapped_asset_address) %}
SELECT
l.block_number,
l.fact_event_logs_id
FROM
{{ fact_logs_model }}
l
LEFT JOIN {{ model }}
d
ON d.ez_decoded_event_logs_id = l.fact_event_logs_id
WHERE
l.contract_address = '{{ wrapped_asset_address }}'
AND l.topics [0] :: STRING = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' -- Transfer
AND d.ez_decoded_event_logs_id IS NULL
{% endtest %}

View File

@ -0,0 +1,31 @@
{% test txs_match_blocks(
model,
blocks_model
) %}
WITH count_txs AS (
SELECT
block_number,
COUNT(*) AS record_count
FROM
{{ model }}
GROUP BY
ALL
),
block_txs AS (
SELECT
block_number,
tx_count AS expected_count
FROM
{{ blocks_model }}
)
SELECT
block_number,
record_count AS actual_count,
expected_count
FROM
block_txs
LEFT JOIN count_txs USING (block_number)
WHERE
record_count != expected_count
OR expected_count IS NULL
{% endtest %}

View File

@ -0,0 +1,45 @@
{{ config (
materialized = 'view',
tags = ['evm']
) }}
WITH meta AS (
SELECT
job_created_time AS _inserted_timestamp,
file_name,
CAST(SPLIT_PART(SPLIT_PART(file_name, '/', 6), '_', 1) AS INTEGER) AS _partition_by_block_number,
TO_DATE(
concat_ws('-', SPLIT_PART(file_name, '/', 3), SPLIT_PART(file_name, '/', 4), SPLIT_PART(file_name, '/', 5))
) AS _partition_by_created_date
FROM
TABLE(
information_schema.external_table_file_registration_history(
start_time => DATEADD('day', -3, CURRENT_TIMESTAMP()),
table_name => '{{ source( "bronze_streamline", "evm_decoded_logs") }}')
) A
)
SELECT
block_number,
id :: STRING AS id,
DATA,
metadata,
b.file_name,
_inserted_timestamp,
s._partition_by_block_number AS _partition_by_block_number,
s._partition_by_created_date AS _partition_by_created_date
FROM
{{ source(
"bronze_streamline",
"evm_decoded_logs"
) }}
s
JOIN meta b
ON b.file_name = metadata$filename
AND b._partition_by_block_number = s._partition_by_block_number
AND b._partition_by_created_date = s._partition_by_created_date
WHERE
b._partition_by_block_number = s._partition_by_block_number
AND b._partition_by_created_date = s._partition_by_created_date
AND s._partition_by_created_date >= DATEADD('day', -2, CURRENT_TIMESTAMP())
AND DATA :error IS NULL
AND DATA IS NOT NULL

View File

@ -0,0 +1,44 @@
{{ config (
materialized = 'view',
tags = ['evm']
) }}
WITH meta AS (
SELECT
registered_on AS _inserted_timestamp,
file_name,
CAST(SPLIT_PART(SPLIT_PART(file_name, '/', 6), '_', 1) AS INTEGER) AS _partition_by_block_number,
TO_DATE(
concat_ws('-', SPLIT_PART(file_name, '/', 3), SPLIT_PART(file_name, '/', 4), SPLIT_PART(file_name, '/', 5))
) AS _partition_by_created_date
FROM
TABLE(
information_schema.external_table_files(
table_name => '{{ source( "bronze_streamline", "evm_decoded_logs") }}'
)
) A
)
SELECT
block_number,
id :: STRING AS id,
DATA,
metadata,
b.file_name,
_inserted_timestamp,
s._partition_by_block_number AS _partition_by_block_number,
s._partition_by_created_date AS _partition_by_created_date
FROM
{{ source(
"bronze_streamline",
"evm_decoded_logs"
) }}
s
JOIN meta b
ON b.file_name = metadata$filename
AND b._partition_by_block_number = s._partition_by_block_number
AND b._partition_by_created_date = s._partition_by_created_date
WHERE
b._partition_by_block_number = s._partition_by_block_number
AND b._partition_by_created_date = s._partition_by_created_date
AND DATA :error IS NULL
AND DATA IS NOT NULL

View File

@ -0,0 +1,110 @@
{{ config(
materialized = 'incremental',
unique_key = "contract_address",
full_refresh = false,
tags = ['evm']
) }}
WITH base AS (
SELECT
contract_address,
latest_event_block AS latest_block
FROM
{{ ref('silver_evm__relevant_contracts') }}
WHERE
total_event_count >= 25
{% if is_incremental() %}
AND contract_address NOT IN (
SELECT
contract_address
FROM
{{ this }}
)
{% endif %}
ORDER BY
total_event_count DESC
LIMIT
200
), function_sigs AS (
SELECT
'0x313ce567' AS function_sig,
'decimals' AS function_name
UNION
SELECT
'0x06fdde03',
'name'
UNION
SELECT
'0x95d89b41',
'symbol'
),
all_reads AS (
SELECT
*
FROM
base
JOIN function_sigs
ON 1 = 1
),
ready_reads AS (
SELECT
contract_address,
latest_block,
function_sig,
RPAD(
function_sig,
64,
'0'
) AS input,
utils.udf_json_rpc_call(
'eth_call',
[{'to': contract_address, 'from': null, 'data': input}, utils.udf_int_to_hex(latest_block)],
concat_ws(
'-',
contract_address,
input,
latest_block
)
) AS rpc_request
FROM
all_reads
),
node_call AS (
SELECT
contract_address,
latest_block,
function_sig,
input,
live.udf_api(
'POST',
'{Service}',
OBJECT_CONSTRUCT(
'Content-Type',
'application/json'
),
rpc_request,
'Vault/prod/flow/evm/mainnet'
) AS response
FROM
ready_reads
WHERE
EXISTS (
SELECT
1
FROM
ready_reads
LIMIT
1
)
)
SELECT
contract_address,
latest_block AS block_number,
function_sig,
NULL AS function_input,
response,
SYSDATE() :: TIMESTAMP AS _inserted_timestamp
FROM
node_call

View File

@ -0,0 +1,15 @@
version: 2
models:
- name: bronze_evm_api__token_reads
columns:
- name: _INSERTED_TIMESTAMP
tests:
- not_null
- dbt_expectations.expect_row_values_to_have_recent_data:
datepart: day
interval: 1
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- TIMESTAMP_LTZ
- TIMESTAMP_NTZ

View File

@ -0,0 +1,182 @@
{% docs evm_blocks_table_doc %}
This table contains block level data for this EVM blockchain. This table can be used to analyze trends at a block level, for example gas fees vs. total transactions over time. For more information, please see [Etherscan Resources](https://etherscan.io/directory/Learning_Resources/Ethereum) or [The Ethereum Organization](https://ethereum.org/en/developers/docs/blocks/)
{% enddocs %}
{% docs evm_block_header_json %}
This JSON column contains the block header details.
{% enddocs %}
{% docs evm_blockchain %}
The blockchain on which transactions are being confirmed.
{% enddocs %}
{% docs evm_blocks_hash %}
The hash of the block header for a given block.
{% enddocs %}
{% docs evm_blocks_nonce %}
Block nonce is a value used during mining to demonstrate proof of work for a given block.
{% enddocs %}
{% docs evm_difficulty %}
The effort required to mine the block.
{% enddocs %}
{% docs evm_extra_data %}
Any data included by the miner for a given block.
{% enddocs %}
{% docs evm_gas_limit %}
Total gas limit provided by all transactions in the block.
{% enddocs %}
{% docs evm_gas_used %}
Total gas used in the block.
{% enddocs %}
{% docs evm_network %}
The network on the blockchain used by a transaction.
{% enddocs %}
{% docs evm_parent_hash %}
The hash of the block from which a given block is generated. Also known as the parent block.
{% enddocs %}
{% docs evm_receipts_root %}
The root of the state trie.
{% enddocs %}
{% docs evm_sha3_uncles %}
The mechanism which Ethereum Javascript RLP encodes an empty string.
{% enddocs %}
{% docs evm_size %}
Block size, which is determined by a given block's gas limit.
{% enddocs %}
{% docs evm_total_difficulty %}
Total difficulty of the chain at a given block.
{% enddocs %}
{% docs evm_tx_count %}
Total number of transactions within a block.
{% enddocs %}
{% docs evm_uncle_blocks %}
Uncle blocks occur when two blocks are mined and broadcasted at the same time, with the same block number. The block validated across the most nodes will be added to the primary chain, and the other one becomes an uncle block. Miners do receive rewards for uncle blocks.
{% enddocs %}
{% docs evm_miner %}
The address of the beneficiary to whom the mining rewards were given
{% enddocs %}
{% docs evm_state_root %}
The root of the final state trie of the block
{% enddocs %}
{% docs evm_transactions_root %}
The root of the transaction trie of the block
{% enddocs %}
{% docs evm_logs_bloom %}
The bloom filter for the logs of the block.
{% enddocs %}
{% docs evm_mix_hash %}
A string of a 256-bit hash encoded as a hexadecimal
{% enddocs %}
{% docs evm_base_fee_per_gas %}
A string of the base fee encoded in hexadecimal format. Please note that this response field will not be included in a block requested before the EIP-1559 upgrade
{% enddocs %}
{% docs evm_blob_gas_used %}
The amount of gas used for blob transactions in the block.
{% enddocs %}
{% docs evm_excess_blob_gas %}
The amount of excess blob gas in the block.
{% enddocs %}
{% docs evm_parent_beacon_block_root %}
The root of the parent beacon block.
{% enddocs %}
{% docs evm_withdrawals %}
The withdrawals for the block.
{% enddocs %}
{% docs evm_withdrawals_root %}
The root of the withdrawals for the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_base_fee_per_gas %}
A string of the base fee encoded in hexadecimal format, converted to integer.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_block_header_json %}
This JSON column contains the block header details.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_blockchain %}
The blockchain on which transactions are being confirmed.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_blocks_hash %}
The hash of the block header for a given block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_blocks_nonce %}
Block nonce is a value used during mining to demonstrate proof of work for a given block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_blocks_table_doc %}
This table contains block level data for the flowEVM Blockchain. This table can be used to analyze trends at a block level, for example gas fees vs. total transactions over time. For more information on EVM transactions, please see [Etherscan Resources](https://etherscan.io/directory/Learning_Resources/Ethereum) or [The Ethereum Organization](https://ethereum.org/en/developers/docs/blocks/)
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_difficulty %}
The effort required to mine the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_extra_data %}
Any data included by the validator for a given block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_gas_limit %}
Total gas limit provided by all transactions in the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_gas_used %}
Total gas used in the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_bloom %}
The bloom filter for the logs of the block. null if pending
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_miner %}
Miner who successfully added a given block to the blockchain.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_mix_hash %}
A string of a 256-bit hash encoded as a hexadecimal
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_network %}
The network on the blockchain used by a transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_nonce %}
The hash of the generated proof-of-work. null if pending
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_parent_hash %}
The hash of the block from which a given block is generated. Also known as the parent block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_receipts_root %}
The root of the state trie.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_sha3_uncles %}
The mechanism which Ethereum Javascript RLP encodes an empty string.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_size %}
Block size, which is determined by a given block's gas limit.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_state_root %}
The root of the final state trie of the block
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_total_difficulty %}
Total difficulty of the chain at a given block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_transactions %}
An array containing transaction response data.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_transactions_root %}
The root of the transaction trie of the block
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_count %}
Total number of transactions within a block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_uncle_blocks %}
Uncle blocks occur when two blocks are mined and broadcasted at the same time, with the same block number. The block validated across the most nodes will be added to the primary chain, and the other one becomes an uncle block. Miners do receive rewards for uncle blocks.
{% enddocs %}

View File

@ -0,0 +1,95 @@
{% docs evm_logs_table_doc %}
This table contains flattened event logs from transactions on this EVM blockchain. Transactions may have multiple events, which are denoted by the event index for a transaction hash. Therefore, this table is unique on the combination of transaction hash and event index. Please see `fact_decoded_event_logs` or `ez_decoded_event_logs` for the decoded event logs.
{% enddocs %}
{% docs evm_event_index %}
Event number within a transaction.
{% enddocs %}
{% docs evm_event_inputs %}
The decoded event inputs for a given event.
{% enddocs %}
{% docs evm_event_removed %}
Whether the event has been removed from the transaction.
{% enddocs %}
{% docs evm_log_id_events %}
This is the primary key for this table. This is a concatenation of the transaction hash and the event index at which the event occurred. This field can be used within other event based tables such as ```fact_transfers``` & ```ez_token_transfers```.
{% enddocs %}
{% docs evm_logs_contract_address %}
The address interacted with for a given event.
{% enddocs %}
{% docs evm_logs_contract_name %}
The name of the contract or token, where possible.
{% enddocs %}
{% docs evm_logs_data %}
The un-decoded event data.
{% enddocs %}
{% docs evm_logs_tx_hash %}
Transaction hash is a unique 66-character identifier that is generated when a transaction is executed. This field will not be unique in this table, as a given transaction can include multiple events.
{% enddocs %}
{% docs evm_topics %}
The un-decoded event input topics.
{% enddocs %}
{% docs evm_topic_0 %}
The first topic of the event, which is a unique identifier for the event.
{% enddocs %}
{% docs evm_topic_1 %}
The second topic of the event, if applicable.
{% enddocs %}
{% docs evm_topic_2 %}
The third topic of the event, if applicable.
{% enddocs %}
{% docs evm_topic_3 %}
The fourth topic of the event, if applicable.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_event_index %}
Event number within a transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_event_inputs %}
The decoded event inputs for a given event.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_event_name %}
The decoded event name for a given event.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_event_removed %}
Whether the event has been removed from the transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_origin_sig %}
The function signature of this transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_log_id_events %}
This is the primary key for this table. This is a concatenation of the transaction hash and the event index at which the event occurred.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_contract_address %}
The address interacted with for a given event.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_contract_name %}
The name of the contract or token, where possible.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_data %}
The un-decoded event data.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_table_doc %}
This table contains flattened event logs from transactions on the flowEVM Blockchain. Transactions may have multiple events, which are denoted by the event index for a transaction hash. Therefore, this table is unique on the combination of transaction hash and event index.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_logs_tx_hash %}
Transaction hash is a unique 66-character identifier that is generated when a transaction is executed. This field will not be unique in this table, as a given transaction can include multiple events.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_origin_from %}
The from address of this transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_origin_to %}
The to address of this transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_topics %}
The un-decoded event input topics.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_block_number %}
Also known as block height. The block number, which indicates the length of the blockchain, increases after the addition of each new block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_block_timestamp %}
The date and time at which the block was produced.
{% enddocs %}

View File

@ -0,0 +1,89 @@
{% docs evm_internal_column %}
Deprecated. This column is no longer used. Please remove from your query by Jan. 10 2024.
{% enddocs %}
{% docs evm_amount_deprecation %}
This column is being deprecated for standardization purposes on Jan. 10 2024. Please use the equivalent column without the native asset prefix. For example, use `amount` instead of `avax_amount`.
{% enddocs %}
{% docs evm_block_number %}
Also known as block height. The block number, which indicates the length of the blockchain, increases after the addition of each new block.
{% enddocs %}
{% docs evm_block_timestamp %}
The date and time at which the block was produced.
{% enddocs %}
{% docs evm_from_address %}
The sending address of this transaction.
{% enddocs %}
{% docs evm_ingested_at %}
Internal column.
{% enddocs %}
{% docs evm_to_address %}
The receiving address of this transaction. This can be a contract address.
{% enddocs %}
{% docs evm_pk %}
The unique identifier for each row in the table.
{% enddocs %}
{% docs evm_inserted_timestamp %}
The UTC timestamp at which the row was inserted into the table.
{% enddocs %}
{% docs evm_modified_timestamp %}
The UTC timestamp at which the row was last modified.
{% enddocs %}
{% docs evm_precise_amount_unadjusted %}
The precise, unadjusted amount of the transaction. This is returned as a string to avoid precision loss.
{% enddocs %}
{% docs evm_precise_amount_adjusted %}
The precise, adjusted amount of the transaction. This is returned as a string to avoid precision loss.
{% enddocs %}
{% docs evm_value_hex %}
The value of the transaction in hexadecimal format.
{% enddocs %}
{% docs evm_column_deprecation_notice %}
This column is being deprecated for standardization purposes.
{% enddocs %}
{% docs evm_table_deprecation_notice %}
This table is being deprecated for standardization purposes.
{% enddocs %}

View File

@ -0,0 +1,69 @@
{% docs evm_labels_table %}
This table contains labels for addresses on this EVM blockchain.
{% enddocs %}
{% docs evm_table_dim_labels %}
The labels table is a store of one-to-one address identifiers, or an address name. Labels are broken out into a "type" (such as cex, dex, dapp, games, etc.) and a "subtype" (ex: contract_deployer, hot_wallet, token_contract, etc.) in order to help classify each address name into similar groups. Our labels are sourced from many different places, but can primarily be grouped into two categories: automatic and manual. Automatic labels are continuously labeled based on certain criteria, such as a known contract deploying another contract, behavior-based algorithms for finding deposit wallets, and consistent data pulls of custom protocol APIs. Manual labels are done periodically to find addresses that cannot be found programmatically such as finding new protocol addresses, centralized exchange hot wallets, or trending addresses. Labels can also be added by our community by using our add-a-label tool (https://science.flipsidecrypto.xyz/add-a-label/) or on-chain with near (https://near.social/lord1.near/widget/Form) and are reviewed by our labels team. A label can be removed by our labels team if it is found to be incorrect or no longer relevant; this generally will only happen for mislabeled deposit wallets.
{% enddocs %}
{% docs evm_project_name %}
The name of the project for this address.
{% enddocs %}
{% docs evm_label %}
The label for this address.
{% enddocs %}
{% docs evm_label_address %}
Address that the label is for. This is the field that should be used to join other tables with labels.
{% enddocs %}
{% docs evm_label_address_name %}
The most granular label for this address.
{% enddocs %}
{% docs evm_label_blockchain %}
The name of the blockchain.
{% enddocs %}
{% docs evm_label_creator %}
The name of the creator of the label.
{% enddocs %}
{% docs evm_label_subtype %}
A sub-category nested within label type providing further detail.
{% enddocs %}
{% docs evm_label_type %}
A high-level category describing the address's main function or ownership.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_decimals %}
The number of decimal places this contract needs adjusted where token values exist. For example, use the decimal field to correctly transform raw amounts in ```fact_token_transfers```.
{% enddocs %}

View File

@ -1,11 +0,0 @@
{% docs internal_column %}
Deprecated. This column is no longer used. Please remove from your query by Jan. 31 2024.
{% enddocs %}
{% docs amount_deprecation %}
This column is being deprecated for standardization purposes on Jan. 31 2024. Please use the equivalent column without the native asset prefix. For example, use `amount` instead of `eth_amount`.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_from_address %}
The sending address of this transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_ingested_at %}
Internal column.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs is_pending %}
A boolean flag indicating if the record is pending or complete.
{% enddocs %}

View File

@ -1,17 +0,0 @@
{% docs precise_amount_unadjusted %}
The precise, unadjusted amount of the transaction. This is returned as a string to avoid precision loss.
{% enddocs %}
{% docs precise_amount_adjusted %}
The precise, adjusted amount of the transaction. This is returned as a string to avoid precision loss.
{% enddocs %}
{% docs tx_fee_precise %}
The precise amount of the transaction fee. This is returned as a string to avoid precision loss.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_symbol %}
The symbol belonging to the address of the token
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_to_address %}
The receiving address of this transaction. This can be a contract address.
{% enddocs %}

View File

@ -0,0 +1,136 @@
{% docs evm_traces_table_doc %}
This table contains flattened trace data for internal contract calls. User-defined functions (UDFs) are available to decode hex encoded fields, including `utils.udf_hex_to_int()`.
{% enddocs %}
{% docs evm_traces_block_no %}
The block number of this transaction.
{% enddocs %}
{% docs evm_traces_blocktime %}
The block timestamp of this transaction.
{% enddocs %}
{% docs evm_traces_call_data %}
The raw JSON data for this trace.
{% enddocs %}
{% docs evm_traces_value %}
The amount of the native asset transferred in this trace.
{% enddocs %}
{% docs evm_traces_from %}
The sending address of this trace. This is not necessarily the from address of the transaction.
{% enddocs %}
{% docs evm_traces_gas %}
The gas supplied for this trace.
{% enddocs %}
{% docs evm_traces_gas_used %}
The gas used for this trace.
{% enddocs %}
{% docs evm_traces_identifier %}
This field represents the position and type of the trace within the transaction.
{% enddocs %}
{% docs evm_trace_index %}
The index of the trace within the transaction.
{% enddocs %}
{% docs evm_traces_input %}
The input data for this trace.
{% enddocs %}
{% docs evm_traces_output %}
The output data for this trace.
{% enddocs %}
{% docs evm_sub_traces %}
The amount of nested sub traces for this trace.
{% enddocs %}
{% docs evm_traces_to %}
The receiving address of this trace. This is not necessarily the to address of the transaction.
{% enddocs %}
{% docs evm_traces_tx_hash %}
The transaction hash for the trace. Please note, this is not necessarily unique in this table as transactions frequently have multiple traces.
{% enddocs %}
{% docs evm_traces_type %}
The type of internal transaction. Common trace types are `CALL`, `DELEGATECALL`, and `STATICCALL`.
{% enddocs %}
{% docs evm_trace_succeeded %}
The boolean value representing if the trace succeeded.
{% enddocs %}
{% docs evm_trace_error_reason %}
The reason for the trace failure, if any.
{% enddocs %}
{% docs evm_trace_address %}
The trace address for this trace.
{% enddocs %}
{% docs evm_revert_reason %}
The reason for the revert, if available.
{% enddocs %}

View File

@ -0,0 +1,249 @@
{% docs evm_tx_table_doc %}
This table contains transaction level data for this EVM blockchain. Each transaction will have a unique transaction hash, along with transaction fees and a value transferred in the native asset when applicable. Transactions may be native asset transfers or interactions with contract addresses. For more information, please see [The Ethereum Organization - Transactions](https://ethereum.org/en/developers/docs/transactions/)
Below are the specific native tokens that correspond to each EVM chain:
| Status | Description |
|------------|-------------|
| ETHEREUM | ETH |
| BINANCE | BNB |
| POLYGON | POL |
| AVALANCHE | AVAX |
| ARBITRUM | ETH |
| OPTIMISM | ETH |
| GNOSIS | xDAI |
| KAIA | KLAY |
| SEI | SEI |
| CORE | CORE |
{% enddocs %}
{% docs evm_cumulative_gas_used %}
The total amount of gas used when this transaction was executed in the block.
{% enddocs %}
{% docs evm_tx_block_hash %}
Block hash is a unique 66-character identifier that is generated when a block is produced.
{% enddocs %}
{% docs evm_tx_fee %}
Amount paid to validate the transaction in the native asset.
{% enddocs %}
{% docs evm_tx_gas_limit %}
Maximum amount of gas allocated for the transaction.
{% enddocs %}
{% docs evm_tx_gas_price %}
Cost per unit of gas in Gwei.
{% enddocs %}
{% docs evm_tx_gas_used %}
Gas used by the transaction.
{% enddocs %}
{% docs evm_tx_hash %}
Transaction hash is a unique 66-character identifier that is generated when a transaction is executed.
{% enddocs %}
{% docs evm_tx_input_data %}
This column contains additional data for this transaction, and is commonly used as part of a contract interaction or as a message to the recipient.
{% enddocs %}
{% docs evm_tx_json %}
This JSON column contains the transaction details, including event logs.
{% enddocs %}
{% docs evm_tx_nonce %}
The number of transactions sent from a given address.
{% enddocs %}
{% docs evm_tx_origin_sig %}
The function signature of the call that triggered this transaction.
{% enddocs %}
{% docs evm_origin_sig %}
The function signature of the contract call that triggered this transaction.
{% enddocs %}
{% docs evm_tx_position %}
The position of the transaction within the block.
{% enddocs %}
{% docs evm_tx_status %}
Status of the transaction.
{% enddocs %}
{% docs evm_value %}
The value transacted in the native asset.
{% enddocs %}
{% docs evm_effective_gas_price %}
The total base charge plus tip paid for each unit of gas, in Gwei.
{% enddocs %}
{% docs evm_max_fee_per_gas %}
The maximum fee per gas of the transaction, in Gwei.
{% enddocs %}
{% docs evm_max_priority_fee_per_gas %}
The maximum priority fee per gas of the transaction, in Gwei.
{% enddocs %}
{% docs evm_r %}
The r value of the transaction signature.
{% enddocs %}
{% docs evm_s %}
The s value of the transaction signature.
{% enddocs %}
{% docs evm_v %}
The v value of the transaction signature.
{% enddocs %}
{% docs evm_tx_succeeded %}
Whether the transaction was successful, returned as a boolean.
{% enddocs %}
{% docs evm_tx_fee_precise %}
The precise amount of the transaction fee. This is returned as a string to avoid precision loss.
{% enddocs %}
{% docs evm_tx_type %}
The type of transaction.
{% enddocs %}
{% docs evm_mint %}
The minting event associated with the transaction
{% enddocs %}
{% docs evm_source_hash %}
The hash of the source transaction that created this transaction
{% enddocs %}
{% docs evm_eth_value %}
The eth value for the transaction
{% enddocs %}
{% docs evm_chain_id %}
The unique identifier for the chain the transaction was executed on.
{% enddocs %}
{% docs evm_l1_fee_precise_raw %}
The raw l1 fee for the transaction, in Gwei.
{% enddocs %}
{% docs evm_l1_fee_precise %}
The precise l1 fee for the transaction, in Gwei.
{% enddocs %}
{% docs evm_y_parity %}
The y parity for the transaction.
{% enddocs %}
{% docs evm_access_list %}
The access list for the transaction.
{% enddocs %}
{% docs evm_l1_base_fee_scalar %}
The scalar l1 base fee for the transaction.
{% enddocs %}
{% docs evm_l1_blob_base_fee %}
The blob base fee for the transaction.
{% enddocs %}
{% docs evm_l1_blob_base_fee_scalar %}
The scalar blob base fee for the transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_block_hash %}
Block hash is a unique 66-character identifier that is generate when a block is produced.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_chain_id %}
The chain id returned by the node.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_cumulative_gas_used %}
The total amount of gas used when this transaction was executed in the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_receipt_type %}
The transaction type as returned by the receipt body.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_fee %}
Amount paid to validate the transaction in ETH.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_gas_limit %}
Maximum amount of gas allocated for the transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_gas_price %}
Cost per unit of gas in Gwei.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_gas_used %}
Gas used by transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_hash %}
Transaction hash is a unique 66-character identifier that is generated when a transaction is executed.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_input_data %}
This column contains additional data for this transaction, and is commonly used as part of a contract interaction or as a message to the recipient.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_json %}
This JSON column contains the transaction details, including event logs.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_nonce %}
The number of transactions sent from a given address.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_origin_sig %}
The function signature of the contract call.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_position %}
The position of the transaction within the block.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_status %}
Status of the transaction.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_table_doc %}
This table contains transaction level data for the flowEVM Blockchain. Each transaction will have a unique transaction hash, along with transactions fees and a ETH value transferred when applicable. Transactions may be native ETH transfers or interactions with contract addresses. For more information, please see [The Ethereum Organization - Transactions](https://ethereum.org/en/developers/docs/transactions/)
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_tx_type %}
Transaction Type as returned by the transaction body.
{% enddocs %}

View File

@ -1,5 +0,0 @@
{% docs flowevm_value %}
The value transacted in ETH.
{% enddocs %}

View File

@ -1,83 +1,64 @@
{{ config(
materialized = 'incremental',
unique_key = "fact_blocks_id",
incremental_strategy = 'merge',
merge_exclude_columns = ["inserted_timestamp"],
cluster_by = ['inserted_timestamp :: DATE', 'ROUND(block_number, -3)'],
persist_docs ={ "relation": true,
"columns": true },
{{ config (
materialized = "incremental",
incremental_strategy = 'delete+insert',
unique_key = "block_number",
cluster_by = ['block_timestamp::DATE'],
tags = ['evm']
) }}
SELECT
block_number,
block_timestamp,
block_json :hash :: STRING AS block_hash,
utils.udf_hex_to_int(
block_json :timestamp :: STRING
) :: TIMESTAMP AS block_timestamp,
'mainnet' AS network,
'flow' AS blockchain,
transaction_count AS tx_count,
difficulty,
total_difficulty,
extra_data,
gas_limit,
gas_used,
block_hash AS HASH,
parent_hash,
receipts_root,
sha3_uncles,
SIZE,
uncles AS uncle_blocks,
OBJECT_CONSTRUCT(
'baseFeePerGas',
base_fee_per_gas,
'difficulty',
difficulty,
'extraData',
extra_data,
'gasLimit',
gas_limit,
'gasUsed',
gas_used,
'hash',
block_hash,
'logsBloom',
logs_bloom,
'miner',
miner,
'nonce',
nonce,
'number',
block_number,
'parentHash',
parent_hash,
'receiptsRoot',
receipts_root,
'sha3Uncles',
sha3_uncles,
'size',
SIZE,
'stateRoot',
state_root,
'timestamp',
block_timestamp,
'totalDifficulty',
total_difficulty,
'transactionsRoot',
transactions_root,
'uncles',
uncles
) AS block_header_json,
evm_blocks_id AS fact_blocks_id,
inserted_timestamp,
modified_timestamp
ARRAY_SIZE(
block_json :transactions
) AS tx_count,
utils.udf_hex_to_int(
block_json :size :: STRING
) :: bigint AS SIZE,
block_json :miner :: STRING AS miner,
block_json :mixHash :: STRING AS mix_hash,
block_json :extraData :: STRING AS extra_data,
block_json :parentHash :: STRING AS parent_hash,
utils.udf_hex_to_int(
block_json :gasUsed :: STRING
) :: bigint AS gas_used,
utils.udf_hex_to_int(
block_json :gasLimit :: STRING
) :: bigint AS gas_limit,
utils.udf_hex_to_int(
block_json :baseFeePerGas :: STRING
) :: bigint AS base_fee_per_gas,
utils.udf_hex_to_int(
block_json :difficulty :: STRING
) :: bigint AS difficulty,
utils.udf_hex_to_int(
block_json :totalDifficulty :: STRING
) :: bigint AS total_difficulty,
block_json :sha3Uncles :: STRING AS sha3_uncles,
block_json :uncles AS uncle_blocks,
utils.udf_hex_to_int(
block_json :nonce :: STRING
) :: bigint AS nonce,
block_json :receiptsRoot :: STRING AS receipts_root,
block_json :stateRoot :: STRING AS state_root,
block_json :transactionsRoot :: STRING AS transactions_root,
block_json :logsBloom :: STRING AS logs_bloom,
{{ dbt_utils.generate_surrogate_key(['block_number']) }} AS fact_blocks_id,
SYSDATE() AS inserted_timestamp,
SYSDATE() AS modified_timestamp
FROM
{{ ref('silver_evm__blocks') }}
WHERE 1=1
{% if is_incremental() %}
WHERE
modified_timestamp >= (
SELECT
MAX(modified_timestamp)
FROM
{{ this }}
AND modified_timestamp > (
SELECT
COALESCE(MAX(modified_timestamp), '1970-01-01' :: TIMESTAMP) AS modified_timestamp
FROM
{{ this }}
)
{% endif %}
{% endif %}

View File

@ -1,51 +1,56 @@
version: 2
models:
- name: core_evm__fact_blocks
description: '{{ doc("flowevm_blocks_table_doc") }}'
tests:
- dbt_utils.recency:
datepart: hour
field: block_timestamp
interval: 2
description: '{{ doc("evm_blocks_table_doc") }}'
columns:
- name: BLOCK_NUMBER
description: '{{ doc("flowevm_block_number") }}'
description: '{{ doc("evm_block_number") }}'
- name: BLOCK_HASH
description: '{{ doc("evm_blocks_hash") }}'
- name: BLOCK_TIMESTAMP
description: '{{ doc("flowevm_block_timestamp") }}'
description: '{{ doc("evm_block_timestamp") }}'
- name: NETWORK
description: '{{ doc("flowevm_network") }}'
- name: BLOCKCHAIN
description: '{{ doc("flowevm_blockchain") }}'
description: '{{ doc("evm_network") }}'
- name: TX_COUNT
description: '{{ doc("flowevm_tx_count") }}'
- name: DIFFICULTY
description: '{{ doc("flowevm_difficulty") }}'
- name: TOTAL_DIFFICULTY
description: '{{ doc("flowevm_total_difficulty") }}'
- name: EXTRA_DATA
description: '{{ doc("flowevm_extra_data") }}'
- name: GAS_LIMIT
description: '{{ doc("flowevm_gas_limit") }}'
- name: GAS_USED
description: '{{ doc("flowevm_gas_used") }}'
- name: HASH
description: '{{ doc("flowevm_blocks_hash") }}'
- name: PARENT_HASH
description: '{{ doc("flowevm_parent_hash") }}'
- name: RECEIPTS_ROOT
description: '{{ doc("flowevm_receipts_root") }}'
- name: SHA3_UNCLES
description: '{{ doc("flowevm_sha3_uncles") }}'
description: '{{ doc("evm_tx_count") }}'
- name: SIZE
description: '{{ doc("flowevm_size") }}'
description: '{{ doc("evm_size") }}'
- name: MINER
description: '{{ doc("evm_miner") }}'
- name: BASE_FEE_PER_GAS
description: '{{ doc("evm_base_fee_per_gas") }}'
- name: MIX_HASH
description: '{{ doc("evm_mix_hash") }}'
- name: EXTRA_DATA
description: '{{ doc("evm_extra_data") }}'
- name: PARENT_HASH
description: '{{ doc("evm_parent_hash") }}'
- name: GAS_USED
description: '{{ doc("evm_gas_used") }}'
- name: GAS_LIMIT
description: '{{ doc("evm_gas_limit") }}'
- name: DIFFICULTY
description: '{{ doc("evm_difficulty") }}'
- name: TOTAL_DIFFICULTY
description: '{{ doc("evm_total_difficulty") }}'
- name: SHA3_UNCLES
description: '{{ doc("evm_sha3_uncles") }}'
- name: UNCLE_BLOCKS
description: '{{ doc("flowevm_uncle_blocks") }}'
- name: BLOCK_HEADER_JSON
description: '{{ doc("flowevm_block_header_json") }}'
description: '{{ doc("evm_uncle_blocks") }}'
- name: NONCE
description: '{{ doc("evm_blocks_nonce") }}'
- name: RECEIPTS_ROOT
description: '{{ doc("evm_receipts_root") }}'
- name: STATE_ROOT
description: '{{ doc("evm_state_root") }}'
- name: TRANSACTIONS_ROOT
description: '{{ doc("evm_transactions_root") }}'
- name: LOGS_BLOOM
description: '{{ doc("evm_logs_bloom") }}'
- name: FACT_BLOCKS_ID
description: '{{ doc("pk_id") }}'
description: '{{ doc("evm_pk") }}'
- name: INSERTED_TIMESTAMP
description: '{{ doc("inserted_timestamp") }}'
description: '{{ doc("evm_inserted_timestamp") }}'
- name: MODIFIED_TIMESTAMP
description: '{{ doc("modified_timestamp") }}'
description: '{{ doc("evm_modified_timestamp") }}'

View File

@ -1,40 +1,223 @@
{{ config(
materialized = 'incremental',
unique_key = "fact_event_logs_id",
incremental_strategy = 'merge',
merge_exclude_columns = ["inserted_timestamp"],
cluster_by = ['inserted_timestamp :: DATE', 'ROUND(block_number, -3)'],
persist_docs ={ "relation": true,
"columns": true },
{{ config (
materialized = "incremental",
incremental_strategy = 'delete+insert',
unique_key = "block_number",
cluster_by = ['block_timestamp::DATE'],
tags = ['evm']
) }}
WITH base AS (
SELECT
block_number,
{% if uses_receipts_by_hash %}
tx_hash,
{% else %}
receipts_json :transactionHash :: STRING AS tx_hash,
{% endif %}
receipts_json,
receipts_json :logs AS full_logs
FROM
{{ ref('silver_evm__receipts') }}
WHERE
1 = 1
AND ARRAY_SIZE(receipts_json :logs) > 0
{% if is_incremental() %}
AND modified_timestamp > (
SELECT
COALESCE(MAX(modified_timestamp), '1970-01-01' :: TIMESTAMP) AS modified_timestamp
FROM
{{ this }})
{% endif %}
),
flattened_logs AS (
SELECT
block_number,
tx_hash,
lower(receipts_json :from :: STRING) AS origin_from_address,
lower(receipts_json :to :: STRING) AS origin_to_address,
CASE
WHEN receipts_json :status :: STRING = '0x1' THEN TRUE
WHEN receipts_json :status :: STRING = '1' THEN TRUE
WHEN receipts_json :status :: STRING = '0x0' THEN FALSE
WHEN receipts_json :status :: STRING = '0' THEN FALSE
ELSE NULL
END AS tx_succeeded,
VALUE :address :: STRING AS contract_address,
VALUE :blockHash :: STRING AS block_hash,
VALUE :blockNumber :: STRING AS block_number_hex,
VALUE :data :: STRING AS DATA,
utils.udf_hex_to_int(
VALUE :logIndex :: STRING
) :: INT AS event_index,
VALUE :removed :: BOOLEAN AS event_removed,
VALUE :topics AS topics,
VALUE :transactionHash :: STRING AS transaction_hash,
utils.udf_hex_to_int(
VALUE :transactionIndex :: STRING
) :: INT AS transaction_index
FROM
base,
LATERAL FLATTEN (
input => full_logs
)
),
new_logs AS (
SELECT
l.block_number,
b.block_timestamp,
l.tx_hash,
l.transaction_index AS tx_position,
l.event_index,
l.contract_address,
l.topics,
l.topics [0] :: STRING AS topic_0,
l.topics [1] :: STRING AS topic_1,
l.topics [2] :: STRING AS topic_2,
l.topics [3] :: STRING AS topic_3,
l.data,
l.event_removed,
txs.from_address AS origin_from_address,
txs.to_address AS origin_to_address,
txs.origin_function_signature,
l.tx_succeeded
FROM
flattened_logs l
LEFT JOIN {{ ref('core_evm__fact_blocks') }}
b
ON l.block_number = b.block_number
{% if is_incremental() %}
AND b.modified_timestamp >= (
SELECT
MAX(modified_timestamp) :: DATE - 1
FROM
{{ this }}
)
{% endif %}
LEFT JOIN {{ ref('core_evm__fact_transactions') }}
txs
ON l.tx_hash = txs.tx_hash
AND l.block_number = txs.block_number
{% if is_incremental() %}
AND txs.modified_timestamp >= (
SELECT
MAX(modified_timestamp) :: DATE - 1
FROM
{{ this }}
)
{% endif %}
)
{% if is_incremental() %},
missing_data AS (
SELECT
t.block_number,
b.block_timestamp AS block_timestamp_heal,
t.tx_hash,
t.tx_position,
t.event_index,
t.contract_address,
t.topics,
t.topic_0,
t.topic_1,
t.topic_2,
t.topic_3,
t.data,
t.event_removed,
txs.from_address AS origin_from_address_heal,
txs.to_address AS origin_to_address_heal,
txs.origin_function_signature AS origin_function_signature_heal,
t.tx_succeeded
FROM
{{ this }}
t
LEFT JOIN {{ ref('core_evm__fact_transactions') }}
txs
ON t.tx_hash = txs.tx_hash
AND t.block_number = txs.block_number
LEFT JOIN {{ ref('core_evm__fact_blocks') }}
b
ON t.block_number = b.block_number
WHERE
t.block_timestamp IS NULL
OR t.origin_function_signature IS NULL
)
{% endif %},
all_logs AS (
SELECT
block_number,
block_timestamp,
tx_hash,
tx_position,
event_index,
contract_address,
topics,
topic_0,
topic_1,
topic_2,
topic_3,
DATA,
event_removed,
origin_from_address,
origin_to_address,
origin_function_signature,
tx_succeeded
FROM
new_logs
{% if is_incremental() %}
UNION ALL
SELECT
block_number,
block_timestamp_heal AS block_timestamp,
tx_hash,
tx_position,
event_index,
contract_address,
topics,
topic_0,
topic_1,
topic_2,
topic_3,
DATA,
event_removed,
origin_from_address_heal AS origin_from_address,
origin_to_address_heal AS origin_to_address,
origin_function_signature_heal AS origin_function_signature,
tx_succeeded
FROM
missing_data
{% endif %}
)
SELECT
block_number,
block_timestamp,
tx_hash,
origin_function_signature,
origin_from_address,
origin_to_address,
tx_position,
event_index,
contract_address,
topics,
topic_0,
topic_1,
topic_2,
topic_3,
DATA,
event_removed,
tx_status,
_log_id,
evm_logs_id AS fact_event_logs_id,
inserted_timestamp,
modified_timestamp
origin_from_address,
origin_to_address,
origin_function_signature,
tx_succeeded,
{{ dbt_utils.generate_surrogate_key(['tx_hash','event_index']) }} AS fact_event_logs_id,
SYSDATE() AS inserted_timestamp,
SYSDATE() AS modified_timestamp
FROM
{{ ref('silver_evm__logs') }}
{% if is_incremental() %}
WHERE
modified_timestamp >= (
SELECT
MAX(modified_timestamp)
FROM
{{ this }}
)
{% endif %}
all_logs qualify ROW_NUMBER() over (
PARTITION BY fact_event_logs_id
ORDER BY
block_number DESC,
block_timestamp DESC nulls last,
origin_function_signature DESC nulls last
) = 1

View File

@ -1,43 +1,46 @@
version: 2
models:
- name: core_evm__fact_event_logs
description: '{{ doc("flowevm_logs_table_doc") }}'
tests:
- dbt_utils.recency:
datepart: hour
field: block_timestamp
interval: 2
description: '{{ doc("evm_logs_table_doc") }}'
columns:
- name: BLOCK_NUMBER
description: '{{ doc("flowevm_block_number") }}'
description: '{{ doc("evm_block_number") }}'
- name: BLOCK_TIMESTAMP
description: '{{ doc("flowevm_block_timestamp") }}'
description: '{{ doc("evm_block_timestamp") }}'
- name: TX_HASH
description: '{{ doc("flowevm_logs_tx_hash") }}'
description: '{{ doc("evm_tx_hash") }}'
- name: TX_POSITION
description: '{{ doc("evm_tx_position") }}'
- name: EVENT_INDEX
description: '{{ doc("flowevm_event_index") }}'
description: '{{ doc("evm_event_index") }}'
- name: CONTRACT_ADDRESS
description: '{{ doc("flowevm_logs_contract_address") }}'
description: '{{ doc("evm_logs_contract_address") }}'
- name: TOPICS
description: '{{ doc("flowevm_topics") }}'
description: '{{ doc("evm_topics") }}'
- name: TOPIC_0
description: '{{ doc("evm_topic_0") }}'
- name: TOPIC_1
description: '{{ doc("evm_topic_1") }}'
- name: TOPIC_2
description: '{{ doc("evm_topic_2") }}'
- name: TOPIC_3
description: '{{ doc("evm_topic_3") }}'
- name: DATA
description: '{{ doc("flowevm_logs_data") }}'
description: '{{ doc("evm_logs_data") }}'
- name: EVENT_REMOVED
description: '{{ doc("flowevm_event_removed") }}'
- name: _LOG_ID
description: '{{ doc("internal_column") }}'
- name: TX_STATUS
description: '{{ doc("flowevm_tx_status") }}'
- name: ORIGIN_FUNCTION_SIGNATURE
description: '{{ doc("flowevm_origin_sig") }}'
description: '{{ doc("evm_event_removed") }}'
- name: ORIGIN_FROM_ADDRESS
description: '{{ doc("flowevm_origin_from") }}'
description: '{{ doc("evm_from_address") }}'
- name: ORIGIN_TO_ADDRESS
description: '{{ doc("flowevm_origin_to") }}'
description: '{{ doc("evm_to_address") }}'
- name: ORIGIN_FUNCTION_SIGNATURE
description: '{{ doc("evm_origin_sig") }}'
- name: TX_SUCCEEDED
description: '{{ doc("evm_tx_succeeded") }}'
- name: FACT_EVENT_LOGS_ID
description: '{{ doc("pk_id") }}'
description: '{{ doc("evm_pk") }}'
- name: INSERTED_TIMESTAMP
description: '{{ doc("inserted_timestamp") }}'
description: '{{ doc("evm_inserted_timestamp") }}'
- name: MODIFIED_TIMESTAMP
description: '{{ doc("modified_timestamp") }}'
description: '{{ doc("evm_modified_timestamp") }}'

View File

@ -0,0 +1,379 @@
{{ config(
materialized = "incremental",
incremental_strategy = 'delete+insert',
unique_key = "block_number",
cluster_by = ['block_timestamp::DATE'],
tags = ['evm']
) }}
WITH silver_traces AS (
SELECT
block_number,
tx_position,
trace_address,
parent_trace_address,
trace_address_array,
trace_json,
traces_id,
'regular' AS source
FROM {{ ref('silver_evm__traces') }}
WHERE 1 = 1
{% if is_incremental() %}
AND modified_timestamp > (
SELECT COALESCE(MAX(modified_timestamp), '1970-01-01'::TIMESTAMP) AS modified_timestamp
FROM {{ this }}
)
{% endif %}
),
sub_traces AS (
SELECT
block_number,
tx_position,
parent_trace_address,
COUNT(*) AS sub_traces
FROM silver_traces
GROUP BY
block_number,
tx_position,
parent_trace_address
),
trace_index_array AS (
SELECT
block_number,
tx_position,
trace_address,
ARRAY_AGG(flat_value) AS number_array
FROM (
SELECT
block_number,
tx_position,
trace_address,
IFF(VALUE::STRING = 'ORIGIN', -1, VALUE::INT) AS flat_value
FROM silver_traces,
LATERAL FLATTEN(input => trace_address_array)
)
GROUP BY
block_number,
tx_position,
trace_address
),
trace_index_sub_traces AS (
SELECT
b.block_number,
b.tx_position,
b.trace_address,
IFNULL(sub_traces, 0) AS sub_traces,
number_array,
ROW_NUMBER() OVER (
PARTITION BY b.block_number, b.tx_position
ORDER BY number_array ASC
) - 1 AS trace_index,
b.trace_json,
b.traces_id,
b.source
FROM silver_traces b
LEFT JOIN sub_traces s
ON b.block_number = s.block_number
AND b.tx_position = s.tx_position
AND b.trace_address = s.parent_trace_address
JOIN trace_index_array n
ON b.block_number = n.block_number
AND b.tx_position = n.tx_position
AND b.trace_address = n.trace_address
),
errored_traces AS (
SELECT
block_number,
tx_position,
trace_address,
trace_json
FROM trace_index_sub_traces
WHERE trace_json:error::STRING IS NOT NULL
),
error_logic AS (
SELECT
b0.block_number,
b0.tx_position,
b0.trace_address,
b0.trace_json:error::STRING AS error,
b1.trace_json:error::STRING AS any_error,
b2.trace_json:error::STRING AS origin_error
FROM trace_index_sub_traces b0
LEFT JOIN errored_traces b1
ON b0.block_number = b1.block_number
AND b0.tx_position = b1.tx_position
AND b0.trace_address RLIKE CONCAT('^', b1.trace_address, '(_[0-9]+)*$')
LEFT JOIN errored_traces b2
ON b0.block_number = b2.block_number
AND b0.tx_position = b2.tx_position
AND b2.trace_address = 'ORIGIN'
),
aggregated_errors AS (
SELECT
block_number,
tx_position,
trace_address,
error,
IFF(
MAX(any_error) IS NULL AND error IS NULL AND origin_error IS NULL,
TRUE,
FALSE
) AS trace_succeeded
FROM error_logic
GROUP BY
block_number,
tx_position,
trace_address,
error,
origin_error
),
json_traces AS (
SELECT
block_number,
tx_position,
trace_address,
sub_traces,
number_array,
trace_index,
trace_succeeded,
trace_json:error::STRING AS error_reason,
trace_json:revertReason::STRING AS revert_reason,
lower(trace_json:from::STRING) AS from_address,
lower(trace_json:to::STRING) AS to_address,
IFNULL(trace_json:value::STRING, '0x0') AS value_hex,
IFNULL(utils.udf_hex_to_int(trace_json:value::STRING), '0') AS value_precise_raw,
utils.udf_decimal_adjust(value_precise_raw, 18) AS value_precise,
value_precise::FLOAT AS value,
utils.udf_hex_to_int(trace_json:gas::STRING)::INT AS gas,
utils.udf_hex_to_int(trace_json:gasUsed::STRING)::INT AS gas_used,
trace_json:input::STRING AS input,
trace_json:output::STRING AS output,
trace_json:type::STRING AS type,
traces_id
FROM trace_index_sub_traces
JOIN aggregated_errors USING (
block_number,
tx_position,
trace_address
)
),
incremental_traces AS (
SELECT
f.block_number,
t.tx_hash,
t.block_timestamp,
t.origin_function_signature,
t.from_address AS origin_from_address,
t.to_address AS origin_to_address,
t.tx_position,
f.trace_index,
f.from_address AS from_address,
f.to_address AS to_address,
f.value_hex,
f.value_precise_raw,
f.value_precise,
f.value,
f.gas,
f.gas_used,
f.input,
f.output,
f.type,
f.sub_traces,
f.error_reason,
f.revert_reason,
f.traces_id,
f.trace_succeeded,
f.trace_address,
t.tx_succeeded
FROM json_traces f
LEFT OUTER JOIN {{ ref('core_evm__fact_transactions') }} t
ON f.tx_position = t.tx_position
AND f.block_number = t.block_number
{% if is_incremental() %}
AND t.modified_timestamp >= (
SELECT DATEADD('hour', -24, MAX(modified_timestamp))
FROM {{ this }}
)
{% endif %}
)
{% if is_incremental() %},
overflow_blocks AS (
SELECT DISTINCT block_number
FROM silver_traces
WHERE source = 'overflow'
),
heal_missing_data AS (
SELECT
t.block_number,
txs.tx_hash,
txs.block_timestamp AS block_timestamp_heal,
txs.origin_function_signature AS origin_function_signature_heal,
txs.from_address AS origin_from_address_heal,
txs.to_address AS origin_to_address_heal,
txs.tx_position,
t.trace_index,
t.from_address,
t.to_address,
t.value_hex,
t.value_precise_raw,
t.value_precise,
t.value,
t.gas,
t.gas_used,
t.input,
t.output,
t.type,
t.sub_traces,
t.error_reason,
t.revert_reason,
t.fact_traces_id AS traces_id,
t.trace_succeeded,
t.trace_address,
txs.tx_succeeded AS tx_succeeded_heal
FROM {{ this }} t
JOIN {{ ref('core_evm__fact_transactions') }} txs
ON t.tx_position = txs.tx_position
AND t.block_number = txs.block_number
WHERE t.tx_position IS NULL
OR t.block_timestamp IS NULL
OR t.tx_succeeded IS NULL
)
{% endif %},
all_traces AS (
SELECT
block_number,
tx_hash,
block_timestamp,
origin_function_signature,
origin_from_address,
origin_to_address,
tx_position,
trace_index,
from_address,
to_address,
value_hex,
value_precise_raw,
value_precise,
value,
gas,
gas_used,
input,
output,
type,
sub_traces,
error_reason,
revert_reason,
trace_succeeded,
trace_address,
tx_succeeded
FROM incremental_traces
{% if is_incremental() %}
UNION ALL
SELECT
block_number,
tx_hash,
block_timestamp_heal AS block_timestamp,
origin_function_signature_heal AS origin_function_signature,
origin_from_address_heal AS origin_from_address,
origin_to_address_heal AS origin_to_address,
tx_position,
trace_index,
from_address,
to_address,
value_hex,
value_precise_raw,
value_precise,
value,
gas,
gas_used,
input,
output,
type,
sub_traces,
error_reason,
revert_reason,
trace_succeeded,
trace_address,
tx_succeeded_heal AS tx_succeeded
FROM heal_missing_data
UNION ALL
SELECT
block_number,
tx_hash,
block_timestamp,
origin_function_signature,
origin_from_address,
origin_to_address,
tx_position,
trace_index,
from_address,
to_address,
value_hex,
value_precise_raw,
value_precise,
value,
gas,
gas_used,
input,
output,
type,
sub_traces,
error_reason,
revert_reason,
trace_succeeded,
trace_address,
tx_succeeded
FROM {{ this }}
JOIN overflow_blocks USING (block_number)
{% endif %}
)
SELECT
block_number,
block_timestamp,
tx_hash,
tx_position,
trace_index,
from_address,
to_address,
input,
output,
type,
trace_address,
sub_traces,
value,
value_precise_raw,
value_precise,
value_hex,
gas,
gas_used,
origin_from_address,
origin_to_address,
origin_function_signature,
trace_succeeded,
error_reason,
revert_reason,
tx_succeeded,
{{ dbt_utils.generate_surrogate_key(['tx_hash', 'trace_index']) }} AS fact_traces_id,
SYSDATE() AS inserted_timestamp,
SYSDATE() AS modified_timestamp
FROM all_traces
QUALIFY (ROW_NUMBER() OVER (
PARTITION BY block_number, tx_position, trace_index
ORDER BY modified_timestamp DESC, block_timestamp DESC NULLS LAST
)) = 1

View File

@ -0,0 +1,62 @@
version: 2
models:
- name: core_evm__fact_traces
description: '{{ doc("evm_traces_table_doc") }}'
columns:
- name: BLOCK_NUMBER
description: '{{ doc("evm_block_number") }}'
- name: BLOCK_TIMESTAMP
description: '{{ doc("evm_block_timestamp") }}'
- name: TX_HASH
description: '{{ doc("evm_tx_hash") }}'
- name: TX_POSITION
description: '{{ doc("evm_tx_position") }}'
- name: TRACE_INDEX
description: '{{ doc("evm_trace_index") }}'
- name: FROM_ADDRESS
description: '{{ doc("evm_from_address") }}'
- name: TO_ADDRESS
description: '{{ doc("evm_to_address") }}'
- name: INPUT
description: '{{ doc("evm_traces_input") }}'
- name: OUTPUT
description: '{{ doc("evm_traces_output") }}'
- name: TYPE
description: '{{ doc("evm_traces_type") }}'
- name: TRACE_ADDRESS
description: '{{ doc("evm_trace_address") }}'
- name: SUB_TRACES
description: '{{ doc("evm_sub_traces") }}'
- name: VALUE
description: '{{ doc("evm_value") }}'
- name: VALUE_PRECISE_RAW
description: '{{ doc("evm_precise_amount_unadjusted") }}'
- name: VALUE_PRECISE
description: '{{ doc("evm_precise_amount_adjusted") }}'
- name: VALUE_HEX
description: '{{ doc("evm_value_hex") }}'
- name: GAS
description: '{{ doc("evm_traces_gas") }}'
- name: GAS_USED
description: '{{ doc("evm_traces_gas_used") }}'
- name: ORIGIN_FROM_ADDRESS
description: '{{ doc("evm_traces_from") }}'
- name: ORIGIN_TO_ADDRESS
description: '{{ doc("evm_traces_to") }}'
- name: ORIGIN_FUNCTION_SIGNATURE
description: '{{ doc("evm_origin_sig") }}'
- name: TRACE_SUCCEEDED
description: '{{ doc("evm_trace_succeeded") }}'
- name: ERROR_REASON
description: '{{ doc("evm_trace_error_reason") }}'
- name: REVERT_REASON
description: '{{ doc("evm_revert_reason") }}'
- name: TX_SUCCEEDED
description: '{{ doc("evm_tx_succeeded") }}'
- name: FACT_TRACES_ID
description: '{{ doc("evm_pk") }}'
- name: INSERTED_TIMESTAMP
description: '{{ doc("evm_inserted_timestamp") }}'
- name: MODIFIED_TIMESTAMP
description: '{{ doc("evm_modified_timestamp") }}'

View File

@ -1,50 +1,348 @@
{{ config(
materialized = 'incremental',
unique_key = "fact_transactions_id",
{{ config (
materialized = "incremental",
incremental_strategy = 'delete+insert',
cluster_by = ['inserted_timestamp :: DATE', 'ROUND(block_number, -3)'],
persist_docs ={ "relation": true,
"columns": true },
unique_key = "block_number",
cluster_by = ['block_timestamp::DATE'],
tags = ['evm']
) }}
SELECT
block_number,
block_timestamp,
block_hash,
tx_hash,
nonce,
POSITION,
origin_function_signature,
from_address,
to_address,
VALUE,
value_precise_unadj AS value_precise_raw,
value_precise_adj AS value_precise,
tx_fee,
tx_fee_precise,
gas_price_adj AS gas_price,
effective_gas_price,
gas AS gas_limit,
gas_used,
cumulative_gas_used,
input_data,
tx_status AS status,
tx_succeeded,
r,
s,
v,
evm_txs_id AS fact_transactions_id,
inserted_timestamp,
modified_timestamp
FROM
{{ ref('silver_evm__transactions') }}
WITH base AS (
SELECT
block_number,
tx_position,
transaction_json
FROM
{{ ref('silver_evm__transactions') }}
{% if is_incremental() %}
WHERE
modified_timestamp >= (
modified_timestamp > (
SELECT
MAX(modified_timestamp)
COALESCE(MAX(modified_timestamp), '1970-01-01' :: TIMESTAMP) AS modified_timestamp
FROM
{{ this }}
)
{{ this }})
{% endif %}
),
transactions_fields AS (
SELECT
block_number,
tx_position,
transaction_json :blockHash :: STRING AS block_hash,
transaction_json :blockNumber :: STRING AS block_number_hex,
lower(transaction_json :from :: STRING) AS from_address,
utils.udf_hex_to_int(
transaction_json :gas :: STRING
) :: bigint AS gas_limit,
utils.udf_hex_to_int(
transaction_json :gasPrice :: STRING
) :: bigint AS gas_price,
transaction_json :hash :: STRING AS tx_hash,
transaction_json :input :: STRING AS input_data,
LEFT(
input_data,
10
) AS origin_function_signature,
utils.udf_hex_to_int(
transaction_json :nonce :: STRING
) :: bigint AS nonce,
transaction_json :r :: STRING AS r,
transaction_json :s :: STRING AS s,
lower(transaction_json :to :: STRING) AS to_address1,
CASE
WHEN to_address1 = '' THEN NULL
ELSE to_address1
END AS to_address,
utils.udf_hex_to_int(
transaction_json :transactionIndex :: STRING
) :: bigint AS transaction_index,
utils.udf_hex_to_int(
transaction_json :type :: STRING
) :: bigint AS tx_type,
utils.udf_hex_to_int(
transaction_json :v :: STRING
) :: bigint AS v,
TRY_TO_NUMBER(
utils.udf_hex_to_int(
transaction_json :maxFeePerGas :: STRING
)
) / pow(
10,
9
) AS max_fee_per_gas,
TRY_TO_NUMBER(
utils.udf_hex_to_int(
transaction_json :maxPriorityFeePerGas :: STRING
)
) / pow(
10,
9
) AS max_priority_fee_per_gas,
utils.udf_hex_to_int(
transaction_json :value :: STRING
) AS value_precise_raw,
utils.udf_decimal_adjust(
value_precise_raw,
18
) AS value_precise,
value_precise :: FLOAT AS VALUE,
utils.udf_hex_to_int(transaction_json :yParity :: STRING):: bigint AS y_parity,
transaction_json :accessList AS access_list,
FROM
base
),
new_transactions AS (
SELECT
txs.block_number,
txs.block_hash,
b.block_timestamp,
txs.tx_hash,
txs.from_address,
txs.to_address,
txs.origin_function_signature,
txs.value,
txs.value_precise_raw,
txs.value_precise,
txs.max_fee_per_gas,
txs.max_priority_fee_per_gas,
txs.y_parity,
txs.access_list,
utils.udf_decimal_adjust(
txs.gas_price * utils.udf_hex_to_int(
r.receipts_json :gasUsed :: STRING
) :: bigint,
18
) AS tx_fee_precise,
COALESCE(
tx_fee_precise :: FLOAT,
0
) AS tx_fee,
CASE
WHEN r.receipts_json :status :: STRING = '0x1' THEN TRUE
WHEN r.receipts_json :status :: STRING = '1' THEN TRUE
WHEN r.receipts_json :status :: STRING = '0x0' THEN FALSE
WHEN r.receipts_json :status :: STRING = '0' THEN FALSE
ELSE NULL
END AS tx_succeeded,
txs.tx_type,
txs.nonce,
txs.tx_position,
txs.input_data,
txs.gas_price / pow(
10,
9
) AS gas_price,
utils.udf_hex_to_int(
r.receipts_json :gasUsed :: STRING
) :: bigint AS gas_used,
txs.gas_limit,
utils.udf_hex_to_int(
r.receipts_json :cumulativeGasUsed :: STRING
) :: bigint AS cumulative_gas_used,
utils.udf_hex_to_int(
r.receipts_json :effectiveGasPrice :: STRING
) :: bigint AS effective_gas_price,
txs.r,
txs.s,
txs.v
FROM
transactions_fields txs
LEFT JOIN {{ ref('core_evm__fact_blocks') }}
b
ON txs.block_number = b.block_number
{% if is_incremental() %}
AND b.modified_timestamp >= (
SELECT
MAX(modified_timestamp) :: DATE - 1
FROM
{{ this }}
)
{% endif %}
LEFT JOIN {{ ref('silver_evm__receipts') }}
r
ON txs.block_number = r.block_number
AND txs.tx_hash = r.receipts_json :transactionHash :: STRING
{% if is_incremental() %}
AND r.modified_timestamp >= (
SELECT
MAX(modified_timestamp) :: DATE - 1
FROM
{{ this }}
)
{% endif %}
)
{% if is_incremental() %},
missing_data AS (
SELECT
t.block_number,
b.block_timestamp AS block_timestamp_heal,
t.tx_hash,
t.from_address,
t.to_address,
t.origin_function_signature,
t.value,
t.value_precise_raw,
t.value_precise,
t.max_fee_per_gas,
t.max_priority_fee_per_gas,
t.y_parity,
t.access_list,
utils.udf_decimal_adjust(
t.gas_price * utils.udf_hex_to_int(
r.receipts_json :gasUsed :: STRING
) :: bigint,
9
) AS tx_fee_precise_heal,
COALESCE(
tx_fee_precise_heal :: FLOAT,
0
) AS tx_fee_heal,
CASE
WHEN r.receipts_json :status :: STRING = '0x1' THEN TRUE
WHEN r.receipts_json :status :: STRING = '0x0' THEN FALSE
ELSE NULL
END AS tx_succeeded_heal,
t.tx_type,
t.nonce,
t.tx_position,
t.input_data,
t.gas_price,
utils.udf_hex_to_int(
r.receipts_json :gasUsed :: STRING
) :: bigint AS gas_used_heal,
t.gas_limit,
utils.udf_hex_to_int(
r.receipts_json :cumulativeGasUsed :: STRING
) :: bigint AS cumulative_gas_used_heal,
utils.udf_hex_to_int(
r.receipts_json :effectiveGasPrice :: STRING
) :: bigint AS effective_gas_price_heal,
t.r,
t.s,
t.v
FROM
{{ this }}
t
LEFT JOIN {{ ref('core_evm__fact_blocks') }}
b
ON t.block_number = b.block_number
LEFT JOIN {{ ref('silver_evm__receipts') }}
r
ON t.block_number = r.block_number
AND t.tx_hash = r.receipts_json :transactionHash :: STRING
WHERE
t.block_timestamp IS NULL
OR t.tx_succeeded IS NULL
)
{% endif %},
all_transactions AS (
SELECT
block_number,
block_timestamp,
tx_hash,
from_address,
to_address,
origin_function_signature,
VALUE,
value_precise_raw,
value_precise,
max_fee_per_gas,
max_priority_fee_per_gas,
y_parity,
access_list,
tx_fee,
tx_fee_precise,
tx_succeeded,
tx_type,
nonce,
tx_position,
input_data,
gas_price,
gas_used,
gas_limit,
cumulative_gas_used,
effective_gas_price,
r,
s,
v
FROM
new_transactions
{% if is_incremental() %}
UNION ALL
SELECT
block_number,
block_timestamp_heal AS block_timestamp,
tx_hash,
from_address,
to_address,
origin_function_signature,
VALUE,
value_precise_raw,
value_precise,
max_fee_per_gas,
max_priority_fee_per_gas,
y_parity,
access_list,
tx_fee_heal AS tx_fee,
tx_fee_precise_heal AS tx_fee_precise,
tx_succeeded_heal AS tx_succeeded,
tx_type,
nonce,
tx_position,
input_data,
gas_price,
gas_used_heal AS gas_used,
gas_limit,
cumulative_gas_used_heal AS cumulative_gas_used,
effective_gas_price_heal AS effective_gas_price,
r,
s,
v
FROM
missing_data
{% endif %}
)
SELECT
block_number,
block_timestamp,
tx_hash,
from_address,
to_address,
origin_function_signature,
VALUE,
value_precise_raw,
value_precise,
tx_fee,
tx_fee_precise,
tx_succeeded,
tx_type,
nonce,
tx_position,
input_data,
gas_price,
gas_used,
gas_limit,
cumulative_gas_used,
effective_gas_price,
max_fee_per_gas,
max_priority_fee_per_gas,
y_parity,
access_list,
r,
s,
v,
{{ dbt_utils.generate_surrogate_key(['tx_hash']) }} AS fact_transactions_id,
SYSDATE() AS inserted_timestamp,
SYSDATE() AS modified_timestamp
FROM
all_transactions qualify ROW_NUMBER() over (
PARTITION BY fact_transactions_id
ORDER BY
block_number DESC,
block_timestamp DESC nulls last,
tx_succeeded DESC nulls last
) = 1

View File

@ -1,67 +1,68 @@
version: 2
models:
- name: core_evm__fact_transactions
description: '{{ doc("flowevm_tx_table_doc") }}'
tests:
- dbt_utils.recency:
datepart: hour
field: block_timestamp
interval: 2
description: '{{ doc("evm_tx_table_doc") }}'
columns:
- name: BLOCK_NUMBER
description: '{{ doc("flowevm_block_number") }}'
description: '{{ doc("evm_block_number") }}'
- name: BLOCK_TIMESTAMP
description: '{{ doc("flowevm_block_timestamp") }}'
- name: BLOCK_HASH
description: '{{ doc("flowevm_block_hash") }}'
description: '{{ doc("evm_block_timestamp") }}'
- name: TX_HASH
description: '{{ doc("flowevm_tx_hash") }}'
- name: NONCE
description: '{{ doc("flowevm_tx_nonce") }}'
- name: POSITION
description: '{{ doc("flowevm_tx_position") }}'
description: '{{ doc("evm_tx_hash") }}'
- name: FROM_ADDRESS
description: '{{ doc("flowevm_from_address") }}'
description: '{{ doc("evm_from_address") }}'
- name: TO_ADDRESS
description: '{{ doc("flowevm_to_address") }}'
description: '{{ doc("evm_to_address") }}'
- name: ORIGIN_FUNCTION_SIGNATURE
description: '{{ doc("evm_tx_origin_sig") }}'
- name: VALUE
description: '{{ doc("flowevm_value") }}'
description: '{{ doc("evm_value") }}'
- name: VALUE_PRECISE_RAW
description: '{{ doc("precise_amount_unadjusted") }}'
description: '{{ doc("evm_precise_amount_unadjusted") }}'
- name: VALUE_PRECISE
description: '{{ doc("precise_amount_adjusted") }}'
description: '{{ doc("evm_precise_amount_adjusted") }}'
- name: TX_FEE
description: '{{ doc("flowevm_tx_fee") }}'
description: '{{ doc("evm_tx_fee") }}'
- name: TX_FEE_PRECISE
description: '{{ doc("tx_fee_precise") }}'
- name: GAS_PRICE
description: '{{ doc("flowevm_tx_gas_price") }}'
- name: EFFECTIVE_GAS_PRICE
description: The total base charge plus tip paid for each unit of gas, in Gwei.
- name: GAS_LIMIT
description: '{{ doc("flowevm_tx_gas_limit") }}'
- name: GAS_USED
description: '{{ doc("flowevm_tx_gas_used") }}'
- name: CUMULATIVE_GAS_USED
description: '{{ doc("flowevm_cumulative_gas_used") }}'
- name: STATUS
description: '{{ doc("flowevm_tx_status") }}'
description: '{{ doc("evm_tx_fee_precise") }}'
- name: TX_SUCCEEDED
description: '{{ doc("tx_succeeded") }}'
description: '{{ doc("evm_tx_succeeded") }}'
- name: TX_TYPE
description: '{{ doc("evm_tx_type") }}'
- name: NONCE
description: '{{ doc("evm_tx_nonce") }}'
- name: TX_POSITION
description: '{{ doc("evm_tx_position") }}'
- name: INPUT_DATA
description: '{{ doc("flowevm_tx_input_data") }}'
- name: ORIGIN_FUNCTION_SIGNATURE
description: '{{ doc("flowevm_tx_origin_sig") }}'
description: '{{ doc("evm_tx_input_data") }}'
- name: GAS_PRICE
description: '{{ doc("evm_tx_gas_price") }}'
- name: GAS_USED
description: '{{ doc("evm_tx_gas_used") }}'
- name: GAS_LIMIT
description: '{{ doc("evm_tx_gas_limit") }}'
- name: CUMULATIVE_GAS_USED
description: '{{ doc("evm_cumulative_gas_used") }}'
- name: EFFECTIVE_GAS_PRICE
description: '{{ doc("evm_effective_gas_price") }}'
- name: R
description: The r value of the transaction signature.
description: '{{ doc("evm_r") }}'
- name: S
description: The s value of the transaction signature.
description: '{{ doc("evm_s") }}'
- name: V
description: The v value of the transaction signature.
description: '{{ doc("evm_v") }}'
- name: MAX_FEE_PER_GAS
description: '{{ doc("evm_max_fee_per_gas") }}'
- name: MAX_PRIORITY_FEE_PER_GAS
description: '{{ doc("evm_max_priority_fee_per_gas") }}'
- name: Y_PARITY
description: '{{ doc("evm_y_parity") }}'
- name: ACCESS_LIST
description: '{{ doc("evm_access_list") }}'
- name: FACT_TRANSACTIONS_ID
description: '{{ doc("pk_id") }}'
description: '{{ doc("evm_pk") }}'
- name: INSERTED_TIMESTAMP
description: '{{ doc("inserted_timestamp") }}'
description: '{{ doc("evm_inserted_timestamp") }}'
- name: MODIFIED_TIMESTAMP
description: '{{ doc("modified_timestamp") }}'
description: '{{ doc("evm_modified_timestamp") }}'

View File

@ -0,0 +1,9 @@
{{ config (
materialized = "view",
tags = ['full_evm_test']
) }}
SELECT
*
FROM
{{ ref('core_evm__fact_blocks') }}

View File

@ -0,0 +1,145 @@
version: 2
models:
- name: test_gold_evm__fact_blocks_full
description: "This is a view used to test all of the gold fact blocks model."
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- BLOCK_NUMBER
- sequence_gaps:
column_name: BLOCK_NUMBER
where: BLOCK_TIMESTAMP < CURRENT_DATE - 1
columns:
- name: BLOCK_NUMBER
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: BLOCK_HASH
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: BLOCK_TIMESTAMP
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- TIMESTAMP_LTZ
- TIMESTAMP_NTZ
- dbt_expectations.expect_row_values_to_have_recent_data:
datepart: hour
interval: 2
- name: NETWORK
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: ^[a-zA-Z0-9_]+$
- name: TX_COUNT
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: SIZE
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: MINER
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: EXTRA_DATA
tests:
- not_null
- name: PARENT_HASH
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: GAS_USED
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: GAS_LIMIT
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: DIFFICULTY
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: SHA3_UNCLES
tests:
- not_null
- name: UNCLE_BLOCKS
tests:
- not_null
- name: NONCE
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- NUMBER
- FLOAT
- name: RECEIPTS_ROOT
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: STATE_ROOT
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: TRANSACTIONS_ROOT
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: LOGS_BLOOM
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: 0[xX][0-9a-fA-F]+
- name: FACT_BLOCKS_ID
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_unique
- name: INSERTED_TIMESTAMP
tests:
- not_null
- dbt_expectations.expect_row_values_to_have_recent_data:
datepart: hour
interval: 2
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- TIMESTAMP_LTZ
- TIMESTAMP_NTZ
- name: MODIFIED_TIMESTAMP
tests:
- not_null
- dbt_expectations.expect_row_values_to_have_recent_data:
datepart: hour
interval: 2
- dbt_expectations.expect_column_values_to_be_in_type_list:
column_type_list:
- TIMESTAMP_LTZ
- TIMESTAMP_NTZ

View File

@ -0,0 +1,16 @@
{{ config (
materialized = "view",
tags = ['recent_evm_test']
) }}
SELECT
*
FROM
{{ ref('core_evm__fact_blocks') }}
WHERE
block_number > (
SELECT
block_number
FROM
{{ ref('_evm_block_lookback') }}
)

Some files were not shown because too many files have changed in this diff Show More