From 296350c56d0f008073bd1368691de42cdc29a962 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 13:43:26 +0000 Subject: [PATCH 01/18] action: update to publishedVersion: 1.5.4 for polygon-digital-carbon --- polygon-digital-carbon/src/utils/version.ts | 4 ++-- polygon-digital-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/polygon-digital-carbon/src/utils/version.ts b/polygon-digital-carbon/src/utils/version.ts index bc1df704..e774ff3b 100644 --- a/polygon-digital-carbon/src/utils/version.ts +++ b/polygon-digital-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.5.3'; - export const PUBLISHED_VERSION = '1.5.3'; \ No newline at end of file + export const SCHEMA_VERSION = '1.5.4'; + export const PUBLISHED_VERSION = '1.5.4'; \ No newline at end of file diff --git a/polygon-digital-carbon/version.json b/polygon-digital-carbon/version.json index 7c402674..957a7b8b 100644 --- a/polygon-digital-carbon/version.json +++ b/polygon-digital-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "1.5.3", "publishedVersion": "1.5.3"} +{"schemaVersion": "1.5.4", "publishedVersion": "1.5.4"} From 885fcb62966c97e0edfe9d73347ccd6f09ffa9b2 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 13:47:14 +0000 Subject: [PATCH 02/18] action: update to publishedVersion: 1.6.8 for carbonmark --- carbonmark/src/utils/version.ts | 4 ++-- carbonmark/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/carbonmark/src/utils/version.ts b/carbonmark/src/utils/version.ts index 85f34af8..deec544e 100644 --- a/carbonmark/src/utils/version.ts +++ b/carbonmark/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.6.8'; - export const PUBLISHED_VERSION = '1.6.7'; \ No newline at end of file + export const SCHEMA_VERSION = '1.6.9'; + export const PUBLISHED_VERSION = '1.6.8'; \ No newline at end of file diff --git a/carbonmark/version.json b/carbonmark/version.json index 143e4f14..91e3f00c 100644 --- a/carbonmark/version.json +++ b/carbonmark/version.json @@ -1 +1 @@ -{"schemaVersion": "1.6.8", "publishedVersion": "1.6.7"} +{"schemaVersion": "1.6.9", "publishedVersion": "1.6.8"} From a3a319dd2b78358a7601419953d4a292867af7a1 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 13:48:38 +0000 Subject: [PATCH 03/18] action: update to publishedVersion: 0.0.9 for polygon-bridged-carbon --- polygon-bridged-carbon/src/utils/version.ts | 4 ++-- polygon-bridged-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/polygon-bridged-carbon/src/utils/version.ts b/polygon-bridged-carbon/src/utils/version.ts index 4741f89d..92fe2eea 100644 --- a/polygon-bridged-carbon/src/utils/version.ts +++ b/polygon-bridged-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '0.0.10'; - export const PUBLISHED_VERSION = '0.0.8'; \ No newline at end of file + export const SCHEMA_VERSION = '0.0.11'; + export const PUBLISHED_VERSION = '0.0.9'; \ No newline at end of file diff --git a/polygon-bridged-carbon/version.json b/polygon-bridged-carbon/version.json index a87e1ea2..f5c5808b 100644 --- a/polygon-bridged-carbon/version.json +++ b/polygon-bridged-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.10", "publishedVersion": "0.0.8"} +{"schemaVersion": "0.0.11", "publishedVersion": "0.0.9"} From ad88b0c3b0b22b1d25ca08db1032d73b6bf2ec1e Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 13:52:11 +0000 Subject: [PATCH 04/18] action: update to publishedVersion: 0.0.8 for user-carbon --- user-carbon/src/utils/version.ts | 4 ++-- user-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/user-carbon/src/utils/version.ts b/user-carbon/src/utils/version.ts index bf3e12d6..c31d338b 100644 --- a/user-carbon/src/utils/version.ts +++ b/user-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '0.0.7'; - export const PUBLISHED_VERSION = '0.0.7'; \ No newline at end of file + export const SCHEMA_VERSION = '0.0.9'; + export const PUBLISHED_VERSION = '0.0.8'; \ No newline at end of file diff --git a/user-carbon/version.json b/user-carbon/version.json index 128807c7..0c1e3390 100644 --- a/user-carbon/version.json +++ b/user-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.7", "publishedVersion": "0.0.7"} +{"schemaVersion": "0.0.9", "publishedVersion": "0.0.8"} From eb30756af422e7d15b6fe0f9556bcdc4a55ae85c Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 13:53:21 +0000 Subject: [PATCH 05/18] action: update to publishedVersion: 1.0.6 for pairs --- pairs/src/utils/version.ts | 4 ++-- pairs/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pairs/src/utils/version.ts b/pairs/src/utils/version.ts index de9412d1..c4867bc9 100644 --- a/pairs/src/utils/version.ts +++ b/pairs/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.0.5'; - export const PUBLISHED_VERSION = '1.0.5'; \ No newline at end of file + export const SCHEMA_VERSION = '1.0.7'; + export const PUBLISHED_VERSION = '1.0.6'; \ No newline at end of file diff --git a/pairs/version.json b/pairs/version.json index 253959f5..556b2071 100644 --- a/pairs/version.json +++ b/pairs/version.json @@ -1 +1 @@ -{"schemaVersion": "1.0.5", "publishedVersion": "1.0.5"} +{"schemaVersion": "1.0.7", "publishedVersion": "1.0.6"} From defd564056d9059e354038d082aeb9ba63e50dda Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 16:45:41 +0000 Subject: [PATCH 06/18] action: update to publishedVersion: 1.6.9 for carbonmark --- carbonmark/src/utils/version.ts | 4 ++-- carbonmark/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/carbonmark/src/utils/version.ts b/carbonmark/src/utils/version.ts index deec544e..65f68d1f 100644 --- a/carbonmark/src/utils/version.ts +++ b/carbonmark/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.6.9'; - export const PUBLISHED_VERSION = '1.6.8'; \ No newline at end of file + export const SCHEMA_VERSION = '1.6.10'; + export const PUBLISHED_VERSION = '1.6.9'; \ No newline at end of file diff --git a/carbonmark/version.json b/carbonmark/version.json index 91e3f00c..8634869d 100644 --- a/carbonmark/version.json +++ b/carbonmark/version.json @@ -1 +1 @@ -{"schemaVersion": "1.6.9", "publishedVersion": "1.6.8"} +{"schemaVersion": "1.6.10", "publishedVersion": "1.6.9"} From 8789607454f124b5bd4c524cf65c81398adb412c Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 16:47:14 +0000 Subject: [PATCH 07/18] action: update to publishedVersion: 0.0.10 for polygon-bridged-carbon --- polygon-bridged-carbon/src/utils/version.ts | 2 +- polygon-bridged-carbon/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polygon-bridged-carbon/src/utils/version.ts b/polygon-bridged-carbon/src/utils/version.ts index 92fe2eea..1e41559d 100644 --- a/polygon-bridged-carbon/src/utils/version.ts +++ b/polygon-bridged-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts export const SCHEMA_VERSION = '0.0.11'; - export const PUBLISHED_VERSION = '0.0.9'; \ No newline at end of file + export const PUBLISHED_VERSION = '0.0.10'; \ No newline at end of file diff --git a/polygon-bridged-carbon/version.json b/polygon-bridged-carbon/version.json index f5c5808b..2a1ad0f0 100644 --- a/polygon-bridged-carbon/version.json +++ b/polygon-bridged-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.11", "publishedVersion": "0.0.9"} +{"schemaVersion": "0.0.11", "publishedVersion": "0.0.10"} From 36cee3d934a8f234c9d15a9f279f65e05aeef322 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 16:50:40 +0000 Subject: [PATCH 08/18] action: update to publishedVersion: 0.0.9 for user-carbon --- user-carbon/src/utils/version.ts | 2 +- user-carbon/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user-carbon/src/utils/version.ts b/user-carbon/src/utils/version.ts index c31d338b..1776f052 100644 --- a/user-carbon/src/utils/version.ts +++ b/user-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts export const SCHEMA_VERSION = '0.0.9'; - export const PUBLISHED_VERSION = '0.0.8'; \ No newline at end of file + export const PUBLISHED_VERSION = '0.0.9'; \ No newline at end of file diff --git a/user-carbon/version.json b/user-carbon/version.json index 0c1e3390..def50fe2 100644 --- a/user-carbon/version.json +++ b/user-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.9", "publishedVersion": "0.0.8"} +{"schemaVersion": "0.0.9", "publishedVersion": "0.0.9"} From bc82bd91ff5c7d3b7c4fdabdd387d68e7c73edcd Mon Sep 17 00:00:00 2001 From: deploy-action Date: Fri, 4 Apr 2025 16:51:50 +0000 Subject: [PATCH 09/18] action: update to publishedVersion: 1.0.7 for pairs --- pairs/src/utils/version.ts | 2 +- pairs/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pairs/src/utils/version.ts b/pairs/src/utils/version.ts index c4867bc9..25624674 100644 --- a/pairs/src/utils/version.ts +++ b/pairs/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts export const SCHEMA_VERSION = '1.0.7'; - export const PUBLISHED_VERSION = '1.0.6'; \ No newline at end of file + export const PUBLISHED_VERSION = '1.0.7'; \ No newline at end of file diff --git a/pairs/version.json b/pairs/version.json index 556b2071..a34ad6f2 100644 --- a/pairs/version.json +++ b/pairs/version.json @@ -1 +1 @@ -{"schemaVersion": "1.0.7", "publishedVersion": "1.0.6"} +{"schemaVersion": "1.0.7", "publishedVersion": "1.0.7"} From f25f8a70d8525353b14802f48de3d3d7b08389f1 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Tue, 29 Apr 2025 04:09:30 +0000 Subject: [PATCH 10/18] action: update to publishedVersion: 1.6.10 for carbonmark --- carbonmark/src/utils/version.ts | 2 +- carbonmark/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/carbonmark/src/utils/version.ts b/carbonmark/src/utils/version.ts index 65f68d1f..b91ea1eb 100644 --- a/carbonmark/src/utils/version.ts +++ b/carbonmark/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts export const SCHEMA_VERSION = '1.6.10'; - export const PUBLISHED_VERSION = '1.6.9'; \ No newline at end of file + export const PUBLISHED_VERSION = '1.6.10'; \ No newline at end of file diff --git a/carbonmark/version.json b/carbonmark/version.json index 8634869d..8d8bf660 100644 --- a/carbonmark/version.json +++ b/carbonmark/version.json @@ -1 +1 @@ -{"schemaVersion": "1.6.10", "publishedVersion": "1.6.9"} +{"schemaVersion": "1.6.10", "publishedVersion": "1.6.10"} From 4e30f55adbacc8df27cdb1b02e559a99dc1fdca4 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Mon, 19 May 2025 17:30:54 +0000 Subject: [PATCH 11/18] action: update to publishedVersion: 1.5.5 for polygon-digital-carbon --- polygon-digital-carbon/src/utils/version.ts | 4 ++-- polygon-digital-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/polygon-digital-carbon/src/utils/version.ts b/polygon-digital-carbon/src/utils/version.ts index e774ff3b..c06c5ff1 100644 --- a/polygon-digital-carbon/src/utils/version.ts +++ b/polygon-digital-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.5.4'; - export const PUBLISHED_VERSION = '1.5.4'; \ No newline at end of file + export const SCHEMA_VERSION = '1.5.5'; + export const PUBLISHED_VERSION = '1.5.5'; \ No newline at end of file diff --git a/polygon-digital-carbon/version.json b/polygon-digital-carbon/version.json index 957a7b8b..e43310db 100644 --- a/polygon-digital-carbon/version.json +++ b/polygon-digital-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "1.5.4", "publishedVersion": "1.5.4"} +{"schemaVersion": "1.5.5", "publishedVersion": "1.5.5"} From a54f971475fbf016d8c755af89f870d5fabfcc00 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Mon, 19 May 2025 17:34:13 +0000 Subject: [PATCH 12/18] action: update to publishedVersion: 1.6.11 for carbonmark --- carbonmark/src/utils/version.ts | 4 ++-- carbonmark/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/carbonmark/src/utils/version.ts b/carbonmark/src/utils/version.ts index b91ea1eb..d6a8cbb7 100644 --- a/carbonmark/src/utils/version.ts +++ b/carbonmark/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.6.10'; - export const PUBLISHED_VERSION = '1.6.10'; \ No newline at end of file + export const SCHEMA_VERSION = '1.6.11'; + export const PUBLISHED_VERSION = '1.6.11'; \ No newline at end of file diff --git a/carbonmark/version.json b/carbonmark/version.json index 8d8bf660..c37e919d 100644 --- a/carbonmark/version.json +++ b/carbonmark/version.json @@ -1 +1 @@ -{"schemaVersion": "1.6.10", "publishedVersion": "1.6.10"} +{"schemaVersion": "1.6.11", "publishedVersion": "1.6.11"} From 5554dc83398a4ea792dc6b506ec9abe3a23441a8 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Mon, 19 May 2025 17:35:40 +0000 Subject: [PATCH 13/18] action: update to publishedVersion: 0.0.11 for polygon-bridged-carbon --- polygon-bridged-carbon/src/utils/version.ts | 4 ++-- polygon-bridged-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/polygon-bridged-carbon/src/utils/version.ts b/polygon-bridged-carbon/src/utils/version.ts index 1e41559d..da7643bc 100644 --- a/polygon-bridged-carbon/src/utils/version.ts +++ b/polygon-bridged-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '0.0.11'; - export const PUBLISHED_VERSION = '0.0.10'; \ No newline at end of file + export const SCHEMA_VERSION = '0.0.12'; + export const PUBLISHED_VERSION = '0.0.11'; \ No newline at end of file diff --git a/polygon-bridged-carbon/version.json b/polygon-bridged-carbon/version.json index 2a1ad0f0..6b4f852b 100644 --- a/polygon-bridged-carbon/version.json +++ b/polygon-bridged-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.11", "publishedVersion": "0.0.10"} +{"schemaVersion": "0.0.12", "publishedVersion": "0.0.11"} From 4971a6b20446170c26d718aef5cdd10d53e3c080 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Mon, 19 May 2025 17:38:52 +0000 Subject: [PATCH 14/18] action: update to publishedVersion: 0.0.10 for user-carbon --- user-carbon/src/utils/version.ts | 4 ++-- user-carbon/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/user-carbon/src/utils/version.ts b/user-carbon/src/utils/version.ts index 1776f052..fd0d4982 100644 --- a/user-carbon/src/utils/version.ts +++ b/user-carbon/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '0.0.9'; - export const PUBLISHED_VERSION = '0.0.9'; \ No newline at end of file + export const SCHEMA_VERSION = '0.0.10'; + export const PUBLISHED_VERSION = '0.0.10'; \ No newline at end of file diff --git a/user-carbon/version.json b/user-carbon/version.json index def50fe2..b4ebcf58 100644 --- a/user-carbon/version.json +++ b/user-carbon/version.json @@ -1 +1 @@ -{"schemaVersion": "0.0.9", "publishedVersion": "0.0.9"} +{"schemaVersion": "0.0.10", "publishedVersion": "0.0.10"} From 14459eaf25b22e87be32f173470bb5d20b377355 Mon Sep 17 00:00:00 2001 From: deploy-action Date: Mon, 19 May 2025 17:40:05 +0000 Subject: [PATCH 15/18] action: update to publishedVersion: 1.0.8 for pairs --- pairs/src/utils/version.ts | 4 ++-- pairs/version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pairs/src/utils/version.ts b/pairs/src/utils/version.ts index 25624674..7aabc389 100644 --- a/pairs/src/utils/version.ts +++ b/pairs/src/utils/version.ts @@ -1,3 +1,3 @@ // This file is auto-generated by set-version.ts - export const SCHEMA_VERSION = '1.0.7'; - export const PUBLISHED_VERSION = '1.0.7'; \ No newline at end of file + export const SCHEMA_VERSION = '1.0.8'; + export const PUBLISHED_VERSION = '1.0.8'; \ No newline at end of file diff --git a/pairs/version.json b/pairs/version.json index a34ad6f2..4616c88a 100644 --- a/pairs/version.json +++ b/pairs/version.json @@ -1 +1 @@ -{"schemaVersion": "1.0.7", "publishedVersion": "1.0.7"} +{"schemaVersion": "1.0.8", "publishedVersion": "1.0.8"} From 9ac7ddc8544660851291e2c8c437f03bb1f21013 Mon Sep 17 00:00:00 2001 From: psparacino Date: Fri, 20 Jun 2025 17:05:41 -0400 Subject: [PATCH 16/18] initial twap impl --- lib/utils/Constants.ts | 3 -- pairs/schema.graphql | 7 ++++ pairs/src/Pair.ts | 90 ++++++++++++++++++++++-------------------- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/lib/utils/Constants.ts b/lib/utils/Constants.ts index 0991872b..0b38a732 100644 --- a/lib/utils/Constants.ts +++ b/lib/utils/Constants.ts @@ -142,6 +142,3 @@ export const ICR_MIGRATION_HASHES = [ // Global constants export const KGS_PER_TONNE = BigDecimal.fromString('1000') - -// Price guard constants -export const MIN_PRICE_GUARD = BigInt.fromI32(1000) diff --git a/pairs/schema.graphql b/pairs/schema.graphql index 44d44e73..e1d8b5b2 100644 --- a/pairs/schema.graphql +++ b/pairs/schema.graphql @@ -31,6 +31,13 @@ type Swap @entity { pair: Pair! } +type PairTwapState @entity { + id: ID! # pair address + price0Cumul: BigInt! # last snapshot of price0CumulativeLast + price1Cumul: BigInt! # last snapshot of price1CumulativeLast + timestamp: BigInt! # snapshot timestamp +} + # Subgraph Versioning type SubgraphVersion @entity(immutable: true) { diff --git a/pairs/src/Pair.ts b/pairs/src/Pair.ts index aaad55e2..b6c84f67 100644 --- a/pairs/src/Pair.ts +++ b/pairs/src/Pair.ts @@ -17,10 +17,9 @@ import { KLIMA_BCT_PAIR_BLOCK, KLIMA_MCO2_PAIR_BLOCK, KLIMA_CCO2_PAIR_BLOCK, - MIN_PRICE_GUARD, } from '../../lib/utils/Constants' import { BigInt, BigDecimal, log, ethereum } from '@graphprotocol/graph-ts' -import { Pair, Token, Swap, SubgraphVersion } from '../generated/schema' +import { Pair, Token, Swap, SubgraphVersion, PairTwapState } from '../generated/schema' import { Swap as SwapEvent, Pair as PairContract } from '../generated/KLIMA_USDC/Pair' import { ERC20 as ERC20Contract } from '../generated/KLIMA_USDC/ERC20' import { Address } from '@graphprotocol/graph-ts' @@ -30,6 +29,12 @@ import { hourTimestamp } from '../../lib/utils/Dates' import { PriceUtil } from '../../lib/utils/Price' import { SCHEMA_VERSION, PUBLISHED_VERSION } from './utils/version' +const Q112 = BigInt.fromI32(2).pow(112 as u8) + +export function decodeUQ112x112(x: BigInt): BigDecimal { + return x.toBigDecimal().div(Q112.toBigDecimal()) +} + // Create or Load Token export function getCreateToken(address: Address): Token { let token = Token.load(address.toHexString()) @@ -150,27 +155,6 @@ function toUnits(x: BigInt, decimals: number): BigDecimal { return x.toBigDecimal().div(denom) } -function minPriceGuard( - quote: BigInt, - token0_dec: number, - token1_dec: number, - amountIn: BigInt, - amountOut: BigInt, - hash: string, - pair: PairContract -): BigDecimal { - // if value is greater than minimum, return price as is and avoid unnecessary calls - if (quote.ge(MIN_PRICE_GUARD)) { - return toUnits(amountIn, token0_dec).div(toUnits(amountOut, token1_dec)) - } - // throw a warning in the logs if triggered - log.warning('Price guard triggered for {}', [hash]) - // if value is less than minimum and the 10^6 <> 10^18 diff blows up the math, return pair spot price - let reserves = pair.getReserves() - - return toUnits(reserves.value0, token0_dec).div(toUnits(reserves.value1, token1_dec)) -} - export function handleSwap(event: SwapEvent): void { let treasury_address = TREASURY_ADDRESS let pair = getCreatePair(event.address) @@ -178,7 +162,6 @@ export function handleSwap(event: SwapEvent): void { let total_lp = toUnits(contract.totalSupply(), 18) let tokenBalance = toUnits(contract.balanceOf(treasury_address), 18) let ownedLP = total_lp == BigDecimalZero ? BigDecimalZero : tokenBalance.div(total_lp) - let hour_timestamp = hourTimestamp(event.block.timestamp) let hourlyId = event.address.toHexString() + hour_timestamp @@ -205,16 +188,43 @@ export function handleSwap(event: SwapEvent): void { volume = token0qty } + const TWAP_WINDOW = BigInt.fromI32(600) // 10 min window + let twapState = PairTwapState.load(event.address.toHexString()) + if (twapState == null) { + twapState = new PairTwapState(event.address.toHexString()) + twapState.price0Cumul = BigIntZero + twapState.price1Cumul = BigIntZero + twapState.timestamp = BigIntZero + } + + let price0CumulativeLast = contract.price0CumulativeLast() + let price1CumulativeLast = contract.price1CumulativeLast() + let now = event.block.timestamp + + // https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles + // update price using TWAP if the window has passed + if (twapState.timestamp.gt(BigIntZero) && now.minus(twapState.timestamp).ge(TWAP_WINDOW)) { + let timeDiff = now.minus(twapState.timestamp) // seconds + // we set the price using the averaged price of the last 10 minutes + let twap0 = decodeUQ112x112(price0CumulativeLast.minus(twapState.price0Cumul)) // price0 × dt + .div(timeDiff.toBigDecimal()) // ← average price0 + price = twap0 + } + + //for initial swap or those within the first 10 minutes, read reserves and set price + if (price == BigDecimalZero) { + const r = contract.getReserves() + const t0 = (Token.load(pair.token0) as Token).decimals + const t1 = (Token.load(pair.token1) as Token).decimals + if (r.value0.gt(BigIntZero) && r.value1.gt(BigIntZero)) { + price = toUnits(r.value0, t0).div(toUnits(r.value1, t1)) + } else { + /* no liquidity → ignore this dust swap */ + return + } + } + if (event.params.amount0In == BigIntZero && event.params.amount0Out != BigIntZero) { - price = minPriceGuard( - event.params.amount0Out, - token0_decimals, - token1_decimals, - event.params.amount0Out, - event.params.amount1In, - event.transaction.hash.toHexString(), - contract - ) token0qty = toUnits(event.params.amount0Out, token0_decimals) token1qty = toUnits(event.params.amount1In, token1_decimals) lastreserves0 = toUnits(contract.getReserves().value0, token0_decimals).plus(token0qty) @@ -226,15 +236,6 @@ export function handleSwap(event: SwapEvent): void { volume = token0qty } if (event.params.amount0Out == BigIntZero && event.params.amount0In != BigIntZero) { - price = minPriceGuard( - event.params.amount0In, - token0_decimals, - token1_decimals, - event.params.amount0In, - event.params.amount1Out, - event.transaction.hash.toHexString(), - contract - ) token0qty = toUnits(event.params.amount0In, token0_decimals) token1qty = toUnits(event.params.amount1Out, token1_decimals) lastreserves0 = toUnits(contract.getReserves().value0, token0_decimals).minus(token0qty) @@ -366,6 +367,11 @@ export function handleSwap(event: SwapEvent): void { pair.lastupdate = hour_timestamp pair.save() } + + twapState.price0Cumul = price0CumulativeLast + twapState.price1Cumul = price1CumulativeLast + twapState.timestamp = now + twapState.save() } export function handleSetSubgraphVersion(block: ethereum.Block): void { From 188e3a23047b78a80d412d59d67075784156ec07 Mon Sep 17 00:00:00 2001 From: psparacino Date: Fri, 20 Jun 2025 17:27:20 -0400 Subject: [PATCH 17/18] updated tests for twap impl --- pairs/tests/.bin/swaps.wasm | Bin 68097 -> 70977 bytes pairs/tests/.latest.json | 2 +- pairs/tests/swaps.test.ts | 117 ++++++++++++++++++++++++++++---- pairs/tests/swapsHelper.test.ts | 18 +++++ tests/.latest.json | 2 +- 5 files changed, 123 insertions(+), 16 deletions(-) diff --git a/pairs/tests/.bin/swaps.wasm b/pairs/tests/.bin/swaps.wasm index 7c711c032609517016ac19259cf6cf41a7a946b8..c2603e0a34920c77ff2d6bb83dd63d951ffa8137 100644 GIT binary patch delta 19446 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 delta 17814 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 { beforeEach(() => { create_SWAP_EVENT_MOCKS() + + // Set up realistic TWAP mocks for KLIMA_CCO2_PAIR + // Simulate price0 cumulative that increased by 1e18 over 600 seconds (10 minutes) + // This represents a price change from 1.0 to 2.0 over 10 minutes + createMockedFunction(KLIMA_CCO2_PAIR, 'price0CumulativeLast', 'price0CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('2000000000000000000000000')), // Current cumulative + ]) + createMockedFunction(KLIMA_CCO2_PAIR, 'price1CumulativeLast', 'price1CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1500000000000000000000000')), // Different cumulative + ]) + + // Set up realistic TWAP mocks for NCT_USDC_PAIR + // Simulate a more stable price with smaller changes + createMockedFunction(NCT_USDC_PAIR, 'price0CumulativeLast', 'price0CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1100000000000000000000000')), // Small increase + ]) + createMockedFunction(NCT_USDC_PAIR, 'price1CumulativeLast', 'price1CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('900000000000000000000000')), // Small decrease + ]) }) test('KLIMA_CCO2_PAIR:Initial swap updates pair price correctly. ', () => { @@ -50,13 +84,21 @@ describe('handleSwap', () => { let amount0Out = BigInt.fromI32(0) let amount1Out = BigInt.fromI32(2000000000) - let swapEvent = newSwapEvent(KLIMA_CCO2_PAIR, amount0In, amount1In, amount0Out, amount1Out, toAddress) + let swapEvent = newSwapEvent( + KLIMA_CCO2_PAIR, + amount0In, + amount1In, + amount0Out, + amount1Out, + toAddress, + BigInt.fromI32(0) + ) handleSwap(swapEvent) - // Assert that the pair price is updated correctly - assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentprice', '0.01846581475982910603740163507456394') - assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentpricepertonne', '18.46581475982910603740163507456394') + // Assert that the pair price is updated correctly (TWAP logic) + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentprice', '1002.004008016032064128256513026052') + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentpricepertonne', '1002004.008016032064128256513026052') }) test('KLIMA_CCO2_PAIR:Subsequent swap updates pair price correctly', () => { @@ -66,25 +108,40 @@ describe('handleSwap', () => { let amount0Out = BigInt.fromI32(0) let amount1Out = BigInt.fromI32(500000000) - let swapEvent = newSwapEvent(KLIMA_CCO2_PAIR, amount0In, amount1In, amount0Out, amount1Out, toAddress) + let swapEvent = newSwapEvent( + KLIMA_CCO2_PAIR, + amount0In, + amount1In, + amount0Out, + amount1Out, + toAddress, + BigInt.fromI32(0) + ) handleSwap(swapEvent) - // Assert that the pair price is updated correctly - assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentprice', '0.004616453689957276509350408768640985') - assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentpricepertonne', '4.616453689957276509350408768640985') + // Assert that the pair price is updated correctly (TWAP logic) + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentprice', '1002.004008016032064128256513026052') + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentpricepertonne', '1002004.008016032064128256513026052') }) // ──────────────────────────────────────────────────────────────────────────── test('NCT_USDC_PAIR: Dust-quote swap returns spot price', () => { - // 1 wei USDC → 1 111 wei NCT (the pathological trade) let toAddress = Address.fromString('0x0123012301230123012301230123012301230123') let amount0In = BigInt.fromI32(1) // 1 wei USDC let amount1In = BigInt.fromI32(0) let amount0Out = BigInt.fromI32(0) let amount1Out = BigInt.fromI32(1111) // 1 111 wei NCT - let swapEvent = newSwapEvent(NCT_USDC_PAIR, amount0In, amount1In, amount0Out, amount1Out, toAddress) + let swapEvent = newSwapEvent( + NCT_USDC_PAIR, + amount0In, + amount1In, + amount0Out, + amount1Out, + toAddress, + BigInt.fromI32(0) + ) handleSwap(swapEvent) @@ -92,6 +149,38 @@ describe('handleSwap', () => { assert.fieldEquals('Pair', NCT_USDC_PAIR.toHex(), 'currentprice', '0.4427864244831998538451559952378756') }) + test('KLIMA_CCO2_PAIR: TWAP calculation with proper time window', () => { + // Create initial TWAP state with timestamp 600 seconds ago (10 minutes) + let twapState = new PairTwapState(KLIMA_CCO2_PAIR.toHex()) + twapState.price0Cumul = BigInt.fromString('1000000000000000000000000') // Previous cumulative + twapState.price1Cumul = BigInt.fromString('1000000000000000000000000') // Previous cumulative + twapState.timestamp = BigInt.fromI32(0) // 600 seconds ago + twapState.save() + + let toAddress = Address.fromString('0x0987654321098765432109876543210987654321') + let amount0In = BigInt.fromI32(1000) + let amount1In = BigInt.fromI32(0) + let amount0Out = BigInt.fromI32(0) + let amount1Out = BigInt.fromI32(2000000000) + + // Use timestamp 600 (current time) to trigger TWAP calculation + let swapEvent = newSwapEvent( + KLIMA_CCO2_PAIR, + amount0In, + amount1In, + amount0Out, + amount1Out, + toAddress, + BigInt.fromI32(600) + ) + + handleSwap(swapEvent) + + // The TWAP calculation should be: (2000000000000000000000000 - 1000000000000000000000000) / 600 / 2^112 + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentprice', '1002.004008016032064128256513026052') + assert.fieldEquals('Pair', KLIMA_CCO2_PAIR.toHex(), 'currentpricepertonne', '1002004.008016032064128256513026052') + }) + afterEach(() => { clearStore() }) diff --git a/pairs/tests/swapsHelper.test.ts b/pairs/tests/swapsHelper.test.ts index d4a3e653..00c291f8 100644 --- a/pairs/tests/swapsHelper.test.ts +++ b/pairs/tests/swapsHelper.test.ts @@ -31,6 +31,14 @@ function create_KLIMA_USDC_PAIR_MOCKS(): void { ethereum.Value.fromUnsignedBigInt(BigInt.fromString('2518999568458520093807838')), ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1725456599')), ]) + + // Add TWAP-related mocks + createMockedFunction(KLIMA_USDC_PAIR, 'price0CumulativeLast', 'price0CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1000000000000000000000000')), + ]) + createMockedFunction(KLIMA_USDC_PAIR, 'price1CumulativeLast', 'price1CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1000000000000000000000000')), + ]) } function create_KLIMA_ERC20_V1_CONTRACT_MOCKS(): void { @@ -85,6 +93,16 @@ function createPairMocks( ethereum.Value.fromUnsignedBigInt(getReserves[1]), ethereum.Value.fromUnsignedBigInt(getReserves[2]), ]) + + // Add TWAP-related mocks for all pairs except KLIMA_CCO2_PAIR + if (pair != KLIMA_CCO2_PAIR) { + createMockedFunction(pair, 'price0CumulativeLast', 'price0CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('1100000000000000000000000')), + ]) + createMockedFunction(pair, 'price1CumulativeLast', 'price1CumulativeLast():(uint256)').returns([ + ethereum.Value.fromUnsignedBigInt(BigInt.fromString('900000000000000000000000')), + ]) + } } function create_KLIMA_CCO2_PAIR_MOCKS(): void { diff --git a/tests/.latest.json b/tests/.latest.json index e823e6a9..f9d81a6e 100644 --- a/tests/.latest.json +++ b/tests/.latest.json @@ -1,4 +1,4 @@ { "version": "0.6.0", - "timestamp": 1745853456171 + "timestamp": 1750453746774 } \ No newline at end of file From eadfbcb2dcce4c012544dd47394d512fddf97d0b Mon Sep 17 00:00:00 2001 From: psparacino Date: Fri, 20 Jun 2025 17:28:57 -0400 Subject: [PATCH 18/18] pairs: minor version --- pairs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pairs/package.json b/pairs/package.json index e4402cac..7fa2ecb4 100644 --- a/pairs/package.json +++ b/pairs/package.json @@ -1,6 +1,6 @@ { "name": "klimadao-pairs", - "version": "1.0.8", + "version": "1.1.0", "license": "MIT", "scripts": { "codegen": "graph codegen",