-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create cow_amm_lp_and_tvl_4047078.sql #17
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file needs to end in .sql
for it to be picked up. Also, please make sure formatting is correct (you can look at the other files in the rep). For this you likely need to edit the file in vscode or some other editor.
Also, given that the other folders are mevblocker
and cowprotocol
, the folder should probably be cowamm
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
@@ -0,0 +1,48 @@ | |||
with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you comment the high level query file (documenting required parameters) and even the subqueries (I think the other files in the repo can serve as an example) so that it's clear what and how this query is doing things?
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
total_tvl/total_lp as lp_token_price | ||
from total_tvl t1 | ||
join total_lp t2 on t1.day=t2.day | ||
where t1.day>=date'2024-07-30' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a parameter (start date of the analysis)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the date when we added the first liquidity to balancer amm.
Ideally, I would start the chart from the first time someone added the liquidity to the pool, but this will add more logic (hence, will be a bit slower).
I can add a parameter as you mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think users should be able to chose a custom start date (we can set the default to the pool creation in the final visualisation)
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
time, | ||
blockchain, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: These two seem unused
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
cow_amm_address, | ||
token_1_balance_usd+token_2_balance_usd as tvl, | ||
RANK() OVER (PARTITION BY date(time) ORDER BY time DESC) AS tvl_rank | ||
from dune.cowprotocol.result_balancer_cow_amm_base_query_v_2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure we want to rely on this materialized view for TVL? Is it updating reliably now (last time I checked it was stuck many days in the past)?
Have you tried using something like
select day, balance
from tokens_ethereum.balances_daily
where address = {{ cow_amm }}
and token_address = {{ token }}
and blockchain = 'ethereum'
to get the TVL?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I did check that table. It is way heavier and takes longer to compute the values (takes ~4mins to get those values), hence, I was trying to avoid it, but if there is more confidence I can update it. Ultimately it gives the same values.
In the past few days, the table (dune.cowprotocol.result_balancer_cow_amm_base_query_v_2) didn't have any issues, but I did not find a way to check the historical view of the refreshes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to not use balances_daily
if it is too slow. I wonder if we can use a similar approach as for the LP tokens (summing up transfers of token1 and token2 in and out of this pool and multiply it with the price at the end of each day) to get the final balance efficiently without relying on the materialized view.
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
t1.day, | ||
total_tvl, | ||
total_lp, | ||
lp_supply, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this? It's the supply delta per day, isn't it? I don't think this is relevant in the final table (I find current name is confusing given there is total_lp which is supposed the be the total_lp_supply).
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
)) t (day) --noqa: AL01 | ||
), | ||
|
||
-- Finds the CoW AMM pool address given tokens specified in query parameters (regardless of order) | ||
cow_amm_pool as ( | ||
select blockchain, address, token_1_address, token_2_address | ||
from query_3959044 q |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This query should also move under version_control. Can you add it in a separate PR please?
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
) | ||
|
||
-- per day lp token total supply changes of the CoW AMM pool by looking at burn/mint events | ||
, get_lp_balance as ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
, get_lp_balance as ( | |
, lp_balance_delta as ( |
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
-- per day lp token total supply changes of the CoW AMM pool by looking at burn/mint events | ||
, get_lp_balance as ( | ||
select date(evt_block_time) as day, | ||
sum(case when "from" = 0x0000000000000000000000000000000000000000 THEN (value/1e18) ELSE -(value/1e18) END) as lp_supply |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned on the other PR, dividing by 1e18 here causes rounding errors and will make it impossible to get exact results. If this is needed at all it should happen after all summation is done at the end of the query.
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
, lp_total_supply as ( | ||
SELECT | ||
date_range.day, | ||
COALESCE(v.total_lp, LAG(v.total_lp) OVER (ORDER BY date_range.day)) AS total_lp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work when there is a gap of two days imo (cf. comment on other PR)
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
LEFT JOIN | ||
total_lp v ON date_range.day = v.day | ||
) | ||
-- Compute tvl by multiplying each day's closing price with bet transfers in and out of the pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- Compute tvl by multiplying each day's closing price with bet transfers in and out of the pool | |
-- Compute tvl by multiplying each day's closing price with net transfers in and out of the pool |
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
SELECT x.day, SUM(amount * price_close) as total_tvl FROM ( | ||
SELECT date(evt_block_time) as day, | ||
symbol, | ||
-(value/POW(10,decimals)) as amount |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also here, I think basic math should be on raw integer amounts to avoid rounding errors you get from using division and floats.
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
SELECT date(evt_block_time) as day, | ||
symbol, | ||
-(value/POW(10,decimals)) as amount | ||
FROM erc20_ethereum.evt_transfer a LEFT JOIN tokens.erc20 b ON a.contract_address = b.contract_address and blockchain in (select blockchain from cow_amm_pool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't really make sense to support any blockchain here if the table you query from is erc20_ethereum.evt_transfer
(it won't have any records for gnosis).
We can make a PR later to make these queries multi-chain compatible (let's focus on getting mainnet data for now).
cow_amm/cow_amm_lp_and_tvl_4047078
Outdated
) | ||
|
||
, total_tvl as ( | ||
select day, blockchain, cow_amm_address, tvl as total_tvl | ||
select day, sum(total_tvl) over (order by day) as total_tvl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens here if a token didn't trade for a day? TVL may have gaps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed that the same way as for the lp supply
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but I think there are still two subtle issues with the tvl query that should be fixed before merging.
get_tvl as ( | ||
select | ||
x.day, | ||
sum(amount * price_close / pow(10, decimals)) as total_tvl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't change anything compared to the logic before (you are still going into floating number before you are summing up all the in and out transfers thus creating imprecision).
Instead, this needs to become (first summing the whole wei amounts and only then dividing by decimals):
sum(amount * price_close / pow(10, decimals)) as total_tvl | |
sum(amount) * price_close / pow(10, decimals) as total_tvl |
If you want to see an example of the floating imprecision you can run the two python lines which give different output:
(1/6)+(1/6)+(1/6)+(1/6)+(1/6)+(1/6)
(1+1+1+1+1+1)/6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this is not going to work in this query as price and decimals vary per token. So it either has to be done per day per token like this:
select day, sum(total_tvl)
from (
select
x.day,
x.contract_address,
decimals,
price_close,
sum(amount) * price_close / pow(10, decimals) as total_tvl
Or aggregated.
-value as amount | ||
from erc20_ethereum.evt_transfer | ||
where | ||
"from" in (select address from cow_amm_pool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we filter on the token here? Otherwise sending a random token to the USDC/WETH pool would increase its TVL which seems wrong. You can see that this did happen: https://etherscan.io/address/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc#code
select | ||
blockchain, | ||
address, | ||
token_1_address, | ||
token_2_address | ||
from query_3959044 | ||
where ((token_1_address = {{token_a}} and token_2_address = {{token_b}}) or (token_2_address = {{token_a}} and token_1_address = {{token_b}})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens here if there is more than one AMM per token pair?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should not be a problem, since we are not selecting a specific pool but rather a token pair, in the next steps we will sum all the tvl and lp supply for all these pools. This is actually the case with the token pair we are testing, so I find it find. Do you see any issues with such approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm pretty sure the math doesn't check out when adding lp tokens across multiple pools, as lp tokens may have a different price per pool.
Take the following example
- pool a has $100 TVL and 100 LP tokens (1LP token = $1)
- pool b has $100 TVL and 10 LP tokens (1LP token = $10)
If we add this up, we would get $200 TVL for 110 LP tokens, making us believe on LP token is worth $1.8
Now let's say $10 are redeemed. Here it matters in which pool they are redeemed because:
- if redeemed in pool a, it will burn 10 LP tokens (leading to $190TVL and 100 LP tokens)
- if redeemed in pool b, it will burn 1LP token (leading to $190TVL and 109 LP tokens)
In each case we would end up with a different view of how much 1 LP token is worth.
So in summary, we need to fix ourselves to a specific pool (likely the biggest, for now I went with the most recently deployed one in the other query I wrote)
-- Assess initial investment in lp tokens | ||
select 10000 * lp_token_price as investment | ||
from final | ||
where day = timestamp '{{start}}' | ||
) / lp_token_price as current_value_of_investment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the / and * also need to be inverted here
total_tvl, | ||
rank() over (partition by (date_range.day) order by tvl.day desc) as latest | ||
from date_range | ||
inner join total_tvl_prep as tvl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a helper query in #27 which we can use here instead of total_tvl_prep which should simplify this query quite a bit.
cow_amm_pool as ( | ||
select distinct | ||
cowamm_address as address, | ||
blockchain, | ||
token_1_address, | ||
token_2_address | ||
from ( | ||
select | ||
t.blockchain, | ||
cowamm_address, | ||
token_1_reserve as token_1_balance, | ||
token_2_reserve as token_2_balance, | ||
t.token_1_address, | ||
t.token_2_address, | ||
count(coalesce(token_1_reserve, token_2_reserve)) over (partition by cow_amm_nb order by "time" desc) as "temp" | ||
from query_3959058 as t | ||
left join | ||
(select | ||
*, | ||
count(address) over (order by address, token_1_address, token_2_address) as cow_amm_nb | ||
from query_3959044) as p | ||
on | ||
t.cowamm_address = p.address and t.blockchain = p.blockchain | ||
and t.token_1_address = p.token_1_address and t.token_2_address = p.token_2_address | ||
|
||
where | ||
((t.token_1_address = {{token_a}} and t.token_2_address = {{token_b}}) or (t.token_2_address = {{token_a}} and t.token_1_address = {{token_b}})) | ||
) where temp = 1 | ||
and token_1_balance > 0 and token_2_balance > 0 | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure it it makes sense to keep this complex logic to avoid empty test pools.
The previous query shows the test pools, but it should not affect the result as they are empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this query doing (the comment was not updated to reflect the new logic)? It looks quite bizarre. We are taking some count of addresses of one query as a partitioning key in another one to count the token_1 reserve?
I would simply order by created_at (which is a column that was added to 3959044.
The query find the relevant cow amm pool, get lp token balance based on the incoming and outgoing transfers. Then we use the exciting materialized table to calculate TVL for the same pool.
03f6262
to
9190bd3
Compare
* Create cow_amm_lp_and_tvl_4047078 The query find the relevant cow amm pool, get lp token balance based on the incoming and outgoing transfers. Then we use the exciting materialized table to calculate TVL for the same pool. * add gitignore for .env to present for pushing secret * Adding fixes to the CoW AMM query * Adding .sql to the query name * Addressing comments * Addressing sqlfluff issues * Addressing sqlfluff issues * Addressing additional comments * Alligning sqlfluff file with the uniswap pr * Adding comments * Calculation fix * Only one pool per token pair * Additional condition * wip * use tvl_by_tx subquery and other simplification/performance improvements * improve lookback --------- Co-authored-by: Felix Leupold <[email protected]>
The query find the relevant cow amm pool, get lp token balance based on the incoming and outgoing ethereum transfers.
Then we use the existing materialized table (result_balancer_cow_amm_base_query_v_2) to calculate TVL for the same pool.