Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add izumiswap adapter #18

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions adapters/izumiswap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "izumiswap",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node dist/index.js",
"compile": "tsc",
"watch": "tsc -w",
"clear": "rm -rf dist"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/big.js": "^6.2.2",
"big.js": "^6.2.1",
"bignumber.js": "^9.1.2",
"csv-parser": "^3.0.0",
"decimal.js-light": "^2.5.1",
"fast-csv": "^5.0.1",
"jsbi": "^4.3.0",
"tiny-invariant": "^1.3.1",
"toformat": "^2.0.0",
"viem": "^2.8.13"
},
"devDependencies": {
"@types/node": "^20.11.17",
"typescript": "^5.3.3"
}
}
30 changes: 30 additions & 0 deletions adapters/izumiswap/src/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const enum CHAINS{
MODE = 34443,
LINEA = 59144,
}
export const enum PROTOCOLS{
SUPSWAP = 0,
IZISWAP = 1,
}

export const enum AMM_TYPES{
UNISWAPV3 = 0,
IZISWAP = 1
}

export const SUBGRAPH_URLS = {
[CHAINS.MODE]: {
[PROTOCOLS.IZISWAP]: {
[AMM_TYPES.IZISWAP]: "https://graph-node-api.izumi.finance/query/subgraphs/name/izi-swap-mode"
}
},
[CHAINS.LINEA]: {
[PROTOCOLS.IZISWAP]: {
[AMM_TYPES.IZISWAP]: "https://api.studio.thegraph.com/query/24334/izumi-subgraph-linea/version/latest"
}
}
}
export const RPC_URLS = {
[CHAINS.MODE]: "https://rpc.goldsky.com",
[CHAINS.LINEA]: "https://rpc.linea.build",
}
137 changes: 137 additions & 0 deletions adapters/izumiswap/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import BigNumber from "bignumber.js";
import { CHAINS, PROTOCOLS, AMM_TYPES } from "./config/config";
import { getLPValueByUserAndPoolFromPositions, getPositionAtBlock, getPositionDetailsFromPosition, getPositionsForAddressByPoolAtBlock, getTimestampAtBlock } from "./utils/subgraphDetails";
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};

import { promisify } from 'util';
import stream from 'stream';
import csv from 'csv-parser';
import fs from 'fs';
import { format } from 'fast-csv';
import { write } from 'fast-csv';

//Uncomment the following lines to test the getPositionAtBlock function

// const position = getPositionAtBlock(
// 0, // block number 0 for latest block
// 2, // position id
// CHAINS.MODE, // chain id
// PROTOCOLS.SUPSWAP, // protocol
// AMM_TYPES.UNISWAPV3 // amm type
// );
// position.then((position) => {
// // print response
// const result = getPositionDetailsFromPosition(position);
// console.log(`${JSON.stringify(result,null, 4)}
// `)
// });

interface BlockData {
blockNumber: number;
blockTimestamp: number;
}

interface CSVRow {
block_number: number;
timestamp: number;
user_address: string;
token_address: string;
token_balance: string;
token_symbol: string;
usd_price: number;
}

const pipeline = promisify(stream.pipeline);

const readBlocksFromCSV = async (filePath: string): Promise<number[]> => {
const blocks: number[] = [];
await pipeline(
fs.createReadStream(filePath),
csv(),
async function* (source) {
for await (const chunk of source) {
// Assuming each row in the CSV has a column 'block' with the block number
if (chunk.block) blocks.push(parseInt(chunk.block, 10));
}
}
);
return blocks;
};


const getData = async () => {
const snapshotBlocks = [
3055683
]; //await readBlocksFromCSV('src/sdk/mode_chain_daily_blocks.csv');

const csvRows: CSVRow[] = [];

for (let block of snapshotBlocks) {
const positions = await getPositionsForAddressByPoolAtBlock(
block, "", "", CHAINS.LINEA, PROTOCOLS.IZISWAP, AMM_TYPES.IZISWAP
);

console.log(`Block: ${block}`);
console.log("Positions: ", positions.length);

const timestamp = await getTimestampAtBlock(block);

// Assuming this part of the logic remains the same
let positionsWithUSDValue = positions.map(getPositionDetailsFromPosition);
let lpValueByUsers = getLPValueByUserAndPoolFromPositions(positionsWithUSDValue);

lpValueByUsers.forEach((value, key) => {
value.forEach((tokenBalance, tokenKey) => {
// Accumulate CSV row data
csvRows.push({
block_number: block,
timestamp: timestamp / 1000,
user_address: key,
token_address: tokenKey,
token_symbol: tokenBalance.tokenSymbol,
token_balance: tokenBalance.tokenBalance.toString(),
usd_price: tokenBalance.usdPrice,
});
});
});
}

// Write the CSV output to a file
const ws = fs.createWriteStream('outputData.csv');
write(csvRows, { headers: true }).pipe(ws).on('finish', () => {
console.log("CSV file has been written.");
});
};

export const getUserTVLByBlock = async (blocks: BlockData) => {
const { blockNumber, blockTimestamp } = blocks
const positions = await getPositionsForAddressByPoolAtBlock(
blockNumber, "", "", CHAINS.LINEA, PROTOCOLS.IZISWAP, AMM_TYPES.IZISWAP
);

let positionsWithUSDValue = positions.map(getPositionDetailsFromPosition);
let lpValueByUsers = getLPValueByUserAndPoolFromPositions(positionsWithUSDValue);

const csvRows: CSVRow[] = [];
lpValueByUsers.forEach((value, key) => {
value.forEach((tokenBalance, tokenKey) => {
csvRows.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: key,
token_address: tokenKey,
token_symbol: tokenBalance.tokenSymbol,
token_balance: tokenBalance.tokenBalance.toString(),
usd_price: tokenBalance.usdPrice,
});
});
});

