Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/mappings/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getNativePriceInUSD,
getTrackedAmountUSD,
sqrtPriceX96ToTokenPrices,
updateZoraContentTokenPricing,
} from '../utils/pricing'

export function handleSwap(event: SwapEvent): void {
Expand Down Expand Up @@ -154,6 +155,12 @@ export function handleSwapHelper(event: SwapEvent, subgraphConfig: SubgraphConfi
token0.derivedETH = findNativePerToken(token0, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked)
token1.derivedETH = findNativePerToken(token1, wrappedNativeAddress, stablecoinAddresses, minimumNativeLocked)

// Update pricing for Zora content tokens if applicable
const ZORA_CONTENT_TOKEN_HOOK = '0x9ea932730a7787000042e34390b8e435dd839040'
if (pool.hooks.toLowerCase() == ZORA_CONTENT_TOKEN_HOOK.toLowerCase()) {
updateZoraContentTokenPricing(pool, token0, token1, minimumNativeLocked)
}

/**
* Things afffected by new USD rates
*/
Expand Down
66 changes: 66 additions & 0 deletions src/utils/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,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)
}
}
Loading