From 5003c2057afb4e8f615aa2b43baf928f7effdaaa Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:47:02 +0900 Subject: [PATCH 01/18] refactor: streamline code by removing unused imports and entities, and add contract interaction tracking --- schema.graphql | 645 +---------------------- src/mappings/book-manager/cancel.ts | 114 ---- src/mappings/book-manager/claim.ts | 221 -------- src/mappings/book-manager/make.ts | 141 ----- src/mappings/book-manager/open.ts | 125 ----- src/mappings/book-manager/take.ts | 605 +-------------------- src/mappings/book-manager/transfer.ts | 33 -- src/mappings/core.ts | 24 +- src/mappings/interval-updates.ts | 355 ------------- src/mappings/liquidity-vault/burn.ts | 128 ----- src/mappings/liquidity-vault/mint.ts | 87 --- src/mappings/liquidity-vault/open.ts | 57 -- src/mappings/liquidity-vault/strategy.ts | 85 --- src/mappings/liquidity-vault/transfer.ts | 145 ----- src/mappings/router-gateway.ts | 169 ------ 15 files changed, 35 insertions(+), 2899 deletions(-) delete mode 100644 src/mappings/book-manager/cancel.ts delete mode 100644 src/mappings/book-manager/claim.ts delete mode 100644 src/mappings/book-manager/make.ts delete mode 100644 src/mappings/book-manager/open.ts delete mode 100644 src/mappings/book-manager/transfer.ts delete mode 100644 src/mappings/interval-updates.ts delete mode 100644 src/mappings/liquidity-vault/burn.ts delete mode 100644 src/mappings/liquidity-vault/mint.ts delete mode 100644 src/mappings/liquidity-vault/open.ts delete mode 100644 src/mappings/liquidity-vault/strategy.ts delete mode 100644 src/mappings/liquidity-vault/transfer.ts delete mode 100644 src/mappings/router-gateway.ts diff --git a/schema.graphql b/schema.graphql index fe3ceaa..6d01beb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1,654 +1,23 @@ -type Token @entity(immutable: false) { - # immutable values - # token address - id: Bytes! - # token symbol - symbol: String! - # token name - name: String! - # token decimals - decimals: BigInt! - - # mutable values - # current price - priceUSD: BigDecimal! - # volume in token units - volume: BigDecimal! - # volume in derived USD - volumeUSD: BigDecimal! - - # liquidity vault protocol fee - liquidityVaultProtocolFee: BigDecimal! - # liquidity vault protocol fee USD - liquidityVaultProtocolFeeUSD: BigDecimal! - - # router gateway protocol fee - routerGatewayProtocolFee: BigDecimal! - # router gateway protocol fee USD - routerGatewayProtocolFeeUSD: BigDecimal! - - # protocolFees in token units (liquidity vault + router gateway) - protocolFees: BigDecimal! - # protocolFees in USD (liquidity vault + router gateway) - protocolFeesUSD: BigDecimal! - - # number of pools containing this token - bookCount: BigInt! - # liquidity across all books in token units - totalValueLocked: BigDecimal! - # liquidity across all books in derived USD - totalValueLockedUSD: BigDecimal! - # derived fields - tokenDayData: [TokenDayData!]! @derivedFrom(field: "token") - books: [Book!]! @derivedFrom(field: "base") -} - -type Book @entity(immutable: false) { - # immutable values - # book id - id: ID! - # creation - createdAtTimestamp: BigInt! - # block book was created at - createdAtBlockNumber: BigInt! - # quote - quote: Token! - # base - base: Token! - # unit size - unitSize: BigInt! - # maker policy - makerPolicy: BigInt! - # maker fee - makerFee: BigDecimal! - isMakerFeeInQuote: Boolean! - # taker policy - takerPolicy: BigInt! - # taker fee - takerFee: BigDecimal! - isTakerFeeInQuote: Boolean! - # hooks - hooks: Bytes! - # bindings pool if exists - pool: Pool - - # mutable values - # current price tracker - priceRaw: BigInt! - # quote per base - price: BigDecimal! - # base per quote - inversePrice: BigDecimal! - # current tick - tick: BigInt! - # all time quote swapped - volumeQuote: BigDecimal! - # all time base swapped - volumeBase: BigDecimal! - # all time USD swapped - volumeUSD: BigDecimal! - # all time protocolFees quote - protocolFeesQuote: BigDecimal! - # all time protocolFees base - protocolFeesBase: BigDecimal! - # all time protocolFees derived USD - protocolFeesUSD: BigDecimal! - # total TVL across all ticks (denominated in quote token units) - totalValueLocked: BigDecimal! - # tvl USD - totalValueLockedUSD: BigDecimal! - # last taken timestamp - lastTakenTimestamp: BigInt! - # last taken block number - lastTakenBlockNumber: BigInt! - # derived fields - depths: [Depth!]! @derivedFrom(field: "book") - openOrders: [OpenOrder!]! @derivedFrom(field: "book") - takes: [Take!]! @derivedFrom(field: "book") -} - -type Depth @entity(immutable: false) { - # immutable values - # `${bookId}-${tick}` - id: ID! - # book - book: Book! - # tick - tick: BigInt! - # current price tracker - priceRaw: BigInt! - # quote per base - price: BigDecimal! - # base per quote - inversePrice: BigDecimal! - - # mutable values - # amount - unitAmount: BigInt! - baseAmount: BigInt! - quoteAmount: BigInt! - # latest tick index - latestTakenOrderIndex: BigInt! -} - -type OpenOrder @entity(immutable: false) { - # immutable values - # orderId - id: ID! - # time of txn - timestamp: BigInt! - # book position is within - book: Book! - # allow indexing by tokens - quote: Token! - # allow indexing by tokens - base: Token! - # txn origin - origin: Bytes! # the EOA that initiated the txn - # current price tracker - priceRaw: BigInt! - # current tick - tick: BigInt! - # current order index - orderIndex: BigInt! - # quote per base - price: BigDecimal! - # base per quote - inversePrice: BigDecimal! - - # mutable values - # owner of position where liquidity made to - owner: Bytes! - - # order size (descending when cancel) - amountUSD: BigDecimal! - unitAmount: BigInt! - baseAmount: BigInt! - quoteAmount: BigInt! - - # filled (ascending when taken) - filledUnitAmount: BigInt! - filledBaseAmount: BigInt! - filledQuoteAmount: BigInt! - - # claimed (descending when claim) - claimedUnitAmount: BigInt! - claimedBaseAmount: BigInt! - claimedQuoteAmount: BigInt! - - # claimable (ascending when taken) - claimableUnitAmount: BigInt! - claimableBaseAmount: BigInt! - claimableQuoteAmount: BigInt! - - # cancelable (descending when fill or cancel) - cancelableUnitAmount: BigInt! - cancelableBaseAmount: BigInt! - cancelableQuoteAmount: BigInt! -} - -type Transaction @entity(immutable: true) { - # txn hash - id: ID! - # block txn was included in - blockNumber: BigInt! - # timestamp txn was confirmed - timestamp: BigInt! - # gas used during txn execution - gasUsed: BigInt! - gasPrice: BigInt! - # address of the txn sender - from: Bytes! - # address of the txn receiver - to: Bytes - # txn value - value: BigInt! - # derived values - takes: [Take!]! @derivedFrom(field: "transaction") -} - -type ChartLog @entity(immutable: false) { - # `${baseToken}-${quoteToken}-${intervalType}-${timestamp}` - id: ID! - # `${baseToken}-${quoteToken}` - base: Token! - quote: Token! - marketCode: String! - # interval type: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 1d, 1w - intervalType: String! - # normalized candle timestamp of the block where event occurred (second) - timestamp: BigInt! - open: BigDecimal! - high: BigDecimal! - low: BigDecimal! - close: BigDecimal! - # total traded volume in base token (sum of bid + ask filled) - baseVolume: BigDecimal! - bidBookBaseVolume: BigDecimal! - askBookBaseVolume: BigDecimal! -} - -type Pool @entity(immutable: false) { - # immutable values - # pool key - id: Bytes! - # salt - salt: Bytes! - # strategy contract address - strategy: Bytes! - # creation - createdAtTimestamp: BigInt! - # block pool was created at - createdAtBlockNumber: BigInt! - # transaction pool was created in - createdAtTransaction: Transaction! - # amount of tokenA deposited at pool creation - initialTokenAAmount: BigInt! - # amount of tokenB deposited at pool creation - initialTokenBAmount: BigInt! - # total supply of liquidity tokens minted at pool creation - initialTotalSupply: BigInt! - # initial price of liquidity tokens in USD - initialLPPriceUSD: BigDecimal! - # initial mint transaction - initialMintTransaction: Transaction - # tokenA - tokenA: Token! - # tokenB - tokenB: Token! - # bookA - bookA: Book! - # bookB - bookB: Book! - - # mutable values - # oracle price - oraclePrice: BigInt! - # total supply of liquidity tokens - totalSupply: BigInt! - # total liquidity of tokenA - liquidityA: BigInt! - # total liquidity of tokenB - liquidityB: BigInt! - # current lp tracker - lpPriceUSD: BigDecimal! - # current priceA tracker - priceA: BigDecimal! - priceARaw: BigInt! - tickA: BigInt! - # current priceB tracker - priceB: BigDecimal! - priceBRaw: BigInt! - tickB: BigInt! - # all time tokenA swapped - volumeTokenA: BigDecimal! - # all time tokenB swapped - volumeTokenB: BigDecimal! - # all time USD swapped - volumeUSD: BigDecimal! - # protocolFees in tokenA units - protocolFeesTokenA: BigDecimal! - # protocolFees in tokenB units - protocolFeesTokenB: BigDecimal! - # protocolFees in tokenA USD - protocolFeesAUSD: BigDecimal! - # protocolFees in tokenB USD - protocolFeesBUSD: BigDecimal! - # all time spread profit in USD - spreadProfitUSD: BigDecimal! - # tvl USD - totalValueLockedUSD: BigDecimal! - # hourly snapshots of pool data - poolHourData: [PoolHourData!]! @derivedFrom(field: "pool") - # daily snapshots of pool data - poolDayData: [PoolDayData!]! @derivedFrom(field: "pool") -} - -type User @entity(immutable: false) { - # wallet address (only eoa) - id: Bytes! - # user discovery metadata - firstSeenTimestamp: BigInt! - firstSeenBlockNumber: BigInt! - # volume in native token units - nativeVolume: BigDecimal! - - # derived fields - userDayData: [UserDayData!]! @derivedFrom(field: "user") -} - -type UserPoolBalance @entity(immutable: false) { - # `${user}-${pool}` - id: ID! - - # pointers - user: User! - pool: Pool! - - # current LP token balance of the user - lpBalance: BigInt! - - # current value of LP (in USD) - lpBalanceUSD: BigDecimal! - - # accumulated cost basis in USD (tolal amount of USD spent to acquire current LP balance) - costBasisUSD: BigDecimal! - - # average entry price of LP (average USD price per LP token based on cost basis = costBasisUSD / lpBalance) - averageLPPriceUSD: BigDecimal! - - # accumulate token0 deposited by user - totalTokenADeposited: BigInt! - - # accumulate token1 deposited by user - totalTokenBDeposited: BigInt! -} - -type BookDayData @entity(immutable: false) { - # `${bookId}-{periodStartUnix}` - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # pointer to book - book: Book! - # quote per base - price: BigDecimal! - # base per quote - inversePrice: BigDecimal! - # volume in quote units - volumeQuote: BigDecimal! - # volume in base units - volumeBase: BigDecimal! - # volume in USD - volumeUSD: BigDecimal! - # protocolFees in quote units - protocolFeesQuote: BigDecimal! - # protocolFees in base units - protocolFeesBase: BigDecimal! - # protocolFees in USD - protocolFeesUSD: BigDecimal! - # tvl derived in quote token units (denominated in quote token units) - totalValueLocked: BigDecimal! - # tvl derived in USD at end of period - totalValueLockedUSD: BigDecimal! - # opening price (=quote per base) - open: BigDecimal! - # high price (=quote per base) - high: BigDecimal! - # low price (=quote per base) - low: BigDecimal! - # close price (=quote per base) - close: BigDecimal! -} - -type TokenDayData @entity(immutable: false) { - # token address concatendated with date - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # pointer to token - token: Token! - # pointer to clober day data - cloberDayData: CloberDayData! - - # volume in token units - volume: BigDecimal! - # volume in derived USD - volumeUSD: BigDecimal! - # tvl derived in token units (denominated in quote token units) - totalValueLocked: BigDecimal! - # tvl derived in USD at end of period - totalValueLockedUSD: BigDecimal! - # price at end of period in USD - priceUSD: BigDecimal! - - # liquidity vault protocol fee - liquidityVaultProtocolFee: BigDecimal! - # liquidity vault protocol fee USD - liquidityVaultProtocolFeeUSD: BigDecimal! - - # router gateway protocol fee - routerGatewayProtocolFee: BigDecimal! - # router gateway protocol fee USD - routerGatewayProtocolFeeUSD: BigDecimal! - - # protocolFees in token units (liquidity vault + router gateway) - protocolFees: BigDecimal! - # protocolFees in USD (liquidity vault + router gateway) - protocolFeesUSD: BigDecimal! - - # opening price USD - open: BigDecimal! - # high price USD - high: BigDecimal! - # low price USD - low: BigDecimal! - # close price USD - close: BigDecimal! -} - # Data accumulated and condensed into day stats for all of Clober type CloberDayData @entity(immutable: false) { # timestamp rounded to current day by dividing by 86400 id: ID! # timestamp rounded to current day by dividing by 86400 date: Int! - # number of daily transactions - txCount: BigInt! - # number of daily wallets - walletCount: BigInt! - # number of daily new wallets - newWalletCount: BigInt! # derived fields - tokenDayData: [TokenDayData!]! @derivedFrom(field: "cloberDayData") - transactionTypes: [TransactionTypeDayData!]! @derivedFrom(field: "cloberDayData") - routerDayData: [RouterDayData!]! @derivedFrom(field: "cloberDayData") + contractInteractionDayData: [ContractInteractionDayData!]! @derivedFrom(field: "cloberDayData") } -type TransactionTypeDayData @entity(immutable: false) { - # ${type}-${timestamp rounded to current day by dividing by 86400} +type ContractInteractionDayData @entity(immutable: false) { + # `${contractAddress}-{periodStartUnix}` id: ID! # timestamp rounded to current day by dividing by 86400 date: Int! # pointer to clober day data cloberDayData: CloberDayData! - # type of transaction - type: String! - - # tx count - txCount: BigInt! + # contract address + contract: Bytes! + # count of interactions + callCount: Int! } - -type RouterDayData @entity(immutable: false) { - # ${router}-${timestamp rounded to current day by dividing by 86400} - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # pointer to clober day data - cloberDayData: CloberDayData! - # router of swap - router: Bytes! - - # tx count - txCount: BigInt! -} - -type UserDayData @entity(immutable: false) { - # ${wallet}-{timestamp rounded to current day by dividing by 86400} - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # number of daily transactions - txCount: BigInt! - # wallet address - user: User! - - # derived fields - volumes: [UserDayVolume!]! @derivedFrom(field: "userDayData") -} - -type UserDayVolume @entity(immutable: false) { - # ${wallet}-${token.id}-${timestamp rounded to current day by dividing by 86400} - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # wallet address - user: Bytes! - # pointer to user day data - userDayData: UserDayData! - # binding to token - token: Token! - # volume in token units - volume: BigDecimal! - # volume in derived USD - volumeUSD: BigDecimal! -} - -# Data accumulated and condensed into day stats for each pool -type PoolDayData @entity(immutable: false) { - # `${poolKey}-{periodStartUnix}` - id: ID! - # timestamp rounded to current day by dividing by 86400 - date: Int! - # pointer to pool - pool: Pool! - - # oracle price - oraclePrice: BigInt! - # total supply of liquidity tokens - totalSupply: BigInt! - # total liquidity of tokenA - liquidityA: BigInt! - # total liquidity of tokenB - liquidityB: BigInt! - # current lp tracker - lpPriceUSD: BigDecimal! - # current priceA tracker - priceA: BigDecimal! - priceARaw: BigInt! - tickA: BigInt! - # current priceB tracker - priceB: BigDecimal! - priceBRaw: BigInt! - tickB: BigInt! - # tokenA swapped - volumeTokenA: BigDecimal! - # tokenB swapped - volumeTokenB: BigDecimal! - # USD swapped - volumeUSD: BigDecimal! - # protocolFees in tokenA units - protocolFeesTokenA: BigDecimal! - # protocolFees in tokenB units - protocolFeesTokenB: BigDecimal! - # protocolFees in tokenA USD - protocolFeesAUSD: BigDecimal! - # protocolFees in tokenB USD - protocolFeesBUSD: BigDecimal! - # spread profit in USD - spreadProfitUSD: BigDecimal! - # tvl derived in USD at end of period - totalValueLockedUSD: BigDecimal! -} - -# hourly stats tracker for pool -type PoolHourData @entity(immutable: false) { - # ${poolKey}-{periodStartUnix} - id: ID! - # unix timestamp for start of hour - date: Int! - # pointer to pool - pool: Pool! - - # oracle price - oraclePrice: BigInt! - # total supply of liquidity tokens - totalSupply: BigInt! - # total liquidity of tokenA - liquidityA: BigInt! - # total liquidity of tokenB - liquidityB: BigInt! - # current lp tracker - lpPriceUSD: BigDecimal! - # current priceA tracker - priceA: BigDecimal! - priceARaw: BigInt! - tickA: BigInt! - # current priceB tracker - priceB: BigDecimal! - priceBRaw: BigInt! - tickB: BigInt! - # tokenA swapped - volumeTokenA: BigDecimal! - # tokenB swapped - volumeTokenB: BigDecimal! - # USD swapped - volumeUSD: BigDecimal! - # protocolFees in tokenA units - protocolFeesTokenA: BigDecimal! - # protocolFees in tokenB units - protocolFeesTokenB: BigDecimal! - # protocolFees in tokenA USD - protocolFeesAUSD: BigDecimal! - # protocolFees in tokenB USD - protocolFeesBUSD: BigDecimal! - # spread profit in USD - spreadProfitUSD: BigDecimal! - # tvl derived in USD at end of period - totalValueLockedUSD: BigDecimal! -} - -# entity for take event on clober book -type Take @entity(immutable: true) { - # {txHash}-{logIndex} - id: ID! - # pointer to transaction - transaction: Transaction! - # timestamp of transaction - timestamp: BigInt! - # book - book: Book! - # allow indexing by tokens - inputToken: Token! - # allow indexing by tokens - outputToken: Token! - # txn origin - origin: Bytes! # the EOA that initiated the txn - # amount In - inputAmount: BigInt! - # amount Out - outputAmount: BigInt! - # amount In USD - amountUSD: BigDecimal! - # index within the txn - logIndex: BigInt -} - -# entity for swap event on clober meta aggregator -type Swap @entity(immutable: true) { - # {txHash}-{logIndex} - id: ID! - # pointer to transaction - transaction: Transaction! - # timestamp of transaction - timestamp: BigInt! - # allow indexing by tokens - inputToken: Bytes! - # allow indexing by tokens - outputToken: Bytes! - # txn origin - origin: Bytes! # the EOA that initiated the txn - # amount In - inputAmount: BigInt! - # amount Out - outputAmount: BigInt! - # amount In USD - amountUSD: BigDecimal! - # index within the txn - logIndex: BigInt - # router address - router: Bytes! - # fee in ouputToken wei - fee: BigInt! -} \ No newline at end of file diff --git a/src/mappings/book-manager/cancel.ts b/src/mappings/book-manager/cancel.ts deleted file mode 100644 index 62fc503..0000000 --- a/src/mappings/book-manager/cancel.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Address, store } from '@graphprotocol/graph-ts' - -import { Cancel } from '../../../generated/BookManager/BookManager' -import { - decodeBookIDFromOrderID, - getPendingUnitAmount, -} from '../../common/order' -import { - getBookOrLog, - getDepthOrLog, - getOpenOrderOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { tickToPrice } from '../../common/tick' -import { unitToBase, unitToQuote } from '../../common/amount' -import { convertTokenToDecimal } from '../../common/utils' -import { calculateValueUSD, getTokenUSDPriceFlat } from '../../common/pricing' -import { - updateBookDayData, - updateDayData, - updateTokenDayData, -} from '../interval-updates' -import { OPERATOR } from '../../common/chain' - -export function handleCancel(event: Cancel): void { - if ( - event.transaction.to && - !event.transaction.to!.equals(Address.fromString(OPERATOR)) - ) { - updateDayData(event, 'CANCEL') - } - - if (event.params.unit.isZero()) { - return - } - - const bookID = decodeBookIDFromOrderID(event.params.orderId) - const book = getBookOrLog(bookID, 'CANCEL') - if (book === null) { - return - } - - const openOrderID = event.params.orderId.toString() - const openOrder = getOpenOrderOrLog(openOrderID, 'CANCEL') - if (openOrder === null) { - return - } - - const depthID = bookID.concat('-').concat(openOrder.tick.toString()) - const depth = getDepthOrLog(depthID, 'CANCEL') - if (depth === null) { - return - } - - const quote = getTokenOrLog(book.quote, 'CANCEL') - const base = getTokenOrLog(book.base, 'CANCEL') - if (quote && base) { - const priceRaw = tickToPrice(openOrder.tick.toI32()) - - const quoteAmount = unitToQuote(book.unitSize, event.params.unit) - const quoteAmountDecimal = convertTokenToDecimal( - quoteAmount, - quote.decimals, - ) - const quoteInUSD = getTokenUSDPriceFlat(quote) - - const baseAmount = unitToBase(book.unitSize, event.params.unit, priceRaw) - const baseInUSD = getTokenUSDPriceFlat(base) - - // update quote data - quote.totalValueLocked = quote.totalValueLocked.minus(quoteAmountDecimal) - quote.totalValueLockedUSD = quote.totalValueLocked.times(quoteInUSD) - - // book data - book.totalValueLocked = book.totalValueLocked.minus(quoteAmountDecimal) - book.totalValueLockedUSD = book.totalValueLocked.times(quoteInUSD) - - // open order data - openOrder.unitAmount = openOrder.unitAmount.minus(event.params.unit) - openOrder.quoteAmount = openOrder.quoteAmount.minus(quoteAmount) - openOrder.baseAmount = openOrder.baseAmount.minus(baseAmount) - openOrder.amountUSD = calculateValueUSD( - convertTokenToDecimal(openOrder.quoteAmount, quote.decimals), - quoteInUSD, - convertTokenToDecimal(openOrder.baseAmount, base.decimals), - baseInUSD, - ) - - openOrder.cancelableUnitAmount = openOrder.cancelableUnitAmount.minus( - event.params.unit, - ) - openOrder.cancelableQuoteAmount = - openOrder.cancelableQuoteAmount.minus(quoteAmount) - openOrder.cancelableBaseAmount = - openOrder.cancelableBaseAmount.minus(baseAmount) - - // depth data - depth.unitAmount = depth.unitAmount.minus(event.params.unit) - depth.quoteAmount = depth.quoteAmount.minus(quoteAmount) - depth.baseAmount = depth.baseAmount.minus(baseAmount) - - updateBookDayData(book, event) - updateTokenDayData(quote, quoteInUSD, event) - - if (getPendingUnitAmount(openOrder).isZero()) { - store.remove('OpenOrder', openOrderID) - } else { - openOrder.save() - } - depth.save() - book.save() - quote.save() - } -} diff --git a/src/mappings/book-manager/claim.ts b/src/mappings/book-manager/claim.ts deleted file mode 100644 index dc2cfd1..0000000 --- a/src/mappings/book-manager/claim.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - Address, - BigDecimal, - BigInt, - ethereum, - log, - store, -} from '@graphprotocol/graph-ts' - -import { Claim } from '../../../generated/BookManager/BookManager' -import { - decodeBookIDFromOrderID, - getPendingUnitAmount, -} from '../../common/order' -import { - getBookOrLog, - getOpenOrderOrLog, - getPoolOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { unitToBase, unitToQuote } from '../../common/amount' -import { tickToPrice } from '../../common/tick' -import { OpenOrder, Pool } from '../../../generated/schema' -import { TWO_BD, ZERO_BD } from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { getTokenUSDPriceFlat } from '../../common/pricing' -import { - updateBookDayData, - updateDayData, - updatePoolDayData, - updatePoolHourData, - updateTokenDayData, -} from '../interval-updates' -import { LIQUIDITY_VAULT, OPERATOR } from '../../common/chain' - -function updatePool( - pool: Pool, - baseClaimedAmountDecimal: BigDecimal, - marketQuoteInUSD: BigDecimal, - openOrder: OpenOrder, - event: ethereum.Event, -): void { - let spreadInUsd = pool.priceB.minus(pool.priceA).times(marketQuoteInUSD) - if (spreadInUsd.lt(BigDecimal.zero())) { - spreadInUsd = ZERO_BD - } - - if ( - BigInt.fromString(pool.bookA).equals(BigInt.fromString(openOrder.book)) || - BigInt.fromString(pool.bookB).equals(BigInt.fromString(openOrder.book)) - ) { - const spreadDeltaInUsd = spreadInUsd - .div(TWO_BD) - .times(baseClaimedAmountDecimal) - pool.spreadProfitUSD = pool.spreadProfitUSD.plus(spreadDeltaInUsd) - - const poolHourData = updatePoolHourData(pool, event) - const poolDayData = updatePoolDayData(pool, event) - - // update intervals - poolHourData.spreadProfitUSD = - poolHourData.spreadProfitUSD.plus(spreadDeltaInUsd) - poolDayData.spreadProfitUSD = - poolDayData.spreadProfitUSD.plus(spreadDeltaInUsd) - - pool.save() - poolHourData.save() - poolDayData.save() - } else { - log.warning('Pool {} does not contain book {}', [ - pool.id.toString(), - openOrder.book.toString(), - ]) - } -} - -export function handleClaim(event: Claim): void { - if ( - event.transaction.to && - !event.transaction.to!.equals(Address.fromString(OPERATOR)) - ) { - updateDayData(event, 'CLAIM') - } - - if (event.params.unit.isZero()) { - return - } - - const bookID = decodeBookIDFromOrderID(event.params.orderId) - const book = getBookOrLog(bookID, 'CLAIM') - if (book === null) { - return - } - - const openOrderID = event.params.orderId.toString() - const openOrder = getOpenOrderOrLog(openOrderID, 'CLAIM') - if (openOrder === null) { - return - } - - const quote = getTokenOrLog(book.quote, 'CLAIM') - const base = getTokenOrLog(book.base, 'CLAIM') - if (quote && base) { - const priceRaw = tickToPrice(openOrder.tick.toI32()) - - const quoteAmount = unitToQuote(book.unitSize, event.params.unit) - const baseAmount = unitToBase(book.unitSize, event.params.unit, priceRaw) - - // claimed data - openOrder.claimedUnitAmount = openOrder.claimedUnitAmount.plus( - event.params.unit, - ) - openOrder.claimedBaseAmount = openOrder.claimedBaseAmount.plus(baseAmount) - openOrder.claimedQuoteAmount = - openOrder.claimedQuoteAmount.plus(quoteAmount) - - // claimable data - openOrder.claimableUnitAmount = openOrder.claimableUnitAmount.minus( - event.params.unit, - ) - openOrder.claimableBaseAmount = - openOrder.claimableBaseAmount.minus(baseAmount) - openOrder.claimableQuoteAmount = - openOrder.claimableQuoteAmount.minus(quoteAmount) - - const baseInUSD = getTokenUSDPriceFlat(base) - const quoteInUSD = getTokenUSDPriceFlat(quote) - - if ( - book.pool !== null && - Address.fromBytes(openOrder.owner).equals( - Address.fromString(LIQUIDITY_VAULT), - ) - ) { - const pool = getPoolOrLog(book.pool!, 'CLAIM') as Pool - const isClaimingBidBook = BigInt.fromString(pool.bookA!).equals( - BigInt.fromString(bookID), - ) - const baseClaimedAmountDecimal = isClaimingBidBook - ? convertTokenToDecimal(baseAmount, base.decimals) - : convertTokenToDecimal(quoteAmount, quote.decimals) - const marketQuoteInUSD = isClaimingBidBook ? quoteInUSD : baseInUSD - if (pool) { - updatePool( - pool, - baseClaimedAmountDecimal, - marketQuoteInUSD, - openOrder, - event, - ) - } - } - - if (book.makerFee.gt(ZERO_BD)) { - // interval data - const bookDayData = updateBookDayData(book, event) - const quoteDayData = updateTokenDayData(quote, quoteInUSD, event) - const baseDayData = updateTokenDayData(base, baseInUSD, event) - - if (book.isMakerFeeInQuote) { - const protocolFeesQuote = convertTokenToDecimal( - quoteAmount, - quote.decimals, - ).times(book.makerFee) - const protocolFeesInUSD = protocolFeesQuote.times(quoteInUSD) - - book.protocolFeesQuote = book.protocolFeesQuote.plus(protocolFeesQuote) - book.protocolFeesUSD = book.protocolFeesUSD.plus(protocolFeesInUSD) - - quote.protocolFees = quote.protocolFees.plus(protocolFeesQuote) - quote.protocolFeesUSD = quote.protocolFeesUSD.plus(protocolFeesInUSD) - - bookDayData.protocolFeesQuote = - bookDayData.protocolFeesQuote.plus(protocolFeesQuote) - bookDayData.protocolFeesUSD = - bookDayData.protocolFeesUSD.plus(protocolFeesInUSD) - - quoteDayData.protocolFees = - quoteDayData.protocolFees.plus(protocolFeesQuote) - quoteDayData.protocolFeesUSD = - quoteDayData.protocolFeesUSD.plus(protocolFeesInUSD) - } else { - const protocolFeesBase = convertTokenToDecimal( - baseAmount, - base.decimals, - ).times(book.makerFee) - const protocolFeesInUSD = protocolFeesBase.times(baseInUSD) - - book.protocolFeesBase = book.protocolFeesBase.plus(protocolFeesBase) - book.protocolFeesUSD = book.protocolFeesUSD.plus(protocolFeesInUSD) - - base.protocolFees = base.protocolFees.plus(protocolFeesBase) - base.protocolFeesUSD = base.protocolFeesUSD.plus(protocolFeesInUSD) - - bookDayData.protocolFeesBase = - bookDayData.protocolFeesBase.plus(protocolFeesBase) - bookDayData.protocolFeesUSD = - bookDayData.protocolFeesUSD.plus(protocolFeesInUSD) - - baseDayData.protocolFees = - baseDayData.protocolFees.plus(protocolFeesBase) - baseDayData.protocolFeesUSD = - baseDayData.protocolFeesUSD.plus(protocolFeesInUSD) - } - - // save - book.save() - quote.save() - base.save() - bookDayData.save() - quoteDayData.save() - baseDayData.save() - } - - if (getPendingUnitAmount(openOrder).isZero()) { - store.remove('OpenOrder', openOrderID) - } else { - openOrder.save() - } - } -} diff --git a/src/mappings/book-manager/make.ts b/src/mappings/book-manager/make.ts deleted file mode 100644 index c09b686..0000000 --- a/src/mappings/book-manager/make.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Address, BigInt } from '@graphprotocol/graph-ts' - -import { Make } from '../../../generated/BookManager/BookManager' -import { Depth, OpenOrder } from '../../../generated/schema' -import { unitToBase, unitToQuote } from '../../common/amount' -import { - formatInvertedPrice, - formatPrice, - tickToPrice, -} from '../../common/tick' -import { ZERO_BI } from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { calculateValueUSD, getTokenUSDPriceFlat } from '../../common/pricing' -import { encodeOrderID } from '../../common/order' -import { - updateBookDayData, - updateDayData, - updateTokenDayData, -} from '../interval-updates' -import { getBookOrLog, getTokenOrLog } from '../../common/entity-getters' -import { OPERATOR } from '../../common/chain' - -export function handleMake(event: Make): void { - if ( - event.transaction.to && - !event.transaction.to!.equals(Address.fromString(OPERATOR)) - ) { - updateDayData(event, 'MAKE') - } - - const book = getBookOrLog(event.params.bookId.toString(), 'MAKE') - if (book === null) { - return - } - - const quote = getTokenOrLog(book.quote, 'MAKE') - const base = getTokenOrLog(book.base, 'MAKE') - if (quote && base) { - const tick = BigInt.fromI32(event.params.tick) - const priceRaw = tickToPrice(tick.toI32()) - const orderID = encodeOrderID(book.id, tick, event.params.orderIndex) - - const quoteAmount = unitToQuote(book.unitSize, event.params.unit) - const quoteAmountDecimal = convertTokenToDecimal( - quoteAmount, - quote.decimals, - ) - const quoteInUSD = getTokenUSDPriceFlat(quote) - - const baseAmount = unitToBase(book.unitSize, event.params.unit, priceRaw) - const baseAmountDecimal = convertTokenToDecimal(baseAmount, base.decimals) - const baseInUSD = getTokenUSDPriceFlat(base) - - const amountUSD = calculateValueUSD( - quoteAmountDecimal, - quoteInUSD, - baseAmountDecimal, - baseInUSD, - ) - - // update quote data - quote.totalValueLocked = quote.totalValueLocked.plus(quoteAmountDecimal) - quote.totalValueLockedUSD = quote.totalValueLocked.times(quoteInUSD) - - // book data - book.totalValueLocked = book.totalValueLocked.plus(quoteAmountDecimal) - book.totalValueLockedUSD = book.totalValueLocked.times(quoteInUSD) - - // open order data - const openOrder = new OpenOrder(orderID.toString()) - openOrder.timestamp = event.block.timestamp - openOrder.book = book.id - openOrder.quote = quote.id - openOrder.base = base.id - openOrder.origin = event.transaction.from - openOrder.owner = event.params.user - openOrder.priceRaw = priceRaw - openOrder.tick = tick - openOrder.orderIndex = event.params.orderIndex - openOrder.price = formatPrice(priceRaw, base.decimals, quote.decimals) // checked - openOrder.inversePrice = formatInvertedPrice( - priceRaw, - base.decimals, - quote.decimals, - ) // checked - // initial - openOrder.amountUSD = amountUSD - openOrder.unitAmount = event.params.unit - openOrder.baseAmount = baseAmount - openOrder.quoteAmount = quoteAmount - // filled - openOrder.filledUnitAmount = ZERO_BI - openOrder.filledBaseAmount = ZERO_BI - openOrder.filledQuoteAmount = ZERO_BI - // claimed - openOrder.claimedUnitAmount = ZERO_BI - openOrder.claimedBaseAmount = ZERO_BI - openOrder.claimedQuoteAmount = ZERO_BI - // claimable - openOrder.claimableUnitAmount = ZERO_BI - openOrder.claimableBaseAmount = ZERO_BI - openOrder.claimableQuoteAmount = ZERO_BI - // open - openOrder.cancelableUnitAmount = event.params.unit - openOrder.cancelableBaseAmount = baseAmount - openOrder.cancelableQuoteAmount = quoteAmount - - // depth data - const depthID = book.id.toString().concat('-').concat(tick.toString()) - let depth = Depth.load(depthID) - if (depth === null) { - depth = new Depth(depthID) - depth.book = book.id - depth.tick = tick - depth.latestTakenOrderIndex = ZERO_BI - depth.unitAmount = event.params.unit - depth.baseAmount = baseAmount - depth.quoteAmount = quoteAmount - depth.priceRaw = priceRaw - depth.price = formatPrice(priceRaw, base.decimals, quote.decimals) // checked - depth.inversePrice = formatInvertedPrice( - priceRaw, - base.decimals, - quote.decimals, - ) // checked - } else { - depth.unitAmount = depth.unitAmount.plus(event.params.unit) - depth.baseAmount = depth.baseAmount.plus(baseAmount) - depth.quoteAmount = depth.quoteAmount.plus(quoteAmount) - } - - updateBookDayData(book, event) - updateTokenDayData(quote, quoteInUSD, event) - - // save all - book.save() - quote.save() - openOrder.save() - depth.save() - } -} diff --git a/src/mappings/book-manager/open.ts b/src/mappings/book-manager/open.ts deleted file mode 100644 index 76cc456..0000000 --- a/src/mappings/book-manager/open.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { BigDecimal, BigInt, log } from '@graphprotocol/graph-ts' - -import { Open } from '../../../generated/BookManager/BookManager' -import { Book, Token } from '../../../generated/schema' -import { - fetchTokenDecimals, - fetchTokenName, - fetchTokenSymbol, -} from '../../common/token' -import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' - -const FEE_PRECISION = BigDecimal.fromString('1000000') -const RATE_MASK = BigInt.fromI32(8388607) -const MAX_FEE_RATE = BigInt.fromI32(500000) - -// @ts-ignore -export function getFeeRate(feePolicy: i32): BigDecimal { - const feeBigInt = BigInt.fromI32(feePolicy) - .bitAnd(RATE_MASK) - .minus(MAX_FEE_RATE) - return BigDecimal.fromString(feeBigInt.toString()).div(FEE_PRECISION) -} - -export function getUsesFeeInQuote(feePolicy: i32): boolean { - return BigInt.fromI32(feePolicy).rightShift(23).gt(ZERO_BI) -} - -export function handleBookOpen(event: Open): void { - const book = new Book(event.params.id.toString()) as Book - let quote = Token.load(event.params.quote) - let base = Token.load(event.params.base) - - if (quote === null) { - quote = new Token(event.params.quote) - quote.symbol = fetchTokenSymbol(event.params.quote) - quote.name = fetchTokenName(event.params.quote) - // quote.totalSupply = fetchTokenTotalSupply(event.params.quote) - const decimals = fetchTokenDecimals(event.params.quote) - - // bail if we couldn't figure out the decimals - if (decimals === null) { - log.debug('mybug the decimal on token 0 was null', []) - return - } - - quote.decimals = decimals - quote.volume = ZERO_BD - quote.volumeUSD = ZERO_BD - - quote.liquidityVaultProtocolFee = ZERO_BD - quote.liquidityVaultProtocolFeeUSD = ZERO_BD - quote.routerGatewayProtocolFee = ZERO_BD - quote.routerGatewayProtocolFeeUSD = ZERO_BD - quote.protocolFees = ZERO_BD - quote.protocolFeesUSD = ZERO_BD - - quote.bookCount = ZERO_BI - quote.totalValueLocked = ZERO_BD - quote.totalValueLockedUSD = ZERO_BD - quote.priceUSD = ZERO_BD - } - quote.bookCount = quote.bookCount.plus(ONE_BI) - - if (base === null) { - base = new Token(event.params.base) - base.symbol = fetchTokenSymbol(event.params.base) - base.name = fetchTokenName(event.params.base) - // base.totalSupply = fetchTokenTotalSupply(event.params.base) - const decimals = fetchTokenDecimals(event.params.base) - - // bail if we couldn't figure out the decimals - if (decimals === null) { - log.debug('mybug the decimal on token 0 was null', []) - return - } - - base.decimals = decimals - base.volume = ZERO_BD - base.volumeUSD = ZERO_BD - - base.liquidityVaultProtocolFee = ZERO_BD - base.liquidityVaultProtocolFeeUSD = ZERO_BD - base.routerGatewayProtocolFee = ZERO_BD - base.routerGatewayProtocolFeeUSD = ZERO_BD - base.protocolFees = ZERO_BD - base.protocolFeesUSD = ZERO_BD - - base.bookCount = ZERO_BI - base.totalValueLocked = ZERO_BD - base.totalValueLockedUSD = ZERO_BD - base.priceUSD = ZERO_BD - } - base.bookCount = base.bookCount.plus(ONE_BI) - - book.createdAtTimestamp = event.block.timestamp - book.createdAtBlockNumber = event.block.number - book.quote = quote.id - book.base = base.id - book.unitSize = event.params.unitSize - book.makerPolicy = BigInt.fromI32(event.params.makerPolicy) - book.makerFee = getFeeRate(event.params.makerPolicy) - book.isMakerFeeInQuote = getUsesFeeInQuote(event.params.makerPolicy) - book.takerPolicy = BigInt.fromI32(event.params.takerPolicy) - book.takerFee = getFeeRate(event.params.takerPolicy) - book.isTakerFeeInQuote = getUsesFeeInQuote(event.params.takerPolicy) - book.hooks = event.params.hooks - - book.priceRaw = ZERO_BI - book.price = ZERO_BD - book.inversePrice = ZERO_BD - book.tick = ZERO_BI - book.volumeQuote = ZERO_BD - book.volumeBase = ZERO_BD - book.volumeUSD = ZERO_BD - book.protocolFeesQuote = ZERO_BD - book.protocolFeesBase = ZERO_BD - book.protocolFeesUSD = ZERO_BD - book.totalValueLocked = ZERO_BD - book.totalValueLockedUSD = ZERO_BD - book.lastTakenBlockNumber = ZERO_BI - book.lastTakenTimestamp = ZERO_BI - book.save() - quote.save() - base.save() -} diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 19185a3..3880d46 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -1,589 +1,38 @@ -import { - Address, - BigDecimal, - BigInt, - ethereum, - log, -} from '@graphprotocol/graph-ts' - import { Take } from '../../../generated/BookManager/BookManager' import { - Book, - ChartLog, - OpenOrder, - Pool, - Take as TakeEntity, - Token, + CloberDayData, + ContractInteractionDayData, } from '../../../generated/schema' -import { unitToBase, unitToQuote } from '../../common/amount' -import { encodeOrderID } from '../../common/order' -import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' -import { - getBookOrLog, - getDepthOrLog, - getPoolOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { convertTokenToDecimal } from '../../common/utils' -import { calculateValueUSD, getTokenUSDPriceFlat } from '../../common/pricing' -import { - formatInvertedPrice, - formatPrice, - tickToPrice, -} from '../../common/tick' -import { - updateBookDayData, - updateDayData, - updatePoolDayData, - updatePoolHourData, - updateTokenDayData, - updateUserDayVolume, - updateUserNativeVolume, -} from '../interval-updates' -import { - CHART_LOG_INTERVALS, - encodeChartLogID, - encodeMarketCode, -} from '../../common/chart' -import { - LIQUIDITY_VAULT, - SKIP_CHART, - SKIP_TAKE_AND_SWAP, -} from '../../common/chain' - -function fillOpenOrder( - openOrder: OpenOrder, - unitSize: BigInt, - filledUnitAmount: BigInt, -): void { - const updatedFilledUnitAmount = - openOrder.filledUnitAmount.plus(filledUnitAmount) - openOrder.filledUnitAmount = updatedFilledUnitAmount - openOrder.filledBaseAmount = unitToBase( - unitSize, - updatedFilledUnitAmount, - openOrder.priceRaw, - ) - openOrder.filledQuoteAmount = unitToQuote(unitSize, updatedFilledUnitAmount) - - const claimableUnitAfterFill = - openOrder.claimableUnitAmount.plus(filledUnitAmount) - openOrder.claimableUnitAmount = claimableUnitAfterFill - openOrder.claimableBaseAmount = unitToBase( - unitSize, - claimableUnitAfterFill, - openOrder.priceRaw, - ) - openOrder.claimableQuoteAmount = unitToQuote(unitSize, claimableUnitAfterFill) - - const remainingCancelableUnitAmount = - openOrder.cancelableUnitAmount.minus(filledUnitAmount) - openOrder.cancelableUnitAmount = remainingCancelableUnitAmount - openOrder.cancelableBaseAmount = unitToBase( - unitSize, - remainingCancelableUnitAmount, - openOrder.priceRaw, - ) - openOrder.cancelableQuoteAmount = unitToQuote( - unitSize, - remainingCancelableUnitAmount, - ) - - if (remainingCancelableUnitAmount.lt(ZERO_BI)) { - log.error('[TAKE] Negative cancelable unit amount: {}', [openOrder.id]) - } - - openOrder.save() -} - -function updateChart( - block: ethereum.Block, - takenBaseAmountDecimal: BigDecimal, - takenQuoteAmountDecimal: BigDecimal, - book: Book, - base: Token, - quote: Token, -): void { - for (let i = 0; i < CHART_LOG_INTERVALS.entries.length; i++) { - const entry = CHART_LOG_INTERVALS.entries[i] - const intervalType = entry.key - const intervalInNumber = entry.value - const timestampForAcc = (Math.floor( - (block.timestamp.toI64() as number) / intervalInNumber, - ) * intervalInNumber) as i64 - - // natural chart log - const chartLogID = encodeChartLogID( - base, - quote, - intervalType, - timestampForAcc, - ) - const marketCode = encodeMarketCode(base, quote) - let chartLog = ChartLog.load(chartLogID) - if (chartLog === null) { - chartLog = new ChartLog(chartLogID) - chartLog.marketCode = marketCode - chartLog.base = base.id - chartLog.quote = quote.id - chartLog.intervalType = intervalType - chartLog.timestamp = BigInt.fromI64(timestampForAcc) - chartLog.open = book.price - chartLog.high = book.price - chartLog.low = book.price - chartLog.close = book.price - chartLog.baseVolume = takenBaseAmountDecimal - chartLog.bidBookBaseVolume = takenBaseAmountDecimal - chartLog.askBookBaseVolume = ZERO_BD - } else { - if (book.price.gt(chartLog.high)) { - chartLog.high = book.price - } - if (book.price.lt(chartLog.low)) { - chartLog.low = book.price - } - chartLog.close = book.price - chartLog.baseVolume = chartLog.baseVolume.plus(takenBaseAmountDecimal) - chartLog.bidBookBaseVolume = chartLog.bidBookBaseVolume.plus( - takenBaseAmountDecimal, - ) - } - chartLog.save() - - // inverted chart log - const invertedChartLogID = encodeChartLogID( - quote, - base, - intervalType, - timestampForAcc, - ) - const invertedMarketCode = encodeMarketCode(quote, base) - let invertedChartLog = ChartLog.load(invertedChartLogID) - if (invertedChartLog === null) { - invertedChartLog = new ChartLog(invertedChartLogID) - invertedChartLog.marketCode = invertedMarketCode - invertedChartLog.base = quote.id - invertedChartLog.quote = base.id - invertedChartLog.intervalType = intervalType - invertedChartLog.timestamp = BigInt.fromI64(timestampForAcc) - invertedChartLog.open = book.inversePrice - invertedChartLog.high = book.inversePrice - invertedChartLog.low = book.inversePrice - invertedChartLog.close = book.inversePrice - invertedChartLog.baseVolume = takenQuoteAmountDecimal - invertedChartLog.bidBookBaseVolume = ZERO_BD - invertedChartLog.askBookBaseVolume = takenQuoteAmountDecimal - } else { - if (book.inversePrice.gt(invertedChartLog.high)) { - invertedChartLog.high = book.inversePrice - } - if (book.inversePrice.lt(invertedChartLog.low)) { - invertedChartLog.low = book.inversePrice - } - invertedChartLog.close = book.inversePrice - invertedChartLog.baseVolume = invertedChartLog.baseVolume.plus( - takenQuoteAmountDecimal, - ) - invertedChartLog.askBookBaseVolume = - invertedChartLog.askBookBaseVolume.plus(takenQuoteAmountDecimal) - } - invertedChartLog.save() - } -} - -function updatePool( - pool: Pool, - book: Book, - base: Token, - quote: Token, - baseInUSD: BigDecimal, - quoteInUSD: BigDecimal, - filledUnitAmount: BigInt, - priceRaw: BigInt, - event: ethereum.Event, -): void { - const filledBaseAmount = unitToBase(book.unitSize, filledUnitAmount, priceRaw) - const filledBaseAmountDecimal = convertTokenToDecimal( - filledBaseAmount, - base.decimals, - ) - const filledQuoteAmount = unitToQuote(book.unitSize, filledUnitAmount) - const filledQuoteAmountDecimal = convertTokenToDecimal( - filledQuoteAmount, - quote.decimals, - ) - const filledUSDAmount = calculateValueUSD( - filledQuoteAmountDecimal, - quoteInUSD, - filledBaseAmountDecimal, - baseInUSD, - ) - - const poolHourData = updatePoolHourData(pool, event) - const poolDayData = updatePoolDayData(pool, event) - - if (Address.fromBytes(pool.tokenA).equals(Address.fromBytes(book.base))) { - // ask book - pool.liquidityA = pool.liquidityA.plus(filledBaseAmount) - pool.liquidityB = pool.liquidityB.minus(filledQuoteAmount) - - pool.volumeTokenA = pool.volumeTokenA.plus(filledBaseAmountDecimal) - pool.volumeTokenB = pool.volumeTokenB.plus(filledQuoteAmountDecimal) - pool.volumeUSD = pool.volumeUSD.plus(filledUSDAmount) - - // update interval data - poolHourData.volumeTokenA = poolHourData.volumeTokenA.plus( - filledBaseAmountDecimal, - ) - poolHourData.volumeTokenB = poolHourData.volumeTokenB.plus( - filledQuoteAmountDecimal, - ) - poolHourData.volumeUSD = poolHourData.volumeUSD.plus(filledUSDAmount) - poolDayData.volumeTokenA = poolDayData.volumeTokenA.plus( - filledBaseAmountDecimal, - ) - poolDayData.volumeTokenB = poolDayData.volumeTokenB.plus( - filledQuoteAmountDecimal, - ) - poolDayData.volumeUSD = poolDayData.volumeUSD.plus(filledUSDAmount) - } else if ( - Address.fromBytes(pool.tokenB).equals(Address.fromBytes(book.base)) - ) { - // bid book - pool.liquidityA = pool.liquidityA.minus(filledQuoteAmount) - pool.liquidityB = pool.liquidityB.plus(filledBaseAmount) - - pool.volumeTokenA = pool.volumeTokenA.plus(filledQuoteAmountDecimal) - pool.volumeTokenB = pool.volumeTokenB.plus(filledBaseAmountDecimal) - pool.volumeUSD = pool.volumeUSD.plus(filledUSDAmount) - - // update interval data - poolHourData.volumeTokenA = poolHourData.volumeTokenA.plus( - filledQuoteAmountDecimal, - ) - poolHourData.volumeTokenB = poolHourData.volumeTokenB.plus( - filledBaseAmountDecimal, - ) - poolHourData.volumeUSD = poolHourData.volumeUSD.plus(filledUSDAmount) - poolDayData.volumeTokenA = poolDayData.volumeTokenA.plus( - filledQuoteAmountDecimal, - ) - poolDayData.volumeTokenB = poolDayData.volumeTokenB.plus( - filledBaseAmountDecimal, - ) - poolDayData.volumeUSD = poolDayData.volumeUSD.plus(filledUSDAmount) - } else { - log.error('[TAKE] Pool token mismatch: {} {} vs {} {}', [ - pool.tokenA.toHexString(), - pool.tokenB.toHexString(), - book.base.toHexString(), - book.quote.toHexString(), - ]) - } - - pool.save() - poolHourData.save() - poolDayData.save() -} +import { ONE_BI, ZERO_BI } from '../../common/constants' export function handleTake(event: Take): void { - const functionSignature = event.transaction.input.toHexString().slice(0, 10) - const isInternalOrderCall = - functionSignature == '0xb305b94c' || // make - functionSignature == '0x08b2c1d8' // limit - - if (isInternalOrderCall) { - updateDayData(event, 'TAKE') - } - - if (event.params.unit.isZero()) { - return - } - const tick = BigInt.fromI32(event.params.tick) - const priceRaw = tickToPrice(event.params.tick) - const book = getBookOrLog(event.params.bookId.toString(), 'TAKE') - if (book === null) { - return - } - - const depthID = event.params.bookId - .toString() + const timestamp = event.block.timestamp.toI32() + const dayID = timestamp / 86400 // rounded + const dayStartTimestamp = dayID * 86400 + let cloberDayData = CloberDayData.load(dayID.toString()) + if (cloberDayData === null) { + cloberDayData = new CloberDayData(dayID.toString()) + cloberDayData.date = dayStartTimestamp + } + + const contract = event.transaction.to + const contractInteractionDayDataId = contract + .toHexString() .concat('-') - .concat(tick.toString()) - const depth = getDepthOrLog(depthID, 'TAKE') - if (depth === null) { - return - } - - const quote = getTokenOrLog(book.quote, 'TAKE') - const base = getTokenOrLog(book.base, 'TAKE') - if (quote === null || base === null) { - return - } - - const takenUnitAmount = event.params.unit - const takenBaseAmount = unitToBase(book.unitSize, takenUnitAmount, priceRaw) - const takenBaseAmountDecimal = convertTokenToDecimal( - takenBaseAmount, - base.decimals, - ) - const protocolFeesBase = !book.isTakerFeeInQuote - ? takenBaseAmountDecimal.times(book.takerFee) - : ZERO_BD - - const takenQuoteAmount = unitToQuote(book.unitSize, takenUnitAmount) - const takenQuoteAmountDecimal = convertTokenToDecimal( - takenQuoteAmount, - quote.decimals, - ) - const protocolFeesQuote = book.isTakerFeeInQuote - ? takenQuoteAmountDecimal.times(book.takerFee) - : ZERO_BD - - // book data - book.price = formatPrice(priceRaw, base.decimals, quote.decimals) // this should be first, checked - - const quoteInUSD = getTokenUSDPriceFlat(quote) - const baseInUSD = getTokenUSDPriceFlat(base) - const amountTotalUSD = calculateValueUSD( - takenQuoteAmountDecimal, - quoteInUSD, - takenBaseAmountDecimal, - baseInUSD, - ) - const protocolFeesTotalUSD = calculateValueUSD( - protocolFeesQuote, - quoteInUSD, - protocolFeesBase, - baseInUSD, - ) - - book.priceRaw = priceRaw - book.inversePrice = formatInvertedPrice( - priceRaw, - base.decimals, - quote.decimals, - ) - book.tick = tick - book.volumeQuote = book.volumeQuote.plus(takenQuoteAmountDecimal) - book.volumeBase = book.volumeBase.plus(takenBaseAmountDecimal) - book.volumeUSD = book.volumeUSD.plus(amountTotalUSD) - book.protocolFeesQuote = book.protocolFeesQuote.plus(protocolFeesQuote) - book.protocolFeesBase = book.protocolFeesBase.plus(protocolFeesBase) - book.protocolFeesUSD = book.protocolFeesUSD.plus(protocolFeesTotalUSD) - book.totalValueLocked = book.totalValueLocked.minus(takenQuoteAmountDecimal) - book.totalValueLockedUSD = book.totalValueLocked.times(quoteInUSD) - book.lastTakenTimestamp = event.block.timestamp - book.lastTakenBlockNumber = event.block.number - - // depth data - depth.unitAmount = depth.unitAmount.minus(takenUnitAmount) - depth.quoteAmount = depth.quoteAmount.minus(takenQuoteAmount) - depth.baseAmount = depth.baseAmount.minus(takenBaseAmount) - - // quote token data - quote.priceUSD = quoteInUSD - quote.volume = quote.volume.plus(takenQuoteAmountDecimal) - quote.volumeUSD = quote.volumeUSD.plus(amountTotalUSD) - - // update quote protocol fees - quote.liquidityVaultProtocolFee = quote.liquidityVaultProtocolFee.plus( - book.isTakerFeeInQuote ? protocolFeesQuote : ZERO_BD, - ) - quote.liquidityVaultProtocolFeeUSD = quote.liquidityVaultProtocolFeeUSD.plus( - book.isTakerFeeInQuote ? protocolFeesTotalUSD : ZERO_BD, - ) - quote.protocolFees = quote.protocolFees.plus( - book.isTakerFeeInQuote ? protocolFeesQuote : ZERO_BD, - ) - quote.protocolFeesUSD = quote.protocolFeesUSD.plus( - book.isTakerFeeInQuote ? protocolFeesTotalUSD : ZERO_BD, - ) - quote.totalValueLocked = quote.totalValueLocked.minus(takenQuoteAmountDecimal) - quote.totalValueLockedUSD = quote.totalValueLocked.times(quoteInUSD) - - // base token data - base.priceUSD = baseInUSD - base.volume = base.volume.plus(takenBaseAmountDecimal) - base.volumeUSD = base.volumeUSD.plus(amountTotalUSD) - - // update base protocol fees - base.liquidityVaultProtocolFee = base.liquidityVaultProtocolFee.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesBase, - ) - base.liquidityVaultProtocolFeeUSD = base.liquidityVaultProtocolFeeUSD.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesTotalUSD, - ) - base.protocolFees = base.protocolFees.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesBase, - ) - base.protocolFeesUSD = base.protocolFeesUSD.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesTotalUSD, - ) - // note: do not update base.totalValueLocked - - // interval data - const bookDayData = updateBookDayData(book, event) - const quoteDayData = updateTokenDayData(quote, quoteInUSD, event) - const baseDayData = updateTokenDayData(base, baseInUSD, event) - - // update volume and protocol fees metrics - bookDayData.volumeQuote = bookDayData.volumeQuote.plus( - takenQuoteAmountDecimal, + .concat(dayID.toString()) + let contractInteractionDayData = ContractInteractionDayData.load( + contractInteractionDayDataId, ) - bookDayData.volumeBase = bookDayData.volumeBase.plus(takenBaseAmountDecimal) - bookDayData.volumeUSD = bookDayData.volumeUSD.plus(amountTotalUSD) - bookDayData.protocolFeesQuote = - bookDayData.protocolFeesQuote.plus(protocolFeesQuote) - bookDayData.protocolFeesBase = - bookDayData.protocolFeesBase.plus(protocolFeesBase) - bookDayData.protocolFeesUSD = - bookDayData.protocolFeesUSD.plus(protocolFeesTotalUSD) - - quoteDayData.volume = quoteDayData.volume.plus(takenQuoteAmountDecimal) - quoteDayData.volumeUSD = quoteDayData.volumeUSD.plus(amountTotalUSD) - - // update quote protocol fees - quoteDayData.liquidityVaultProtocolFee = - quoteDayData.liquidityVaultProtocolFee.plus( - book.isTakerFeeInQuote ? protocolFeesQuote : ZERO_BD, - ) - quoteDayData.liquidityVaultProtocolFeeUSD = - quoteDayData.liquidityVaultProtocolFeeUSD.plus( - book.isTakerFeeInQuote ? protocolFeesTotalUSD : ZERO_BD, - ) - quoteDayData.protocolFees = quoteDayData.protocolFees.plus( - book.isTakerFeeInQuote ? protocolFeesQuote : ZERO_BD, - ) - quoteDayData.protocolFeesUSD = quoteDayData.protocolFeesUSD.plus( - book.isTakerFeeInQuote ? protocolFeesTotalUSD : ZERO_BD, - ) - - baseDayData.volume = baseDayData.volume.plus(takenBaseAmountDecimal) - baseDayData.volumeUSD = baseDayData.volumeUSD.plus(amountTotalUSD) - - // update base protocol fees - baseDayData.liquidityVaultProtocolFee = - baseDayData.liquidityVaultProtocolFee.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesBase, - ) - baseDayData.liquidityVaultProtocolFeeUSD = - baseDayData.liquidityVaultProtocolFeeUSD.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesTotalUSD, - ) - baseDayData.protocolFees = baseDayData.protocolFees.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesBase, - ) - baseDayData.protocolFeesUSD = baseDayData.protocolFeesUSD.plus( - book.isTakerFeeInQuote ? ZERO_BD : protocolFeesTotalUSD, - ) - - if (!SKIP_CHART) { - updateChart( - event.block, - takenBaseAmountDecimal, - takenQuoteAmountDecimal, - book, - base, - quote, + if (contractInteractionDayData === null) { + contractInteractionDayData = new ContractInteractionDayData( + contractInteractionDayDataId, ) + contractInteractionDayData.date = dayStartTimestamp + contractInteractionDayData.contract = contract + contractInteractionDayData.callCount = ZERO_BI } - const take = new TakeEntity( - event.transaction.hash - .toHexString() - .concat('-') - .concat(event.logIndex.toString()), - ) - take.transaction = event.transaction.hash.toHexString() - take.timestamp = event.block.timestamp - take.inputToken = book.base - take.outputToken = book.quote - take.book = book.id - take.origin = event.transaction.from - take.inputAmount = takenBaseAmount - take.outputAmount = takenQuoteAmount - take.amountUSD = amountTotalUSD - take.logIndex = event.logIndex - if (!SKIP_TAKE_AND_SWAP) { - take.save() - } - - let currentOrderIndex = depth.latestTakenOrderIndex - let remainingTakenUnitAmount = takenUnitAmount - while (remainingTakenUnitAmount.gt(ZERO_BI)) { - const orderID = encodeOrderID(book.id, tick, currentOrderIndex) - const openOrder = OpenOrder.load(orderID.toString()) - if (openOrder === null) { - currentOrderIndex = currentOrderIndex.plus(ONE_BI) - // mathematically, continue is correct, - // but due to an issue on a specific testnet where events are duplicated or missing, - // it could cause an infinite loop, so changed to break - continue - } - - const openOrderRemainingUnitAmount = openOrder.unitAmount.minus( - openOrder.filledUnitAmount, - ) - let filledUnitAmount = ZERO_BI - if (remainingTakenUnitAmount.lt(openOrderRemainingUnitAmount)) { - filledUnitAmount = remainingTakenUnitAmount - } else { - filledUnitAmount = openOrderRemainingUnitAmount - } - - remainingTakenUnitAmount = remainingTakenUnitAmount.minus(filledUnitAmount) - - fillOpenOrder(openOrder, book.unitSize, filledUnitAmount) - - if ( - book.pool !== null && - Address.fromBytes(openOrder.owner).equals( - Address.fromString(LIQUIDITY_VAULT), - ) - ) { - const pool = getPoolOrLog(book.pool!, 'TAKE') - if (pool) { - updatePool( - pool, - book, - base, - quote, - baseInUSD, - quoteInUSD, - filledUnitAmount, - priceRaw, - event, - ) - } - } - - if (openOrder.unitAmount.equals(openOrder.filledUnitAmount)) { - currentOrderIndex = currentOrderIndex.plus(ONE_BI) - } - } - - if (quoteInUSD.gt(ZERO_BD)) { - updateUserDayVolume(quote, event, takenQuoteAmountDecimal, amountTotalUSD) - } else if (baseInUSD.gt(ZERO_BD)) { - updateUserDayVolume(base, event, takenBaseAmountDecimal, amountTotalUSD) - } - updateUserNativeVolume( - event, - take.inputToken, - take.outputToken, - take.inputAmount, - take.outputAmount, - ) - depth.latestTakenOrderIndex = currentOrderIndex - depth.save() - book.save() - quote.save() - base.save() - bookDayData.save() - quoteDayData.save() - baseDayData.save() - // openOrder.save() // already saved in fillOpenOrder - // chartLog.save() // already saved in updateChart - // invertedChartLog.save() // already saved in updateChart + contractInteractionDayData.callCount = + contractInteractionDayData.callCount.plus(ONE_BI) + contractInteractionDayData.save() } diff --git a/src/mappings/book-manager/transfer.ts b/src/mappings/book-manager/transfer.ts deleted file mode 100644 index e5237ff..0000000 --- a/src/mappings/book-manager/transfer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Address } from '@graphprotocol/graph-ts' - -import { Transfer } from '../../../generated/BookManager/BookManager' -import { ADDRESS_ZERO } from '../../common/constants' -import { getOpenOrderOrLog } from '../../common/entity-getters' -import { updateDayData } from '../interval-updates' -import { OPERATOR } from '../../common/chain' - -export function handleTransfer(event: Transfer): void { - if ( - event.transaction.to && - !event.transaction.to!.equals(Address.fromString(OPERATOR)) - ) { - updateDayData(event, 'TRANSFER') - } - - const from = event.params.from - const to = event.params.to - const orderID = event.params.tokenId - - if (from.toHexString() == ADDRESS_ZERO || to.toHexString() == ADDRESS_ZERO) { - // mint or burn events are handled in the make, cancel, and claim events - return - } - - const openOrder = getOpenOrderOrLog(orderID.toString(), 'TRANSFER') - if (openOrder === null) { - return - } - - openOrder.owner = to - openOrder.save() -} diff --git a/src/mappings/core.ts b/src/mappings/core.ts index 61becf8..a4ead35 100644 --- a/src/mappings/core.ts +++ b/src/mappings/core.ts @@ -1,25 +1,3 @@ -import { handleBookOpen } from './book-manager/open' -import { handleMake } from './book-manager/make' import { handleTake } from './book-manager/take' -import { handleTransfer as handleBookManagerTransfer } from './book-manager/transfer' -import { handleCancel } from './book-manager/cancel' -import { handleClaim } from './book-manager/claim' -import { handlePoolOpen } from './liquidity-vault/open' -import { handleMint } from './liquidity-vault/mint' -import { handleBurn } from './liquidity-vault/burn' -import { handleUpdatePosition } from './liquidity-vault/strategy' -import { handleTransfer as handleLiquidityVaultTransfer } from './liquidity-vault/transfer' -export { - handleBookOpen, - handleMake, - handleTake, - handleBookManagerTransfer, - handleCancel, - handleClaim, - handlePoolOpen, - handleMint, - handleBurn, - handleUpdatePosition, - handleLiquidityVaultTransfer, -} +export { handleTake } diff --git a/src/mappings/interval-updates.ts b/src/mappings/interval-updates.ts deleted file mode 100644 index 97d8426..0000000 --- a/src/mappings/interval-updates.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { - Address, - BigDecimal, - BigInt, - Bytes, - ethereum, -} from '@graphprotocol/graph-ts' - -import { - Book, - BookDayData, - CloberDayData, - Pool, - PoolDayData, - PoolHourData, - Token, - TokenDayData, - Transaction, - TransactionTypeDayData, - User, - UserDayData, - UserDayVolume, -} from '../../generated/schema' -import { - ADDRESS_ZERO, - BI_18, - ONE_BI, - ZERO_BD, - ZERO_BI, -} from '../common/constants' -import { - getOrCreateTransaction, - getOrCreateUserByFrom, -} from '../common/entity-getters' -import { - REFERENCE_TOKEN, - SKIP_TX_ANALYTICS, - SKIP_USER_ANALYTICS, -} from '../common/chain' -import { convertTokenToDecimal } from '../common/utils' - -/** - * Tracks global aggregate data over daily windows - * @param event - * @param eventType - */ -export function updateDayData(event: ethereum.Event, eventType: string): void { - const functionSignature = event.transaction.input.toHexString().slice(0, 10) - - const timestamp = event.block.timestamp.toI32() - const dayID = timestamp / 86400 // rounded - const dayStartTimestamp = dayID * 86400 - let cloberDayData = CloberDayData.load(dayID.toString()) - if (cloberDayData === null) { - cloberDayData = new CloberDayData(dayID.toString()) - cloberDayData.date = dayStartTimestamp - cloberDayData.txCount = ZERO_BI - cloberDayData.walletCount = ZERO_BI - cloberDayData.newWalletCount = ZERO_BI - } - - const user = event.transaction.from.toHexString() - const userDayDataId = user.concat('-').concat(dayID.toString()) - let userDayData = UserDayData.load(userDayDataId) - if (userDayData === null) { - userDayData = new UserDayData(userDayDataId) - userDayData.date = dayStartTimestamp - userDayData.user = Address.fromString(user) - userDayData.txCount = ZERO_BI - - // increment the wallet count on the clober day data - cloberDayData.walletCount = cloberDayData.walletCount.plus(ONE_BI) - } - - const txDayID = functionSignature.concat('-').concat(dayID.toString()) - let txTypeDayData = TransactionTypeDayData.load(txDayID) - if (txTypeDayData === null) { - txTypeDayData = new TransactionTypeDayData(txDayID) - txTypeDayData.date = dayStartTimestamp - txTypeDayData.cloberDayData = cloberDayData.id - txTypeDayData.type = functionSignature - txTypeDayData.txCount = ZERO_BI - } - - if (!SKIP_USER_ANALYTICS && User.load(Address.fromString(user)) === null) { - cloberDayData.newWalletCount = cloberDayData.newWalletCount.plus(ONE_BI) - - getOrCreateUserByFrom(event) - } - - if ( - !SKIP_TX_ANALYTICS && - Transaction.load(event.transaction.hash.toHexString()) === null - ) { - userDayData.txCount = userDayData.txCount.plus(ONE_BI) - cloberDayData.txCount = cloberDayData.txCount.plus(ONE_BI) - txTypeDayData.txCount = txTypeDayData.txCount.plus(ONE_BI) - - getOrCreateTransaction(event) - } - - cloberDayData.save() - if (!SKIP_USER_ANALYTICS) { - userDayData.save() - } - if (!SKIP_TX_ANALYTICS) { - txTypeDayData.save() - } -} - -export function updateUserNativeVolume( - event: ethereum.Event, - inputToken: Bytes, - outputToken: Bytes, - inputAmount: BigInt, - outputAmount: BigInt, -): void { - if (SKIP_USER_ANALYTICS) { - return - } - const isInputNative = inputToken.toHexString() == ADDRESS_ZERO - const isOutputNative = outputToken.toHexString() == ADDRESS_ZERO - const isInputReference = inputToken.toHexString() == REFERENCE_TOKEN - const isOutputReference = outputToken.toHexString() == REFERENCE_TOKEN - const isWrapOrUnwrap = - (isInputNative && isOutputReference) || (isOutputNative && isInputReference) - const isNativeTx = isInputNative || isOutputNative - - if (!isNativeTx || isWrapOrUnwrap) { - return - } - const nativeAmount = isInputNative - ? convertTokenToDecimal(inputAmount, BI_18) - : convertTokenToDecimal(outputAmount, BI_18) - const user = getOrCreateUserByFrom(event) - user.nativeVolume = user.nativeVolume.plus(nativeAmount) - user.save() -} - -export function updateUserDayVolume( - token: Token, - event: ethereum.Event, - volume: BigDecimal, - volumeUSD: BigDecimal, -): void { - if (SKIP_USER_ANALYTICS) { - return - } - const timestamp = event.block.timestamp.toI32() - const dayID = timestamp / 86400 // rounded - const dayStartTimestamp = dayID * 86400 - const user = event.transaction.from.toHexString() - const userDayDataId = user.concat('-').concat(dayID.toString()) - const userDayVolumeID = user - .concat('-') - .concat(token.id.toHexString()) - .concat('-') - .concat(dayID.toString()) - let userDayVolume = UserDayVolume.load(userDayVolumeID) - if (userDayVolume === null) { - userDayVolume = new UserDayVolume(userDayVolumeID) - userDayVolume.date = dayStartTimestamp - userDayVolume.user = Address.fromString(user) - userDayVolume.userDayData = userDayDataId - userDayVolume.token = token.id - userDayVolume.volume = ZERO_BD - userDayVolume.volumeUSD = ZERO_BD - } - userDayVolume.volume = userDayVolume.volume.plus(volume) - userDayVolume.volumeUSD = userDayVolume.volumeUSD.plus(volumeUSD) - userDayVolume.save() -} - -export function updateBookDayData( - book: Book, - event: ethereum.Event, -): BookDayData { - const timestamp = event.block.timestamp.toI32() - const dayID = timestamp / 86400 - const dayStartTimestamp = dayID * 86400 - const dayBookID = book.id.toString().concat('-').concat(dayID.toString()) - let bookDayData = BookDayData.load(dayBookID) - if (bookDayData === null) { - bookDayData = new BookDayData(dayBookID) - bookDayData.date = dayStartTimestamp - bookDayData.book = book.id - // things that dont get initialized always - bookDayData.volumeQuote = ZERO_BD - bookDayData.volumeBase = ZERO_BD - bookDayData.volumeUSD = ZERO_BD - bookDayData.protocolFeesQuote = ZERO_BD - bookDayData.protocolFeesBase = ZERO_BD - bookDayData.protocolFeesUSD = ZERO_BD - bookDayData.open = book.price - bookDayData.high = book.price - bookDayData.low = book.price - bookDayData.close = book.price - } - - if (book.price.gt(bookDayData.high)) { - bookDayData.high = book.price - } - if (book.price.lt(bookDayData.low)) { - bookDayData.low = book.price - } - - bookDayData.price = book.price - bookDayData.close = book.price - bookDayData.inversePrice = book.inversePrice - bookDayData.totalValueLocked = book.totalValueLocked - bookDayData.totalValueLockedUSD = book.totalValueLockedUSD - bookDayData.save() - - return bookDayData as BookDayData -} - -export function updateTokenDayData( - token: Token, - tokenPrice: BigDecimal, - event: ethereum.Event, -): TokenDayData { - const timestamp = event.block.timestamp.toI32() - const dayID = timestamp / 86400 - const dayStartTimestamp = dayID * 86400 - const tokenDayID = Address.fromBytes(token.id) - .toHexString() - .concat('-') - .concat(dayID.toString()) - - let tokenDayData = TokenDayData.load(tokenDayID) - if (tokenDayData === null) { - tokenDayData = new TokenDayData(tokenDayID) - tokenDayData.date = dayStartTimestamp - tokenDayData.token = token.id - tokenDayData.cloberDayData = dayID.toString() - // things that dont get initialized always - tokenDayData.volume = ZERO_BD - tokenDayData.volumeUSD = ZERO_BD - - tokenDayData.liquidityVaultProtocolFee = ZERO_BD - tokenDayData.liquidityVaultProtocolFeeUSD = ZERO_BD - tokenDayData.routerGatewayProtocolFee = ZERO_BD - tokenDayData.routerGatewayProtocolFeeUSD = ZERO_BD - tokenDayData.protocolFees = ZERO_BD - tokenDayData.protocolFeesUSD = ZERO_BD - - tokenDayData.open = tokenPrice - tokenDayData.high = tokenPrice - tokenDayData.low = tokenPrice - tokenDayData.close = tokenPrice - } - - if (tokenPrice.gt(tokenDayData.high)) { - tokenDayData.high = tokenPrice - } - - if (tokenPrice.lt(tokenDayData.low)) { - tokenDayData.low = tokenPrice - } - - tokenDayData.totalValueLocked = token.totalValueLocked - tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD - tokenDayData.priceUSD = tokenPrice - tokenDayData.close = tokenPrice - tokenDayData.save() - - return tokenDayData as TokenDayData -} - -export function updatePoolDayData( - pool: Pool, - event: ethereum.Event, -): PoolDayData { - const timestamp = event.block.timestamp.toI32() - const dayID = timestamp / 86400 - const dayStartTimestamp = dayID * 86400 - const tokenDayID = pool.id.toHexString().concat('-').concat(dayID.toString()) - - let poolDayData = PoolDayData.load(tokenDayID) - if (poolDayData === null) { - poolDayData = new PoolDayData(tokenDayID) - poolDayData.date = dayStartTimestamp - poolDayData.pool = pool.id - // things that dont get initialized always - poolDayData.volumeTokenA = ZERO_BD - poolDayData.volumeTokenB = ZERO_BD - poolDayData.volumeUSD = ZERO_BD - poolDayData.protocolFeesTokenA = ZERO_BD - poolDayData.protocolFeesTokenB = ZERO_BD - poolDayData.protocolFeesAUSD = ZERO_BD - poolDayData.protocolFeesBUSD = ZERO_BD - poolDayData.spreadProfitUSD = ZERO_BD - poolDayData.totalValueLockedUSD = ZERO_BD - } - poolDayData.oraclePrice = pool.oraclePrice - poolDayData.totalSupply = pool.totalSupply - poolDayData.liquidityA = pool.liquidityA - poolDayData.liquidityB = pool.liquidityB - poolDayData.lpPriceUSD = pool.lpPriceUSD - poolDayData.priceA = pool.priceA - poolDayData.priceARaw = pool.priceARaw - poolDayData.tickA = pool.tickA - poolDayData.priceB = pool.priceB - poolDayData.priceBRaw = pool.priceBRaw - poolDayData.tickB = pool.tickB - poolDayData.totalValueLockedUSD = pool.totalValueLockedUSD - poolDayData.save() - - return poolDayData as PoolDayData -} - -export function updatePoolHourData( - pool: Pool, - event: ethereum.Event, -): PoolHourData { - const timestamp = event.block.timestamp.toI32() - const hourIndex = timestamp / 3600 // get unique hour within unix history - const hourStartUnix = hourIndex * 3600 // want the rounded effect - const tokenHourID = pool.id - .toHexString() - .concat('-') - .concat(hourIndex.toString()) - - let poolHourData = PoolHourData.load(tokenHourID) - if (poolHourData === null) { - poolHourData = new PoolHourData(tokenHourID) - poolHourData.date = hourStartUnix - poolHourData.pool = pool.id - // things that dont get initialized always - poolHourData.volumeTokenA = ZERO_BD - poolHourData.volumeTokenB = ZERO_BD - poolHourData.volumeUSD = ZERO_BD - poolHourData.protocolFeesTokenA = ZERO_BD - poolHourData.protocolFeesTokenB = ZERO_BD - poolHourData.protocolFeesAUSD = ZERO_BD - poolHourData.protocolFeesBUSD = ZERO_BD - poolHourData.spreadProfitUSD = ZERO_BD - poolHourData.totalValueLockedUSD = ZERO_BD - } - poolHourData.oraclePrice = pool.oraclePrice - poolHourData.totalSupply = pool.totalSupply - poolHourData.liquidityA = pool.liquidityA - poolHourData.liquidityB = pool.liquidityB - poolHourData.lpPriceUSD = pool.lpPriceUSD - poolHourData.priceA = pool.priceA - poolHourData.priceARaw = pool.priceARaw - poolHourData.tickA = pool.tickA - poolHourData.priceB = pool.priceB - poolHourData.priceBRaw = pool.priceBRaw - poolHourData.tickB = pool.tickB - poolHourData.totalValueLockedUSD = pool.totalValueLockedUSD - poolHourData.save() - - return poolHourData as PoolHourData -} diff --git a/src/mappings/liquidity-vault/burn.ts b/src/mappings/liquidity-vault/burn.ts deleted file mode 100644 index 41d67ca..0000000 --- a/src/mappings/liquidity-vault/burn.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - getOrCreateUserPoolBalance, - getPoolOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { BI_18, ZERO_BD, ZERO_BI } from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { - updateDayData, - updatePoolDayData, - updatePoolHourData, - updateTokenDayData, -} from '../interval-updates' -import { getTokenUSDPriceFlat } from '../../common/pricing' -import { Burn } from '../../../generated/LiquidityVault/LiquidityVault' - -export function handleBurn(event: Burn): void { - updateDayData(event, 'BURN') - - const pool = getPoolOrLog(event.params.key, 'BURN') - if (!pool || event.params.lpAmount.equals(ZERO_BI)) { - return - } - - const tokenA = getTokenOrLog(pool.tokenA, 'BURN') - const tokenB = getTokenOrLog(pool.tokenB, 'BURN') - - if (tokenA && tokenB) { - const feeAInDecimals = convertTokenToDecimal( - event.params.feeA, - tokenA.decimals, - ) - const priceAUSD = getTokenUSDPriceFlat(tokenA) - const feeAInUSD = priceAUSD.times(feeAInDecimals) - const feeBInDecimals = convertTokenToDecimal( - event.params.feeB, - tokenB.decimals, - ) - const priceBUSD = getTokenUSDPriceFlat(tokenB) - const feeBInUSD = priceBUSD.times(feeBInDecimals) - - // update pool state - pool.totalSupply = pool.totalSupply.minus(event.params.lpAmount) - pool.liquidityA = pool.liquidityA.minus(event.params.amountA) - pool.liquidityB = pool.liquidityB.minus(event.params.amountB) - pool.protocolFeesTokenA = pool.protocolFeesTokenA.plus(feeAInDecimals) - pool.protocolFeesTokenB = pool.protocolFeesTokenB.plus(feeBInDecimals) - pool.protocolFeesAUSD = pool.protocolFeesAUSD.plus(feeAInUSD) - pool.protocolFeesBUSD = pool.protocolFeesBUSD.plus(feeBInUSD) - - const lpAmountDecimal = convertTokenToDecimal( - pool.totalSupply, - BI_18, // assuming LP token has 18 decimals - ) - if (lpAmountDecimal.gt(ZERO_BD)) { - const liquidityAInUSD = convertTokenToDecimal( - pool.liquidityA, - tokenA.decimals, - ).times(priceAUSD) - const liquidityBInUSD = convertTokenToDecimal( - pool.liquidityB, - tokenB.decimals, - ).times(priceBUSD) - pool.lpPriceUSD = liquidityAInUSD - .plus(liquidityBInUSD) - .div(lpAmountDecimal) - pool.totalValueLockedUSD = lpAmountDecimal.times(pool.lpPriceUSD) - } else { - pool.lpPriceUSD = ZERO_BD - pool.totalValueLockedUSD = ZERO_BD - } - - const userPoolBalance = getOrCreateUserPoolBalance( - event.transaction.from, - pool.id, - event, - ) - - userPoolBalance.totalTokenADeposited = - userPoolBalance.totalTokenADeposited.minus(event.params.amountA) - userPoolBalance.totalTokenBDeposited = - userPoolBalance.totalTokenBDeposited.minus(event.params.amountB) - userPoolBalance.save() - - // @dev: To calculate the protocol's TVL, we need token.totalValueLocked + pool.totalValueLockedUSD - // since, reducing totalValueLocked twice (cancel -> burn) - // tokenA.totalValueLocked = tokenA.totalValueLocked.minus(amountAInDecimals) - // tokenA.totalValueLockedUSD = tokenA.totalValueLocked.times(priceAUSD) - // tokenB.totalValueLocked = tokenB.totalValueLocked.minus(amountBInDecimals) - // tokenB.totalValueLockedUSD = tokenB.totalValueLocked.times(priceBUSD) - - // update interval - const poolHourData = updatePoolHourData(pool, event) - const poolDayData = updatePoolDayData(pool, event) - const tokenADayData = updateTokenDayData(tokenA, priceAUSD, event) - const tokenBDayData = updateTokenDayData(tokenB, priceBUSD, event) - - poolHourData.protocolFeesTokenA = - poolHourData.protocolFeesTokenA.plus(feeAInDecimals) - poolHourData.protocolFeesTokenB = - poolHourData.protocolFeesTokenB.plus(feeBInDecimals) - poolHourData.protocolFeesAUSD = - poolHourData.protocolFeesAUSD.plus(feeAInUSD) - poolHourData.protocolFeesBUSD = - poolHourData.protocolFeesBUSD.plus(feeBInUSD) - - poolDayData.protocolFeesTokenA = - poolDayData.protocolFeesTokenA.plus(feeAInDecimals) - poolDayData.protocolFeesTokenB = - poolDayData.protocolFeesTokenB.plus(feeBInDecimals) - poolDayData.protocolFeesAUSD = poolDayData.protocolFeesAUSD.plus(feeAInUSD) - poolDayData.protocolFeesBUSD = poolDayData.protocolFeesBUSD.plus(feeBInUSD) - - tokenADayData.protocolFees = tokenADayData.protocolFees.plus(feeAInDecimals) - tokenADayData.protocolFeesUSD = - tokenADayData.protocolFeesUSD.plus(feeAInUSD) - - tokenBDayData.protocolFees = tokenBDayData.protocolFees.plus(feeBInDecimals) - tokenBDayData.protocolFeesUSD = - tokenBDayData.protocolFeesUSD.plus(feeBInUSD) - - poolHourData.save() - poolDayData.save() - tokenADayData.save() - tokenBDayData.save() - pool.save() - } -} diff --git a/src/mappings/liquidity-vault/mint.ts b/src/mappings/liquidity-vault/mint.ts deleted file mode 100644 index e46649c..0000000 --- a/src/mappings/liquidity-vault/mint.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - getOrCreateTransaction, - getOrCreateUserPoolBalance, - getPoolOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { BI_18, ZERO_BI } from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { - updateDayData, - updatePoolDayData, - updatePoolHourData, -} from '../interval-updates' -import { getTokenUSDPriceFlat } from '../../common/pricing' -import { Mint } from '../../../generated/LiquidityVault/LiquidityVault' - -export function handleMint(event: Mint): void { - updateDayData(event, 'MINT') - - const pool = getPoolOrLog(event.params.key, 'MINT') - if (!pool || event.params.lpAmount.equals(ZERO_BI)) { - return - } - - const tokenA = getTokenOrLog(pool.tokenA, 'MINT') - const tokenB = getTokenOrLog(pool.tokenB, 'MINT') - - if (tokenA && tokenB) { - const priceAUSD = getTokenUSDPriceFlat(tokenA) - const priceBUSD = getTokenUSDPriceFlat(tokenB) - - if (pool.initialTokenAAmount.isZero()) { - pool.initialTokenAAmount = event.params.amountA - } - if (pool.initialTokenBAmount.isZero()) { - pool.initialTokenBAmount = event.params.amountB - } - if (pool.initialTotalSupply.isZero()) { - pool.initialTotalSupply = event.params.lpAmount - pool.initialMintTransaction = getOrCreateTransaction(event).id - } - - // update pool state - pool.totalSupply = pool.totalSupply.plus(event.params.lpAmount) - pool.liquidityA = pool.liquidityA.plus(event.params.amountA) - pool.liquidityB = pool.liquidityB.plus(event.params.amountB) - - const lpAmountDecimal = convertTokenToDecimal( - pool.totalSupply, - BI_18, // assuming LP token has 18 decimals - ) - const liquidityAInUSD = convertTokenToDecimal( - pool.liquidityA, - tokenA.decimals, - ).times(priceAUSD) - const liquidityBInUSD = convertTokenToDecimal( - pool.liquidityB, - tokenB.decimals, - ).times(priceBUSD) - pool.lpPriceUSD = liquidityAInUSD.plus(liquidityBInUSD).div(lpAmountDecimal) - pool.totalValueLockedUSD = lpAmountDecimal.times(pool.lpPriceUSD) - - const userPoolBalance = getOrCreateUserPoolBalance( - event.transaction.from, - pool.id, - event, - ) - - userPoolBalance.totalTokenADeposited = - userPoolBalance.totalTokenADeposited.plus(event.params.amountA) - userPoolBalance.totalTokenBDeposited = - userPoolBalance.totalTokenBDeposited.plus(event.params.amountB) - userPoolBalance.save() - - // @dev: To calculate the protocol's TVL, we need token.totalValueLocked + pool.totalValueLockedUSD - // tokenA.totalValueLocked = tokenA.totalValueLocked.plus(amountAInDecimals) - // tokenA.totalValueLockedUSD = tokenA.totalValueLocked.times(priceAUSD) - // tokenB.totalValueLocked = tokenB.totalValueLocked.plus(amountBInDecimals) - // tokenB.totalValueLockedUSD = tokenB.totalValueLocked.times(priceBUSD) - - // update interval - updatePoolHourData(pool, event) - updatePoolDayData(pool, event) - - pool.save() - } -} diff --git a/src/mappings/liquidity-vault/open.ts b/src/mappings/liquidity-vault/open.ts deleted file mode 100644 index 9ef26f0..0000000 --- a/src/mappings/liquidity-vault/open.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Open } from '../../../generated/LiquidityVault/LiquidityVault' -import { - getBookOrLog, - getOrCreateTransaction, -} from '../../common/entity-getters' -import { Pool } from '../../../generated/schema' -import { ZERO_BD, ZERO_BI } from '../../common/constants' - -export function handlePoolOpen(event: Open): void { - const bookA = getBookOrLog(event.params.bookIdA.toString(), 'OPEN') - const bookB = getBookOrLog(event.params.bookIdB.toString(), 'OPEN') - if (bookA && bookB) { - const pool = new Pool(event.params.key) - pool.salt = event.params.salt - pool.strategy = event.params.strategy - pool.createdAtTimestamp = event.block.timestamp - pool.createdAtBlockNumber = event.block.number - pool.createdAtTransaction = getOrCreateTransaction(event).id - pool.initialTokenAAmount = ZERO_BI - pool.initialTokenBAmount = ZERO_BI - pool.initialTotalSupply = ZERO_BI - pool.initialLPPriceUSD = ZERO_BD - pool.tokenA = bookA.quote - pool.tokenB = bookB.quote - pool.bookA = bookA.id - pool.bookB = bookB.id - - pool.oraclePrice = ZERO_BI - pool.totalSupply = ZERO_BI - pool.liquidityA = ZERO_BI - pool.liquidityB = ZERO_BI - pool.lpPriceUSD = ZERO_BD - pool.priceA = ZERO_BD - pool.priceARaw = ZERO_BI - pool.tickA = ZERO_BI - pool.priceB = ZERO_BD - pool.priceBRaw = ZERO_BI - pool.tickB = ZERO_BI - pool.volumeTokenA = ZERO_BD - pool.volumeTokenB = ZERO_BD - pool.volumeUSD = ZERO_BD - pool.protocolFeesTokenA = ZERO_BD - pool.protocolFeesTokenB = ZERO_BD - pool.protocolFeesAUSD = ZERO_BD - pool.protocolFeesBUSD = ZERO_BD - pool.spreadProfitUSD = ZERO_BD - pool.totalValueLockedUSD = ZERO_BD - - // bind book to pool - bookA.pool = pool.id - bookB.pool = pool.id - - pool.save() - bookA.save() - bookB.save() - } -} diff --git a/src/mappings/liquidity-vault/strategy.ts b/src/mappings/liquidity-vault/strategy.ts deleted file mode 100644 index 09bbca9..0000000 --- a/src/mappings/liquidity-vault/strategy.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Address, BigInt } from '@graphprotocol/graph-ts' - -import { getPoolOrLog, getTokenOrLog } from '../../common/entity-getters' -import { - formatInvertedPrice, - formatPrice, - tickToPrice, -} from '../../common/tick' -import { BI_18, BI_8, ONE_BD, ZERO_BD, ZERO_BI } from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { UpdatePosition } from '../../../generated/SimpleOracleStrategy/SimpleOracleStrategy' -import { isStableCoin } from '../../common/token' - -export function handleUpdatePosition(event: UpdatePosition): void { - const pool = getPoolOrLog(event.params.key, 'UPDATE_POSITION') - if (!pool) { - return - } - const tokenA = getTokenOrLog(pool.tokenA, 'UPDATE_POSITION') - const tokenB = getTokenOrLog(pool.tokenB, 'UPDATE_POSITION') - - if (tokenA && tokenB) { - pool.oraclePrice = event.params.oraclePrice - - pool.tickA = BigInt.fromI32(event.params.tickA) - pool.priceARaw = tickToPrice(event.params.tickA) - pool.priceA = formatPrice(pool.priceARaw, tokenB.decimals, tokenA.decimals) - - pool.tickB = BigInt.fromI32(event.params.tickB) - pool.priceBRaw = tickToPrice(event.params.tickB) - pool.priceB = formatInvertedPrice( - pool.priceBRaw, - tokenA.decimals, - tokenB.decimals, - ) - - const tokenAUSDPrice = isStableCoin(Address.fromBytes(tokenA.id)) - ? ONE_BD - : convertTokenToDecimal(event.params.oraclePrice, BI_8) - const tokenBUSDPrice = isStableCoin(Address.fromBytes(tokenB.id)) - ? ONE_BD - : convertTokenToDecimal(event.params.oraclePrice, BI_8) - const initialLpAmountDecimal = convertTokenToDecimal( - pool.initialTotalSupply, - BI_18, // assuming LP token has 18 decimals - ) - if ( - pool.initialLPPriceUSD.equals(ZERO_BD) && - initialLpAmountDecimal.gt(ZERO_BD) && - pool.initialTokenAAmount.gt(ZERO_BI) && - pool.initialTokenBAmount.gt(ZERO_BI) - ) { - const amountAInUSD = convertTokenToDecimal( - pool.initialTokenAAmount, - tokenA.decimals, - ).times(tokenAUSDPrice) - const amountBInUSD = convertTokenToDecimal( - pool.initialTokenBAmount, - tokenB.decimals, - ).times(tokenBUSDPrice) - pool.initialLPPriceUSD = amountAInUSD - .plus(amountBInUSD) - .div(initialLpAmountDecimal) - } - - const lpAmountDecimal = convertTokenToDecimal( - pool.totalSupply, - BI_18, // assuming LP token has 18 decimals - ) - if (lpAmountDecimal.gt(ZERO_BD)) { - const amountAInUSD = convertTokenToDecimal( - pool.liquidityA, - tokenA.decimals, - ).times(tokenAUSDPrice) - const amountBInUSD = convertTokenToDecimal( - pool.liquidityB, - tokenB.decimals, - ).times(tokenBUSDPrice) - pool.lpPriceUSD = amountAInUSD.plus(amountBInUSD).div(lpAmountDecimal) - pool.totalValueLockedUSD = pool.lpPriceUSD.times(lpAmountDecimal) - } - - pool.save() - } -} diff --git a/src/mappings/liquidity-vault/transfer.ts b/src/mappings/liquidity-vault/transfer.ts deleted file mode 100644 index 4769853..0000000 --- a/src/mappings/liquidity-vault/transfer.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - store, - BigDecimal, - Bytes, - BigInt, - Address, -} from '@graphprotocol/graph-ts' - -import { Transfer } from '../../../generated/LiquidityVault/LiquidityVault' -import { updateDayData } from '../interval-updates' -import { - getOrCreateUserPoolBalance, - getPoolOrLog, - getTokenOrLog, -} from '../../common/entity-getters' -import { - ADDRESS_ZERO, - BI_18, - BI_8, - ONE_BD, - ZERO_BD, - ZERO_BI, -} from '../../common/constants' -import { convertTokenToDecimal } from '../../common/utils' -import { UserPoolBalance } from '../../../generated/schema' -import { isStableCoin } from '../../common/token' - -function buyLpToken( - userPoolBalance: UserPoolBalance, - amount: BigInt, - lpPriceUSD: BigDecimal, -): void { - const costToAdd = convertTokenToDecimal(amount, BI_18).times(lpPriceUSD) - userPoolBalance.lpBalance = userPoolBalance.lpBalance.plus(amount) - userPoolBalance.costBasisUSD = userPoolBalance.costBasisUSD.plus(costToAdd) - - const lpBalanceBD = convertTokenToDecimal(userPoolBalance.lpBalance, BI_18) - userPoolBalance.lpBalanceUSD = lpBalanceBD.times(lpPriceUSD) - - userPoolBalance.averageLPPriceUSD = userPoolBalance.lpBalance.gt(ZERO_BI) - ? userPoolBalance.costBasisUSD.div(lpBalanceBD) - : ZERO_BD - - if (userPoolBalance.lpBalance.equals(ZERO_BI)) { - store.remove('UserPoolBalance', userPoolBalance.id) - } else { - userPoolBalance.save() - } -} - -function sellLpToken( - userPoolBalance: UserPoolBalance, - amount: BigInt, - lpPriceUSD: BigDecimal, -): void { - userPoolBalance.lpBalance = userPoolBalance.lpBalance.minus(amount) - userPoolBalance.lpBalanceUSD = convertTokenToDecimal( - userPoolBalance.lpBalance, - BI_18, - ).times(lpPriceUSD) - - if (userPoolBalance.lpBalance.equals(ZERO_BI)) { - store.remove('UserPoolBalance', userPoolBalance.id) - } else { - userPoolBalance.save() - } -} - -export function handleTransfer(event: Transfer): void { - updateDayData(event, 'TRANSFER') - - const key = Bytes.fromHexString( - '0x' + event.params.id.toHexString().slice(2).padStart(64, '0'), - ) - const pool = getPoolOrLog(key, 'TRANSFER') - if ( - !pool || - event.params.amount.equals(ZERO_BI) || - event.params.from.equals(event.params.to) - ) { - return - } - - const tokenA = getTokenOrLog(pool.tokenA, 'TRANSFER') - const tokenB = getTokenOrLog(pool.tokenB, 'TRANSFER') - if (!tokenA || !tokenB) { - return - } - - const oraclePrice = convertTokenToDecimal(pool.oraclePrice, BI_8) - const tokenAUSDPrice = isStableCoin(Address.fromBytes(tokenA.id)) - ? ONE_BD - : oraclePrice - const tokenBUSDPrice = isStableCoin(Address.fromBytes(tokenB.id)) - ? ONE_BD - : oraclePrice - - const isMint = event.params.from.equals(Bytes.fromHexString(ADDRESS_ZERO)) - const isBurn = event.params.to.equals(Bytes.fromHexString(ADDRESS_ZERO)) - const isTransfer = !isMint && !isBurn - - const liquidityAInUSD = convertTokenToDecimal( - pool.liquidityA, - tokenA.decimals, - ).times(tokenAUSDPrice) - const liquidityBInUSD = convertTokenToDecimal( - pool.liquidityB, - tokenB.decimals, - ).times(tokenBUSDPrice) - const totalSupply = convertTokenToDecimal(pool.totalSupply, BI_18) - const lpPriceUSD = - oraclePrice.gt(ZERO_BD) && totalSupply.gt(ZERO_BD) - ? liquidityAInUSD.plus(liquidityBInUSD).div(totalSupply) - : pool.lpPriceUSD - - if (isMint) { - buyLpToken( - getOrCreateUserPoolBalance(event.params.to, key, event), - event.params.amount, - lpPriceUSD, - ) - } else if (isBurn) { - sellLpToken( - getOrCreateUserPoolBalance(event.params.from, key, event), - event.params.amount, - lpPriceUSD, - ) - } else if ( - isTransfer && - !event.params.from.equals(event.params.to) && - !event.params.from.equals(Bytes.fromHexString(ADDRESS_ZERO)) && - !event.params.to.equals(Bytes.fromHexString(ADDRESS_ZERO)) - ) { - sellLpToken( - getOrCreateUserPoolBalance(event.params.from, key, event), - event.params.amount, - lpPriceUSD, - ) - buyLpToken( - getOrCreateUserPoolBalance(event.params.to, key, event), - event.params.amount, - lpPriceUSD, - ) - } -} diff --git a/src/mappings/router-gateway.ts b/src/mappings/router-gateway.ts deleted file mode 100644 index 1343d0e..0000000 --- a/src/mappings/router-gateway.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { log } from '@graphprotocol/graph-ts' - -import { FeeCollected, Swap } from '../../generated/RouterGateway/RouterGateway' -import { - RouterDayData, - Swap as SwapEntity, - Token, -} from '../../generated/schema' -import { ONE_BI, ZERO_BD, ZERO_BI } from '../common/constants' -import { calculateValueUSD, getTokenUSDPriceFlat } from '../common/pricing' -import { convertTokenToDecimal } from '../common/utils' -import { SKIP_TAKE_AND_SWAP } from '../common/chain' - -import { - updateDayData, - updateTokenDayData, - updateUserDayVolume, - updateUserNativeVolume, -} from './interval-updates' - -export function handleSwap(event: Swap): void { - updateDayData(event, 'SWAP') - - const inputToken = Token.load(event.params.inToken) - const outputToken = Token.load(event.params.outToken) - - const swap = new SwapEntity( - event.transaction.hash - .toHexString() - .concat('-') - .concat(event.logIndex.toString()), - ) - swap.transaction = event.transaction.hash.toHexString() - swap.timestamp = event.block.timestamp - swap.inputToken = event.params.inToken - swap.outputToken = event.params.outToken - swap.origin = event.transaction.from - swap.inputAmount = event.params.amountIn - swap.outputAmount = event.params.amountOut - swap.router = event.params.router - swap.fee = ZERO_BI - if ( - inputToken && - outputToken && - swap.inputAmount.ge(ZERO_BI) && - swap.outputAmount.ge(ZERO_BI) - ) { - const inputAmountDecimal = convertTokenToDecimal( - swap.inputAmount, - inputToken.decimals, - ) - const outputAmountDecimal = convertTokenToDecimal( - swap.outputAmount, - outputToken.decimals, - ) - const priceIn = getTokenUSDPriceFlat(inputToken) - const priceOut = getTokenUSDPriceFlat(outputToken) - - swap.amountUSD = calculateValueUSD( - inputAmountDecimal, - priceIn, - outputAmountDecimal, - priceOut, - ) - - if (priceIn.gt(ZERO_BD)) { - updateUserDayVolume(inputToken, event, inputAmountDecimal, swap.amountUSD) - const inputTokenDayData = updateTokenDayData(inputToken, priceIn, event) - inputTokenDayData.volume = - inputTokenDayData.volume.plus(inputAmountDecimal) - inputTokenDayData.volumeUSD = inputTokenDayData.volumeUSD.plus( - swap.amountUSD, - ) - inputTokenDayData.save() - } else if (priceOut.gt(ZERO_BD)) { - updateUserDayVolume( - outputToken, - event, - outputAmountDecimal, - swap.amountUSD, - ) - const outputTokenDayData = updateTokenDayData( - outputToken, - priceOut, - event, - ) - outputTokenDayData.volume = - outputTokenDayData.volume.plus(outputAmountDecimal) - outputTokenDayData.volumeUSD = outputTokenDayData.volumeUSD.plus( - swap.amountUSD, - ) - outputTokenDayData.save() - } - updateUserNativeVolume( - event, - swap.inputToken, - swap.outputToken, - swap.inputAmount, - swap.outputAmount, - ) - } else { - log.warning( - 'Swap USD skipped: inputToken or outputToken missing or invalid amounts. tx: {}', - [event.transaction.hash.toHexString()], - ) - swap.amountUSD = ZERO_BD - } - swap.logIndex = event.logIndex - if (!SKIP_TAKE_AND_SWAP) { - swap.save() - - const dayID = swap.timestamp.toI32() / 86400 // rounded - const routerDayID = swap.router - .toHexString() - .concat('-') - .concat(dayID.toString()) - let routerDayData = RouterDayData.load(routerDayID) - if (routerDayData === null) { - routerDayData = new RouterDayData(routerDayID) - routerDayData.date = dayID - routerDayData.cloberDayData = dayID.toString() - routerDayData.router = swap.router - routerDayData.txCount = ZERO_BI - } - routerDayData.txCount = routerDayData.txCount.plus(ONE_BI) - routerDayData.save() - } -} - -export function handleFeeCollected(event: FeeCollected): void { - const swap = SwapEntity.load( - event.transaction.hash - .toHexString() - .concat('-') - .concat(event.logIndex.minus(ONE_BI).toString()), - ) - const token = Token.load(event.params.token) - if (swap && token) { - const price = getTokenUSDPriceFlat(token) - const feeAmountDecimal = convertTokenToDecimal( - event.params.amount, - token.decimals, - ) - const feeAmountUSD = feeAmountDecimal.times(price) - // update token fees - token.routerGatewayProtocolFee = - token.routerGatewayProtocolFee.plus(feeAmountDecimal) - token.routerGatewayProtocolFeeUSD = - token.routerGatewayProtocolFeeUSD.plus(feeAmountUSD) - token.protocolFees = token.protocolFees.plus(feeAmountDecimal) - token.protocolFeesUSD = token.protocolFeesUSD.plus(feeAmountUSD) - - const tokenDayData = updateTokenDayData(token, price, event) - // update token day data fees - tokenDayData.routerGatewayProtocolFee = - tokenDayData.routerGatewayProtocolFee.plus(feeAmountDecimal) - tokenDayData.routerGatewayProtocolFeeUSD = - tokenDayData.routerGatewayProtocolFeeUSD.plus(feeAmountUSD) - tokenDayData.protocolFees = tokenDayData.protocolFees.plus(feeAmountDecimal) - tokenDayData.protocolFeesUSD = - tokenDayData.protocolFeesUSD.plus(feeAmountUSD) - - swap.fee = event.params.amount - - swap.save() - token.save() - tokenDayData.save() - } -} From d79899627e303c9c4b2ed382670c2fb0b32014ea Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:47:51 +0900 Subject: [PATCH 02/18] refactor: remove unused entities and event handlers from subgraph template --- subgraph.template.yaml | 122 +---------------------------------------- 1 file changed, 1 insertion(+), 121 deletions(-) diff --git a/subgraph.template.yaml b/subgraph.template.yaml index cd0d460..63e1059 100644 --- a/subgraph.template.yaml +++ b/subgraph.template.yaml @@ -16,132 +16,12 @@ dataSources: apiVersion: 0.0.7 language: wasm/assemblyscript entities: - - Token - - Book - - Depth - - OpenOrder - - Transaction - - ChartLog - - Pool - - User - - BookDayData - - TokenDayData - CloberDayData - - TransactionTypeDayData - - UserDayData - - UserDayVolume - - PoolDayData - - PoolHourData - - Take + - ContractInteractionDayData abis: - name: BookManager file: ./abis/BookManager.json - - name: ERC20 - file: ./abis/ERC20.json - - name: ERC20SymbolBytes - file: ./abis/ERC20SymbolBytes.json - - name: ERC20NameBytes - file: ./abis/ERC20NameBytes.json eventHandlers: - - event: Open(indexed uint192,indexed address,indexed - address,uint64,uint24,uint24,address) - handler: handleBookOpen - - event: Make(indexed uint192,indexed address,int24,uint256,uint64,address) - handler: handleMake - event: Take(indexed uint192,indexed address,int24,uint64) handler: handleTake - - event: Cancel(indexed uint256,uint64) - handler: handleCancel - - event: Claim(indexed uint256,uint64) - handler: handleClaim - - event: Transfer(indexed address,indexed address,indexed uint256) - handler: handleBookManagerTransfer file: ./src/mappings/core.ts - - kind: ethereum - name: LiquidityVault - network: {{ network }} - source: - abi: LiquidityVault - address: "{{ LiquidityVault.address }}" - startBlock: {{ LiquidityVault.startBlock }} - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - Pool - - Transaction - - PoolDayData - - PoolHourData - - TokenDayData - - CloberDayData - - UserDayData - - TransactionTypeDayData - - User - - UserPoolBalance - abis: - - name: LiquidityVault - file: ./abis/LiquidityVault.json - eventHandlers: - - event: Open(indexed bytes32,indexed uint192,indexed uint192,bytes32,address) - handler: handlePoolOpen - - event: Mint(indexed address,indexed bytes32,uint256,uint256,uint256) - handler: handleMint - - event: Burn(indexed address,indexed bytes32,uint256,uint256,uint256,uint256,uint256) - handler: handleBurn - - event: Transfer(address,indexed address,indexed address,indexed uint256,uint256) - handler: handleLiquidityVaultTransfer - file: ./src/mappings/core.ts - - kind: ethereum - name: SimpleOracleStrategy - network: {{ network }} - source: - abi: SimpleOracleStrategy - address: "{{ SimpleOracleStrategy.address }}" - startBlock: {{ SimpleOracleStrategy.startBlock }} - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - Pool - abis: - - name: SimpleOracleStrategy - file: ./abis/SimpleOracleStrategy.json - eventHandlers: - - event: UpdatePosition(indexed bytes32,uint256,int24,int24,uint256) - handler: handleUpdatePosition - file: ./src/mappings/core.ts - {{#hasRouterGateway}} - - kind: ethereum - name: RouterGateway - network: {{ network }} - source: - abi: RouterGateway - address: "{{ RouterGateway.address }}" - startBlock: {{ RouterGateway.startBlock }} - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - Swap - - CloberDayData - - TransactionTypeDayData - - RouterDayData - - TokenDayData - - User - - UserDayData - - UserDayVolume - abis: - - name: RouterGateway - file: ./abis/RouterGateway.json - eventHandlers: - - event: Swap(indexed address,indexed address,indexed - address,uint256,uint256,address,bytes4) - handler: handleSwap - receipt: true - - event: FeeCollected(indexed address,indexed address,uint256) - handler: handleFeeCollected - file: ./src/mappings/router-gateway.ts - {{/hasRouterGateway}} From c7295f8b14a2c86c23c06ad86d649e3b927374ba Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:49:45 +0900 Subject: [PATCH 03/18] feat: add bookId validation in handleTake function to filter specific book IDs --- src/mappings/book-manager/take.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 3880d46..55abb32 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -1,3 +1,5 @@ +import { BigInt } from '@graphprotocol/graph-ts' + import { Take } from '../../../generated/BookManager/BookManager' import { CloberDayData, @@ -6,6 +8,22 @@ import { import { ONE_BI, ZERO_BI } from '../../common/constants' export function handleTake(event: Take): void { + const bookId = event.params.bookId + if ( + !bookId.equals( + BigInt.fromString( + '3875727077379471850923186002296331935053867847116966170720', + ), + ) && + !bookId.equals( + BigInt.fromString( + '5954885684956363054050231031211743946744177791604395877538', + ), + ) + ) { + return + } + const timestamp = event.block.timestamp.toI32() const dayID = timestamp / 86400 // rounded const dayStartTimestamp = dayID * 86400 From 0fe8af8a10486d20d77cadf2a2433db75ece2d71 Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:53:10 +0900 Subject: [PATCH 04/18] fix: update callCount type to BigInt and ensure transaction.to is defined in take function --- schema.graphql | 2 +- src/mappings/book-manager/take.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/schema.graphql b/schema.graphql index 6d01beb..864de2d 100644 --- a/schema.graphql +++ b/schema.graphql @@ -19,5 +19,5 @@ type ContractInteractionDayData @entity(immutable: false) { # contract address contract: Bytes! # count of interactions - callCount: Int! + callCount: BigInt! } diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 55abb32..466cc1c 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -23,6 +23,9 @@ export function handleTake(event: Take): void { ) { return } + if (!event.transaction.to) { + return + } const timestamp = event.block.timestamp.toI32() const dayID = timestamp / 86400 // rounded @@ -33,7 +36,7 @@ export function handleTake(event: Take): void { cloberDayData.date = dayStartTimestamp } - const contract = event.transaction.to + const contract = event.transaction.to! const contractInteractionDayDataId = contract .toHexString() .concat('-') From f31a59c6f67afe4d9c11fe92e7ed52bc2c6043bc Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:53:31 +0900 Subject: [PATCH 05/18] fix: redefine ZERO_BI and ONE_BI constants as BigInt in take.ts --- src/common/amount.ts | 18 ---- src/common/chart.ts | 34 ------- src/common/constants.ts | 11 --- src/common/entity-getters.ts | 125 -------------------------- src/common/order.ts | 23 ----- src/common/pricing.ts | 84 ----------------- src/common/static-token-definition.ts | 33 ------- src/common/tick.ts | 80 ----------------- src/common/token.ts | 106 ---------------------- src/common/utils.ts | 32 ------- src/mappings/book-manager/take.ts | 4 +- 11 files changed, 3 insertions(+), 547 deletions(-) delete mode 100644 src/common/amount.ts delete mode 100644 src/common/chart.ts delete mode 100644 src/common/constants.ts delete mode 100644 src/common/entity-getters.ts delete mode 100644 src/common/order.ts delete mode 100644 src/common/pricing.ts delete mode 100644 src/common/static-token-definition.ts delete mode 100644 src/common/tick.ts delete mode 100644 src/common/token.ts delete mode 100644 src/common/utils.ts diff --git a/src/common/amount.ts b/src/common/amount.ts deleted file mode 100644 index 6e36f97..0000000 --- a/src/common/amount.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BigInt } from '@graphprotocol/graph-ts' - -import { PRICE_PRECISION } from './tick' - -export function unitToBase( - unitSize: BigInt, - unitAmount: BigInt, - price: BigInt, -): BigInt { - if (price.isZero()) { - return BigInt.fromI32(0) - } - return unitAmount.times(unitSize).times(PRICE_PRECISION).div(price) -} - -export function unitToQuote(unitSize: BigInt, unitAmount: BigInt): BigInt { - return unitAmount.times(unitSize) -} diff --git a/src/common/chart.ts b/src/common/chart.ts deleted file mode 100644 index 9379147..0000000 --- a/src/common/chart.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TypedMap } from '@graphprotocol/graph-ts' - -import { Token } from '../../generated/schema' - -export const CHART_LOG_INTERVALS = new TypedMap() -CHART_LOG_INTERVALS.set('1m', 60) -CHART_LOG_INTERVALS.set('3m', 3 * 60) -CHART_LOG_INTERVALS.set('5m', 5 * 60) -CHART_LOG_INTERVALS.set('10m', 10 * 60) -CHART_LOG_INTERVALS.set('15m', 15 * 60) -CHART_LOG_INTERVALS.set('30m', 30 * 60) -CHART_LOG_INTERVALS.set('1h', 60 * 60) -CHART_LOG_INTERVALS.set('2h', 2 * 60 * 60) -CHART_LOG_INTERVALS.set('4h', 4 * 60 * 60) -CHART_LOG_INTERVALS.set('6h', 6 * 60 * 60) -CHART_LOG_INTERVALS.set('1d', 24 * 60 * 60) -CHART_LOG_INTERVALS.set('1w', 7 * 24 * 60 * 60) - -export function encodeMarketCode(base: Token, quote: Token): string { - return base.id.toHexString().concat('-').concat(quote.id.toHexString()) -} -export function encodeChartLogID( - base: Token, - quote: Token, - intervalType: string, - timestamp: i64, -): string { - const marketCode = encodeMarketCode(base, quote) - return marketCode - .concat('-') - .concat(intervalType) - .concat('-') - .concat(timestamp.toString()) -} diff --git a/src/common/constants.ts b/src/common/constants.ts deleted file mode 100644 index 0604985..0000000 --- a/src/common/constants.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' - -export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000' - -export const ZERO_BI = BigInt.fromI32(0) -export const ONE_BI = BigInt.fromI32(1) -export const ZERO_BD = BigDecimal.fromString('0') -export const ONE_BD = BigDecimal.fromString('1') -export const TWO_BD = BigDecimal.fromString('2') -export const BI_8 = BigInt.fromI32(8) -export const BI_18 = BigInt.fromI32(18) diff --git a/src/common/entity-getters.ts b/src/common/entity-getters.ts deleted file mode 100644 index 6830ce3..0000000 --- a/src/common/entity-getters.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { BigInt, Bytes, ethereum, log } from '@graphprotocol/graph-ts' - -import { - Book, - Depth, - OpenOrder, - Pool, - Token, - Transaction, - User, - UserPoolBalance, -} from '../../generated/schema' - -import { ZERO_BD, ZERO_BI } from './constants' - -export function getOrCreateUserByFrom(event: ethereum.Event): User { - let user = User.load(event.transaction.from) - if (user === null) { - user = new User(event.transaction.from) - user.firstSeenTimestamp = event.block.timestamp - user.firstSeenBlockNumber = event.block.number - user.nativeVolume = ZERO_BD - } - user.save() - return user as User -} - -export function getOrCreateUser(userID: Bytes, block: ethereum.Block): User { - let user = User.load(userID) - if (user === null) { - user = new User(userID) - user.firstSeenTimestamp = block.timestamp - user.firstSeenBlockNumber = block.number - user.nativeVolume = ZERO_BD - } - user.save() - return user as User -} - -export function getOrCreateTransaction(event: ethereum.Event): Transaction { - let transaction = Transaction.load(event.transaction.hash.toHexString()) - if (transaction === null) { - transaction = new Transaction(event.transaction.hash.toHexString()) - } - transaction.blockNumber = event.block.number - transaction.timestamp = event.block.timestamp - transaction.gasUsed = BigInt.zero() //needs to be moved to transaction receipt - transaction.gasPrice = event.transaction.gasPrice - transaction.from = event.transaction.from - transaction.to = event.transaction.to - transaction.value = event.transaction.value - transaction.save() - return transaction as Transaction -} - -export function getTokenOrLog(tokenID: Bytes, eventType: string): Token | null { - const token = Token.load(tokenID) - if (token === null) { - log.error('[{}] Token not found: {}', [eventType, tokenID.toHexString()]) - } - return token -} - -export function getBookOrLog(bookID: string, eventType: string): Book | null { - const book = Book.load(bookID) - if (book === null) { - log.error('[{}] Book not found: {}', [eventType, bookID]) - } - return book -} - -export function getDepthOrLog( - depthID: string, - eventType: string, -): Depth | null { - const depth = Depth.load(depthID) - if (depth === null) { - log.error('[{}] Depth not found: {}', [eventType, depthID]) - } - return depth -} - -export function getOpenOrderOrLog( - openOrderID: string, - eventType: string, -): OpenOrder | null { - const openOrder = OpenOrder.load(openOrderID) - if (openOrder === null) { - log.error('[{}] Open order not found: {}', [eventType, openOrderID]) - } - return openOrder -} - -export function getPoolOrLog(poolID: Bytes, eventType: string): Pool | null { - const pool = Pool.load(poolID) - if (pool === null) { - log.error('[{}] Pool not found: {}', [eventType, poolID.toHexString()]) - } - return pool -} - -export function getOrCreateUserPoolBalance( - userID: Bytes, - poolID: Bytes, - event: ethereum.Event, -): UserPoolBalance { - const key = userID.toHexString().concat('-').concat(poolID.toHexString()) - let userPoolBalance = UserPoolBalance.load(key) - if (userPoolBalance === null) { - userPoolBalance = new UserPoolBalance(key) - userPoolBalance.user = getOrCreateUser(userID, event.block).id - userPoolBalance.pool = poolID - userPoolBalance.lpBalance = ZERO_BI - userPoolBalance.lpBalanceUSD = ZERO_BD - - userPoolBalance.costBasisUSD = ZERO_BD - userPoolBalance.averageLPPriceUSD = ZERO_BD - - userPoolBalance.totalTokenADeposited = ZERO_BI - userPoolBalance.totalTokenBDeposited = ZERO_BI - - userPoolBalance.save() - } - return userPoolBalance -} diff --git a/src/common/order.ts b/src/common/order.ts deleted file mode 100644 index 636f051..0000000 --- a/src/common/order.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { BigInt } from '@graphprotocol/graph-ts' - -import { OpenOrder } from '../../generated/schema' - -export function encodeOrderID( - bookID: string, - tick: BigInt, - orderIndex: BigInt, -): BigInt { - const bookIDBigInt = BigInt.fromString(bookID) - const tickU24 = BigInt.fromU32((tick.toU32() << 8) >> 8) - return orderIndex - .plus(tickU24.times(BigInt.fromI32(2).pow(40))) - .plus(bookIDBigInt.times(BigInt.fromI32(2).pow(64))) -} - -export function decodeBookIDFromOrderID(orderID: BigInt): string { - return orderID.div(BigInt.fromI32(2).pow(64)).toString() -} - -export function getPendingUnitAmount(openOrder: OpenOrder): BigInt { - return openOrder.cancelableUnitAmount.plus(openOrder.claimableUnitAmount) -} diff --git a/src/common/pricing.ts b/src/common/pricing.ts deleted file mode 100644 index bdf8ed2..0000000 --- a/src/common/pricing.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { BigDecimal } from '@graphprotocol/graph-ts' - -import { Book, Token } from '../../generated/schema' - -import { ADDRESS_ZERO, ONE_BD, ZERO_BD } from './constants' -import { - MINIMUM_USD_LOCKED, - NATIVE_TOKEN_BOOK_ID, - REFERENCE_TOKEN, - STABLE_COINS, -} from './chain' - -export function getTokenUSDPriceFlat(token: Token): BigDecimal { - const tokenID = token.id.toHexString() - - if (STABLE_COINS.includes(tokenID)) { - return ONE_BD - } - - if (tokenID == REFERENCE_TOKEN || tokenID == ADDRESS_ZERO) { - const nativeBidBook = Book.load(NATIVE_TOKEN_BOOK_ID.toString()) - return nativeBidBook !== null ? nativeBidBook.price : ZERO_BD - } - - let bestPrice = ZERO_BD - let largestLiquidity = ZERO_BD - const books = token.books.load() - - if (books !== null) { - for (let i = 0; i < books.length; i++) { - const book = books[i] - if (book === null) { - continue - } - - const quoteToken = Token.load(book.quote) - if (quoteToken === null) { - continue - } - - const quoteTokenID = quoteToken.id.toHexString() - - if ( - STABLE_COINS.includes(quoteTokenID) || - quoteTokenID == REFERENCE_TOKEN || - quoteTokenID == ADDRESS_ZERO - ) { - const quoteUSD = STABLE_COINS.includes(quoteTokenID) - ? ONE_BD - : ((): BigDecimal => { - const native = Book.load(NATIVE_TOKEN_BOOK_ID.toString()) - return native !== null ? native.price : ZERO_BD - })() - - const usdLocked = book.totalValueLocked.times(quoteUSD) - - if ( - usdLocked.gt(MINIMUM_USD_LOCKED) && - usdLocked.gt(largestLiquidity) && - book.price.times(quoteUSD).gt(ZERO_BD) - ) { - largestLiquidity = usdLocked - bestPrice = book.price.times(quoteUSD) - } - } - } - } - - return bestPrice -} - -export function calculateValueUSD( - quoteAmountDecimal: BigDecimal, - quoteInUSD: BigDecimal, - baseAmountDecimal: BigDecimal, - baseInUSD: BigDecimal, -): BigDecimal { - if (quoteInUSD.gt(ZERO_BD)) { - return quoteAmountDecimal.times(quoteInUSD) - } else if (baseInUSD.gt(ZERO_BD)) { - return baseAmountDecimal.times(baseInUSD) - } - return ZERO_BD -} diff --git a/src/common/static-token-definition.ts b/src/common/static-token-definition.ts deleted file mode 100644 index ededccc..0000000 --- a/src/common/static-token-definition.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Address } from '@graphprotocol/graph-ts' - -import { - NATIVE_TOKEN_DEFINITION, - STATIC_TOKEN_DEFINITIONS, - TokenDefinition, -} from './chain' -import { ADDRESS_ZERO } from './constants' - -// Helper for hardcoded tokens -export const getStaticDefinition = ( - tokenAddress: Address, -): TokenDefinition | null => { - const staticDefinitions = STATIC_TOKEN_DEFINITIONS - const tokenAddressHex = tokenAddress.toHexString() - if (tokenAddressHex == ADDRESS_ZERO) { - return NATIVE_TOKEN_DEFINITION - } - - // Search the definition using the address - for (let i = 0; i < staticDefinitions.length; i++) { - const staticDefinition = staticDefinitions[i] - if ( - staticDefinition.address.toHexString().toLowerCase() == - tokenAddressHex.toLowerCase() - ) { - return staticDefinition - } - } - - // If not found, return null - return null -} diff --git a/src/common/tick.ts b/src/common/tick.ts deleted file mode 100644 index 47e9a50..0000000 --- a/src/common/tick.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' - -import { exponentToBigDecimal } from './utils' -import { ONE_BD, ZERO_BD } from './constants' - -const R = [ - BigInt.fromString('79220240490215316061937756560'), // 0xfff97272373d413259a46990 - BigInt.fromString('79212319258289487113226433916'), // 0xfff2e50f5f656932ef12357c - BigInt.fromString('79196479170490597288862688490'), // 0xffe5caca7e10e4e61c3624ea - BigInt.fromString('79164808496886665658930780291'), // 0xffcb9843d60f6159c9db5883 - BigInt.fromString('79101505139923049997807806614'), // 0xff973b41fa98c081472e6896 - BigInt.fromString('78975050245229982702767995059'), // 0xff2ea16466c96a3843ec78b3 - BigInt.fromString('78722746600537056721934508529'), // 0xfe5dee046a99a2a811c461f1 - BigInt.fromString('78220554859095770638340573243'), // 0xfcbe86c7900a88aedcffc83b - BigInt.fromString('77225761753129597550065289036'), // 0xf987a7253ac413176f2b074c - BigInt.fromString('75273969370139069689486932537'), // 0xf3392b0822b70005940c7a39 - BigInt.fromString('71517125791179246722882903167'), // 0xe7159475a2c29b7443b29c7f - BigInt.fromString('64556580881331167221767657719'), // 0xd097f3bdfd2022b8845ad8f7 - BigInt.fromString('52601903197458624361810746399'), // 0xa9f746462d870fdf8a65dc1f - BigInt.fromString('34923947901690145425342545398'), // 0x70d869a156d2a1b890bb3df6 - BigInt.fromString('15394552875315951095595078917'), // 0x31be135f97d08fd981231505 - BigInt.fromString('2991262837734375505310244436'), // 0x9aa508b5b7a84e1c677de54 - BigInt.fromString('112935262922445818024280873'), // 0x5d6af8dedb81196699c329 - BigInt.fromString('160982827401375763736068'), // 0x2216e584f5fa1ea92604 - BigInt.fromString('327099227039063106'), // 0x48a170391f7dc42 - BigInt.fromString('1350452'), // 0x149b34 -] - -export const PRICE_PRECISION = BigInt.fromI32(2).pow(96) - -export function tickToPrice(tick: i32): BigInt { - if (tick > 524287 || tick < -524287) { - throw new Error('Invalid tick') - } - - const absTick = BigInt.fromI32(tick < 0 ? -tick : tick) - let price = BigInt.fromI32(1) - - if (absTick.bitAnd(BigInt.fromI32(1)).notEqual(BigInt.fromI32(0))) { - price = R[0] - } else { - price = BigInt.fromI32(1).leftShift(96) - } - - for (let i = 1; i < 19; i++) { - if (absTick.bitAnd(BigInt.fromI32(1 << i)).notEqual(BigInt.fromI32(0))) { - price = price.times(R[i]).rightShift(96) - } - } - - if (tick > 0) { - price = BigInt.fromString( - '6277101735386680763835789423207666416102355444464034512896', - ).div(price) // 0x1000000000000000000000000000000000000000000000000 - } - - return price -} - -export function formatPrice( - price: BigInt, - baseDecimals: BigInt, - quoteDecimals: BigInt, -): BigDecimal { - return BigDecimal.fromString(price.toString()) - .div(PRICE_PRECISION.toBigDecimal()) - .times(exponentToBigDecimal(baseDecimals)) - .div(exponentToBigDecimal(quoteDecimals)) -} - -export function formatInvertedPrice( - price: BigInt, - baseDecimals: BigInt, - quoteDecimals: BigInt, -): BigDecimal { - if (price.isZero()) { - return ZERO_BD - } - return ONE_BD.div(formatPrice(price, baseDecimals, quoteDecimals)) -} diff --git a/src/common/token.ts b/src/common/token.ts deleted file mode 100644 index 60536cd..0000000 --- a/src/common/token.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* eslint-disable prefer-const */ -import { Address, BigInt } from '@graphprotocol/graph-ts' - -import { ERC20 } from '../../generated/BookManager/ERC20' -import { ERC20SymbolBytes } from '../../generated/BookManager/ERC20SymbolBytes' -import { ERC20NameBytes } from '../../generated/BookManager/ERC20NameBytes' - -import { STABLE_COINS, TokenDefinition } from './chain' -import { getStaticDefinition } from './static-token-definition' -import { isNullEthValue } from './utils' - -export function isStableCoin(tokenAddress: Address): boolean { - let staticStableCoinAddresses = STABLE_COINS - for (let i = 0; i < staticStableCoinAddresses.length; i++) { - if (tokenAddress.equals(Address.fromString(staticStableCoinAddresses[i]))) { - return true - } - } - return false -} - -export function fetchTokenSymbol(tokenAddress: Address): string { - let staticDefinition = getStaticDefinition(tokenAddress) - if (staticDefinition != null) { - return (staticDefinition as TokenDefinition).symbol - } - let contract = ERC20.bind(tokenAddress) - let contractSymbolBytes = ERC20SymbolBytes.bind(tokenAddress) - - // try types string and bytes32 for symbol - let symbolValue = 'unknown' - let symbolResult = contract.try_symbol() - if (symbolResult.reverted) { - let symbolResultBytes = contractSymbolBytes.try_symbol() - if (!symbolResultBytes.reverted) { - // for broken pairs that have no symbol function exposed - if (!isNullEthValue(symbolResultBytes.value.toHexString())) { - symbolValue = symbolResultBytes.value.toString() - } - } - } else { - symbolValue = symbolResult.value - } - - return symbolValue -} - -export function fetchTokenName(tokenAddress: Address): string { - let staticDefinition = getStaticDefinition(tokenAddress) - if (staticDefinition != null) { - return (staticDefinition as TokenDefinition).name - } - let contract = ERC20.bind(tokenAddress) - let contractNameBytes = ERC20NameBytes.bind(tokenAddress) - - // try types string and bytes32 for name - let nameValue = 'unknown' - let nameResult = contract.try_name() - if (nameResult.reverted) { - let nameResultBytes = contractNameBytes.try_name() - if (!nameResultBytes.reverted) { - // for broken exchanges that have no name function exposed - if (!isNullEthValue(nameResultBytes.value.toHexString())) { - nameValue = nameResultBytes.value.toString() - } - } - } else { - nameValue = nameResult.value - } - - return nameValue -} - -// export function fetchTokenTotalSupply(tokenAddress: Address): BigInt { -// let staticDefinition = getStaticDefinition(tokenAddress) -// if (staticDefinition != null) { -// return (staticDefinition as TokenDefinition).totalSupply -// } -// -// let contract = ERC20.bind(tokenAddress) -// let totalSupplyValue = BigInt.zero() -// let totalSupplyResult = contract.try_totalSupply() -// if (!totalSupplyResult.reverted) { -// totalSupplyValue = totalSupplyResult.value -// } -// return totalSupplyValue -// } - -export function fetchTokenDecimals(tokenAddress: Address): BigInt | null { - let staticDefinition = getStaticDefinition(tokenAddress) - if (staticDefinition != null) { - return (staticDefinition as TokenDefinition).decimals - } - let contract = ERC20.bind(tokenAddress) - // try types uint8 for decimals - - let decimalResult = contract.try_decimals() - if (!decimalResult.reverted) { - const decimals = BigInt.fromI32(decimalResult.value) - if (decimals.lt(BigInt.fromI32(255))) { - return decimals - } - } - - return null -} diff --git a/src/common/utils.ts b/src/common/utils.ts deleted file mode 100644 index 26c33b7..0000000 --- a/src/common/utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable prefer-const */ -import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' - -import { ZERO_BI } from './constants' - -export function exponentToBigDecimal(decimals: BigInt): BigDecimal { - let bd = BigDecimal.fromString('1') - - if (decimals < BigInt.fromI32(255)) { - bd = BigInt.fromI32(10) - .pow(decimals.toI32() as u8) - .toBigDecimal() - } - return bd -} - -export function isNullEthValue(value: string): boolean { - return ( - value == - '0x0000000000000000000000000000000000000000000000000000000000000001' - ) -} - -export function convertTokenToDecimal( - tokenAmount: BigInt, - exchangeDecimals: BigInt, -): BigDecimal { - if (exchangeDecimals == ZERO_BI) { - return tokenAmount.toBigDecimal() - } - return tokenAmount.toBigDecimal().div(exponentToBigDecimal(exchangeDecimals)) -} diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 466cc1c..026b8b5 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -5,7 +5,9 @@ import { CloberDayData, ContractInteractionDayData, } from '../../../generated/schema' -import { ONE_BI, ZERO_BI } from '../../common/constants' + +const ZERO_BI = BigInt.fromI32(0) +const ONE_BI = BigInt.fromI32(1) export function handleTake(event: Take): void { const bookId = event.params.bookId From 63c9d4e890f51caa38a4c8e33da19fd93a468539 Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 00:55:34 +0900 Subject: [PATCH 06/18] fix: update subgraph deployment commands to use interaction-contracts naming convention --- script/utils/deploy-utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/script/utils/deploy-utils.ts b/script/utils/deploy-utils.ts index 9a54eb3..85bc130 100644 --- a/script/utils/deploy-utils.ts +++ b/script/utils/deploy-utils.ts @@ -21,7 +21,7 @@ const buildGoldskyDeployCommand = async ( process.exit(1) } - const subgraphName = `v2-subgraph-${network}/${gitHashString}` + const subgraphName = `interaction-contracts-${network}/${gitHashString}` return `goldsky subgraph deploy ${subgraphName} --path .` } @@ -34,7 +34,7 @@ const buildAlchemyDeployCommand = ( throw new Error('ALCHEMY_DEPLOY_KEY must be set') } const deployKey = process.env.ALCHEMY_DEPLOY_KEY - return `graph deploy v2-subgraph-${network} --version-label ${gitHashString} --node https://subgraphs.alchemy.com/api/subgraphs/deploy --deploy-key ${deployKey} --ipfs https://ipfs.satsuma.xyz` + return `graph deploy interaction-contracts-${network} --version-label ${gitHashString} --node https://subgraphs.alchemy.com/api/subgraphs/deploy --deploy-key ${deployKey} --ipfs https://ipfs.satsuma.xyz` } const buildOrmiDeployCommand = ( @@ -46,7 +46,7 @@ const buildOrmiDeployCommand = ( throw new Error('ORMI_DEPLOY_KEY must be set') } const deployKey = process.env.ORMI_DEPLOY_KEY - return `graph deploy v2-subgraph-${network} --version-label ${gitHashString} --node https://api.subgraph.ormilabs.com/deploy --deploy-key ${deployKey} --ipfs https://api.subgraph.ormilabs.com/ipfs` + return `graph deploy interaction-contracts-${network} --version-label ${gitHashString} --node https://api.subgraph.ormilabs.com/deploy --deploy-key ${deployKey} --ipfs https://api.subgraph.ormilabs.com/ipfs` } const buildSentioDeployCommand = ( @@ -59,7 +59,7 @@ const buildSentioDeployCommand = ( } const deployKey = process.env.SENTIO_DEPLOY_KEY network = network.includes('testnet') ? network : `${network}-mainnet` - return `graph deploy clober-dex/v2-subgraph-${network} --version-label ${gitHashString} --node https://app.sentio.xyz/api/v1/graph-node --deploy-key ${deployKey} --ipfs https://app.sentio.xyz/api/v1/ipfs` + return `graph deploy clober-dex/interaction-contracts-${network} --version-label ${gitHashString} --node https://app.sentio.xyz/api/v1/graph-node --deploy-key ${deployKey} --ipfs https://app.sentio.xyz/api/v1/ipfs` } const codegen = async (): Promise => { From e2c0ec1128f3819612222d88e4b42d28c75f2dfd Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 14:27:48 +0900 Subject: [PATCH 07/18] Revert "fix: redefine ZERO_BI and ONE_BI constants as BigInt in take.ts" This reverts commit f31a59c6f67afe4d9c11fe92e7ed52bc2c6043bc. --- src/common/amount.ts | 18 ++++ src/common/chart.ts | 34 +++++++ src/common/constants.ts | 11 +++ src/common/entity-getters.ts | 125 ++++++++++++++++++++++++++ src/common/order.ts | 23 +++++ src/common/pricing.ts | 84 +++++++++++++++++ src/common/static-token-definition.ts | 33 +++++++ src/common/tick.ts | 80 +++++++++++++++++ src/common/token.ts | 106 ++++++++++++++++++++++ src/common/utils.ts | 32 +++++++ src/mappings/book-manager/take.ts | 4 +- 11 files changed, 547 insertions(+), 3 deletions(-) create mode 100644 src/common/amount.ts create mode 100644 src/common/chart.ts create mode 100644 src/common/constants.ts create mode 100644 src/common/entity-getters.ts create mode 100644 src/common/order.ts create mode 100644 src/common/pricing.ts create mode 100644 src/common/static-token-definition.ts create mode 100644 src/common/tick.ts create mode 100644 src/common/token.ts create mode 100644 src/common/utils.ts diff --git a/src/common/amount.ts b/src/common/amount.ts new file mode 100644 index 0000000..6e36f97 --- /dev/null +++ b/src/common/amount.ts @@ -0,0 +1,18 @@ +import { BigInt } from '@graphprotocol/graph-ts' + +import { PRICE_PRECISION } from './tick' + +export function unitToBase( + unitSize: BigInt, + unitAmount: BigInt, + price: BigInt, +): BigInt { + if (price.isZero()) { + return BigInt.fromI32(0) + } + return unitAmount.times(unitSize).times(PRICE_PRECISION).div(price) +} + +export function unitToQuote(unitSize: BigInt, unitAmount: BigInt): BigInt { + return unitAmount.times(unitSize) +} diff --git a/src/common/chart.ts b/src/common/chart.ts new file mode 100644 index 0000000..9379147 --- /dev/null +++ b/src/common/chart.ts @@ -0,0 +1,34 @@ +import { TypedMap } from '@graphprotocol/graph-ts' + +import { Token } from '../../generated/schema' + +export const CHART_LOG_INTERVALS = new TypedMap() +CHART_LOG_INTERVALS.set('1m', 60) +CHART_LOG_INTERVALS.set('3m', 3 * 60) +CHART_LOG_INTERVALS.set('5m', 5 * 60) +CHART_LOG_INTERVALS.set('10m', 10 * 60) +CHART_LOG_INTERVALS.set('15m', 15 * 60) +CHART_LOG_INTERVALS.set('30m', 30 * 60) +CHART_LOG_INTERVALS.set('1h', 60 * 60) +CHART_LOG_INTERVALS.set('2h', 2 * 60 * 60) +CHART_LOG_INTERVALS.set('4h', 4 * 60 * 60) +CHART_LOG_INTERVALS.set('6h', 6 * 60 * 60) +CHART_LOG_INTERVALS.set('1d', 24 * 60 * 60) +CHART_LOG_INTERVALS.set('1w', 7 * 24 * 60 * 60) + +export function encodeMarketCode(base: Token, quote: Token): string { + return base.id.toHexString().concat('-').concat(quote.id.toHexString()) +} +export function encodeChartLogID( + base: Token, + quote: Token, + intervalType: string, + timestamp: i64, +): string { + const marketCode = encodeMarketCode(base, quote) + return marketCode + .concat('-') + .concat(intervalType) + .concat('-') + .concat(timestamp.toString()) +} diff --git a/src/common/constants.ts b/src/common/constants.ts new file mode 100644 index 0000000..0604985 --- /dev/null +++ b/src/common/constants.ts @@ -0,0 +1,11 @@ +import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' + +export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000' + +export const ZERO_BI = BigInt.fromI32(0) +export const ONE_BI = BigInt.fromI32(1) +export const ZERO_BD = BigDecimal.fromString('0') +export const ONE_BD = BigDecimal.fromString('1') +export const TWO_BD = BigDecimal.fromString('2') +export const BI_8 = BigInt.fromI32(8) +export const BI_18 = BigInt.fromI32(18) diff --git a/src/common/entity-getters.ts b/src/common/entity-getters.ts new file mode 100644 index 0000000..6830ce3 --- /dev/null +++ b/src/common/entity-getters.ts @@ -0,0 +1,125 @@ +import { BigInt, Bytes, ethereum, log } from '@graphprotocol/graph-ts' + +import { + Book, + Depth, + OpenOrder, + Pool, + Token, + Transaction, + User, + UserPoolBalance, +} from '../../generated/schema' + +import { ZERO_BD, ZERO_BI } from './constants' + +export function getOrCreateUserByFrom(event: ethereum.Event): User { + let user = User.load(event.transaction.from) + if (user === null) { + user = new User(event.transaction.from) + user.firstSeenTimestamp = event.block.timestamp + user.firstSeenBlockNumber = event.block.number + user.nativeVolume = ZERO_BD + } + user.save() + return user as User +} + +export function getOrCreateUser(userID: Bytes, block: ethereum.Block): User { + let user = User.load(userID) + if (user === null) { + user = new User(userID) + user.firstSeenTimestamp = block.timestamp + user.firstSeenBlockNumber = block.number + user.nativeVolume = ZERO_BD + } + user.save() + return user as User +} + +export function getOrCreateTransaction(event: ethereum.Event): Transaction { + let transaction = Transaction.load(event.transaction.hash.toHexString()) + if (transaction === null) { + transaction = new Transaction(event.transaction.hash.toHexString()) + } + transaction.blockNumber = event.block.number + transaction.timestamp = event.block.timestamp + transaction.gasUsed = BigInt.zero() //needs to be moved to transaction receipt + transaction.gasPrice = event.transaction.gasPrice + transaction.from = event.transaction.from + transaction.to = event.transaction.to + transaction.value = event.transaction.value + transaction.save() + return transaction as Transaction +} + +export function getTokenOrLog(tokenID: Bytes, eventType: string): Token | null { + const token = Token.load(tokenID) + if (token === null) { + log.error('[{}] Token not found: {}', [eventType, tokenID.toHexString()]) + } + return token +} + +export function getBookOrLog(bookID: string, eventType: string): Book | null { + const book = Book.load(bookID) + if (book === null) { + log.error('[{}] Book not found: {}', [eventType, bookID]) + } + return book +} + +export function getDepthOrLog( + depthID: string, + eventType: string, +): Depth | null { + const depth = Depth.load(depthID) + if (depth === null) { + log.error('[{}] Depth not found: {}', [eventType, depthID]) + } + return depth +} + +export function getOpenOrderOrLog( + openOrderID: string, + eventType: string, +): OpenOrder | null { + const openOrder = OpenOrder.load(openOrderID) + if (openOrder === null) { + log.error('[{}] Open order not found: {}', [eventType, openOrderID]) + } + return openOrder +} + +export function getPoolOrLog(poolID: Bytes, eventType: string): Pool | null { + const pool = Pool.load(poolID) + if (pool === null) { + log.error('[{}] Pool not found: {}', [eventType, poolID.toHexString()]) + } + return pool +} + +export function getOrCreateUserPoolBalance( + userID: Bytes, + poolID: Bytes, + event: ethereum.Event, +): UserPoolBalance { + const key = userID.toHexString().concat('-').concat(poolID.toHexString()) + let userPoolBalance = UserPoolBalance.load(key) + if (userPoolBalance === null) { + userPoolBalance = new UserPoolBalance(key) + userPoolBalance.user = getOrCreateUser(userID, event.block).id + userPoolBalance.pool = poolID + userPoolBalance.lpBalance = ZERO_BI + userPoolBalance.lpBalanceUSD = ZERO_BD + + userPoolBalance.costBasisUSD = ZERO_BD + userPoolBalance.averageLPPriceUSD = ZERO_BD + + userPoolBalance.totalTokenADeposited = ZERO_BI + userPoolBalance.totalTokenBDeposited = ZERO_BI + + userPoolBalance.save() + } + return userPoolBalance +} diff --git a/src/common/order.ts b/src/common/order.ts new file mode 100644 index 0000000..636f051 --- /dev/null +++ b/src/common/order.ts @@ -0,0 +1,23 @@ +import { BigInt } from '@graphprotocol/graph-ts' + +import { OpenOrder } from '../../generated/schema' + +export function encodeOrderID( + bookID: string, + tick: BigInt, + orderIndex: BigInt, +): BigInt { + const bookIDBigInt = BigInt.fromString(bookID) + const tickU24 = BigInt.fromU32((tick.toU32() << 8) >> 8) + return orderIndex + .plus(tickU24.times(BigInt.fromI32(2).pow(40))) + .plus(bookIDBigInt.times(BigInt.fromI32(2).pow(64))) +} + +export function decodeBookIDFromOrderID(orderID: BigInt): string { + return orderID.div(BigInt.fromI32(2).pow(64)).toString() +} + +export function getPendingUnitAmount(openOrder: OpenOrder): BigInt { + return openOrder.cancelableUnitAmount.plus(openOrder.claimableUnitAmount) +} diff --git a/src/common/pricing.ts b/src/common/pricing.ts new file mode 100644 index 0000000..bdf8ed2 --- /dev/null +++ b/src/common/pricing.ts @@ -0,0 +1,84 @@ +import { BigDecimal } from '@graphprotocol/graph-ts' + +import { Book, Token } from '../../generated/schema' + +import { ADDRESS_ZERO, ONE_BD, ZERO_BD } from './constants' +import { + MINIMUM_USD_LOCKED, + NATIVE_TOKEN_BOOK_ID, + REFERENCE_TOKEN, + STABLE_COINS, +} from './chain' + +export function getTokenUSDPriceFlat(token: Token): BigDecimal { + const tokenID = token.id.toHexString() + + if (STABLE_COINS.includes(tokenID)) { + return ONE_BD + } + + if (tokenID == REFERENCE_TOKEN || tokenID == ADDRESS_ZERO) { + const nativeBidBook = Book.load(NATIVE_TOKEN_BOOK_ID.toString()) + return nativeBidBook !== null ? nativeBidBook.price : ZERO_BD + } + + let bestPrice = ZERO_BD + let largestLiquidity = ZERO_BD + const books = token.books.load() + + if (books !== null) { + for (let i = 0; i < books.length; i++) { + const book = books[i] + if (book === null) { + continue + } + + const quoteToken = Token.load(book.quote) + if (quoteToken === null) { + continue + } + + const quoteTokenID = quoteToken.id.toHexString() + + if ( + STABLE_COINS.includes(quoteTokenID) || + quoteTokenID == REFERENCE_TOKEN || + quoteTokenID == ADDRESS_ZERO + ) { + const quoteUSD = STABLE_COINS.includes(quoteTokenID) + ? ONE_BD + : ((): BigDecimal => { + const native = Book.load(NATIVE_TOKEN_BOOK_ID.toString()) + return native !== null ? native.price : ZERO_BD + })() + + const usdLocked = book.totalValueLocked.times(quoteUSD) + + if ( + usdLocked.gt(MINIMUM_USD_LOCKED) && + usdLocked.gt(largestLiquidity) && + book.price.times(quoteUSD).gt(ZERO_BD) + ) { + largestLiquidity = usdLocked + bestPrice = book.price.times(quoteUSD) + } + } + } + } + + return bestPrice +} + +export function calculateValueUSD( + quoteAmountDecimal: BigDecimal, + quoteInUSD: BigDecimal, + baseAmountDecimal: BigDecimal, + baseInUSD: BigDecimal, +): BigDecimal { + if (quoteInUSD.gt(ZERO_BD)) { + return quoteAmountDecimal.times(quoteInUSD) + } else if (baseInUSD.gt(ZERO_BD)) { + return baseAmountDecimal.times(baseInUSD) + } + return ZERO_BD +} diff --git a/src/common/static-token-definition.ts b/src/common/static-token-definition.ts new file mode 100644 index 0000000..ededccc --- /dev/null +++ b/src/common/static-token-definition.ts @@ -0,0 +1,33 @@ +import { Address } from '@graphprotocol/graph-ts' + +import { + NATIVE_TOKEN_DEFINITION, + STATIC_TOKEN_DEFINITIONS, + TokenDefinition, +} from './chain' +import { ADDRESS_ZERO } from './constants' + +// Helper for hardcoded tokens +export const getStaticDefinition = ( + tokenAddress: Address, +): TokenDefinition | null => { + const staticDefinitions = STATIC_TOKEN_DEFINITIONS + const tokenAddressHex = tokenAddress.toHexString() + if (tokenAddressHex == ADDRESS_ZERO) { + return NATIVE_TOKEN_DEFINITION + } + + // Search the definition using the address + for (let i = 0; i < staticDefinitions.length; i++) { + const staticDefinition = staticDefinitions[i] + if ( + staticDefinition.address.toHexString().toLowerCase() == + tokenAddressHex.toLowerCase() + ) { + return staticDefinition + } + } + + // If not found, return null + return null +} diff --git a/src/common/tick.ts b/src/common/tick.ts new file mode 100644 index 0000000..47e9a50 --- /dev/null +++ b/src/common/tick.ts @@ -0,0 +1,80 @@ +import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' + +import { exponentToBigDecimal } from './utils' +import { ONE_BD, ZERO_BD } from './constants' + +const R = [ + BigInt.fromString('79220240490215316061937756560'), // 0xfff97272373d413259a46990 + BigInt.fromString('79212319258289487113226433916'), // 0xfff2e50f5f656932ef12357c + BigInt.fromString('79196479170490597288862688490'), // 0xffe5caca7e10e4e61c3624ea + BigInt.fromString('79164808496886665658930780291'), // 0xffcb9843d60f6159c9db5883 + BigInt.fromString('79101505139923049997807806614'), // 0xff973b41fa98c081472e6896 + BigInt.fromString('78975050245229982702767995059'), // 0xff2ea16466c96a3843ec78b3 + BigInt.fromString('78722746600537056721934508529'), // 0xfe5dee046a99a2a811c461f1 + BigInt.fromString('78220554859095770638340573243'), // 0xfcbe86c7900a88aedcffc83b + BigInt.fromString('77225761753129597550065289036'), // 0xf987a7253ac413176f2b074c + BigInt.fromString('75273969370139069689486932537'), // 0xf3392b0822b70005940c7a39 + BigInt.fromString('71517125791179246722882903167'), // 0xe7159475a2c29b7443b29c7f + BigInt.fromString('64556580881331167221767657719'), // 0xd097f3bdfd2022b8845ad8f7 + BigInt.fromString('52601903197458624361810746399'), // 0xa9f746462d870fdf8a65dc1f + BigInt.fromString('34923947901690145425342545398'), // 0x70d869a156d2a1b890bb3df6 + BigInt.fromString('15394552875315951095595078917'), // 0x31be135f97d08fd981231505 + BigInt.fromString('2991262837734375505310244436'), // 0x9aa508b5b7a84e1c677de54 + BigInt.fromString('112935262922445818024280873'), // 0x5d6af8dedb81196699c329 + BigInt.fromString('160982827401375763736068'), // 0x2216e584f5fa1ea92604 + BigInt.fromString('327099227039063106'), // 0x48a170391f7dc42 + BigInt.fromString('1350452'), // 0x149b34 +] + +export const PRICE_PRECISION = BigInt.fromI32(2).pow(96) + +export function tickToPrice(tick: i32): BigInt { + if (tick > 524287 || tick < -524287) { + throw new Error('Invalid tick') + } + + const absTick = BigInt.fromI32(tick < 0 ? -tick : tick) + let price = BigInt.fromI32(1) + + if (absTick.bitAnd(BigInt.fromI32(1)).notEqual(BigInt.fromI32(0))) { + price = R[0] + } else { + price = BigInt.fromI32(1).leftShift(96) + } + + for (let i = 1; i < 19; i++) { + if (absTick.bitAnd(BigInt.fromI32(1 << i)).notEqual(BigInt.fromI32(0))) { + price = price.times(R[i]).rightShift(96) + } + } + + if (tick > 0) { + price = BigInt.fromString( + '6277101735386680763835789423207666416102355444464034512896', + ).div(price) // 0x1000000000000000000000000000000000000000000000000 + } + + return price +} + +export function formatPrice( + price: BigInt, + baseDecimals: BigInt, + quoteDecimals: BigInt, +): BigDecimal { + return BigDecimal.fromString(price.toString()) + .div(PRICE_PRECISION.toBigDecimal()) + .times(exponentToBigDecimal(baseDecimals)) + .div(exponentToBigDecimal(quoteDecimals)) +} + +export function formatInvertedPrice( + price: BigInt, + baseDecimals: BigInt, + quoteDecimals: BigInt, +): BigDecimal { + if (price.isZero()) { + return ZERO_BD + } + return ONE_BD.div(formatPrice(price, baseDecimals, quoteDecimals)) +} diff --git a/src/common/token.ts b/src/common/token.ts new file mode 100644 index 0000000..60536cd --- /dev/null +++ b/src/common/token.ts @@ -0,0 +1,106 @@ +/* eslint-disable prefer-const */ +import { Address, BigInt } from '@graphprotocol/graph-ts' + +import { ERC20 } from '../../generated/BookManager/ERC20' +import { ERC20SymbolBytes } from '../../generated/BookManager/ERC20SymbolBytes' +import { ERC20NameBytes } from '../../generated/BookManager/ERC20NameBytes' + +import { STABLE_COINS, TokenDefinition } from './chain' +import { getStaticDefinition } from './static-token-definition' +import { isNullEthValue } from './utils' + +export function isStableCoin(tokenAddress: Address): boolean { + let staticStableCoinAddresses = STABLE_COINS + for (let i = 0; i < staticStableCoinAddresses.length; i++) { + if (tokenAddress.equals(Address.fromString(staticStableCoinAddresses[i]))) { + return true + } + } + return false +} + +export function fetchTokenSymbol(tokenAddress: Address): string { + let staticDefinition = getStaticDefinition(tokenAddress) + if (staticDefinition != null) { + return (staticDefinition as TokenDefinition).symbol + } + let contract = ERC20.bind(tokenAddress) + let contractSymbolBytes = ERC20SymbolBytes.bind(tokenAddress) + + // try types string and bytes32 for symbol + let symbolValue = 'unknown' + let symbolResult = contract.try_symbol() + if (symbolResult.reverted) { + let symbolResultBytes = contractSymbolBytes.try_symbol() + if (!symbolResultBytes.reverted) { + // for broken pairs that have no symbol function exposed + if (!isNullEthValue(symbolResultBytes.value.toHexString())) { + symbolValue = symbolResultBytes.value.toString() + } + } + } else { + symbolValue = symbolResult.value + } + + return symbolValue +} + +export function fetchTokenName(tokenAddress: Address): string { + let staticDefinition = getStaticDefinition(tokenAddress) + if (staticDefinition != null) { + return (staticDefinition as TokenDefinition).name + } + let contract = ERC20.bind(tokenAddress) + let contractNameBytes = ERC20NameBytes.bind(tokenAddress) + + // try types string and bytes32 for name + let nameValue = 'unknown' + let nameResult = contract.try_name() + if (nameResult.reverted) { + let nameResultBytes = contractNameBytes.try_name() + if (!nameResultBytes.reverted) { + // for broken exchanges that have no name function exposed + if (!isNullEthValue(nameResultBytes.value.toHexString())) { + nameValue = nameResultBytes.value.toString() + } + } + } else { + nameValue = nameResult.value + } + + return nameValue +} + +// export function fetchTokenTotalSupply(tokenAddress: Address): BigInt { +// let staticDefinition = getStaticDefinition(tokenAddress) +// if (staticDefinition != null) { +// return (staticDefinition as TokenDefinition).totalSupply +// } +// +// let contract = ERC20.bind(tokenAddress) +// let totalSupplyValue = BigInt.zero() +// let totalSupplyResult = contract.try_totalSupply() +// if (!totalSupplyResult.reverted) { +// totalSupplyValue = totalSupplyResult.value +// } +// return totalSupplyValue +// } + +export function fetchTokenDecimals(tokenAddress: Address): BigInt | null { + let staticDefinition = getStaticDefinition(tokenAddress) + if (staticDefinition != null) { + return (staticDefinition as TokenDefinition).decimals + } + let contract = ERC20.bind(tokenAddress) + // try types uint8 for decimals + + let decimalResult = contract.try_decimals() + if (!decimalResult.reverted) { + const decimals = BigInt.fromI32(decimalResult.value) + if (decimals.lt(BigInt.fromI32(255))) { + return decimals + } + } + + return null +} diff --git a/src/common/utils.ts b/src/common/utils.ts new file mode 100644 index 0000000..26c33b7 --- /dev/null +++ b/src/common/utils.ts @@ -0,0 +1,32 @@ +/* eslint-disable prefer-const */ +import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' + +import { ZERO_BI } from './constants' + +export function exponentToBigDecimal(decimals: BigInt): BigDecimal { + let bd = BigDecimal.fromString('1') + + if (decimals < BigInt.fromI32(255)) { + bd = BigInt.fromI32(10) + .pow(decimals.toI32() as u8) + .toBigDecimal() + } + return bd +} + +export function isNullEthValue(value: string): boolean { + return ( + value == + '0x0000000000000000000000000000000000000000000000000000000000000001' + ) +} + +export function convertTokenToDecimal( + tokenAmount: BigInt, + exchangeDecimals: BigInt, +): BigDecimal { + if (exchangeDecimals == ZERO_BI) { + return tokenAmount.toBigDecimal() + } + return tokenAmount.toBigDecimal().div(exponentToBigDecimal(exchangeDecimals)) +} diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 026b8b5..466cc1c 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -5,9 +5,7 @@ import { CloberDayData, ContractInteractionDayData, } from '../../../generated/schema' - -const ZERO_BI = BigInt.fromI32(0) -const ONE_BI = BigInt.fromI32(1) +import { ONE_BI, ZERO_BI } from '../../common/constants' export function handleTake(event: Take): void { const bookId = event.params.bookId From b215361587efe9500e0ee6033ecd2447c843f8c4 Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 14:28:02 +0900 Subject: [PATCH 08/18] fix: save cloberDayData after updating callCount in take function --- src/mappings/book-manager/take.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 466cc1c..a670155 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -56,4 +56,5 @@ export function handleTake(event: Take): void { contractInteractionDayData.callCount = contractInteractionDayData.callCount.plus(ONE_BI) contractInteractionDayData.save() + cloberDayData.save() } From 6a0f05d3322c1ca9abb41fe756a281f72ef58e68 Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 14:36:52 +0900 Subject: [PATCH 09/18] fix: add volumeUSD calculation and initialization in handleTake function --- src/mappings/book-manager/take.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index a670155..c64e656 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -5,19 +5,22 @@ import { CloberDayData, ContractInteractionDayData, } from '../../../generated/schema' -import { ONE_BI, ZERO_BI } from '../../common/constants' +import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' +import { tickToPrice } from '../../common/tick' +import { unitToBase } from '../../common/amount' +import { convertTokenToDecimal } from '../../common/utils' export function handleTake(event: Take): void { const bookId = event.params.bookId if ( !bookId.equals( BigInt.fromString( - '3875727077379471850923186002296331935053867847116966170720', + '3875727077379471850923186002296331935053867847116966170720', // ask ), ) && !bookId.equals( BigInt.fromString( - '5954885684956363054050231031211743946744177791604395877538', + '5954885684956363054050231031211743946744177791604395877538', // bid ), ) ) { @@ -26,6 +29,20 @@ export function handleTake(event: Take): void { if (!event.transaction.to) { return } + const isTakingBidBook = bookId.equals( + BigInt.fromString( + '5954885684956363054050231031211743946744177791604395877538', + ), + ) + const priceRaw = tickToPrice(event.params.tick) + const volumeUsd = isTakingBidBook + ? event.params.unit + : unitToBase( + BigInt.fromString('1000000000000'), + event.params.unit, + priceRaw, + ) + const volumeUsdBD = convertTokenToDecimal(volumeUsd, BigInt.fromI32(6)) const timestamp = event.block.timestamp.toI32() const dayID = timestamp / 86400 // rounded @@ -51,10 +68,13 @@ export function handleTake(event: Take): void { contractInteractionDayData.date = dayStartTimestamp contractInteractionDayData.contract = contract contractInteractionDayData.callCount = ZERO_BI + contractInteractionDayData.volumeUSD = ZERO_BD } contractInteractionDayData.callCount = contractInteractionDayData.callCount.plus(ONE_BI) + contractInteractionDayData.volumeUSD = + contractInteractionDayData.volumeUSD.plus(volumeUsdBD) contractInteractionDayData.save() cloberDayData.save() } From f9af19415ef2973461017460bee6a9960f29bbbc Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 14:37:49 +0900 Subject: [PATCH 10/18] fix: add volumeUSD field to schema for accumulated volume tracking --- schema.graphql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/schema.graphql b/schema.graphql index 864de2d..c1c61fb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -20,4 +20,6 @@ type ContractInteractionDayData @entity(immutable: false) { contract: Bytes! # count of interactions callCount: BigInt! + # accumulated volume in USD + volumeUSD: BigDecimal! } From e61788ba79f0a3fd22916fa90e8df09d62875c7c Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 16:05:32 +0900 Subject: [PATCH 11/18] fix: associate cloberDayData with contractInteractionDayData in take function --- src/mappings/book-manager/take.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index c64e656..5358c6f 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -69,6 +69,7 @@ export function handleTake(event: Take): void { contractInteractionDayData.contract = contract contractInteractionDayData.callCount = ZERO_BI contractInteractionDayData.volumeUSD = ZERO_BD + contractInteractionDayData.cloberDayData = cloberDayData.id } contractInteractionDayData.callCount = From 066e8f4438987b26add95109e8cf36aa7fe85c5f Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 16:08:57 +0900 Subject: [PATCH 12/18] fix: add ContractInteraction type and update volumeUSD tracking in take function --- schema.graphql | 9 +++++++++ src/mappings/book-manager/take.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/schema.graphql b/schema.graphql index c1c61fb..de15a24 100644 --- a/schema.graphql +++ b/schema.graphql @@ -9,6 +9,15 @@ type CloberDayData @entity(immutable: false) { contractInteractionDayData: [ContractInteractionDayData!]! @derivedFrom(field: "cloberDayData") } +type ContractInteraction @entity(immutable: false) { + # `${contractAddress}` + id: ID! + # count of interactions + callCount: BigInt! + # accumulated volume in USD + volumeUSD: BigDecimal! +} + type ContractInteractionDayData @entity(immutable: false) { # `${contractAddress}-{periodStartUnix}` id: ID! diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 5358c6f..6b5ac1e 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -3,6 +3,7 @@ import { BigInt } from '@graphprotocol/graph-ts' import { Take } from '../../../generated/BookManager/BookManager' import { CloberDayData, + ContractInteraction, ContractInteractionDayData, } from '../../../generated/schema' import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' @@ -71,11 +72,22 @@ export function handleTake(event: Take): void { contractInteractionDayData.volumeUSD = ZERO_BD contractInteractionDayData.cloberDayData = cloberDayData.id } + let contractInteraction = ContractInteraction.load(contract.toHexString()) + if (contractInteraction === null) { + contractInteraction = new ContractInteraction(contract.toHexString()) + contractInteraction.callCount = ZERO_BI + contractInteraction.volumeUSD = ZERO_BD + } contractInteractionDayData.callCount = contractInteractionDayData.callCount.plus(ONE_BI) contractInteractionDayData.volumeUSD = contractInteractionDayData.volumeUSD.plus(volumeUsdBD) contractInteractionDayData.save() + + contractInteraction.callCount = contractInteraction.callCount.plus(ONE_BI) + contractInteraction.volumeUSD = + contractInteraction.volumeUSD.plus(volumeUsdBD) + cloberDayData.save() } From 0210672ee271631a016b7826f18943d9291fd62a Mon Sep 17 00:00:00 2001 From: graykode Date: Tue, 6 Jan 2026 16:09:38 +0900 Subject: [PATCH 13/18] fix: save contractInteraction and contractInteractionDayData after updating volumeUSD in take function --- src/mappings/book-manager/take.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 6b5ac1e..56498f3 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -83,11 +83,12 @@ export function handleTake(event: Take): void { contractInteractionDayData.callCount.plus(ONE_BI) contractInteractionDayData.volumeUSD = contractInteractionDayData.volumeUSD.plus(volumeUsdBD) - contractInteractionDayData.save() contractInteraction.callCount = contractInteraction.callCount.plus(ONE_BI) contractInteraction.volumeUSD = contractInteraction.volumeUSD.plus(volumeUsdBD) + contractInteractionDayData.save() + contractInteraction.save() cloberDayData.save() } From 7a1f1181b0e5b001a1b9c1dfb5e85d93d4e9b740 Mon Sep 17 00:00:00 2001 From: graykode Date: Thu, 19 Feb 2026 14:02:32 +0900 Subject: [PATCH 14/18] feat: add chain and config files for token definitions and network configuration --- config/base/chain.ts | 62 +++++++++++++++++++++++++++++++++++++++++ config/base/config.json | 16 +++++++++++ 2 files changed, 78 insertions(+) create mode 100644 config/base/chain.ts create mode 100644 config/base/config.json diff --git a/config/base/chain.ts b/config/base/chain.ts new file mode 100644 index 0000000..32beb4f --- /dev/null +++ b/config/base/chain.ts @@ -0,0 +1,62 @@ +import { Address, BigDecimal, BigInt } from '@graphprotocol/graph-ts' +export const SKIP_CHART = true +export const SKIP_TAKE_AND_SWAP = true +export const SKIP_TX_ANALYTICS = true +export const SKIP_USER_ANALYTICS = true + +export const OPERATOR = '0x00f7a0c7e66f0e3a10d9e980e0854ebe0e308625' +export const LIQUIDITY_VAULT = '0xca1f6e4ae690d06e3bf943b9019c5ca060c0b834' + +export class TokenDefinition { + address: Address + symbol: string + name: string + decimals: BigInt +} + +export const NATIVE_TOKEN_DEFINITION: TokenDefinition = { + address: Address.fromString('0x0000000000000000000000000000000000000000'), + symbol: 'ETH', + name: 'Ethereum', + decimals: BigInt.fromI32(18), +} + +export const NATIVE_TOKEN_BOOK_ID: BigInt = BigInt.fromString( + '305798090575971420747066887426250327115295993737352425987', // bid book in ETH/USDC +) + +export const STABLE_COINS: string[] = [ + '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC + '0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca', // USDbC +] + +export const MINIMUM_USD_LOCKED = BigDecimal.fromString('0') + +export const REFERENCE_TOKEN = '0x4200000000000000000000000000000000000006' + +export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = [ + { + address: Address.fromString('0x0000000000000000000000000000000000000000'), + symbol: 'ETH', + name: 'Ethereum', + decimals: BigInt.fromI32(18), + }, + { + address: Address.fromString('0x4200000000000000000000000000000000000006'), + symbol: 'WETH', + name: 'Wrapped Ether', + decimals: BigInt.fromI32(18), + }, + { + address: Address.fromString('0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'), + symbol: 'USDC', + name: 'USD Coin', + decimals: BigInt.fromI32(6), + }, + { + address: Address.fromString('0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca'), + symbol: 'USDbC', + name: 'USD Base Coin', + decimals: BigInt.fromI32(6), + }, +] diff --git a/config/base/config.json b/config/base/config.json new file mode 100644 index 0000000..f94c4bc --- /dev/null +++ b/config/base/config.json @@ -0,0 +1,16 @@ +{ + "network": "base", + "BookManager": { + "address": "0x8ca3a6f4a6260661fcb9a25584c796a1fa380112", + "startBlock": 40941003 + }, + "LiquidityVault": { + "address": "0xca1f6e4ae690d06e3bf943b9019c5ca060c0b834", + "startBlock": 41325337 + }, + "SimpleOracleStrategy": { + "address": "0x29e07197ccf70d0ac6cb0a3c307627819f5f2777", + "startBlock": 41325337 + }, + "hasRouterGateway": false +} \ No newline at end of file From 07a9b71369d23c034b3a0639ad942f63cc3d31fc Mon Sep 17 00:00:00 2001 From: graykode Date: Thu, 19 Feb 2026 14:02:44 +0900 Subject: [PATCH 15/18] feat: add base network configuration to prepare-network.ts --- script/utils/prepare-network.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/script/utils/prepare-network.ts b/script/utils/prepare-network.ts index fbaab0b..de4dde4 100644 --- a/script/utils/prepare-network.ts +++ b/script/utils/prepare-network.ts @@ -9,6 +9,7 @@ export enum NETWORK { MONAD_TESTNET = 'monad-testnet', MONAD_MAINNET = 'monad-mainnet', MONAD = 'monad', // monad-mainnet alias + base = 'base', RISE_SEPOLIA = 'rise-sepolia', ARBITRUM_SEPOLIA = 'arbitrum-sepolia', BERACHAIN_MAINNET = 'berachain-mainnet', From 1a1313dd015d310e2870dafa9592ad28cd6c5a5a Mon Sep 17 00:00:00 2001 From: graykode Date: Thu, 19 Feb 2026 14:53:23 +0900 Subject: [PATCH 16/18] feat: define BID_BOOK_ID and ASK_BOOK_ID constants in chain.ts; simplify book ID checks in handleTake function --- config/base/chain.ts | 8 ++++++++ config/monad/chain.ts | 8 ++++++++ src/mappings/book-manager/take.ts | 21 ++++----------------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/config/base/chain.ts b/config/base/chain.ts index 32beb4f..7b0a791 100644 --- a/config/base/chain.ts +++ b/config/base/chain.ts @@ -25,6 +25,14 @@ export const NATIVE_TOKEN_BOOK_ID: BigInt = BigInt.fromString( '305798090575971420747066887426250327115295993737352425987', // bid book in ETH/USDC ) +export const BID_BOOK_ID: BigInt = BigInt.fromString( + '305798090575971420747066887426250327115295993737352425987', // bid book in ETH/USDC +) + +export const ASK_BOOK_ID: BigInt = BigInt.fromString( + '195945309878431825165287262143162122266744910429476987829', // ask book in ETH/USDC +) + export const STABLE_COINS: string[] = [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC '0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca', // USDbC diff --git a/config/monad/chain.ts b/config/monad/chain.ts index afe95ee..3918ef5 100644 --- a/config/monad/chain.ts +++ b/config/monad/chain.ts @@ -25,6 +25,14 @@ export const NATIVE_TOKEN_BOOK_ID: BigInt = BigInt.fromString( '5954885684956363054050231031211743946744177791604395877538', ) +export const BID_BOOK_ID: BigInt = BigInt.fromString( + '5954885684956363054050231031211743946744177791604395877538', // bid book in ETH/USDC +) + +export const ASK_BOOK_ID: BigInt = BigInt.fromString( + '3875727077379471850923186002296331935053867847116966170720', // bid book in ETH/USDC +) + export const STABLE_COINS: string[] = [ '0x754704bc059f8c67012fed69bc8a327a5aafb603', // USDC '0xe7cd86e13ac4309349f30b3435a9d337750fc82d', // USDT diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 56498f3..9bd24dc 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -10,31 +10,18 @@ import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' import { tickToPrice } from '../../common/tick' import { unitToBase } from '../../common/amount' import { convertTokenToDecimal } from '../../common/utils' +import { BID_BOOK_ID } from '../../common/chain' +import { ASK_BOOK_ID } from '../../../config/base/chain' export function handleTake(event: Take): void { const bookId = event.params.bookId - if ( - !bookId.equals( - BigInt.fromString( - '3875727077379471850923186002296331935053867847116966170720', // ask - ), - ) && - !bookId.equals( - BigInt.fromString( - '5954885684956363054050231031211743946744177791604395877538', // bid - ), - ) - ) { + if (!bookId.equals(BID_BOOK_ID) && !bookId.equals(ASK_BOOK_ID)) { return } if (!event.transaction.to) { return } - const isTakingBidBook = bookId.equals( - BigInt.fromString( - '5954885684956363054050231031211743946744177791604395877538', - ), - ) + const isTakingBidBook = bookId.equals(ASK_BOOK_ID) const priceRaw = tickToPrice(event.params.tick) const volumeUsd = isTakingBidBook ? event.params.unit From 457fdcbb7b477f4a0b3e857de0523837b3236f69 Mon Sep 17 00:00:00 2001 From: graykode Date: Thu, 19 Feb 2026 14:55:06 +0900 Subject: [PATCH 17/18] fix: consolidate BID_BOOK_ID and ASK_BOOK_ID imports in take.ts --- src/mappings/book-manager/take.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 9bd24dc..538733c 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -10,8 +10,7 @@ import { ONE_BI, ZERO_BD, ZERO_BI } from '../../common/constants' import { tickToPrice } from '../../common/tick' import { unitToBase } from '../../common/amount' import { convertTokenToDecimal } from '../../common/utils' -import { BID_BOOK_ID } from '../../common/chain' -import { ASK_BOOK_ID } from '../../../config/base/chain' +import { BID_BOOK_ID, ASK_BOOK_ID } from '../../common/chain' export function handleTake(event: Take): void { const bookId = event.params.bookId From ec141d5f2129b2ef2254fdd40254c3dbf4dd7d7a Mon Sep 17 00:00:00 2001 From: graykode Date: Thu, 19 Feb 2026 16:02:54 +0900 Subject: [PATCH 18/18] fix: correct book ID check in take function to use BID_BOOK_ID --- src/mappings/book-manager/take.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mappings/book-manager/take.ts b/src/mappings/book-manager/take.ts index 538733c..4f418a4 100644 --- a/src/mappings/book-manager/take.ts +++ b/src/mappings/book-manager/take.ts @@ -20,7 +20,7 @@ export function handleTake(event: Take): void { if (!event.transaction.to) { return } - const isTakingBidBook = bookId.equals(ASK_BOOK_ID) + const isTakingBidBook = bookId.equals(BID_BOOK_ID) const priceRaw = tickToPrice(event.params.tick) const volumeUsd = isTakingBidBook ? event.params.unit