From 43fbf525d1902e8e82ba05a8efa69c65ceeab67d Mon Sep 17 00:00:00 2001 From: "Arthur G." Date: Thu, 8 Aug 2024 12:02:47 +0200 Subject: [PATCH 1/5] fix: unwind was invalid without `fundingPayment` Seems like `handleEmergencyWithdraw` never worked before The function was failing because of the empty `fundingPayment` --- src/mapping.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mapping.ts b/src/mapping.ts index 53937e9..d5f4bb8 100644 --- a/src/mapping.ts +++ b/src/mapping.ts @@ -513,6 +513,7 @@ export function handleEmergencyWithdraw(event: EmergencyWithdrawEvent): void { unwind.value = ZERO_BI unwind.timestamp = transaction.timestamp unwind.transaction = transaction.id + unwind.fundingPayment = ZERO_BI position.currentOi = ZERO_BI position.currentDebt = ZERO_BI From db2b787beb16f70f411fea7567d69ff845aa3d89 Mon Sep 17 00:00:00 2001 From: "Arthur G." Date: Thu, 8 Aug 2024 13:17:30 +0200 Subject: [PATCH 2/5] test: handler `Unwind` --- src/__test__/unit/market.test.ts | 63 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/__test__/unit/market.test.ts b/src/__test__/unit/market.test.ts index 89c0467..214a44a 100644 --- a/src/__test__/unit/market.test.ts +++ b/src/__test__/unit/market.test.ts @@ -15,8 +15,11 @@ import { Build as BuildEvent, CacheRiskCalc as CacheRiskCalcEvent, Update as UpdateEvent, + Liquidate as LiquidateEvent, + Unwind as UnwindEvent, + EmergencyWithdraw as EmergencyWithdrawEvent, } from "../../../generated/templates/OverlayV1Market/OverlayV1Market" -import { handleBuild, handleCacheRiskCalc, handleUpdate } from "../../mapping" +import { handleBuild, handleLiquidate, handleUnwind, handleEmergencyWithdraw, handleCacheRiskCalc, handleUpdate } from "../../mapping" import { loadAccount } from "../../utils" import { loadTradingMining } from "../../trading-mining" import { loadReferralProgram, loadReferralPosition } from "../../referral" @@ -46,6 +49,11 @@ const price = BigInt.fromI32(100) const oiAfterBuild = BigInt.fromI32(51) const oiSharesAfterBuild = BigInt.fromI32(1) +// Unwind event parameters +const oiAfterUnwind = BigInt.fromI32(25) +const oiSharesAfterUnwind = BigInt.fromI32(1) +const fraction = BigInt.fromI32(5) + // CacheRiskCalc event parameters const dpUpperLimit = BigInt.fromI32(100) @@ -206,6 +214,33 @@ describe("Market events", () => { }) + describe("Unwind event", () => { + beforeEach(() => { + // Create a Build event to set up the initial position + const buildEvent = createBuildEvent(market, sender, positionId, oi, debt, isLong, price, oi, oiSharesAfterBuild) + handleBuild(buildEvent) + + // Now create an Unwind event to test + const unwindEvent = createUnwindEvent(market, sender, positionId, fraction, BigInt.fromI32(10), price, oiAfterUnwind, oiSharesAfterUnwind) + handleUnwind(unwindEvent) + }) + + afterEach(() => { + clearStore() + }) + + test("creates Unwind entity with correct attributes", () => { + const unwindId = market.concatI32(positionId.toI32()).concatI32(0).toHexString() + + assert.entityCount("Unwind", 1) + assert.fieldEquals("Unwind", unwindId, "owner", sender.toHexString()) + assert.fieldEquals("Unwind", unwindId, "currentOi", oi.toString()) + assert.fieldEquals("Unwind", unwindId, "currentDebt", debt.toString()) + assert.fieldEquals("Unwind", unwindId, "isLong", isLong.toString()) + assert.fieldEquals("Unwind", unwindId, "price", price.toString()) + }) + }) + describe("CacheRiskCalc event", () => { beforeEach(() => { const event = createCacheRiskCalcEvent(market, dpUpperLimit) @@ -299,6 +334,32 @@ function createBuildEvent( return event } +function createUnwindEvent( + market: Address, + sender: Address, + positionId: BigInt, + fraction: BigInt, + mint: BigInt, + price: BigInt, + oiAfterUnwind: BigInt, + oiSharesAfterUnwind: BigInt +): UnwindEvent { + const event = changetype(newMockEvent()) + + event.address = market + event.parameters = new Array() + + event.parameters.push(new ethereum.EventParam("sender", ethereum.Value.fromAddress(sender))) + event.parameters.push(new ethereum.EventParam("positionId", ethereum.Value.fromUnsignedBigInt(positionId))) + event.parameters.push(new ethereum.EventParam("fraction", ethereum.Value.fromUnsignedBigInt(fraction))) + event.parameters.push(new ethereum.EventParam("mint", ethereum.Value.fromUnsignedBigInt(mint))) + event.parameters.push(new ethereum.EventParam("price", ethereum.Value.fromUnsignedBigInt(price))) + event.parameters.push(new ethereum.EventParam("oiAfterUnwind", ethereum.Value.fromUnsignedBigInt(oiAfterUnwind))) + event.parameters.push(new ethereum.EventParam("oiSharesAfterUnwind", ethereum.Value.fromUnsignedBigInt(oiSharesAfterUnwind))) + + return event +} + function createCacheRiskCalcEvent( market: Address, dpUpperLimit: BigInt From 70b92a9b3f9de3245305fa7afb45b1a5d1034a12 Mon Sep 17 00:00:00 2001 From: "Arthur G." Date: Thu, 8 Aug 2024 13:18:55 +0200 Subject: [PATCH 3/5] test: add check that `Build` entity is created --- src/__test__/unit/market.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/__test__/unit/market.test.ts b/src/__test__/unit/market.test.ts index 214a44a..ca8268f 100644 --- a/src/__test__/unit/market.test.ts +++ b/src/__test__/unit/market.test.ts @@ -93,6 +93,17 @@ describe("Market events", () => { assert.entityCount("Market", 1) }) + test("creates Build entity with correct attributes", () => { + const marketId = market.concatI32(positionId.toI32()).toHexString() + + assert.entityCount("Build", 1) + assert.fieldEquals("Build", marketId, "owner", sender.toHexString()) + assert.fieldEquals("Build", marketId, "currentOi", oi.toString()) + assert.fieldEquals("Build", marketId, "currentDebt", debt.toString()) + assert.fieldEquals("Build", marketId, "isLong", isLong.toString()) + assert.fieldEquals("Build", marketId, "price", price.toString()) + }) + describe("Trading Mining", () => { test("creates TradingMiningEpochVolume entity", () => { From f96fb90613e03c9f0a561b8c5c12819ecb0799bf Mon Sep 17 00:00:00 2001 From: "Arthur G." Date: Thu, 8 Aug 2024 13:20:17 +0200 Subject: [PATCH 4/5] test: handler `Liquidate` --- src/__test__/unit/market.test.ts | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/__test__/unit/market.test.ts b/src/__test__/unit/market.test.ts index ca8268f..b4d5e31 100644 --- a/src/__test__/unit/market.test.ts +++ b/src/__test__/unit/market.test.ts @@ -54,6 +54,10 @@ const oiAfterUnwind = BigInt.fromI32(25) const oiSharesAfterUnwind = BigInt.fromI32(1) const fraction = BigInt.fromI32(5) +// Liquidate event parameters +const oiAfterLiquidate = BigInt.fromI32(0) +const oiSharesAfterLiquidate = BigInt.fromI32(0) + // CacheRiskCalc event parameters const dpUpperLimit = BigInt.fromI32(100) @@ -252,6 +256,34 @@ describe("Market events", () => { }) }) + describe("Liquidate event", () => { + beforeEach(() => { + // Create a Build event to set up the initial position + const buildEvent = createBuildEvent(market, sender, positionId, oi, debt, isLong, price, oi, oiSharesAfterBuild) + handleBuild(buildEvent) + + // Now create a Liquidate event to test + const liquidateEvent = createLiquidateEvent(market, zeroAddress, sender, positionId, BigInt.fromI32(10), price, oiAfterLiquidate, oiSharesAfterLiquidate) + handleLiquidate(liquidateEvent) + }) + + afterEach(() => { + clearStore() + }) + + test("creates Liquidate entity with correct attributes", () => { + const liquidateId = market.concatI32(positionId.toI32()).toHexString(); + + assert.entityCount("Liquidate", 1) + assert.fieldEquals("Liquidate", liquidateId, "owner", sender.toHexString()) + assert.fieldEquals("Liquidate", liquidateId, "sender", zeroAddress.toHexString()) + assert.fieldEquals("Liquidate", liquidateId, "currentOi", oi.toString()) + assert.fieldEquals("Liquidate", liquidateId, "currentDebt", debt.toString()) + assert.fieldEquals("Liquidate", liquidateId, "isLong", isLong.toString()) + assert.fieldEquals("Liquidate", liquidateId, "price", price.toString()) + }) + }) + describe("CacheRiskCalc event", () => { beforeEach(() => { const event = createCacheRiskCalcEvent(market, dpUpperLimit) @@ -371,6 +403,32 @@ function createUnwindEvent( return event } +function createLiquidateEvent( + market: Address, + sender: Address, + owner: Address, + positionId: BigInt, + mint: BigInt, + price: BigInt, + oiAfterLiquidate: BigInt, + oiSharesAfterLiquidate: BigInt +): LiquidateEvent { + const event = changetype(newMockEvent()) + + event.address = market + event.parameters = new Array() + + event.parameters.push(new ethereum.EventParam("sender", ethereum.Value.fromAddress(sender))) + event.parameters.push(new ethereum.EventParam("owner", ethereum.Value.fromAddress(owner))) + event.parameters.push(new ethereum.EventParam("positionId", ethereum.Value.fromUnsignedBigInt(positionId))) + event.parameters.push(new ethereum.EventParam("mint", ethereum.Value.fromUnsignedBigInt(mint))) + event.parameters.push(new ethereum.EventParam("price", ethereum.Value.fromUnsignedBigInt(price))) + event.parameters.push(new ethereum.EventParam("oiAfterLiquidate", ethereum.Value.fromUnsignedBigInt(oiAfterLiquidate))) + event.parameters.push(new ethereum.EventParam("oiSharesAfterLiquidate", ethereum.Value.fromUnsignedBigInt(oiSharesAfterLiquidate))) + + return event +} + function createCacheRiskCalcEvent( market: Address, dpUpperLimit: BigInt From f29ddbce0ea9e6814d282a10aad72a7cb0a75835 Mon Sep 17 00:00:00 2001 From: "Arthur G." Date: Thu, 8 Aug 2024 13:23:33 +0200 Subject: [PATCH 5/5] test: handler `EmergencyWithdraw` --- src/__test__/unit/market.test.ts | 62 +++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/__test__/unit/market.test.ts b/src/__test__/unit/market.test.ts index b4d5e31..963a31c 100644 --- a/src/__test__/unit/market.test.ts +++ b/src/__test__/unit/market.test.ts @@ -23,7 +23,7 @@ import { handleBuild, handleLiquidate, handleUnwind, handleEmergencyWithdraw, ha import { loadAccount } from "../../utils" import { loadTradingMining } from "../../trading-mining" import { loadReferralProgram, loadReferralPosition } from "../../referral" -import { PERIPHERY_ADDRESS, TRADING_MINING_ADDRESS, REFERRAL_ADDRESS, ADDRESS_ZERO } from "../../utils/constants" +import { PERIPHERY_ADDRESS, TRADING_MINING_ADDRESS, REFERRAL_ADDRESS, ADDRESS_ZERO, ONE_18DEC_BI } from "../../utils/constants" import { setupMarketMockedFunctions, setupTradingMiningMockedFunctions } from "./shared/mockedFunctions" import { MARKET_COLLATERAL, MARKET_PCD_HOLDER, MARKET_POSITION_ID, MARKET_SENDER } from "./shared/constants" @@ -284,6 +284,48 @@ describe("Market events", () => { }) }) + describe("EmergencyWithdraw event", () => { + beforeEach(() => { + // Create a Build event to set up the initial position + const buildEvent = createBuildEvent(market, sender, positionId, oi, debt, isLong, price, oi, oiSharesAfterBuild) + handleBuild(buildEvent) + + // Now create an EmergencyWithdraw event to test + const emergencyWithdrawEvent = createEmergencyWithdrawEvent(market, sender, positionId, collateral) + handleEmergencyWithdraw(emergencyWithdrawEvent) + }) + + afterEach(() => { + clearStore() + }) + + test("creates an Unwound and withdraws Position collateral", () => { + const _positionId = market.concatI32(positionId.toI32()) + const unwindId = _positionId.concatI32(0).toHexString() + + assert.entityCount("Unwind", 1) + assert.fieldEquals("Unwind", unwindId, "position", _positionId.toHexString()) + assert.fieldEquals("Unwind", unwindId, "owner", sender.toHexString()) + assert.fieldEquals("Unwind", unwindId, "size", collateral.toString()) + assert.fieldEquals("Unwind", unwindId, "transferAmount", collateral.toString()) + assert.fieldEquals("Unwind", unwindId, "currentOi", oi.toString()) + assert.fieldEquals("Unwind", unwindId, "currentDebt", debt.toString()) + assert.fieldEquals("Unwind", unwindId, "isLong", isLong.toString()) + assert.fieldEquals("Unwind", unwindId, "price", "0") + assert.fieldEquals("Unwind", unwindId, "fraction", ONE_18DEC_BI.toString()) + assert.fieldEquals("Unwind", unwindId, "fractionOfPosition", ONE_18DEC_BI.toString()) + assert.fieldEquals("Unwind", unwindId, "volume", "0") + assert.fieldEquals("Unwind", unwindId, "mint", "0") + assert.fieldEquals("Unwind", unwindId, "fundingPayment", "0") + assert.fieldEquals("Unwind", unwindId, "collateral", "0") + assert.fieldEquals("Unwind", unwindId, "value", "0") + + assert.fieldEquals("Position", _positionId.toHexString(), "currentOi", "0") + assert.fieldEquals("Position", _positionId.toHexString(), "currentDebt", "0") + assert.fieldEquals("Position", _positionId.toHexString(), "fractionUnwound", ONE_18DEC_BI.toString()) + }) + }) + describe("CacheRiskCalc event", () => { beforeEach(() => { const event = createCacheRiskCalcEvent(market, dpUpperLimit) @@ -429,6 +471,24 @@ function createLiquidateEvent( return event } +function createEmergencyWithdrawEvent( + market: Address, + sender: Address, + positionId: BigInt, + collateral: BigInt +): EmergencyWithdrawEvent { + const event = changetype(newMockEvent()) + + event.address = market + event.parameters = new Array() + + event.parameters.push(new ethereum.EventParam("sender", ethereum.Value.fromAddress(sender))) + event.parameters.push(new ethereum.EventParam("positionId", ethereum.Value.fromUnsignedBigInt(positionId))) + event.parameters.push(new ethereum.EventParam("collateral", ethereum.Value.fromUnsignedBigInt(collateral))) + + return event +} + function createCacheRiskCalcEvent( market: Address, dpUpperLimit: BigInt