diff --git a/Makalu/contracts/subgraph/.gitignore b/Makalu/contracts/subgraph/.gitignore new file mode 100644 index 00000000..96808947 --- /dev/null +++ b/Makalu/contracts/subgraph/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +generated/ +build/ +.turbo/ diff --git a/Makalu/contracts/subgraph/README.md b/Makalu/contracts/subgraph/README.md new file mode 100644 index 00000000..e33c6d52 --- /dev/null +++ b/Makalu/contracts/subgraph/README.md @@ -0,0 +1,58 @@ +# Lithoswap V2 Subgraph (Makalu) + +Indexes the Lithoswap V2 DEX on Lithosphere Makalu (700777) for pool, price and +volume analytics used by the explorer. It mirrors the pattern of the Kamet DEX +subgraph (self-hosted graph-node on vps2, `subgraph.litho.ai`) but targets our +**V2** contracts — the Kamet subgraph is **v3-shaped** (`sqrtPriceX96`, tick +math) and does not index v2, so this is a v2 fork of that approach, not a copy. + +## What it tracks + +Reserves, reserve-ratio prices (`token0Price` = token1 per token0), per-token +and per-pair **volume in token units**, swap/mint/burn events, and daily +aggregates (`PairDayData`, `TokenDayData`). **USD pricing is intentionally +omitted** — Makalu has no stablecoin pool to anchor it. When one lands, add a +`Bundle` + derived-ETH pricing (the canonical Uniswap-V2 approach) on top. + +## Configure after deploying the DEX + +The factory address and start block are placeholders until the DEX is deployed +(`Makalu/contracts/scripts/deploy-dex.ts` writes `deployments/dex-700777.json`). +Fill both in `networks.json` (and/or `subgraph.yaml`): + +- `LithoswapV2Factory.address` → the deployed `LithoswapV2Factory` +- `startBlock` → the block the factory was deployed in (avoids scanning genesis) + +## Build & deploy + +```sh +cd Makalu/contracts/subgraph +pnpm install +pnpm codegen # generates ./generated from schema + ABIs +pnpm build:makalu # applies networks.json, compiles the wasm mappings +pnpm deploy # → subgraph.litho.ai (self-hosted graph-node on vps2) +``` + +`codegen` + `build` are the correctness gate for the AssemblyScript mappings — +run them wherever `@graphprotocol/graph-cli` and network access are available +(vps2 or CI); they are not run in this offline workspace. + +## Consuming from the explorer + +Query `https://subgraph.litho.ai/subgraphs/name/litho/lithoswap`. Example — top +pools by tx count with current price: + +```graphql +{ + pairs(first: 10, orderBy: txCount, orderDirection: desc) { + id + token0 { symbol } + token1 { symbol } + reserve0 + reserve1 + token0Price + volumeToken0 + txCount + } +} +``` diff --git a/Makalu/contracts/subgraph/abis/ERC20.json b/Makalu/contracts/subgraph/abis/ERC20.json new file mode 100644 index 00000000..c0a1efb0 --- /dev/null +++ b/Makalu/contracts/subgraph/abis/ERC20.json @@ -0,0 +1,30 @@ +[ + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/Makalu/contracts/subgraph/abis/LithoswapV2Factory.json b/Makalu/contracts/subgraph/abis/LithoswapV2Factory.json new file mode 100644 index 00000000..3136aa36 --- /dev/null +++ b/Makalu/contracts/subgraph/abis/LithoswapV2Factory.json @@ -0,0 +1,30 @@ +[ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "token0", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "token1", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "pair", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "PairCreated", + "type": "event" + }, + { + "inputs": [], + "name": "allPairsLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "getPair", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/Makalu/contracts/subgraph/abis/LithoswapV2Pair.json b/Makalu/contracts/subgraph/abis/LithoswapV2Pair.json new file mode 100644 index 00000000..52ade362 --- /dev/null +++ b/Makalu/contracts/subgraph/abis/LithoswapV2Pair.json @@ -0,0 +1,87 @@ +[ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount0", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount1", "type": "uint256" } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount0", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount1", "type": "uint256" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount0In", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount1In", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount0Out", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount1Out", "type": "uint256" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint112", "name": "reserve0", "type": "uint112" }, + { "indexed": false, "internalType": "uint112", "name": "reserve1", "type": "uint112" } + ], + "name": "Sync", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "token0", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReserves", + "outputs": [ + { "internalType": "uint112", "name": "reserve0", "type": "uint112" }, + { "internalType": "uint112", "name": "reserve1", "type": "uint112" }, + { "internalType": "uint32", "name": "blockTimestampLast", "type": "uint32" } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/Makalu/contracts/subgraph/networks.json b/Makalu/contracts/subgraph/networks.json new file mode 100644 index 00000000..926a8928 --- /dev/null +++ b/Makalu/contracts/subgraph/networks.json @@ -0,0 +1,8 @@ +{ + "makalu": { + "LithoswapV2Factory": { + "address": "0x0000000000000000000000000000000000000000", + "startBlock": 0 + } + } +} diff --git a/Makalu/contracts/subgraph/package.json b/Makalu/contracts/subgraph/package.json new file mode 100644 index 00000000..f4af4f72 --- /dev/null +++ b/Makalu/contracts/subgraph/package.json @@ -0,0 +1,18 @@ +{ + "name": "@lithosphere/lithoswap-subgraph", + "version": "0.1.0", + "private": true, + "description": "Lithoswap V2 subgraph — pools, prices and volume on Lithosphere Makalu", + "scripts": { + "codegen": "graph codegen", + "build": "graph build", + "build:makalu": "graph build --network makalu", + "create:local": "graph create --node http://localhost:8020/ litho/lithoswap", + "deploy:local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 litho/lithoswap", + "deploy": "graph deploy --node https://subgraph.litho.ai/deploy/ --ipfs https://subgraph.litho.ai/ipfs/ litho/lithoswap" + }, + "devDependencies": { + "@graphprotocol/graph-cli": "0.71.0", + "@graphprotocol/graph-ts": "0.32.0" + } +} diff --git a/Makalu/contracts/subgraph/schema.graphql b/Makalu/contracts/subgraph/schema.graphql new file mode 100644 index 00000000..c0e9f859 --- /dev/null +++ b/Makalu/contracts/subgraph/schema.graphql @@ -0,0 +1,116 @@ +# Lithoswap V2 subgraph schema (Makalu). +# +# Focused on on-chain facts that don't need a USD reference: reserves, +# reserve-ratio prices, token-denominated volumes, liquidity/swap events, and +# daily aggregates for charts. USD pricing is intentionally omitted — Makalu has +# no stablecoin pool to anchor it; add a Bundle + derived pricing later if one +# lands. + +type LithoswapFactory @entity { + " Factory address " + id: ID! + pairCount: Int! + txCount: BigInt! + totalVolumeToken: BigDecimal! # summed across pairs, token units (not USD) +} + +type Token @entity { + " Token address " + id: ID! + symbol: String! + name: String! + decimals: BigInt! + totalSupply: BigInt! + tradeVolume: BigDecimal! # cumulative volume in this token's units + txCount: BigInt! + totalLiquidity: BigDecimal! # amount of this token pooled across all pairs +} + +type Pair @entity { + " Pair (pool) address " + id: ID! + token0: Token! + token1: Token! + reserve0: BigDecimal! + reserve1: BigDecimal! + totalSupply: BigDecimal! # LP token supply + " token1 per token0 (reserve1/reserve0) " + token0Price: BigDecimal! + " token0 per token1 (reserve0/reserve1) " + token1Price: BigDecimal! + volumeToken0: BigDecimal! + volumeToken1: BigDecimal! + txCount: BigInt! + createdAtTimestamp: BigInt! + createdAtBlockNumber: BigInt! +} + +type Transaction @entity { + " Transaction hash " + id: ID! + blockNumber: BigInt! + timestamp: BigInt! + mints: [Mint!]! @derivedFrom(field: "transaction") + burns: [Burn!]! @derivedFrom(field: "transaction") + swaps: [Swap!]! @derivedFrom(field: "transaction") +} + +type Mint @entity { + " txhash-logindex " + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + sender: Bytes! + amount0: BigDecimal! + amount1: BigDecimal! +} + +type Burn @entity { + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + sender: Bytes! + to: Bytes! + amount0: BigDecimal! + amount1: BigDecimal! +} + +type Swap @entity { + id: ID! + transaction: Transaction! + timestamp: BigInt! + pair: Pair! + sender: Bytes! + from: Bytes! + to: Bytes! + amount0In: BigDecimal! + amount1In: BigDecimal! + amount0Out: BigDecimal! + amount1Out: BigDecimal! +} + +type PairDayData @entity { + " pairAddress-dayId " + id: ID! + date: Int! + pair: Pair! + token0: Token! + token1: Token! + reserve0: BigDecimal! + reserve1: BigDecimal! + dailyVolumeToken0: BigDecimal! + dailyVolumeToken1: BigDecimal! + dailyTxns: BigInt! +} + +type TokenDayData @entity { + " tokenAddress-dayId " + id: ID! + date: Int! + token: Token! + dailyVolumeToken: BigDecimal! + totalLiquidityToken: BigDecimal! + dailyTxns: BigInt! +} diff --git a/Makalu/contracts/subgraph/src/factory.ts b/Makalu/contracts/subgraph/src/factory.ts new file mode 100644 index 00000000..fc5767e7 --- /dev/null +++ b/Makalu/contracts/subgraph/src/factory.ts @@ -0,0 +1,73 @@ +/* eslint-disable prefer-const */ +import { Address } from '@graphprotocol/graph-ts'; +import { PairCreated } from '../generated/LithoswapV2Factory/LithoswapV2Factory'; +import { LithoswapFactory, Pair, Token } from '../generated/schema'; +import { LithoswapV2Pair as PairTemplate } from '../generated/templates'; +import { + ONE_BI, + ZERO_BD, + ZERO_BI, + fetchTokenDecimals, + fetchTokenName, + fetchTokenSymbol, + fetchTokenTotalSupply, +} from './helpers'; + +// Factory address is read from the event, so no constant is hardcoded here. +function loadOrCreateFactory(address: string): LithoswapFactory { + let factory = LithoswapFactory.load(address); + if (factory === null) { + factory = new LithoswapFactory(address); + factory.pairCount = 0; + factory.txCount = ZERO_BI; + factory.totalVolumeToken = ZERO_BD; + } + return factory as LithoswapFactory; +} + +function loadOrCreateToken(address: string): Token { + let token = Token.load(address); + if (token === null) { + let addr = Address.fromString(address); + token = new Token(address); + token.symbol = fetchTokenSymbol(addr); + token.name = fetchTokenName(addr); + token.decimals = fetchTokenDecimals(addr); + token.totalSupply = fetchTokenTotalSupply(addr); + token.tradeVolume = ZERO_BD; + token.txCount = ZERO_BI; + token.totalLiquidity = ZERO_BD; + } + return token as Token; +} + +export function handleNewPair(event: PairCreated): void { + let factory = loadOrCreateFactory(event.address.toHexString()); + factory.pairCount = factory.pairCount + 1; + factory.txCount = factory.txCount.plus(ONE_BI); + + let token0 = loadOrCreateToken(event.params.token0.toHexString()); + let token1 = loadOrCreateToken(event.params.token1.toHexString()); + token0.save(); + token1.save(); + + let pair = new Pair(event.params.pair.toHexString()); + pair.token0 = token0.id; + pair.token1 = token1.id; + pair.reserve0 = ZERO_BD; + pair.reserve1 = ZERO_BD; + pair.totalSupply = ZERO_BD; + pair.token0Price = ZERO_BD; + pair.token1Price = ZERO_BD; + pair.volumeToken0 = ZERO_BD; + pair.volumeToken1 = ZERO_BD; + pair.txCount = ZERO_BI; + pair.createdAtTimestamp = event.block.timestamp; + pair.createdAtBlockNumber = event.block.number; + pair.save(); + + // Start indexing the new pair's events. + PairTemplate.create(event.params.pair); + + factory.save(); +} diff --git a/Makalu/contracts/subgraph/src/helpers.ts b/Makalu/contracts/subgraph/src/helpers.ts new file mode 100644 index 00000000..a0772401 --- /dev/null +++ b/Makalu/contracts/subgraph/src/helpers.ts @@ -0,0 +1,92 @@ +/* eslint-disable prefer-const */ +import { BigInt, BigDecimal, Address, ethereum } from '@graphprotocol/graph-ts'; +import { ERC20 } from '../generated/LithoswapV2Factory/ERC20'; +import { Pair, PairDayData, Token, TokenDayData } from '../generated/schema'; + +export let ZERO_BI = BigInt.fromI32(0); +export let ONE_BI = BigInt.fromI32(1); +export let ZERO_BD = BigDecimal.fromString('0'); +export let ONE_BD = BigDecimal.fromString('1'); + +export function exponentToBigDecimal(decimals: BigInt): BigDecimal { + let bd = ONE_BD; + for (let i = ZERO_BI; i.lt(decimals); i = i.plus(ONE_BI)) { + bd = bd.times(BigDecimal.fromString('10')); + } + return bd; +} + +/** Scale a raw token amount by its decimals into a human BigDecimal. */ +export function convertTokenToDecimal(tokenAmount: BigInt, exchangeDecimals: BigInt): BigDecimal { + if (exchangeDecimals == ZERO_BI) return tokenAmount.toBigDecimal(); + return tokenAmount.toBigDecimal().div(exponentToBigDecimal(exchangeDecimals)); +} + +export function fetchTokenSymbol(tokenAddress: Address): string { + let contract = ERC20.bind(tokenAddress); + let result = contract.try_symbol(); + return result.reverted ? 'unknown' : result.value; +} + +export function fetchTokenName(tokenAddress: Address): string { + let contract = ERC20.bind(tokenAddress); + let result = contract.try_name(); + return result.reverted ? 'unknown' : result.value; +} + +export function fetchTokenDecimals(tokenAddress: Address): BigInt { + let contract = ERC20.bind(tokenAddress); + let result = contract.try_decimals(); + return result.reverted ? BigInt.fromI32(18) : BigInt.fromI32(result.value); +} + +export function fetchTokenTotalSupply(tokenAddress: Address): BigInt { + let contract = ERC20.bind(tokenAddress); + let result = contract.try_totalSupply(); + return result.reverted ? ZERO_BI : result.value; +} + +/** Load-or-create today's PairDayData, refreshing reserves and bumping the txn + * counter. The caller adds volume and saves. */ +export function updatePairDayData(event: ethereum.Event): PairDayData { + let timestamp = event.block.timestamp.toI32(); + let dayID = timestamp / 86400; + let dayStart = dayID * 86400; + let id = event.address.toHexString().concat('-').concat(BigInt.fromI32(dayID).toString()); + let pair = Pair.load(event.address.toHexString())!; + + let data = PairDayData.load(id); + if (data === null) { + data = new PairDayData(id); + data.date = dayStart; + data.pair = pair.id; + data.token0 = pair.token0; + data.token1 = pair.token1; + data.dailyVolumeToken0 = ZERO_BD; + data.dailyVolumeToken1 = ZERO_BD; + data.dailyTxns = ZERO_BI; + } + data.reserve0 = pair.reserve0; + data.reserve1 = pair.reserve1; + data.dailyTxns = data.dailyTxns.plus(ONE_BI); + return data as PairDayData; +} + +export function updateTokenDayData(token: Token, event: ethereum.Event): TokenDayData { + let timestamp = event.block.timestamp.toI32(); + let dayID = timestamp / 86400; + let dayStart = dayID * 86400; + let id = token.id.concat('-').concat(BigInt.fromI32(dayID).toString()); + + let data = TokenDayData.load(id); + if (data === null) { + data = new TokenDayData(id); + data.date = dayStart; + data.token = token.id; + data.dailyVolumeToken = ZERO_BD; + data.dailyTxns = ZERO_BI; + } + data.totalLiquidityToken = token.totalLiquidity; + data.dailyTxns = data.dailyTxns.plus(ONE_BI); + return data as TokenDayData; +} diff --git a/Makalu/contracts/subgraph/src/pair.ts b/Makalu/contracts/subgraph/src/pair.ts new file mode 100644 index 00000000..d490bac7 --- /dev/null +++ b/Makalu/contracts/subgraph/src/pair.ts @@ -0,0 +1,160 @@ +/* eslint-disable prefer-const */ +import { BigInt, ethereum } from '@graphprotocol/graph-ts'; +import { + Sync, + Swap as SwapEvent, + Mint as MintEvent, + Burn as BurnEvent, + LithoswapV2Pair as PairContract, +} from '../generated/templates/LithoswapV2Pair/LithoswapV2Pair'; +import { Pair, Token, Transaction, Swap, Mint, Burn } from '../generated/schema'; +import { + ONE_BI, + ZERO_BD, + convertTokenToDecimal, + updatePairDayData, + updateTokenDayData, +} from './helpers'; + +function loadOrCreateTransaction(event: ethereum.Event): Transaction { + let id = event.transaction.hash.toHexString(); + let tx = Transaction.load(id); + if (tx === null) { + tx = new Transaction(id); + tx.blockNumber = event.block.number; + tx.timestamp = event.block.timestamp; + tx.save(); + } + return tx as Transaction; +} + +export function handleSync(event: Sync): void { + let pair = Pair.load(event.address.toHexString()); + if (pair === null) return; + let token0 = Token.load(pair.token0)!; + let token1 = Token.load(pair.token1)!; + + // Roll the old reserves out of each token's pooled total before overwriting. + token0.totalLiquidity = token0.totalLiquidity.minus(pair.reserve0); + token1.totalLiquidity = token1.totalLiquidity.minus(pair.reserve1); + + pair.reserve0 = convertTokenToDecimal(event.params.reserve0, token0.decimals); + pair.reserve1 = convertTokenToDecimal(event.params.reserve1, token1.decimals); + + token0.totalLiquidity = token0.totalLiquidity.plus(pair.reserve0); + token1.totalLiquidity = token1.totalLiquidity.plus(pair.reserve1); + + pair.token0Price = pair.reserve0.gt(ZERO_BD) ? pair.reserve1.div(pair.reserve0) : ZERO_BD; + pair.token1Price = pair.reserve1.gt(ZERO_BD) ? pair.reserve0.div(pair.reserve1) : ZERO_BD; + + let contract = PairContract.bind(event.address); + let supply = contract.try_totalSupply(); + if (!supply.reverted) { + pair.totalSupply = convertTokenToDecimal(supply.value, BigInt.fromI32(18)); + } + + token0.save(); + token1.save(); + pair.save(); +} + +export function handleSwap(event: SwapEvent): void { + let pair = Pair.load(event.address.toHexString()); + if (pair === null) return; + let token0 = Token.load(pair.token0)!; + let token1 = Token.load(pair.token1)!; + + let amount0In = convertTokenToDecimal(event.params.amount0In, token0.decimals); + let amount1In = convertTokenToDecimal(event.params.amount1In, token1.decimals); + let amount0Out = convertTokenToDecimal(event.params.amount0Out, token0.decimals); + let amount1Out = convertTokenToDecimal(event.params.amount1Out, token1.decimals); + let amount0Total = amount0In.plus(amount0Out); + let amount1Total = amount1In.plus(amount1Out); + + pair.volumeToken0 = pair.volumeToken0.plus(amount0Total); + pair.volumeToken1 = pair.volumeToken1.plus(amount1Total); + pair.txCount = pair.txCount.plus(ONE_BI); + + token0.tradeVolume = token0.tradeVolume.plus(amount0Total); + token1.tradeVolume = token1.tradeVolume.plus(amount1Total); + token0.txCount = token0.txCount.plus(ONE_BI); + token1.txCount = token1.txCount.plus(ONE_BI); + + token0.save(); + token1.save(); + pair.save(); + + let tx = loadOrCreateTransaction(event); + let swap = new Swap( + event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()), + ); + swap.transaction = tx.id; + swap.timestamp = event.block.timestamp; + swap.pair = pair.id; + swap.sender = event.params.sender; + swap.from = event.transaction.from; + swap.to = event.params.to; + swap.amount0In = amount0In; + swap.amount1In = amount1In; + swap.amount0Out = amount0Out; + swap.amount1Out = amount1Out; + swap.save(); + + let pdd = updatePairDayData(event); + pdd.dailyVolumeToken0 = pdd.dailyVolumeToken0.plus(amount0Total); + pdd.dailyVolumeToken1 = pdd.dailyVolumeToken1.plus(amount1Total); + pdd.save(); + + let t0dd = updateTokenDayData(token0, event); + t0dd.dailyVolumeToken = t0dd.dailyVolumeToken.plus(amount0Total); + t0dd.save(); + + let t1dd = updateTokenDayData(token1, event); + t1dd.dailyVolumeToken = t1dd.dailyVolumeToken.plus(amount1Total); + t1dd.save(); +} + +export function handleMint(event: MintEvent): void { + let pair = Pair.load(event.address.toHexString()); + if (pair === null) return; + let token0 = Token.load(pair.token0)!; + let token1 = Token.load(pair.token1)!; + + let tx = loadOrCreateTransaction(event); + let mint = new Mint( + event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()), + ); + mint.transaction = tx.id; + mint.timestamp = event.block.timestamp; + mint.pair = pair.id; + mint.sender = event.params.sender; + mint.amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals); + mint.amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals); + mint.save(); + + pair.txCount = pair.txCount.plus(ONE_BI); + pair.save(); +} + +export function handleBurn(event: BurnEvent): void { + let pair = Pair.load(event.address.toHexString()); + if (pair === null) return; + let token0 = Token.load(pair.token0)!; + let token1 = Token.load(pair.token1)!; + + let tx = loadOrCreateTransaction(event); + let burn = new Burn( + event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()), + ); + burn.transaction = tx.id; + burn.timestamp = event.block.timestamp; + burn.pair = pair.id; + burn.sender = event.params.sender; + burn.to = event.params.to; + burn.amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals); + burn.amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals); + burn.save(); + + pair.txCount = pair.txCount.plus(ONE_BI); + pair.save(); +} diff --git a/Makalu/contracts/subgraph/subgraph.yaml b/Makalu/contracts/subgraph/subgraph.yaml new file mode 100644 index 00000000..5000b8b2 --- /dev/null +++ b/Makalu/contracts/subgraph/subgraph.yaml @@ -0,0 +1,68 @@ +specVersion: 0.0.5 +description: Lithoswap V2 — pools, prices, and volume on Lithosphere Makalu +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum/contract + name: LithoswapV2Factory + # network name must match the graph-node's configured chain for Makalu. + network: makalu + source: + # Filled from deployments/dex-700777.json (LithoswapV2Factory) after deploy. + # Override via networks.json (`graph build --network makalu`). + address: "0x0000000000000000000000000000000000000000" + abi: LithoswapV2Factory + startBlock: 0 + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./src/factory.ts + entities: + - LithoswapFactory + - Pair + - Token + abis: + - name: LithoswapV2Factory + file: ./abis/LithoswapV2Factory.json + - name: LithoswapV2Pair + file: ./abis/LithoswapV2Pair.json + - name: ERC20 + file: ./abis/ERC20.json + eventHandlers: + - event: PairCreated(indexed address,indexed address,address,uint256) + handler: handleNewPair +templates: + - kind: ethereum/contract + name: LithoswapV2Pair + network: makalu + source: + abi: LithoswapV2Pair + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./src/pair.ts + entities: + - Pair + - Token + - Transaction + - Mint + - Burn + - Swap + - PairDayData + - TokenDayData + abis: + - name: LithoswapV2Pair + file: ./abis/LithoswapV2Pair.json + - name: ERC20 + file: ./abis/ERC20.json + eventHandlers: + - event: Sync(uint112,uint112) + handler: handleSync + - event: Swap(indexed address,uint256,uint256,uint256,uint256,indexed address) + handler: handleSwap + - event: Mint(indexed address,uint256,uint256) + handler: handleMint + - event: Burn(indexed address,uint256,uint256,indexed address) + handler: handleBurn