Skip to content

Commit

Permalink
Feature: Adds collection of CL fees to aggregator. (#159)
Browse files Browse the repository at this point in the history
* Generating tests for Collect event.

* Add CLPool Collect fee aggregation.

* Adding CL Collect Fees aggregator event.

* Clean up test with proper fee computation.

* Break down volume and fee tests and reformat.
  • Loading branch information
jfarid27 authored Oct 24, 2024
1 parent 608eebd commit 7b026da
Show file tree
Hide file tree
Showing 2 changed files with 483 additions and 114 deletions.
181 changes: 156 additions & 25 deletions src/EventHandlers/CLPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,72 @@ import {
CLPool_SetFeeProtocol,
CLPool_Swap,
CLPoolAggregator,
Token,
} from "generated";
import { set_whitelisted_prices } from "../PriceOracle";
import { normalizeTokenAmountTo1e18 } from "../Helpers";
import { multiplyBase1e18, abs } from "../Maths";
import { updateCLPoolAggregator } from "../Aggregators/CLPoolAggregator";

/**
* Updates the fee amounts for a CLPoolAggregator based on event data.
*
* This function calculates the new total fees for both tokens in a liquidity pool
* and their equivalent value in USD. It normalizes the token amounts to a base of 1e18
* for consistent calculations and updates the total fees in the aggregator.
*
* @param clPoolAggregator - The current state of the CLPoolAggregator, containing existing fee data.
* @param event - The event data containing the fee amounts for token0 and token1.
* @param token0Instance - The instance of token0, containing its decimals and price per USD.
* @param token1Instance - The instance of token1, containing its decimals and price per USD.
*
* @returns An object containing the updated total fees for token0, token1, and their equivalent in USD.
*
* The returned object has the following structure:
* - `totalFees0`: The updated total fees for token0, normalized to 1e18.
* - `totalFees1`: The updated total fees for token1, normalized to 1e18.
* - `totalFeesUSD`: The updated total fees in USD, calculated using the normalized token fees and their prices.
*/
function updateCLPoolFees(
clPoolAggregator: CLPoolAggregator,
event: any,
token0Instance: Token | undefined,
token1Instance: Token | undefined
) {

let tokenUpdateData = {
totalFees0: clPoolAggregator.totalFees0,
totalFees1: clPoolAggregator.totalFees1,
totalFeesUSD: clPoolAggregator.totalFeesUSD,
};

if (token0Instance) {
const incomingFees0 = normalizeTokenAmountTo1e18(
event.params.amount0,
Number(token0Instance.decimals)
);
tokenUpdateData.totalFees0 += incomingFees0;
tokenUpdateData.totalFeesUSD += multiplyBase1e18(
incomingFees0,
token0Instance.pricePerUSDNew
);
}

if (token1Instance) {
const incomingFees1 = normalizeTokenAmountTo1e18(
event.params.amount1,
Number(token1Instance.decimals)
);
tokenUpdateData.totalFees1 += incomingFees1;
tokenUpdateData.totalFeesUSD += multiplyBase1e18(
incomingFees1,
token1Instance.pricePerUSDNew
);
}

return tokenUpdateData;
}

CLPool.Burn.handler(async ({ event, context }) => {
const entity: CLPool_Burn = {
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
Expand All @@ -33,35 +93,106 @@ CLPool.Burn.handler(async ({ event, context }) => {
context.CLPool_Burn.set(entity);
});

CLPool.Collect.handler(async ({ event, context }) => {
const entity: CLPool_Collect = {
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
owner: event.params.owner,
recipient: event.params.recipient,
tickLower: event.params.tickLower,
tickUpper: event.params.tickUpper,
amount0: event.params.amount0,
amount1: event.params.amount1,
sourceAddress: event.srcAddress,
timestamp: new Date(event.block.timestamp * 1000),
chainId: event.chainId,
};
CLPool.Collect.handlerWithLoader({
loader: async ({ event, context }) => {
const pool_id = event.srcAddress;
const pool_created = await context.CLFactory_PoolCreated.getWhere.pool.eq(
pool_id
);

if (!pool_created || pool_created.length === 0) {
context.log.error(`Pool ${pool_id} not found during collect`);
return null;
}

const [token0Instance, token1Instance, clPoolAggregator] =
await Promise.all([
context.Token.get(pool_created[0].token0),
context.Token.get(pool_created[0].token1),
context.CLPoolAggregator.get(pool_id),
]);

return { clPoolAggregator, token0Instance, token1Instance };
},
handler: async ({ event, context, loaderReturn }) => {

const entity: CLPool_Collect = {
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
owner: event.params.owner,
recipient: event.params.recipient,
tickLower: event.params.tickLower,
tickUpper: event.params.tickUpper,
amount0: event.params.amount0,
amount1: event.params.amount1,
sourceAddress: event.srcAddress,
timestamp: new Date(event.block.timestamp * 1000),
chainId: event.chainId,
};

context.CLPool_Collect.set(entity);

if (loaderReturn && loaderReturn.clPoolAggregator) {
const { clPoolAggregator, token0Instance, token1Instance } = loaderReturn;

context.CLPool_Collect.set(entity);
const tokenUpdateData = updateCLPoolFees(clPoolAggregator, event, token0Instance, token1Instance);

updateCLPoolAggregator(
tokenUpdateData,
clPoolAggregator,
new Date(event.block.timestamp * 1000),
context
);
}
},
});

CLPool.CollectFees.handler(async ({ event, context }) => {
const entity: CLPool_CollectFees = {
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
recipient: event.params.recipient,
amount0: event.params.amount0,
amount1: event.params.amount1,
sourceAddress: event.srcAddress,
timestamp: new Date(event.block.timestamp * 1000),
chainId: event.chainId,
};
CLPool.CollectFees.handlerWithLoader({
loader: async ({ event, context }) => {
const pool_id = event.srcAddress;
const pool_created = await context.CLFactory_PoolCreated.getWhere.pool.eq(
pool_id
);

if (!pool_created || pool_created.length === 0) {
context.log.error(`Pool ${pool_id} not found during collect`);
return null;
}

const [token0Instance, token1Instance, clPoolAggregator] =
await Promise.all([
context.Token.get(pool_created[0].token0),
context.Token.get(pool_created[0].token1),
context.CLPoolAggregator.get(pool_id),
]);

context.CLPool_CollectFees.set(entity);
return { clPoolAggregator, token0Instance, token1Instance };
},
handler: async ({ event, context, loaderReturn }) => {
const entity: CLPool_CollectFees = {
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
recipient: event.params.recipient,
amount0: event.params.amount0,
amount1: event.params.amount1,
sourceAddress: event.srcAddress,
timestamp: new Date(event.block.timestamp * 1000),
chainId: event.chainId,
};

context.CLPool_CollectFees.set(entity);

if (loaderReturn && loaderReturn.clPoolAggregator) {
const { clPoolAggregator, token0Instance, token1Instance } = loaderReturn;

const tokenUpdateData = updateCLPoolFees(clPoolAggregator, event, token0Instance, token1Instance);

updateCLPoolAggregator(
tokenUpdateData,
clPoolAggregator,
new Date(event.block.timestamp * 1000),
context
);
}
}
});

CLPool.Flash.handler(async ({ event, context }) => {
Expand Down
Loading

0 comments on commit 7b026da

Please sign in to comment.