-
Notifications
You must be signed in to change notification settings - Fork 90
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 #18 from izumiFinance/add-izumiswap-adapter
add izumiswap adapter
- Loading branch information
Showing
7 changed files
with
972 additions
and
0 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
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" | ||
} | ||
} |
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,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", | ||
} |
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,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"); | ||
}); |
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,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 | ||
} |
Oops, something went wrong.