Spellbook DevLog #1

如何寻找 Sushiswap 在 avalanche_c 上的 swap 事件表

开发dex.trades时,如果有一个表 Swap 事件表,则事半功倍

拿sushiswap举例,我们要寻找sushiswap在avalanche_c链上已部署的合约地址,最直接的方法就是进官方开发文档里找。

https://docs.sushi.com/docs/Developers/Deployment%20Addresses

sushiswap deployment address
sushiswap deployment address

然后我们去snowtrace.io,查询SushiV2Factory地址

SushiswapV2Factory transactions
SushiswapV2Factory transactions

可以看到工厂合约在Transactions页面有许多创建交易对的记录。

这时我们进入Internal Txns页面,可以看到新建的合约。

这些新建的合约便是SushiswapPair,每个Pair合约下面我们会

SushiswapV2Factory Internal Txns
SushiswapV2Factory Internal Txns

确认了之后,我们只要去Dune上提交工厂合约解析:

https://dune.com/contracts/new

值得注意的是,我们需要勾选一些高级选项:

勾选该合约是一个工厂合约,并创建了许多实例
勾选该合约是一个工厂合约,并创建了许多实例

这样我们就可以在Dune上直接查到解码后的Sushiswap avalanche_c交易记录表了

sushiswap_v2_avalanche_c.Pair_evt_Swap
sushiswap_v2_avalanche_c.Pair_evt_Swap

如果没有解析这个表的话,如何能查到sushiswap在avalanche_c上面的交易记录呢?

可以使用avalanche_c.logs原始数据表直接解析:

{{ config(
    schema = 'sushiswap_avalanche_c'
    ,alias = 'trades'
    ,partition_by = ['block_date']
    ,materialized = 'incremental'
    ,file_format = 'delta'
    ,incremental_strategy = 'merge'
    ,unique_key = ['block_date', 'blockchain', 'project', 'version', 'tx_hash', 'evt_index', 'trace_address']
    ,post_hook='{{ expose_spells(\'["avalanche_c"]\',
                                      "project",
                                      "sushiswap",
                                    \'["hosuke", "zhongyiio"]\') }}'
    )
}}

{% set project_start_date = '2022-01-07' %}

WITH sushiswap_decodes AS (

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapETHForExactTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactETHForTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactTokensForETH') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactTokensForTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapTokensForExactETH') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapTokensForExactTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactETHForTokensSupportingFeeOnTransferTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactTokensForETHSupportingFeeOnTransferTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}

    UNION ALL

    SELECT
        call_block_time,
        call_trace_address,
        call_tx_hash,
        contract_address,
        `to`
    FROM {{ source('sushiswap_v2_avalanche_c', 'SushiSwapRouter_call_swapExactTokensForTokensSupportingFeeOnTransferTokens') }}
    WHERE call_success = true
    {% if is_incremental() %}
    AND call_block_time >= date_trunc("day", now() - interval '1 week')
    {% endif %}
),

sushiswap_decodes_with_log AS (
    SELECT
        bytea2numeric_v2(substr(l.data, 3, 64))                    AS amount0In,
        bytea2numeric_v2(substr(l.data, 3 + 64, 64))               AS amount1In,
        bytea2numeric_v2(substr(l.data, 3 + 64 + 64, 64))          AS amount0Out,
        bytea2numeric_v2(substr(l.data, 3 + 64 + 64 + 64 + 1, 64)) AS amount1Out,
        l.index                                                    AS evt_index,
        p.token0                                                   AS token0,
        p.token1                                                   AS token1,
        call_block_time,
        call_trace_address,
        call_tx_hash,
        t.contract_address,
        call_trace_address,
        `to`
    FROM sushiswap_decodes t
    INNER JOIN {{ source('avalanche_c', 'logs') }} l
        ON t.call_tx_hash = l.tx_hash
        AND l.topic1 = "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"
        {% if is_incremental() %}
        AND l.block_time >= date_trunc("day", now() - interval '1 week')
        {% else %}
        AND l.block_time >= '{{ project_start_date }}'
        {% endif %}
    INNER JOIN {{ source('sushiswap_v2_avalanche_c', 'SushiV2Factory_evt_PairCreated') }} p
        ON l.contract_address = p.pair
),

