|
| 1 | +-- This query is the basis for experiments with capping rewards by a fraction of protocol fees |
| 2 | +-- |
| 3 | +-- It is under version control in https://github.com/cowprotocol/dune-queries |
| 4 | +-- |
| 5 | +-- Parameters: |
| 6 | +-- {{start_time}} - the timestamp for which the analysis should start (inclusively) |
| 7 | +-- {{end_time}} - the timestamp for which the analysis should end (exclusively) |
| 8 | +-- {{blockchain}} - network to run the analysis on |
| 9 | +-- {{volume_fee_bps_stable}} - fraction of volume charged as fee on correlated tokens |
| 10 | +-- {{volume_fee_bps_variable}} - fraction of volume charged as fee on uncorrelated tokens |
| 11 | +-- |
| 12 | +-- The columns of the result are |
| 13 | +-- - time: time of the auction (deadline) |
| 14 | +-- - auction_id: id of the auction |
| 15 | +-- - solver: winning solver in that auction |
| 16 | +-- - xrate_type: either 'stable' for trades between highly correlated tokens, 'variable' for trades between uncorrelated tokens, |
| 17 | +-- None if a classification was not possible |
| 18 | +-- - protocol_fee: sum of protocol fees (excluding fees charged by partners) charged by a solver, in native token |
| 19 | +-- - volume: sum of volume of trades, in native token |
| 20 | +-- - new_protocol_fee: new protocol fee when changing the volume fee for some class of orders |
| 21 | +-- - score: sum of winning scores, in native token |
| 22 | +-- - uncapped_reward: uncapped second price reward for the solver in that auction |
| 23 | +-- - reward: current reward |
| 24 | +-- - new_reward: reward based on capping from above by new_protocol_fee, the original cap from below applies |
| 25 | +-- - old_reward: reward based on static caps |
| 26 | +-- - profit: protocol profit as difference of protocol fee and reward |
| 27 | +-- - new_profit: same as profit but for new reward and new protocol fee |
| 28 | +-- - reward_missed: amount a solver could have gotten from taking a cut instead of getting a capped reward; |
| 29 | +-- this is a measure of how much solvers can gain from acting strategically with their bidding |
| 30 | +-- - new_reward_missed: same as reward_missed but for new reward |
| 31 | +-- - old_reward_missed: same as reward_missed but for old reward |
| 32 | + |
| 33 | + |
| 34 | +with wrapped_native_token as ( |
| 35 | + select |
| 36 | + case '{{blockchain}}' |
| 37 | + when 'ethereum' then 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 -- WETH |
| 38 | + when 'gnosis' then 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d -- WXDAI |
| 39 | + when 'arbitrum' then 0x82af49447d8a07e3bd95bd0d56f35241523fbab1 -- WETH |
| 40 | + when 'base' then 0x4200000000000000000000000000000000000006 -- WETH |
| 41 | + when 'avalanche_c' then 0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7 -- WAVAX |
| 42 | + when 'polygon' then 0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270 -- WPOL |
| 43 | + when 'bnb' then 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c -- WBNB |
| 44 | + end as native_token_address |
| 45 | +), |
| 46 | + |
| 47 | +reward_caps as ( |
| 48 | + select |
| 49 | + case '{{blockchain}}' --noqa: PRS, LT02 |
| 50 | + when 'ethereum' then cast(0.012 * 1e18 as int256) -- 0.012 ETH |
| 51 | + when 'arbitrum' then cast(0.012 * 1e18 as int256) -- 0.012 ETH |
| 52 | + when 'base' then cast(0.012 * 1e18 as int256) -- 0.012 ETH |
| 53 | + when 'gnosis' then cast(10 * 1e18 as int256) -- 10 xDAI |
| 54 | + when 'avalanche_c' then cast(0.4 * 1e18 as int256) -- 0.4 AVAX |
| 55 | + when 'polygon' then cast(40 * 1e18 as int256) -- 40 POL |
| 56 | + when 'bnb' then cast(0.048 * 1e18 as int256) -- 0.048 BNB |
| 57 | + end as upper_cap, |
| 58 | + case '{{blockchain}}' |
| 59 | + when 'ethereum' then cast(0.01 * 1e18 as int256) -- 0.01 ETH |
| 60 | + when 'arbitrum' then cast(0.01 * 1e18 as int256) -- 0.01 ETH |
| 61 | + when 'base' then cast(0.01 * 1e18 as int256) -- 0.01 ETH |
| 62 | + when 'gnosis' then cast(10 * 1e18 as int256) -- 10 xDAI |
| 63 | + when 'avalanche_c' then cast(0.3 * 1e18 as int256) -- 0.3 AVAX |
| 64 | + when 'polygon' then cast(30 * 1e18 as int256) -- 30 POL |
| 65 | + when 'bnb' then cast(0.04 * 1e18 as int256) -- 0.04 BNB |
| 66 | + end as lower_cap |
| 67 | +), |
| 68 | + |
| 69 | +per_solver_auction_data as ( |
| 70 | + select |
| 71 | + b.time, |
| 72 | + rbd.auction_id, |
| 73 | + rbd.solver, |
| 74 | + rbd.uncapped_payment_native_token as uncapped_reward, |
| 75 | + rbd.capped_payment as reward, |
| 76 | + sum(rbd.winning_score) as score, |
| 77 | + coalesce(sum((rod.protocol_fee - coalesce(rod.partner_fee, 0)) * rod.protocol_fee_native_price), 0) as protocol_fee, -- this is the actual revenue of the protocol |
| 78 | + coalesce(sum(coalesce(rod.protocol_volume_fee, 0) * rod.protocol_fee_native_price), 0) as protocol_volume_fee, |
| 79 | + coalesce(sum(case when t.order_type = 'SELL' then t.atoms_bought * rod.protocol_fee_native_price else t.atoms_sold * rod.protocol_fee_native_price end), 0) as volume, |
| 80 | + bool_and( |
| 81 | + case |
| 82 | + when t.order_type = 'SELL' then abs((rod.protocol_fee_native_price * t.atoms_bought * p.price / 1e18) / coalesce(t.buy_value_usd, t.usd_value) - 1) < 0.2 |
| 83 | + else abs((rod.protocol_fee_native_price * t.atoms_sold * p.price / 1e18) / coalesce(t.sell_value_usd, t.usd_value) - 1) < 0.2 |
| 84 | + end |
| 85 | + ) as native_prices_are_accurate, |
| 86 | + bool_or(t.tx_hash is not null) as at_least_partial_success, -- this implies that there is data on trades which makes checking native prices meaningful |
| 87 | + if(bool_and(st.ref_date is not null), 'stable', if(bool_and(t.sell_token_address is not null and st.ref_date is null), 'variable')) as xrate_type |
| 88 | + from "query_4351957(blockchain='{{blockchain}}')" as rbd |
| 89 | + left join "query_4364122(blockchain='{{blockchain}}')" as rod |
| 90 | + on rbd.auction_id = rod.auction_id and rbd.solver = rod.solver and rbd.tx_hash = rod.tx_hash |
| 91 | + left join cow_protocol_{{blockchain}}.trades as t |
| 92 | + on rod.order_uid = t.order_uid and rod.tx_hash = t.tx_hash |
| 93 | + left join {{blockchain}}.blocks as b |
| 94 | + on rbd.block_deadline = b.number |
| 95 | + left join prices.day as p |
| 96 | + on date_trunc('day', b.time) = p.timestamp |
| 97 | + and p.contract_address = (select * from wrapped_native_token) |
| 98 | + and p.blockchain = '{{blockchain}}' |
| 99 | + left join "query_5719467(blockchain='{{blockchain}}', start_date='{{start_time}}', end_date='{{end_time}}')" as st |
| 100 | + on t.sell_token_address = st.sell_token_address |
| 101 | + and t.buy_token_address = st.buy_token_address |
| 102 | + and t.block_date = date(st.ref_date) |
| 103 | + where b.time >= (timestamp '{{start_time}}') and b.time < (timestamp '{{end_time}}') |
| 104 | + group by 1, 2, 3, 4, 5 |
| 105 | +), |
| 106 | + |
| 107 | +rewards_per_auction as ( |
| 108 | + select |
| 109 | + time, |
| 110 | + auction_id, |
| 111 | + solver, |
| 112 | + xrate_type, |
| 113 | + protocol_fee, |
| 114 | + protocol_volume_fee, |
| 115 | + volume, |
| 116 | + protocol_fee - protocol_volume_fee + (volume + protocol_volume_fee) * if(xrate_type = 'stable', {{volume_fee_bps_stable}}, {{volume_fee_bps_variable}}) / 1e4 as new_protocol_fee, |
| 117 | + score, |
| 118 | + uncapped_reward, |
| 119 | + reward |
| 120 | + from per_solver_auction_data |
| 121 | + where |
| 122 | + ( |
| 123 | + native_prices_are_accurate -- this filters out cases where native prices are not accurate |
| 124 | + and uncapped_reward < volume -- this filters out cases where native prices were corrected but rewards are too large |
| 125 | + ) |
| 126 | + or not at_least_partial_success -- this makes sure the filtering is only applied if some onchain data exists |
| 127 | +), |
| 128 | + |
| 129 | +new_rewards_per_auction as ( |
| 130 | + select |
| 131 | + *, |
| 132 | + least(new_protocol_fee, greatest(uncapped_reward, -(select lower_cap from reward_caps))) as new_reward, |
| 133 | + least((select upper_cap from reward_caps), greatest(uncapped_reward, -(select lower_cap from reward_caps))) as old_reward |
| 134 | + from rewards_per_auction |
| 135 | +) |
| 136 | + |
| 137 | +select |
| 138 | + *, |
| 139 | + protocol_fee - reward as profit, |
| 140 | + new_protocol_fee - new_reward as new_profit, |
| 141 | + if(uncapped_reward >=0, uncapped_reward - reward, 0) as reward_missed, |
| 142 | + if(uncapped_reward >=0, uncapped_reward - new_reward, 0) as new_reward_missed, |
| 143 | + if(uncapped_reward >=0, uncapped_reward - old_reward, 0) as old_reward_missed |
| 144 | +from new_rewards_per_auction |
0 commit comments