return csvRows
};

getData().then(() => {
console.log("Done");
});
143 changes: 143 additions & 0 deletions adapters/izumiswap/src/utils/positionMath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import BigNumber from "bignumber.js";

export interface TokenInfoFormatted {
chainId: number;
name?: string;
symbol: string;
address: string;
decimal: number;
}
export interface Liquidity {
leftPoint: number;
rightPoint: number;
liquidity: string;
decimalX: number;
decimalY: number;
}

export const point2PoolPriceUndecimalSqrt = (point: number) : number => {
return (1.0001 ** point) ** 0.5;
}

export const _getAmountY = (
liquidity: BigNumber,
sqrtPriceL: number,
sqrtPriceR: number,
sqrtRate: number,
upper: boolean,
): BigNumber => {
const numerator = sqrtPriceR - sqrtPriceL;
const denominator = sqrtRate - 1;
if (!upper) {
const amount = new BigNumber(liquidity.times(numerator).div(denominator).toFixed(0, 3));
return amount;
} else {
const amount = new BigNumber(liquidity.times(numerator).div(denominator).toFixed(0, 2));
return amount;
}
}

export const _getAmountX = (
liquidity: BigNumber,
leftPt: number,
rightPt: number,
sqrtPriceR: number,
sqrtRate: number,
upper: boolean,
): BigNumber => {
const sqrtPricePrPc = Math.pow(sqrtRate, rightPt - leftPt + 1);
const sqrtPricePrPd = Math.pow(sqrtRate, rightPt + 1);

const numerator = sqrtPricePrPc - sqrtRate;
const denominator = sqrtPricePrPd - sqrtPriceR;

if (!upper) {
const amount = new BigNumber(liquidity.times(numerator).div(denominator).toFixed(0, 3));
return amount;
} else {
const amount = new BigNumber(liquidity.times(numerator).div(denominator).toFixed(0, 2));
return amount;
}
}

export const _liquidity2AmountYAtPoint = (
liquidity: BigNumber,
sqrtPrice: number,
upper: boolean
): BigNumber => {
const amountY = liquidity.times(sqrtPrice);
if (!upper) {
return new BigNumber(amountY.toFixed(0, 3));
} else {
return new BigNumber(amountY.toFixed(0, 2));
}
}

export const _liquidity2AmountXAtPoint = (
liquidity: BigNumber,
sqrtPrice: number,
upper: boolean
): BigNumber => {
const amountX = liquidity.div(sqrtPrice);
if (!upper) {
return new BigNumber(amountX.toFixed(0, 3));
} else {
return new BigNumber(amountX.toFixed(0, 2));
}
}

export const amount2Decimal = (amount: BigNumber, decimal: number): number => {
return Number(amount.div(10 ** decimal))
}

export const getLiquidityValue = (
liquidity: Liquidity,
currentPoint: number
): {amountXDecimal: number, amountYDecimal: number, amountX: BigNumber, amountY: BigNumber} => {

let amountX = new BigNumber(0);
let amountY = new BigNumber(0);
const liquid = liquidity.liquidity;
const sqrtRate = Math.sqrt(1.0001);
const leftPtNum = Number(liquidity.leftPoint);
const rightPtNum = Number(liquidity.rightPoint);
// compute amountY without currentPt
if (leftPtNum < currentPoint) {
const rightPt: number = Math.min(currentPoint, rightPtNum);
const sqrtPriceR = point2PoolPriceUndecimalSqrt(rightPt);
const sqrtPriceL = point2PoolPriceUndecimalSqrt(leftPtNum);
amountY = _getAmountY(new BigNumber(liquid), sqrtPriceL, sqrtPriceR, sqrtRate, false);
}

// compute amountX without currentPt
if (rightPtNum > currentPoint + 1) {
const leftPt: number = Math.max(currentPoint + 1, leftPtNum);
const sqrtPriceR = point2PoolPriceUndecimalSqrt(rightPtNum);
amountX = _getAmountX(new BigNumber(liquid), leftPt, rightPtNum, sqrtPriceR, sqrtRate, false);
}

// compute amountX and amountY on currentPt
if (leftPtNum <= currentPoint && rightPtNum > currentPoint) {
const liquidityValue = new BigNumber(liquidity.liquidity);
const maxLiquidityYAtCurrentPt = new BigNumber(0);
const liquidityYAtCurrentPt = liquidityValue.gt(maxLiquidityYAtCurrentPt) ? maxLiquidityYAtCurrentPt : liquidityValue;
const liquidityXAtCurrentPt = liquidityValue.minus(liquidityYAtCurrentPt);
const currentSqrtPrice = point2PoolPriceUndecimalSqrt(currentPoint);
amountX = amountX.plus(_liquidity2AmountXAtPoint(liquidityXAtCurrentPt, currentSqrtPrice, false));
amountY = amountY.plus(_liquidity2AmountYAtPoint(liquidityYAtCurrentPt, currentSqrtPrice, false));
}
const amountXDecimal:number = amount2Decimal(
amountX, liquidity.decimalX
)?? 0;
const amountYDecimal:number = amount2Decimal(
amountY, liquidity.decimalY
)?? 0;
return {
amountX, amountXDecimal,
amountY, amountYDecimal
};
}

export const PositionMath = {
getLiquidityValue
}
Loading
Loading