sushiswap_dex AS (
    SELECT  call_block_time                                              AS block_time,
            `to`                                                         AS taker,
            ''                                                           AS maker,
            CASE WHEN amount0Out = 0 THEN amount1Out ELSE amount0Out END AS token_bought_amount_raw,
            CASE WHEN amount0In = 0 THEN amount1In ELSE amount0In END    AS token_sold_amount_raw,
            cast(NULL as double)                                         AS amount_usd,
            CASE WHEN amount0Out = 0 THEN token1 ELSE token0 END         AS token_bought_address,
            CASE WHEN amount0In = 0 THEN token1 ELSE token0 END          AS token_sold_address,
            contract_address                                             AS project_contract_address,
            call_tx_hash                                                 AS tx_hash,
            call_trace_address                                           AS trace_address,
            evt_index
    FROM sushiswap_decodes_with_log
)

SELECT
    'avalanche_c'                                                      AS blockchain,
    'sushiswap'                                                        AS project,
    '2'                                                                AS version,
    try_cast(date_trunc('DAY', sushiswap_dex.block_time) AS date)      AS block_date,
    sushiswap_dex.block_time,
    erc20a.symbol                                                      AS token_bought_symbol,
    erc20b.symbol                                                      AS token_sold_symbol,
    case
        when lower(erc20a.symbol) > lower(erc20b.symbol) then concat(erc20b.symbol, '-', erc20a.symbol)
        else concat(erc20a.symbol, '-', erc20b.symbol)
        end                                                            AS token_pair,
    sushiswap_dex.token_bought_amount_raw / power(10, erc20a.decimals) AS token_bought_amount,
    sushiswap_dex.token_sold_amount_raw / power(10, erc20b.decimals)   AS token_sold_amount,
    sushiswap_dex.token_bought_amount_raw,
    sushiswap_dex.token_sold_amount_raw,
    coalesce(
            sushiswap_dex.amount_usd
        , (sushiswap_dex.token_bought_amount_raw / power(10, p_bought.decimals)) * p_bought.price
        , (sushiswap_dex.token_sold_amount_raw / power(10, p_sold.decimals)) * p_sold.price
        )                                                              AS amount_usd,
    sushiswap_dex.token_bought_address,
    sushiswap_dex.token_sold_address,
    coalesce(sushiswap_dex.taker, tx.from)                             AS taker,
    sushiswap_dex.maker,
    sushiswap_dex.project_contract_address,
    sushiswap_dex.tx_hash,
    tx.from                                                            AS tx_from,
    tx.to                                                              AS tx_to,
    sushiswap_dex.trace_address,
    sushiswap_dex.evt_index
from sushiswap_dex
inner join {{ source('avalanche_c', 'transactions') }} tx
    on sushiswap_dex.tx_hash = tx.hash
    {% if is_incremental() %}
    and tx.block_time >= date_trunc("day", now() - interval '1 week')
    {% else %}
    and tx.block_time >= '{{project_start_date}}'
    {% endif %}
left join {{ ref('tokens_erc20') }} erc20a
    on erc20a.contract_address = sushiswap_dex.token_bought_address
    and erc20a.blockchain = 'avalanche_c'
left join {{ ref('tokens_erc20') }} erc20b
    on erc20b.contract_address = sushiswap_dex.token_sold_address
    and erc20b.blockchain = 'avalanche_c'
left join {{ source('prices', 'usd') }} p_bought
    on p_bought.minute = date_trunc('minute', sushiswap_dex.block_time)
    and p_bought.contract_address = sushiswap_dex.token_bought_address
    and p_bought.blockchain = 'avalanche_c'
    {% if is_incremental() %}
    and p_bought.minute >= date_trunc("day", now() - interval '1 week')
    {% else %}
    and p_bought.minute >= '{{project_start_date}}'
    {% endif %}
left join {{ source('prices', 'usd') }} p_sold
    on p_sold.minute = date_trunc('minute', sushiswap_dex.block_time)
    and p_sold.contract_address = sushiswap_dex.token_sold_address
    and p_sold.blockchain = 'avalanche_c'
    {% if is_incremental() %}
    and p_sold.minute >= date_trunc("day", now() - interval '1 week')
    {% else %}
    and p_sold.minute >= '{{project_start_date}}'
    {% endif %}
;