-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from bvotteler/feat-add-cumulative-amm-volumes
Feat: Add cumulative dex volumes per pool and exchanged currency
- Loading branch information
Showing
20 changed files
with
737 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module.exports = class Data1675434206425 { | ||
name = 'Data1675434206425' | ||
|
||
async up(db) { | ||
await db.query(`CREATE TABLE "cumulative_dex_trading_volume_per_pool" ("id" character varying NOT NULL, "pool_id" text NOT NULL, "pool_type" character varying(8) NOT NULL, "till_timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "amounts" jsonb NOT NULL, CONSTRAINT "PK_c9bb1ee57bff1390d948e3e6f12" PRIMARY KEY ("id"))`) | ||
await db.query(`CREATE INDEX "IDX_bd6bc9a6ce9e1fcb81b0650c0f" ON "cumulative_dex_trading_volume_per_pool" ("pool_id") `) | ||
await db.query(`CREATE INDEX "IDX_a903319c2555960f188406a839" ON "cumulative_dex_trading_volume_per_pool" ("till_timestamp") `) | ||
} | ||
|
||
async down(db) { | ||
await db.query(`DROP TABLE "cumulative_dex_trading_volume_per_pool"`) | ||
await db.query(`DROP INDEX "public"."IDX_bd6bc9a6ce9e1fcb81b0650c0f"`) | ||
await db.query(`DROP INDEX "public"."IDX_a903319c2555960f188406a839"`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
import { SubstrateBlock } from "@subsquid/substrate-processor"; | ||
import { CumulativeDexTradingVolumePerPool, Currency, fromJsonPooledToken, PooledToken } from "../../model"; | ||
import { Ctx, EventItem } from "../../processor"; | ||
import { DexGeneralAssetSwapEvent, DexStableCurrencyExchangeEvent } from "../../types/events"; | ||
import { currencyId } from "../encoding"; | ||
import { SwapDetails, updateCumulativeDexVolumesForStablePool, updateCumulativeDexVolumesForStandardPool } from "../utils/cumulativeVolumes"; | ||
import EntityBuffer from "../utils/entityBuffer"; | ||
import { getStablePoolCurrencyByIndex } from "../utils/pools"; | ||
|
||
function isPooledToken(currency: Currency): currency is PooledToken { | ||
try { | ||
fromJsonPooledToken(currency); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Combines the given arrays into in/out pairs as an array of {@link SwapDetails}. | ||
* @param currencies The currencies in the swap path | ||
* @param atomicBalances The swapped balances, in atomic units and same order as currencies | ||
* @returns An array of pair-wise combined {@link SwapDetails}. | ||
* @throws {@link Error} | ||
* Throws an error if currencies length does not match balances length, or if a passed in currency is not a {@link PooledToken} | ||
*/ | ||
function createPairWiseSwapDetails(currencies: Currency[], atomicBalances: bigint[]): SwapDetails[] { | ||
if (currencies.length !== atomicBalances.length) { | ||
throw new Error(`Cannot combine pair wise swap details; currency count [${ | ||
currencies.length | ||
}] does not match balance count [${ | ||
atomicBalances.length | ||
}]`); | ||
} | ||
|
||
const swapDetailsList: SwapDetails[] = []; | ||
for(let idx = 0; (idx + 1) < currencies.length; idx++) { | ||
const inIdx = idx; | ||
const outIdx = idx + 1; | ||
const currencyIn = currencies[inIdx]; | ||
const currencyOut = currencies[outIdx]; | ||
|
||
if (!isPooledToken(currencyIn)) { | ||
throw new Error(`Cannot combine pair wise swap details; unexpected currency type ${ | ||
currencyIn.isTypeOf | ||
} in pool, skip processing of DexGeneralAssetSwapEvent`); | ||
} else if (!isPooledToken(currencyOut)) { | ||
throw new Error(`Unexpected currency type ${ | ||
currencyOut.isTypeOf | ||
} in pool, skip processing of DexGeneralAssetSwapEvent`); | ||
} | ||
|
||
swapDetailsList.push({ | ||
from: { | ||
currency: currencyIn, | ||
atomicAmount: atomicBalances[inIdx] | ||
}, | ||
to: { | ||
currency: currencyOut, | ||
atomicAmount: atomicBalances[outIdx] | ||
} | ||
}); | ||
} | ||
|
||
return swapDetailsList; | ||
} | ||
|
||
export async function dexGeneralAssetSwap( | ||
ctx: Ctx, | ||
block: SubstrateBlock, | ||
item: EventItem, | ||
entityBuffer: EntityBuffer | ||
): Promise<void> { | ||
const rawEvent = new DexGeneralAssetSwapEvent(ctx, item.event); | ||
let currencies: Currency[] = []; | ||
let atomicBalances: bigint[] = []; | ||
|
||
if (rawEvent.isV1021000) { | ||
const [, , swapPath, balances] = rawEvent.asV1021000; | ||
currencies = swapPath.map(currencyId.encode); | ||
atomicBalances = balances; | ||
} else { | ||
ctx.log.warn("UNKOWN EVENT VERSION: DexGeneral.AssetSwap"); | ||
return; | ||
} | ||
|
||
// we can only use pooled tokens, check we have not other ones | ||
for (const currency of currencies) { | ||
if (!isPooledToken(currency)) { | ||
ctx.log.error(`Unexpected currency type ${currency.isTypeOf} in pool, skip processing of DexGeneralAssetSwapEvent`); | ||
return; | ||
} | ||
} | ||
|
||
let swapDetailsList: SwapDetails[]; | ||
try { | ||
swapDetailsList = createPairWiseSwapDetails(currencies, atomicBalances); | ||
} catch (e) { | ||
ctx.log.error((e as Error).message); | ||
return; | ||
} | ||
|
||
// construct and await sequentially, otherwise some operations may try to read values from | ||
// the entity buffer before it has been updated | ||
for (const swapDetails of swapDetailsList) { | ||
const entity = await updateCumulativeDexVolumesForStandardPool( | ||
ctx.store, | ||
new Date(block.timestamp), | ||
swapDetails, | ||
entityBuffer | ||
); | ||
|
||
entityBuffer.pushEntity(CumulativeDexTradingVolumePerPool.name, entity); | ||
} | ||
} | ||
|
||
export async function dexStableCurrencyExchange( | ||
ctx: Ctx, | ||
block: SubstrateBlock, | ||
item: EventItem, | ||
entityBuffer: EntityBuffer | ||
): Promise<void> { | ||
const rawEvent = new DexStableCurrencyExchangeEvent(ctx, item.event); | ||
let poolId: number; | ||
let inIndex: number; | ||
let outIndex: number; | ||
let inAmount: bigint; | ||
let outAmount: bigint; | ||
|
||
if (rawEvent.isV1021000) { | ||
const event = rawEvent.asV1021000; | ||
poolId = event.poolId; | ||
inIndex = event.inIndex; | ||
outIndex = event.outIndex; | ||
inAmount = event.inAmount; | ||
outAmount = event.outAmount; | ||
} else { | ||
ctx.log.warn("UNKOWN EVENT VERSION: DexStable.CurrencyExchange"); | ||
return; | ||
} | ||
|
||
const outCurrency = await getStablePoolCurrencyByIndex(ctx, block, poolId, outIndex); | ||
const inCurrency = await getStablePoolCurrencyByIndex(ctx, block, poolId, inIndex); | ||
|
||
if (!isPooledToken(inCurrency)) { | ||
ctx.log.error(`Unexpected currencyIn type ${inCurrency.isTypeOf}, skip processing of DexGeneralAssetSwapEvent`); | ||
return; | ||
} | ||
if (!isPooledToken(outCurrency)) { | ||
ctx.log.error(`Unexpected currencyOut type ${outCurrency.isTypeOf}, skip processing of DexGeneralAssetSwapEvent`); | ||
return; | ||
} | ||
|
||
const swapDetails: SwapDetails = { | ||
from: { | ||
currency: inCurrency, | ||
atomicAmount: inAmount | ||
}, | ||
to: { | ||
currency: outCurrency, | ||
atomicAmount: outAmount | ||
} | ||
}; | ||
|
||
const entityPromise = updateCumulativeDexVolumesForStablePool( | ||
ctx.store, | ||
new Date(block.timestamp), | ||
poolId, | ||
swapDetails, | ||
entityBuffer | ||
); | ||
|
||
entityBuffer.pushEntity( | ||
CumulativeDexTradingVolumePerPool.name, | ||
await entityPromise | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from "./dex"; | ||
export * from "./issue"; | ||
export * from "./redeem"; | ||
export * from "./vault"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.