Skip to content

Commit 1c18cd4

Browse files
[CoW Protocol] Second part of Linea integration for CoW Protocol (#8982)
* First part of Linea integration for CoW Protocol * Update dbt_subprojects/dex/models/_projects/cow_protocol/_schema.yml * Fix indentation * [CoW Protocol] Second part of Linea integration * Update dbt_subprojects/dex/models/_projects/cow_protocol/linea/cow_protocol_linea_trades.sql * Add external solvers for Linea --------- Co-authored-by: jeff-dude <[email protected]>
1 parent db4cd45 commit 1c18cd4

File tree

5 files changed

+312
-0
lines changed

5 files changed

+312
-0
lines changed

dbt_subprojects/hourly_spellbook/models/_project/cow_protocol/cow_protocol_batches.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,27 @@ FROM
183183
unwraps,
184184
token_approvals
185185
FROM {{ ref('cow_protocol_bnb_batches') }}
186+
187+
UNION ALL
188+
189+
SELECT
190+
'linea' AS blockchain,
191+
'cow_protocol' AS project,
192+
'1' AS version,
193+
block_date,
194+
block_time,
195+
num_trades,
196+
dex_swaps,
197+
batch_value,
198+
solver_address,
199+
tx_hash,
200+
gas_price,
201+
gas_used,
202+
tx_cost_usd,
203+
fee_value,
204+
call_data_size,
205+
unwraps,
206+
token_approvals
207+
FROM {{ ref('cow_protocol_linea_batches') }}
208+
186209
)
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{{ config(
2+
schema = 'cow_protocol_linea',
3+
alias = 'batches',
4+
materialized='incremental',
5+
partition_by = ['block_date'],
6+
unique_key = ['tx_hash'],
7+
on_schema_change='sync_all_columns',
8+
file_format ='delta',
9+
incremental_strategy='merge',
10+
incremental_predicates = [incremental_predicate('DBT_INTERNAL_DEST.block_time')],
11+
post_hook='{{ expose_spells(blockchains = \'["linea"]\',
12+
spell_type = "project",
13+
spell_name = "cow_protocol",
14+
contributors = \'["harisang"]\') }}'
15+
)
16+
}}
17+
18+
with
19+
solvers_ranked as (
20+
select
21+
t.block_date,
22+
t.block_number,
23+
t.tx_hash,
24+
t."from" as solver,
25+
solvers.name,
26+
row_number() over (partition by t.tx_hash order by t.trace_address asc nulls first) as rn
27+
from {{ source('linea', 'traces') }} t
28+
inner join {{ ref('cow_protocol_linea_solvers') }} solvers
29+
on t."from" = solvers.address
30+
{% if is_incremental() %}
31+
where {{ incremental_predicate('block_time') }}
32+
{% endif %}
33+
),
34+
35+
batch_counts as (
36+
select try_cast(date_trunc('day', s.evt_block_time) as date) as block_date,
37+
s.evt_block_number,
38+
s.evt_block_time,
39+
s.evt_tx_hash,
40+
sr.solver,
41+
sr.name,
42+
sum(
43+
case
44+
when selector != 0x2e1a7d4d -- unwrap
45+
and selector != 0x095ea7b3 -- approval
46+
then 1
47+
else 0
48+
end
49+
) as dex_swaps,
50+
sum(case when selector = 0x2e1a7d4d then 1 else 0 end) as unwraps,
51+
sum(case when selector = 0x095ea7b3 then 1 else 0 end) as token_approvals
52+
from {{ source('gnosis_protocol_v2_linea', 'GPv2Settlement_evt_Settlement') }} s
53+
left outer join {{ source('gnosis_protocol_v2_linea', 'GPv2Settlement_evt_Interaction') }} i
54+
on i.evt_tx_hash = s.evt_tx_hash
55+
{% if is_incremental() %}
56+
and {{ incremental_predicate('i.evt_block_time') }}
57+
{% endif %}
58+
left join solvers_ranked sr
59+
on s.evt_tx_hash = sr.tx_hash
60+
and s.evt_block_date = sr.block_date
61+
and s.evt_block_number = sr.block_number
62+
and sr.rn = 1
63+
{% if is_incremental() %}
64+
where {{ incremental_predicate('s.evt_block_time') }}
65+
{% endif %}
66+
group by s.evt_block_number, s.evt_block_time, s.evt_tx_hash, sr.solver, sr.name
67+
),
68+
69+
batch_values as (
70+
select
71+
tx_hash,
72+
count(*) as num_trades,
73+
sum(usd_value) as batch_value,
74+
sum(fee_usd) as fee_value,
75+
price as eth_price
76+
from {{ source('cow_protocol_linea', 'trades') }}
77+
left outer join {{ source('prices', 'usd') }} as p
78+
on p.contract_address = 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f
79+
{% if is_incremental() %}
80+
and {{ incremental_predicate('minute') }}
81+
{% endif %}
82+
and p.minute = date_trunc('minute', block_time)
83+
and blockchain = 'linea'
84+
{% if is_incremental() %}
85+
where {{ incremental_predicate('block_time') }}
86+
{% endif %}
87+
group by tx_hash, price
88+
),
89+
90+
combined_batch_info as (
91+
select
92+
b.block_date,
93+
evt_block_number as block_number,
94+
evt_block_time as block_time,
95+
num_trades,
96+
dex_swaps,
97+
batch_value,
98+
solver as solver_address,
99+
evt_tx_hash as tx_hash,
100+
gas_price,
101+
gas_used,
102+
((gas_price / pow(10, 9)) * gas_used * eth_price) / pow(10, 9) as tx_cost_usd,
103+
fee_value,
104+
2 * bytearray_length(data) / 1024 as call_data_size,
105+
unwraps,
106+
token_approvals
107+
from batch_counts b
108+
join batch_values t
109+
on b.evt_tx_hash = t.tx_hash
110+
inner join {{ source('linea', 'transactions') }} tx
111+
on evt_tx_hash = hash
112+
and evt_block_number = block_number
113+
{% if is_incremental() %}
114+
AND {{ incremental_predicate('block_time') }}
115+
{% endif %}
116+
where num_trades > 0 --! Exclude Withdraw Batches
117+
)
118+
119+
select * from combined_batch_info
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{{ config(
2+
alias='eth_flow_orders',
3+
schema='cow_protocol_linea',
4+
materialized='incremental',
5+
partition_by = ['block_month'],
6+
unique_key = ['block_month', 'tx_hash', 'order_uid'],
7+
on_schema_change='sync_all_columns',
8+
file_format ='delta',
9+
incremental_strategy='merge',
10+
incremental_predicates = [incremental_predicate('DBT_INTERNAL_DEST.block_time')],
11+
post_hook='{{ expose_spells(\'["linea"]\',
12+
"project",
13+
"cow_protocol",
14+
\'["cowprotocol"]\') }}'
15+
)
16+
}}
17+
18+
-- PoC Query: https://dune.com/queries/2715069
19+
with
20+
eth_flow_orders as (
21+
select
22+
sender,
23+
cast(date_trunc('month', evt_block_time) as date) as block_month,
24+
evt_block_time as block_time,
25+
evt_block_number as block_number,
26+
evt_tx_hash as tx_hash,
27+
case
28+
when event.contract_address in (
29+
0xba3cb449bd2b4adddbc894d8697f5170800eadec
30+
) then 'prod'
31+
when event.contract_address in (
32+
0x04501b9b1d52e67f6862d157e00d13419d2d6e95
33+
) then 'barn'
34+
end as environment,
35+
date_format(
36+
from_unixtime(bytearray_to_decimal(from_hex(substring(cast(data as varchar), 19, 8)))),
37+
'%Y-%m-%d %T'
38+
) AS valid_to,
39+
bytearray_substring(data, 1, 8) as quote_id_hex,
40+
bytearray_to_decimal(bytearray_substring(data, 1, 8)) as quote_id,
41+
cast(JSON_EXTRACT_SCALAR(event."order", '$.sellAmount') as uint256) as sell_amount,
42+
cast(JSON_EXTRACT_SCALAR(event."order", '$.feeAmount') as uint256) as fee_amount,
43+
cast(JSON_EXTRACT_SCALAR(event."order", '$.buyAmount') as uint256) as buy_amount,
44+
from_hex(JSON_EXTRACT_SCALAR(event."order", '$.buyToken')) as buy_token,
45+
from_hex(JSON_EXTRACT_SCALAR(event."order", '$.receiver')) as receiver,
46+
from_hex(JSON_EXTRACT_SCALAR(event."order", '$.appData')) as app_hash,
47+
-- OrderHash returned by createOrder with excluded fix values (owner = contract_address, validTo = max u32)
48+
-- https://github.com/cowprotocol/ethflowcontract/blob/9c74c8ba36ff9ff3e255172b02454f831c066865/src/CoWSwapEthFlow.sol#L81-L84
49+
bytearray_concat(
50+
bytearray_concat(output_orderHash, bytearray_substring(event.contract_address, 1, 20)),
51+
from_hex('0xffffffff')
52+
) as order_uid
53+
from {{ source('cow_protocol_linea', 'CoWSwapEthFlow_evt_OrderPlacement') }} event
54+
inner join {{ source('cow_protocol_linea', 'CoWSwapEthFlow_call_createOrder') }} call
55+
on call_block_number = evt_block_number
56+
and call_tx_hash = evt_tx_hash
57+
and call_success = true
58+
{% if is_incremental() %}
59+
WHERE {{ incremental_predicate('evt_block_time') }}
60+
AND {{ incremental_predicate('call_block_time') }}
61+
{% endif %}
62+
)
63+
64+
select * from eth_flow_orders
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
version: 2
2+
3+
models:
4+
- name: cow_protocol_linea_solvers
5+
data_tests:
6+
- dbt_utils.unique_combination_of_columns:
7+
combination_of_columns:
8+
- address
9+
meta:
10+
blockchain: linea
11+
project: cow_protocol
12+
contributors: harisang
13+
config:
14+
tags: ["linea", "cow_protocol", "solver"]
15+
description: >
16+
CoW Protocol solvers list on Linea
17+
- name: cow_protocol_linea_batches
18+
meta:
19+
blockchain: linea
20+
project: cow_protocol
21+
contributors: harisang
22+
config:
23+
tags: ["linea", "cow_protocol", "trades", "dex", "aggregator", "auction"]
24+
description: >
25+
CoW Protocol enriched batches table on Linea
26+
data_tests:
27+
- unique:
28+
column_name: tx_hash
29+
30+
- name: cow_protocol_linea_eth_flow_orders
31+
meta:
32+
blockchain: linea
33+
project: cow_protocol
34+
contributors: cowprotocol
35+
config:
36+
tags: [ "linea", "cow_protocol", "eth-flow", "orders"]
37+
description: >
38+
ETHFlow enables the sale of Native ETH via CoW Protocol. This works essentially by placing an (onchain) order,
39+
through the ETHFlow contract (https://github.com/cowprotocol/ethflowcontract) sending native which then wraps
40+
the asset as an ERC20. The order is filled through this intermediary contract that uses ERC1271 signature
41+
verification to place the order on the user's behalf.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{{ config(
2+
schema = 'cow_protocol_linea',
3+
alias='solvers',
4+
post_hook='{{ expose_spells(blockchains = \'["linea"]\',
5+
spell_type = "project",
6+
spell_name = "cow_protocol",
7+
contributors = \'["harisang"]\') }}'
8+
)}}
9+
10+
WITH
11+
-- Aggregate the solver added and removed events into a single table
12+
-- with true/false for adds/removes respectively
13+
solver_activation_events as (
14+
select solver, evt_block_number, evt_index, True as activated
15+
from {{ source('gnosis_protocol_v2_linea', 'GPv2AllowListAuthentication_evt_SolverAdded') }}
16+
union
17+
select solver, evt_block_number, evt_index, False as activated
18+
from {{ source('gnosis_protocol_v2_linea', 'GPv2AllowListAuthentication_evt_SolverRemoved') }}
19+
),
20+
-- Sorting by (evt_block_number, evt_index) allows us to pick the most recent activation status of each unique solver
21+
ranked_solver_events as (
22+
select
23+
rank() over (partition by solver order by evt_block_number desc, evt_index desc) as rk,
24+
solver,
25+
evt_block_number,
26+
evt_index,
27+
activated as active
28+
from solver_activation_events
29+
),
30+
registered_solvers as (
31+
select solver, active
32+
from ranked_solver_events
33+
where rk = 1
34+
),
35+
-- Manually inserting environment and name for each "known" solver
36+
known_solver_metadata (address, environment, name) as (
37+
select *
38+
from (
39+
VALUES
40+
(0xeeD424986A909d3552CB6D108840E16B41DfD6ac, 'barn', 'Baseline'),
41+
(0xD72728C165C2e941d41749026c41d414C6679636, 'prod', 'Baseline'),
42+
(0x57dc4958b5691D3C6A5b58c71a5074eeC7eE7888, 'barn', 'Gnosis_0x'),
43+
(0x920E180FbB32D2B14EA51D95630afe3F8205b278, 'prod', 'Gnosis_0x'),
44+
(0x920E180FbB32D2B14EA51D95630afe3F8205b278, 'prod', 'Gnosis_0x'),
45+
(0xE2A37F6Bc84f01e6c28aA45738Ef72ff8c4652Bc, 'barn', 'ExtQuasiModo'),
46+
(0x2B1ee79a53e3539659b30693Bb03C180487B3Ee4, 'prod', 'ExtQuasiModo'),
47+
(0x975CF2c0897bf910F60b21693eD304374F79cD44, 'barn', 'Helixbox'),
48+
(0x6a18b02a1E4530886842DC1D0c41869F5819c98a, 'prod', 'Helixbox'),
49+
(0xd6689Af61cADf834729AfCfB6956F79c273AED37, 'barn', 'Kipseli'),
50+
(0xaf900C9e0b8d8664D683c282Fd88923809a41f17, 'prod', 'Kipseli'),
51+
(0xBfd885cC9b21e8a167eC41577520ef133d4aF36B, 'barn', 'Wraxyn'),
52+
(0x2bE0F2E120938DB793764D9e9Ee123c3CF21FEdc, 'prod', 'Wraxyn'),
53+
(0x674325BbAdBb66e06A674Fd69f7b40fE01aB1De5, 'barn', 'TSolver'),
54+
(0x13C8360b175C1eB7cbA7d11DD91aEF0a1A79ab08, 'prod', 'TSolver'),
55+
(0x2de8e2B69e05A3A58E29646363A5Ef284884d64d, 'barn', 'ApeOut_1inch'),
56+
(0xC103B939e69959a0cD079e54Bc2F0CC352bF3F9E, 'prod', 'ApeOut_1inch')
57+
) as _
58+
)
59+
-- Combining the metadata with current activation status for final table
60+
select solver as address,
61+
case when environment is not null then environment else 'new' end as environment,
62+
case when name is not null then name else 'Uncatalogued' end as name,
63+
active
64+
from registered_solvers
65+
left outer join known_solver_metadata on solver = address

0 commit comments

Comments
 (0)