Skip to content
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

Merged
merged 16 commits into from
Sep 12, 2024
Merged

Create cow_amm_lp_and_tvl_4047078.sql #17

merged 16 commits into from
Sep 12, 2024

Conversation

olgafetisova
Copy link
Contributor

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.

Copy link
Contributor

@fleupold fleupold left a 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

@@ -0,0 +1,48 @@
with
Copy link
Contributor

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 Show resolved Hide resolved
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'
Copy link
Contributor

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)

Copy link
Contributor Author

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.

Copy link
Contributor

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)

Comment on lines 24 to 25
time,
blockchain,
Copy link
Contributor

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_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
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

t1.day,
total_tvl,
total_lp,
lp_supply,
Copy link
Contributor

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).

@olgafetisova olgafetisova changed the title Create cow_amm_lp_and_tvl_4047078 Create cow_amm_lp_and_tvl_4047078.sql Sep 9, 2024
)) 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
Copy link
Contributor

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?

)

-- per day lp token total supply changes of the CoW AMM pool by looking at burn/mint events
, get_lp_balance as (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
, get_lp_balance as (
, lp_balance_delta as (

-- 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
Copy link
Contributor

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.

, 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
Copy link
Contributor

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)

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- 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

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
Copy link
Contributor

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.

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)
Copy link
Contributor

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).

)

, 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
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

@fleupold fleupold left a 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
Copy link
Contributor

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):

Suggested change
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

Copy link
Contributor Author

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)
Copy link
Contributor

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

image

Comment on lines 21 to 27
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}}))
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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)

Comment on lines 144 to 148
-- 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
Copy link
Contributor

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

@fleupold fleupold mentioned this pull request Sep 10, 2024
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
Copy link
Contributor

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.

Comment on lines 20 to 49
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
),
Copy link
Contributor Author

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.

Copy link
Contributor

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.

@fleupold fleupold force-pushed the olgafetisova-patch-2 branch from 03f6262 to 9190bd3 Compare September 11, 2024 10:08
@fleupold fleupold merged commit 9e43d66 into main Sep 12, 2024
1 check passed
@fleupold fleupold deleted the olgafetisova-patch-2 branch September 12, 2024 13:10
harisang pushed a commit that referenced this pull request Sep 12, 2024
* 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants