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 metavault adapter #26

Merged
merged 4 commits into from
May 3, 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/metavault/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "metavault",
"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"
}
}
91 changes: 91 additions & 0 deletions adapters/metavault/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { CHAINS, PROTOCOLS, AMM_TYPES } from "./sdk/config";
import { getPositionDetailsFromPosition, getPositionsForAddressByPoolAtBlock, getTimestampAtBlock, getTradeLiquidityForAddressByPoolAtBlock } from "./sdk/subgraphDetails";
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};

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

type OutputDataSchemaRow = {
block_number: number;
timestamp: number;
user_address: string;
token_address: string;
token_balance: number;
token_symbol?: string;
usd_price: number;
};


export const getUserTVLByBlock = async ({
blockNumber,
blockTimestamp,
}: BlockData): Promise<OutputDataSchemaRow[]> => {
return await getPoolData({ blockNumber, blockTimestamp });
}

export const getPoolData = async ({
blockNumber,
blockTimestamp,
}: BlockData): Promise<OutputDataSchemaRow[]> => {
const allCsvRows: OutputDataSchemaRow[] = []; // Array to accumulate CSV rows for all blocks
try {
// const blockTimestamp = new Date(await getTimestampAtBlock(blockNumber)).toISOString();
const positions = await getPositionsForAddressByPoolAtBlock(
blockNumber, "", "", CHAINS.L2_CHAIN_ID, PROTOCOLS.METAVAULT, AMM_TYPES.UNISWAPV3
);

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

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

positionsWithUSDValue.forEach((value, key) => {
// Accumulate CSV row data
if (value.token0DecimalValue > 0) {
allCsvRows.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: value.owner,
token_address: value.token0.id,
token_balance: value.token0DecimalValue,
usd_price: 0,
});
}
if (value.token1DecimalValue > 0) {
allCsvRows.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: value.owner,
token_address: value.token1.id,
token_balance: value.token1DecimalValue,
usd_price: 0,
});
}
});
const liquidities = await getTradeLiquidityForAddressByPoolAtBlock(
blockNumber, "", "", CHAINS.L2_CHAIN_ID, PROTOCOLS.METAVAULT, AMM_TYPES.TRADE
);
liquidities.forEach((value, key) => {
if (value.amount > 0) {
allCsvRows.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: value.user,
token_address: value.asset,
token_balance: value.amount,
usd_price: 0,
});
}
});

} catch (error) {
console.error(`An error occurred for block ${blockNumber}:`, error);
}
return allCsvRows
}
35 changes: 35 additions & 0 deletions adapters/metavault/src/sdk/blockApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export const readBlocksFromApi = async (startTime: number, endTime: number): Promise<any[]> => {
const results = []
for (let i = startTime; i <= endTime; i += 3600) {
let response = await fetch(`https://api.lineascan.build/api?module=block&action=getblocknobytime&timestamp=${i}&closest=after&apikey=ADD_API_KEY`, {
headers: { "Content-Type": "application/json" },
});

const json = await response.json()
// sleep
await new Promise(r => setTimeout(r, 1000));
results.push(Number(json.result))
}
console.log(results);

return results

// daily blocks
return [
1459540, 1473940, 1488339, 1502715, 1517109, 1531509,
1545909, 1560309, 1574707, 1589104, 1603499, 1617898,
1632296, 1646696, 1661096, 1675487, 1689885, 1704285,
1718685, 1733085, 1747485, 1761885, 1779844, 1800972,
1822511, 1844067, 1865652, 1887247, 1908844, 1930429,
1951984, 1973539, 1994976, 2016544, 2038130, 2059720,
2081313, 2102851, 2124303, 2145723, 2166829, 2188347,
2209908, 2231357, 2252825, 2274361, 2295942, 2317539,
2339139, 2360738, 2382328, 2403928, 2425521, 2447121,
2468721, 2490321, 2511921, 2533521, 2555120, 2576720,
2598320, 2619920, 2641520, 2663120, 2684720, 2706320,
2727920, 2749520, 2771120, 2792720, 2814320, 2835920,
2857520, 2879120, 2900720, 2922320, 2943907, 2965507,
2987107, 3008707, 3030307, 3051907, 3073507, 3095107,
3116707
]
}
24 changes: 24 additions & 0 deletions adapters/metavault/src/sdk/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const enum CHAINS{
L2_CHAIN_ID = 59144,
}
export const enum PROTOCOLS{
METAVAULT = 0,
}

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

export const SUBGRAPH_URLS = {
[CHAINS.L2_CHAIN_ID]: {
[PROTOCOLS.METAVAULT]: {
[AMM_TYPES.UNISWAPV3]: "https://api.studio.thegraph.com/query/55804/linea-v3/version/latest",
[AMM_TYPES.TRADE]: "https://api.studio.thegraph.com/query/55804/linea-trade/version/latest"
}
},

}
export const RPC_URLS = {
[CHAINS.L2_CHAIN_ID]: "https://rpc.linea.build"
}
24 changes: 24 additions & 0 deletions adapters/metavault/src/sdk/entities/positions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Q128 } from '../utils/internalConstants'
import { subIn256 } from '../utils/tickLibrary'

export abstract class PositionLibrary {
/**
* Cannot be constructed.
*/
private constructor() {}

// replicates the portions of Position#update required to compute unaccounted fees
public static getTokensOwed(
feeGrowthInside0LastX128: bigint,
feeGrowthInside1LastX128: bigint,
liquidity: bigint,
feeGrowthInside0X128: bigint,
feeGrowthInside1X128: bigint
) {
const tokensOwed0 = (subIn256(feeGrowthInside0X128, feeGrowthInside0LastX128) * liquidity) / Q128

const tokensOwed1 = (subIn256(feeGrowthInside1X128, feeGrowthInside1LastX128) * liquidity) / Q128

return [tokensOwed0, tokensOwed1]
}
}
37 changes: 37 additions & 0 deletions adapters/metavault/src/sdk/mathUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { BigNumber } from 'bignumber.js';

export const getPrice = (sqrtPriceX96: BigNumber, Decimal0: number, Decimal1: number)=> {
console.log("sqrtPriceX96 : " + sqrtPriceX96.toString());
console.log("Decimal0 : " + Decimal0);
console.log("Decimal1 : " + Decimal1);

const twoPower96 = new BigNumber(2).pow(96);
const tenPowerDecimal0 = new BigNumber(10).pow(Decimal0);
const tenPowerDecimal1 = new BigNumber(10).pow(Decimal1);

// Perform calculations using BigNumber for high precision arithmetic
const priceSquared = (sqrtPriceX96.dividedBy(twoPower96)).pow(2);

console.log("priceSquared : " + priceSquared.toString());
const ratio = priceSquared.multipliedBy(tenPowerDecimal0).dividedBy(tenPowerDecimal1);
console.log("ratio : " + ratio.toString());
// Convert to string with fixed decimal places for display
const buyOneOfToken0 = ratio.toFixed(Decimal1);
const buyOneOfToken1 = new BigNumber(1).div(ratio).toFixed(Decimal0);

console.log(`price of token0 in value of token1 : ${buyOneOfToken0}`);
console.log(`price of token1 in value of token0 : ${buyOneOfToken1}`);
console.log("");

// Convert to lowest decimal representation for display
const buyOneOfToken0Wei = ratio.multipliedBy(tenPowerDecimal1).toFixed(0);
const buyOneOfToken1Wei = new BigNumber(1).div(ratio).multipliedBy(tenPowerDecimal0).toFixed(0);

console.log(`price of token0 in value of token1 in lowest decimal : ${buyOneOfToken0Wei}`);
console.log(`price of token1 in value of token1 in lowest decimal : ${buyOneOfToken1Wei}`);
console.log("");
}

// // Example usage with BigNumber inputs:
// // Convert string inputs to BigNumber. Ensure the input values are strings to prevent precision loss.
// getPrice(new BigNumber('3956146591263498000000000'), 18, 6);
Empty file.
51 changes: 51 additions & 0 deletions adapters/metavault/src/sdk/positionDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
function getTickAtSqrtPrice(sqrtPriceX96: bigint): number {
const Q96: bigint = 2n ** 96n;
return Math.floor(Math.log(Number(sqrtPriceX96 / Q96) ** 2) / Math.log(1.0001));
}

export const getTokenAmounts = async(
liquidity: bigint,
sqrtPriceX96: bigint,
tickLow: number,
tickHigh: number,
Decimal0: number,
Decimal1: number
)=> {
const Q96: bigint = 2n ** 96n;
const sqrtRatioA: number = Math.sqrt(1.0001 ** tickLow);
const sqrtRatioB: number = Math.sqrt(1.0001 ** tickHigh);
const currentTick: number = getTickAtSqrtPrice(sqrtPriceX96);
const sqrtPrice: number = Number(sqrtPriceX96 / Q96);
let amount0: bigint = 0n;
let amount1: bigint = 0n;

// print all the values
console.log("liquidity : " + liquidity.toString());
console.log("sqrtPriceX96 : " + sqrtPriceX96.toString());
console.log("tickLow : " + tickLow);
console.log("tickHigh : " + tickHigh);
console.log("Decimal0 : " + Decimal0);
console.log("Decimal1 : " + Decimal1);
console.log("sqrtRatioA : " + sqrtRatioA);
console.log("sqrtRatioB : " + sqrtRatioB);
console.log("currentTick : " + currentTick);
console.log("sqrtPrice : " + sqrtPrice);


if (currentTick < tickLow) {
amount0 = BigInt(Math.floor(Number(liquidity) * ((sqrtRatioB - sqrtRatioA) / (sqrtRatioA * sqrtRatioB))));
} else if (currentTick >= tickHigh) {
amount1 = BigInt(Math.floor(Number(liquidity) * (sqrtRatioB - sqrtRatioA)));
} else if (currentTick >= tickLow && currentTick < tickHigh) {
amount0 = BigInt(Math.floor(Number(liquidity) * ((sqrtRatioB - sqrtPrice) / (sqrtPrice * sqrtRatioB))));
amount1 = BigInt(Math.floor(Number(liquidity) * (sqrtPrice - sqrtRatioA)));
}
let amount0Human: string = (Number(amount0) / 10 ** Decimal0).toFixed(Decimal0);
let amount1Human: string = (Number(amount1) / 10 ** Decimal1).toFixed(Decimal1);

console.log("Amount Token0 in lowest decimal: " + amount0.toString());
console.log("Amount Token1 in lowest decimal: " + amount1.toString());
console.log("Amount Token0 : " + amount0Human);
console.log("Amount Token1 : " + amount1Human);
return [amount0, amount1];
}
Loading