From 320b474ce81218670b142fa82c82014ad747268e Mon Sep 17 00:00:00 2001 From: LeadDev Date: Sat, 14 May 2022 19:27:16 +0530 Subject: [PATCH] feat: add funding observation --- rage/generated/schema.ts | 67 +++++++++++++++++++++ rage/schema.graphql | 42 +++++++++---- rage/src/mappings/clearinghouse/handlers.ts | 13 ++++ rage/src/utils/index.ts | 21 ++++++- 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/rage/generated/schema.ts b/rage/generated/schema.ts index 11d5c13..b2d31e1 100644 --- a/rage/generated/schema.ts +++ b/rage/generated/schema.ts @@ -1958,6 +1958,15 @@ export class RageTradePool extends Entity { set dayData(value: string) { this.set("dayData", Value.fromString(value)); } + + get fundingObservations(): Array { + let value = this.get("fundingObservations"); + return value.toStringArray(); + } + + set fundingObservations(value: Array) { + this.set("fundingObservations", Value.fromStringArray(value)); + } } export class VToken extends Entity { @@ -2067,6 +2076,64 @@ export class VPoolWrapper extends Entity { } } +export class FundingObservation extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id !== null, "Cannot save FundingObservation entity without an ID"); + assert( + id.kind == ValueKind.STRING, + "Cannot save FundingObservation entity with non-string ID. " + + 'Considering using .toHex() to convert the "id" to a string.' + ); + store.set("FundingObservation", id.toString(), this); + } + + static load(id: string): FundingObservation | null { + return store.get("FundingObservation", id) as FundingObservation | null; + } + + get id(): string { + let value = this.get("id"); + return value.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get timestamp(): BigInt { + let value = this.get("timestamp"); + return value.toBigInt(); + } + + set timestamp(value: BigInt) { + this.set("timestamp", Value.fromBigInt(value)); + } + + get fundingRate(): BigDecimal { + let value = this.get("fundingRate"); + return value.toBigDecimal(); + } + + set fundingRate(value: BigDecimal) { + this.set("fundingRate", Value.fromBigDecimal(value)); + } + + get pool(): string { + let value = this.get("pool"); + return value.toString(); + } + + set pool(value: string) { + this.set("pool", Value.fromString(value)); + } +} + export class Collection extends Entity { constructor(id: string) { super(); diff --git a/rage/schema.graphql b/rage/schema.graphql index caf7622..126de86 100644 --- a/rage/schema.graphql +++ b/rage/schema.graphql @@ -28,17 +28,20 @@ type Account @entity { "Total number of swaps made by the account" tokenPositionChangeEntriesCount: BigInt! "list all swaps made by the account" - tokenPositionChangeEntries: [TokenPositionChangeEntry!]! @derivedFrom(field: "account") + tokenPositionChangeEntries: [TokenPositionChangeEntry!]! + @derivedFrom(field: "account") "list of all margin/collateral tokens deposited by the account, currently only USDC" margin: [Collateral!]! @derivedFrom(field: "account") "total number time a funding payment realized for an account" fundingPaymentRealizedEntriesCount: BigInt! "list of funding payment realized entries for an account" - fundingPaymentRealizedEntries: [FundingPaymentRealizedEntry!]! @derivedFrom(field: "account") + fundingPaymentRealizedEntries: [FundingPaymentRealizedEntry!]! + @derivedFrom(field: "account") "total number of liquidations that occurred for this account" tokenPositionLiquidatedEntriesCount: BigInt! "list of all liquidations that occurred for this account" - tokenPositionLiquidatedEntries: [TokenPositionLiquidatedEntry!]! @derivedFrom(field: "account") + tokenPositionLiquidatedEntries: [TokenPositionLiquidatedEntry!]! + @derivedFrom(field: "account") "list of all V-Token tokens positions held by the account, currently only ETH" tokenPositions: [TokenPosition!]! @derivedFrom(field: "account") "total number of margin changes made by the account ie. withdraws and deposits" @@ -148,13 +151,15 @@ type TokenPosition @entity { "Total number of swaps made by the account, for this pool" tokenPositionChangeEntriesCount: BigInt! "list all swaps made by the account, for this pool" - tokenPositionChangeEntries: [TokenPositionChangeEntry!]! @derivedFrom(field: "tokenPosition") + tokenPositionChangeEntries: [TokenPositionChangeEntry!]! + @derivedFrom(field: "tokenPosition") "total number time a funding payment realized entry was created for this position" fundingPaymentRealizedEntriesCount: BigInt! "timestamp of the last funding payment realized entry for this position" lastFundingPaymentRealizedEntryTimestamp: BigInt! "list of funding payment realized entries for this position" - fundingPaymentRealizedEntries: [FundingPaymentRealizedEntry!]! @derivedFrom(field: "tokenPosition") + fundingPaymentRealizedEntries: [FundingPaymentRealizedEntry!]! + @derivedFrom(field: "tokenPosition") "list of id(s) of the token position change entries, that are 'open' positions, used for calculating the pnl" openPositionEntries: [String!]! "the latest token position change entry, used in calculation for TokenPositionLiquidated event" @@ -162,7 +167,8 @@ type TokenPosition @entity { "total number of liquidations that occurred for this position" tokenPositionLiquidatedEntriesCount: BigInt! "list of all liquidations that occurred for this position" - tokenPositionLiquidatedEntries: [TokenPositionLiquidatedEntry!]! @derivedFrom(field: "tokenPosition") + tokenPositionLiquidatedEntries: [TokenPositionLiquidatedEntry!]! + @derivedFrom(field: "tokenPosition") "total funding payment amount for this position" totalRealizedFundingPaymentAmount: BigDecimal! "latest sum of all the A terms in the pool, at the time of the position change" @@ -178,7 +184,7 @@ type TokenPosition @entity { "sum aff (vTokenQuantity * entryPrice), across all token position change entries" entryValue: BigDecimal! "entryPrice = abs(entryValue / netPosition)" - entryPrice: BigDecimal! + entryPrice: BigDecimal! } """ @@ -194,7 +200,7 @@ token position change """ type MarginChangeEntry @entity { "unique id of the margin change entry" - id: ID! + id: ID! "block.timestamp of the transaction of the margin change entry" timestamp: BigInt! "transaction.hash of the event that triggered this margin change entry" @@ -422,6 +428,8 @@ type RageTradePool @entity { hourData: Collection! "list of collection of candles, recorded for each day" dayData: Collection! + "list of funding observations" + fundingObservations: [FundingObservation!]! @derivedFrom(field: "pool") } type VToken @entity { @@ -444,6 +452,16 @@ type VPoolWrapper @entity { pool: RageTradePool! } +type FundingObservation @entity { + id: ID! + "timestamp of the observation" + timestamp: BigInt! + "funding rate over 24hrs - (virtualPrice - realPrice) / (realPrice * 24)" + fundingRate: BigDecimal! + "pool to which the observation belongs to" + pool: RageTradePool! +} + type Collection @entity { "unique id of the collection" id: ID! @@ -699,7 +717,7 @@ type UniswapV3Transaction @entity { } type UniswapV3Mint @entity { - "transaction hash + "#" + index in mints Transaction array" + "transaction hash + " #" + index in mints Transaction array" id: ID! "which txn the mint was included in" transaction: UniswapV3Transaction! @@ -734,7 +752,7 @@ type UniswapV3Mint @entity { } type UniswapV3Burn @entity { - "transaction hash + "#" + index in mints Transaction array" + "transaction hash + " #" + index in mints Transaction array" id: ID! "txn burn was included in" transaction: UniswapV3Transaction! @@ -767,7 +785,7 @@ type UniswapV3Burn @entity { } type UniswapV3Swap @entity { - "transaction hash + "#" + index in swaps Transaction array" + "transaction hash + " #" + index in swaps Transaction array" id: ID! "pointer to transaction" transaction: UniswapV3Transaction! @@ -800,7 +818,7 @@ type UniswapV3Swap @entity { } type UniswapV3Collect @entity { - "transaction hash + "#" + index in collect Transaction array" + "transaction hash + " #" + index in collect Transaction array" id: ID! "pointer to txn" transaction: UniswapV3Transaction! diff --git a/rage/src/mappings/clearinghouse/handlers.ts b/rage/src/mappings/clearinghouse/handlers.ts index 1a84e9c..88b3d1a 100644 --- a/rage/src/mappings/clearinghouse/handlers.ts +++ b/rage/src/mappings/clearinghouse/handlers.ts @@ -26,6 +26,7 @@ import { min, parsePriceX128, parseSqrtPriceX96, + recordFundingObservation, safeDiv, } from '../../utils'; import { UniswapV3Pool } from '../../../generated/templates/UniswapV3Pool/UniswapV3Pool'; @@ -69,6 +70,12 @@ export function handleTokenPositionChanged(event: TokenPositionChanged): void { ] ); + recordFundingObservation( + event.params.poolId, + event.block.timestamp, + getFundingRate(event.params.poolId) + ); + // update token position let account = getAccount(event.params.accountId); @@ -538,6 +545,12 @@ export function handleTokenPositionFundingPaymentRealized( rageTradePool.fundingRate = getFundingRate(event.params.poolId); + recordFundingObservation( + event.params.poolId, + event.block.timestamp, + rageTradePool.fundingRate + ); + entry.side = tokenPosition.netPosition.gt(ZERO_BD) ? 'long' : 'short'; tokenPosition.lastFundingPaymentRealizedEntryTimestamp = entry.timestamp; diff --git a/rage/src/utils/index.ts b/rage/src/utils/index.ts index 25bafaf..a93926b 100644 --- a/rage/src/utils/index.ts +++ b/rage/src/utils/index.ts @@ -1,6 +1,9 @@ /* eslint-disable prefer-const */ import { BigInt, BigDecimal, ethereum, log } from '@graphprotocol/graph-ts'; -import { UniswapV3Transaction } from '../../generated/schema'; +import { + FundingObservation, + UniswapV3Transaction, +} from '../../generated/schema'; import { ONE_BI, ZERO_BI, @@ -14,6 +17,7 @@ import { Address } from '@graphprotocol/graph-ts'; import { ClearingHouse } from '../../generated/ClearingHouse/ClearingHouse'; import { VPoolWrapperLogic } from '../../generated/templates/VPoolWrapperLogic/VPoolWrapperLogic'; import { contracts } from './addresses'; +import { getRageTradePoolId } from '../mappings/ragetradeFactory/rageTradePool'; export function exponentToBigDecimal(decimals: BigInt): BigDecimal { let bd = BigDecimal.fromString('1'); @@ -289,3 +293,18 @@ export function min(a: BigDecimal, b: BigDecimal): BigDecimal { export function max(a: BigDecimal, b: BigDecimal): BigDecimal { return a.gt(b) ? a : b; } + +export function recordFundingObservation( + poolId: BigInt, + timestamp: BigInt, + fundingRate: BigDecimal +): void { + let observationId = generateId([poolId.toHexString(), timestamp.toString()]); + if (!FundingObservation.load(observationId)) { + let observation = new FundingObservation(observationId); + observation.pool = getRageTradePoolId(poolId); + observation.timestamp = timestamp; + observation.fundingRate = fundingRate; + observation.save(); + } +}