From 04e648f85884d1e29c26d873b97c1b8cfe1a31a9 Mon Sep 17 00:00:00 2001 From: matteen Date: Thu, 7 Aug 2025 12:28:05 -0400 Subject: [PATCH 1/3] wip --- src/mappings/swap.ts | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/mappings/swap.ts b/src/mappings/swap.ts index ccb9ea3..1597cab 100644 --- a/src/mappings/swap.ts +++ b/src/mappings/swap.ts @@ -154,6 +154,66 @@ export function handleSwapHelper(event: SwapEvent, subgraphConfig: SubgraphConfi token0.derivedETH = findNativePerToken(token0, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked) token1.derivedETH = findNativePerToken(token1, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked) + // Special pricing logic for Zora content token pools only + // Zora content tokens are paired with creator tokens that have established pricing + const ZORA_CONTENT_TOKEN_HOOK = '0x9ea932730a7787000042e34390b8e435dd839040' + + // Only apply this logic to Zora content token pools + if (pool.hooks.toLowerCase() == ZORA_CONTENT_TOKEN_HOOK.toLowerCase()) { + // Check if we have a content token (no whitelistPools) paired with a creator token (has pricing) + let contentToken: Token | null = null + let creatorToken: Token | null = null + + // Identify content vs creator token based on whitelistPools and derivedETH + if ( + token0.whitelistPools.length == 0 && + token0.derivedETH.equals(ZERO_BD) && + token1.whitelistPools.length > 0 && + token1.derivedETH.gt(ZERO_BD) + ) { + contentToken = token0 + creatorToken = token1 + } else if ( + token1.whitelistPools.length == 0 && + token1.derivedETH.equals(ZERO_BD) && + token0.whitelistPools.length > 0 && + token0.derivedETH.gt(ZERO_BD) + ) { + contentToken = token1 + creatorToken = token0 + } + + // If we have a valid content/creator token pair, derive the content token price + if (contentToken && creatorToken) { + let contentTokenReserve: BigDecimal + let creatorTokenReserve: BigDecimal + + if (contentToken.id == pool.token0) { + contentTokenReserve = pool.totalValueLockedToken0 + creatorTokenReserve = pool.totalValueLockedToken1 + } else { + contentTokenReserve = pool.totalValueLockedToken1 + creatorTokenReserve = pool.totalValueLockedToken0 + } + + // Calculate ETH value locked in the creator token side + const ethLockedInCreatorToken = creatorTokenReserve.times(creatorToken.derivedETH) + + // Only proceed if we have sufficient liquidity and positive reserves + if ( + contentTokenReserve.gt(ZERO_BD) && + creatorTokenReserve.gt(ZERO_BD) && + ethLockedInCreatorToken.gt(minimumNativeLocked) + ) { + // Price ratio from pool reserves: how many content tokens per creator token + const priceRatio = creatorTokenReserve.div(contentTokenReserve) + + // Derive content token ETH price using the creator token's established rate + contentToken.derivedETH = priceRatio.times(creatorToken.derivedETH) + } + } + } + /** * Things afffected by new USD rates */ From 95b1c8e7c2e40c28f17c66947de53807150f5b0c Mon Sep 17 00:00:00 2001 From: matteen Date: Thu, 7 Aug 2025 12:39:59 -0400 Subject: [PATCH 2/3] pull into function --- src/mappings/swap.ts | 59 ++---------------------------------- src/utils/pricing.ts | 71 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/mappings/swap.ts b/src/mappings/swap.ts index 1597cab..b8152b0 100644 --- a/src/mappings/swap.ts +++ b/src/mappings/swap.ts @@ -17,6 +17,7 @@ import { getNativePriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToTokenPrices, + updateZoraContentTokenPricing, } from '../utils/pricing' export function handleSwap(event: SwapEvent): void { @@ -154,64 +155,10 @@ export function handleSwapHelper(event: SwapEvent, subgraphConfig: SubgraphConfi token0.derivedETH = findNativePerToken(token0, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked) token1.derivedETH = findNativePerToken(token1, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked) - // Special pricing logic for Zora content token pools only - // Zora content tokens are paired with creator tokens that have established pricing + // Update pricing for Zora content tokens if applicable const ZORA_CONTENT_TOKEN_HOOK = '0x9ea932730a7787000042e34390b8e435dd839040' - - // Only apply this logic to Zora content token pools if (pool.hooks.toLowerCase() == ZORA_CONTENT_TOKEN_HOOK.toLowerCase()) { - // Check if we have a content token (no whitelistPools) paired with a creator token (has pricing) - let contentToken: Token | null = null - let creatorToken: Token | null = null - - // Identify content vs creator token based on whitelistPools and derivedETH - if ( - token0.whitelistPools.length == 0 && - token0.derivedETH.equals(ZERO_BD) && - token1.whitelistPools.length > 0 && - token1.derivedETH.gt(ZERO_BD) - ) { - contentToken = token0 - creatorToken = token1 - } else if ( - token1.whitelistPools.length == 0 && - token1.derivedETH.equals(ZERO_BD) && - token0.whitelistPools.length > 0 && - token0.derivedETH.gt(ZERO_BD) - ) { - contentToken = token1 - creatorToken = token0 - } - - // If we have a valid content/creator token pair, derive the content token price - if (contentToken && creatorToken) { - let contentTokenReserve: BigDecimal - let creatorTokenReserve: BigDecimal - - if (contentToken.id == pool.token0) { - contentTokenReserve = pool.totalValueLockedToken0 - creatorTokenReserve = pool.totalValueLockedToken1 - } else { - contentTokenReserve = pool.totalValueLockedToken1 - creatorTokenReserve = pool.totalValueLockedToken0 - } - - // Calculate ETH value locked in the creator token side - const ethLockedInCreatorToken = creatorTokenReserve.times(creatorToken.derivedETH) - - // Only proceed if we have sufficient liquidity and positive reserves - if ( - contentTokenReserve.gt(ZERO_BD) && - creatorTokenReserve.gt(ZERO_BD) && - ethLockedInCreatorToken.gt(minimumNativeLocked) - ) { - // Price ratio from pool reserves: how many content tokens per creator token - const priceRatio = creatorTokenReserve.div(contentTokenReserve) - - // Derive content token ETH price using the creator token's established rate - contentToken.derivedETH = priceRatio.times(creatorToken.derivedETH) - } - } + updateZoraContentTokenPricing(pool, token0, token1, minimumNativeLocked) } /** diff --git a/src/utils/pricing.ts b/src/utils/pricing.ts index 8809b43..7f58503 100644 --- a/src/utils/pricing.ts +++ b/src/utils/pricing.ts @@ -17,7 +17,10 @@ export function sqrtPriceX96ToTokenPrices( const num = sqrtPriceX96.times(sqrtPriceX96).toBigDecimal() const denom = BigDecimal.fromString(Q192.toString()) - const price1 = num.div(denom).times(exponentToBigDecimal(token0Decimals)).div(exponentToBigDecimal(token1Decimals)) + const price1 = num + .div(denom) + .times(exponentToBigDecimal(token0Decimals)) + .div(exponentToBigDecimal(token1Decimals)) const price0 = safeDiv(BigDecimal.fromString('1'), price1) return [price0, price1] @@ -140,3 +143,69 @@ export function calculateAmountUSD( ): BigDecimal { return amount0.times(token0DerivedETH.times(ethPriceUSD)).plus(amount1.times(token1DerivedETH.times(ethPriceUSD))) } + +/** + * Updates pricing for Zora content tokens that are paired with creator tokens + * Content tokens have no whitelistPools but can derive pricing from creator tokens that do + */ +export function updateZoraContentTokenPricing( + pool: Pool, + token0: Token, + token1: Token, + minimumNativeLocked: BigDecimal, +): void { + // Check if we have a content token (no whitelistPools) paired with a creator token (has pricing) + let contentToken: Token | null = null + let creatorToken: Token | null = null + + // Identify content vs creator token based on whitelistPools and derivedETH + if ( + token0.whitelistPools.length == 0 && + token0.derivedETH.equals(ZERO_BD) && + token1.whitelistPools.length > 0 && + token1.derivedETH.gt(ZERO_BD) + ) { + contentToken = token0 + creatorToken = token1 + } else if ( + token1.whitelistPools.length == 0 && + token1.derivedETH.equals(ZERO_BD) && + token0.whitelistPools.length > 0 && + token0.derivedETH.gt(ZERO_BD) + ) { + contentToken = token1 + creatorToken = token0 + } + + // If we have a valid content/creator token pair, derive the content token price + if (!contentToken || !creatorToken) { + return + } + + let contentTokenReserve: BigDecimal + let creatorTokenReserve: BigDecimal + + if (contentToken.id == pool.token0) { + contentTokenReserve = pool.totalValueLockedToken0 + creatorTokenReserve = pool.totalValueLockedToken1 + } else { + contentTokenReserve = pool.totalValueLockedToken1 + creatorTokenReserve = pool.totalValueLockedToken0 + } + + // Calculate ETH value locked in the creator token side + const ethLockedInCreatorToken = creatorTokenReserve.times(creatorToken.derivedETH) + + // Only proceed if we have sufficient liquidity and positive reserves + if ( + contentTokenReserve.gt(ZERO_BD) && + creatorTokenReserve.gt(ZERO_BD) && + ethLockedInCreatorToken.gt(minimumNativeLocked) + ) { + // Price ratio from pool reserves: how many content tokens per creator token + const priceRatio = creatorTokenReserve.div(contentTokenReserve) + + // Derive content token ETH price using the creator token's established rate + contentToken.derivedETH = priceRatio.times(creatorToken.derivedETH) + } +} From 6ffead326179c5f7a586cb739d7e246114ecd4a9 Mon Sep 17 00:00:00 2001 From: matteen Date: Thu, 7 Aug 2025 12:43:02 -0400 Subject: [PATCH 3/3] format --- src/utils/pricing.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/utils/pricing.ts b/src/utils/pricing.ts index 7f58503..e171bf3 100644 --- a/src/utils/pricing.ts +++ b/src/utils/pricing.ts @@ -17,10 +17,7 @@ export function sqrtPriceX96ToTokenPrices( const num = sqrtPriceX96.times(sqrtPriceX96).toBigDecimal() const denom = BigDecimal.fromString(Q192.toString()) - const price1 = num - .div(denom) - .times(exponentToBigDecimal(token0Decimals)) - .div(exponentToBigDecimal(token1Decimals)) + const price1 = num.div(denom).times(exponentToBigDecimal(token0Decimals)).div(exponentToBigDecimal(token1Decimals)) const price0 = safeDiv(BigDecimal.fromString('1'), price1) return [price0, price1]