diff --git a/models/descriptions/columns.md b/models/descriptions/columns.md index 7027898..9e906e5 100644 --- a/models/descriptions/columns.md +++ b/models/descriptions/columns.md @@ -262,6 +262,10 @@ Surrogate key for the transactions fact table. Generated unique identifier by co Surrogate key for the tokens dimension table. Generated unique identifier for each token metadata record, typically derived from the coin type or on-chain metadata. Enables efficient token lookups, joins across fact tables, and lineage tracing from raw on-chain data to analytics-ready attributes. In Sui, this is critical for accurate token identification, decimal normalization, and cross-model analytics involving token flows and balances. {% enddocs %} +{% docs ez_bridge_activity_id %} +Surrogate key for the events table. Generated unique identifier combining transaction digest and event index, ensuring each event emission is uniquely addressable. Used as the primary key for event tracking, analytics workflows, and cross-model joins. In Sui, this supports granular dApp analytics, protocol monitoring, and event-driven application logic by enabling precise event referencing and lineage analysis. +{% enddocs %} + {% docs coin_types_id %} Surrogate key for coin types. Generated unique identifier for each coin type, supporting classification, indexing, and efficient joins across analytics queries. In Sui, this enables fast aggregation and filtering by token type, supporting DeFi analytics, token velocity studies, and ecosystem-wide token usage analysis. {% enddocs %} @@ -446,4 +450,128 @@ USD value of the amount at transaction time. Example: 1000.50 +{% enddocs %} + + +{% enddocs %} + +{% docs ez_bridge_activity_platform %} + +The protocol or application facilitating the cross-chain bridge transfer. + +Example: 'wormhole' + +{% enddocs %} + +{% docs ez_bridge_activity_protocol %} + +The protocol or application facilitating the cross-chain bridge transfer. + +Example: 'wormhole' + +{% enddocs %} + +{% docs ez_bridge_activity_protocol_version %} + +The version of protocol or application facilitating the cross-chain bridge transfer. + +Example: 'v1' + +{% enddocs %} + +{% docs ez_bridge_activity_direction %} + +The directions of the cross-chain bridge transfer. + +Example: 'inbound' + +{% enddocs %} + +{% docs ez_bridge_activity_sender %} + +The Sui address that directly sent tokens to the bridge contract. + +Example: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890' + +{% enddocs %} + +{% docs ez_bridge_activity_receiver %} + +The address designated to receive tokens on the destination chain (or on the source chain, for intermediate steps). + +Example: '0x9876543210987654321098765432109876543210987654321098765432109876' + +{% enddocs %} + + +{% docs ez_bridge_activity_destination_chain %} + +The target blockchain network for the bridged assets. + +Example: 'ethereum' + +{% enddocs %} + +{% docs ez_bridge_activity_source_chain %} + +The originating blockchain network for the bridged assets. + +Example: 'ethereum' + +{% enddocs %} + +{% docs ez_bridge_activity_bridge_address %} + +The Sui object or package address handling the bridge operation. + +Example: '0x26efee2b51c911237888e5dc6702868abca3c7ac12c53f76ef8eba0697695e3d' + +{% enddocs %} + +{% docs ez_bridge_activity_coin_type %} + +The coin type or token identifier for the asset being bridged on Sui. + +Example: '0x2::sui::SUI' + +{% enddocs %} + +{% docs ez_bridge_activity_token_symbol %} + +The symbol identifier for the bridged token. + +Example: 'SUI' + +{% enddocs %} + +{% docs ez_bridge_activity_amount_unadj %} + +The raw token amount without decimal adjustment. + +Example: 1000000000 + +{% enddocs %} + +{% docs ez_bridge_activity_amount %} + +The decimal-adjusted amount of tokens bridged. + +Example: 1.0 + +{% enddocs %} + +{% docs ez_bridge_activity_amount_usd %} + +The hourly close USD value of bridged tokens at the time of the transaction. + +Example: 1000.50 + +{% enddocs %} + +{% docs ez_bridge_activity_token_is_verified %} + +Whether the token is verified by the Flipside team. + +Example: true + {% enddocs %} \ No newline at end of file diff --git a/models/descriptions/tables.md b/models/descriptions/tables.md index a5fd04c..867554e 100644 --- a/models/descriptions/tables.md +++ b/models/descriptions/tables.md @@ -36,4 +36,9 @@ Fact table enumerating all inputs consumed by transactions on the Sui blockchain {% docs core__fact_transactions %} Fact table decomposing every transaction on the Sui blockchain into its constituent commands and payloads. Each row represents a single command (e.g., Move call, transfer, split, merge) within a programmable transaction block, capturing execution order, command type, and argument details. Enables granular analysis of smart contract interactions, dApp usage patterns, and transaction complexity. Supports lineage tracing from high-level user actions to low-level on-chain effects, including Move function calls and resource transfers. Critical for protocol analytics, developer adoption tracking, and understanding composability in the Sui ecosystem. +{% enddocs %} + + +{% docs defi__ez_bridge_activity %} +Enhanced fact table providing comprehensive cross-chain bridge analytics by consolidating bridge-related events from multiple protocols (Sui Bridge, Wormhole) into a unified dataset. Each row represents a single cross-chain asset movement event enriched with protocol metadata, token information, and USD pricing. Serves as the primary table for cross-chain DeFi analysis, bridge protocol comparison, and capital flow tracking by normalizing bridge events across different protocols into a consistent format. The table automatically applies decimal precision adjustments and USD conversions, enabling direct comparison of bridge volumes and user activity across different chains and token types. Includes complete transaction context, source/destination chain mapping, and protocol identification to support comprehensive cross-chain analytics, security monitoring, and risk assessment. Essential for DeFi dashboards, bridge protocol analysis, and multi-chain ecosystem studies that require unified cross-chain data and standardized bridge event tracking. {% enddocs %} \ No newline at end of file diff --git a/models/gold/defi/defi__ez_bridge_activity.sql b/models/gold/defi/defi__ez_bridge_activity.sql new file mode 100644 index 0000000..46589e7 --- /dev/null +++ b/models/gold/defi/defi__ez_bridge_activity.sql @@ -0,0 +1,82 @@ +{{ config ( + materialized = "incremental", + unique_key = ['block_timestamp::DATE','tx_digest','event_index'], + cluster_by = ['block_timestamp::DATE'], + incremental_predicates = ["dynamic_range_predicate", "block_timestamp::date"], + merge_exclude_columns = ["inserted_timestamp"], + tags = ['gold','non_core'] +) }} + +WITH base AS ( + + SELECT + checkpoint_number, + block_timestamp, + tx_digest, + tx_sender, + event_index, + source_chain, + destination_chain, + amount AS amount_unadj, + source_address, + destination_address, + coin_type, + bridge_address, + all_bridges_id, + inserted_timestamp, + modified_timestamp, + _INVOCATION_ID, + direction, + platform + FROM + {{ ref('silver_bridge__all_bridges') }} + +{% if is_incremental() %} +WHERE + modified_timestamp >= ( + SELECT + COALESCE(MAX(modified_timestamp), '1970-01-01' :: TIMESTAMP) AS modified_timestamp + FROM + {{ this }}) + {% endif %} + ) +SELECT + checkpoint_number, + block_timestamp, + tx_digest, + tx_sender, + event_index, + bridge_address, + platform, + platform AS protocol, + 'v1' AS protocol_version, + direction, + source_chain, + destination_chain, + source_address AS sender, + destination_address AS receiver, + coin_type, + b.symbol AS symbol, + amount_unadj, + amount_unadj / pow( + 10, + b.decimals + ) AS amount, + (amount / pow(10, b.decimals)) * C.price AS amount_usd, + COALESCE( + C.token_is_verified, + FALSE + ) AS token_is_verified, + all_bridges_id AS ez_bridge_activity_id, + SYSDATE() AS inserted_timestamp, + SYSDATE() AS modified_timestamp +FROM + base A + LEFT JOIN {{ ref('core__dim_tokens') }} + b USING(coin_type) + LEFT JOIN {{ ref('price__ez_prices_hourly') }} C + ON A.coin_type = C.token_address + AND DATE_TRUNC( + 'hour', + block_timestamp + ) = C.hour diff --git a/models/gold/defi/gold_defi.yml b/models/gold/defi/gold_defi.yml new file mode 100644 index 0000000..b40e96e --- /dev/null +++ b/models/gold/defi/gold_defi.yml @@ -0,0 +1,92 @@ +version: 2 + +models: + - name: defi__ez_bridge_activity + description: "{{ doc('defi__ez_bridge_activity') }}" + config: + contract: + enforced: false + columns: + - name: CHECKPOINT_NUMBER + description: "{{ doc('checkpoint_number') }}" + data_type: NUMBER + tests: + - not_null + - name: BLOCK_TIMESTAMP + description: "{{ doc('block_timestamp') }}" + data_type: TIMESTAMP_NTZ + tests: + - not_null + - name: TX_DIGEST + description: "{{ doc('tx_digest') }}" + data_type: VARCHAR + tests: + - not_null + - name: TX_SENDER + description: "{{ doc('tx_sender') }}" + data_type: VARCHAR + - name: EVENT_INDEX + description: "{{ doc('event_index') }}" + data_type: NUMBER + tests: + - not_null + - name: bridge_address + description: "{{ doc('ez_bridge_activity_bridge_address') }}" + data_type: VARCHAR + tests: + - not_null + - name: platform + description: "{{ doc('ez_bridge_activity_platform') }}" + data_type: VARCHAR + tests: + - not_null + - name: protocol + description: "{{ doc('ez_bridge_activity_protocol') }}" + data_type: VARCHAR + tests: + - not_null + - name: protocol_version + description: "{{ doc('ez_bridge_activity_protocol_version') }}" + data_type: VARCHAR + - name: direction + description: "{{ doc('ez_bridge_activity_direction') }}" + data_type: VARCHAR + tests: + - not_null + - name: source_chain + description: "{{ doc('ez_bridge_activity_source_chain') }}" + data_type: VARCHAR + - name: destination_chain + description: "{{ doc('ez_bridge_activity_destination_chain') }}" + data_type: VARCHAR + - name: sender + description: "{{ doc('ez_bridge_activity_sender') }}" + data_type: VARCHAR + - name: receiver + description: "{{ doc('ez_bridge_activity_receiver') }}" + data_type: VARCHAR + - name: coin_type + description: "{{ doc('coin_type') }}" + data_type: VARCHAR + - name: symbol + description: "{{ doc('symbol') }}" + data_type: VARCHAR + - name: amount_unadj + description: "{{ doc('ez_bridge_activity_amount_unadj') }}" + data_type: NUMBER + - name: amount + description: "{{ doc('ez_bridge_activity_amount') }}" + data_type: NUMBER + - name: amount_usd + description: "{{ doc('ez_bridge_activity_amount_usd') }}" + data_type: NUMBER + - name: token_is_verified + description: "{{ doc('token_is_verified') }}" + data_type: BOOLEAN + - name: ez_bridge_activity_id + description: "{{ doc('ez_bridge_activity_id') }}" + data_type: VARCHAR + tests: + - not_null + - unique + \ No newline at end of file diff --git a/models/silver/defi/bridge/silver_bridge__sui_bridge_inbound.sql b/models/silver/defi/bridge/silver_bridge__sui_bridge_inbound.sql index 1fe697b..c678040 100644 --- a/models/silver/defi/bridge/silver_bridge__sui_bridge_inbound.sql +++ b/models/silver/defi/bridge/silver_bridge__sui_bridge_inbound.sql @@ -72,6 +72,12 @@ bc AS ( {% if is_incremental() %} AND A.block_timestamp :: DATE :: DATE >= '{{ min_bd }}' {% endif %} + +qualify ROW_NUMBER() over( + PARTITION BY A.tx_digest + ORDER BY + balance_change_index DESC +) = 1 ) SELECT A.checkpoint_number, diff --git a/models/silver/defi/bridge/silver_bridge__sui_bridge_outbound.sql b/models/silver/defi/bridge/silver_bridge__sui_bridge_outbound.sql index a4d5791..cfb1735 100644 --- a/models/silver/defi/bridge/silver_bridge__sui_bridge_outbound.sql +++ b/models/silver/defi/bridge/silver_bridge__sui_bridge_outbound.sql @@ -134,6 +134,12 @@ bc AS ( WHERE A.block_timestamp :: DATE :: DATE >= '{{ min_bd }}' {% endif %} + +qualify ROW_NUMBER() over( + PARTITION BY A.tx_digest + ORDER BY + balance_change_index DESC +) = 1 ) SELECT A.checkpoint_number, diff --git a/models/silver/defi/bridge/silver_bridge__wormhole_inbound.sql b/models/silver/defi/bridge/silver_bridge__wormhole_inbound.sql index e32566b..1c45115 100644 --- a/models/silver/defi/bridge/silver_bridge__wormhole_inbound.sql +++ b/models/silver/defi/bridge/silver_bridge__wormhole_inbound.sql @@ -70,6 +70,12 @@ bc AS ( {% if is_incremental() %} AND A.block_timestamp :: DATE :: DATE >= '{{ min_bd }}' {% endif %} + +qualify ROW_NUMBER() over( + PARTITION BY A.tx_digest + ORDER BY + balance_change_index DESC +) = 1 ) SELECT A.checkpoint_number, diff --git a/models/silver/defi/bridge/silver_bridge__wormhole_outbound.sql b/models/silver/defi/bridge/silver_bridge__wormhole_outbound.sql index 220406d..c96db58 100644 --- a/models/silver/defi/bridge/silver_bridge__wormhole_outbound.sql +++ b/models/silver/defi/bridge/silver_bridge__wormhole_outbound.sql @@ -79,11 +79,16 @@ bc AS ( AND A.address_owner = b.tx_sender WHERE amount < 0 - AND coin_type <> '0x2::sui::SUI' {% if is_incremental() %} AND A.block_timestamp :: DATE :: DATE >= '{{ min_bd }}' {% endif %} + +qualify ROW_NUMBER() over( + PARTITION BY A.tx_digest + ORDER BY + balance_change_index DESC +) = 1 ) SELECT A.checkpoint_number,