diff --git a/adapters/metavault/package.json b/adapters/metavault/package.json
new file mode 100644
index 00000000..eccdbff5
--- /dev/null
+++ b/adapters/metavault/package.json
@@ -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"
+  }
+}
\ No newline at end of file
diff --git a/adapters/metavault/src/index.ts b/adapters/metavault/src/index.ts
new file mode 100644
index 00000000..21de8724
--- /dev/null
+++ b/adapters/metavault/src/index.ts
@@ -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
+}
diff --git a/adapters/metavault/src/sdk/blockApi.ts b/adapters/metavault/src/sdk/blockApi.ts
new file mode 100644
index 00000000..5ac856bc
--- /dev/null
+++ b/adapters/metavault/src/sdk/blockApi.ts
@@ -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
+    ]
+}
\ No newline at end of file
diff --git a/adapters/metavault/src/sdk/config.ts b/adapters/metavault/src/sdk/config.ts
new file mode 100644
index 00000000..9fdbfc9f
--- /dev/null
+++ b/adapters/metavault/src/sdk/config.ts
@@ -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"
+}
\ No newline at end of file
diff --git a/adapters/metavault/src/sdk/entities/positions.ts b/adapters/metavault/src/sdk/entities/positions.ts
new file mode 100644
index 00000000..bb410185
--- /dev/null
+++ b/adapters/metavault/src/sdk/entities/positions.ts
@@ -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]
+  }
+}
diff --git a/adapters/metavault/src/sdk/mathUtils.ts b/adapters/metavault/src/sdk/mathUtils.ts
new file mode 100644
index 00000000..d245b2df
--- /dev/null
+++ b/adapters/metavault/src/sdk/mathUtils.ts
@@ -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);
diff --git a/adapters/metavault/src/sdk/poolDetails.ts b/adapters/metavault/src/sdk/poolDetails.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/adapters/metavault/src/sdk/positionDetails.ts b/adapters/metavault/src/sdk/positionDetails.ts
new file mode 100644
index 00000000..a51d248a
--- /dev/null
+++ b/adapters/metavault/src/sdk/positionDetails.ts
@@ -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];
+}
diff --git a/adapters/metavault/src/sdk/subgraphDetails.ts b/adapters/metavault/src/sdk/subgraphDetails.ts
new file mode 100644
index 00000000..9bf18158
--- /dev/null
+++ b/adapters/metavault/src/sdk/subgraphDetails.ts
@@ -0,0 +1,386 @@
+import BigNumber from "bignumber.js";
+import { AMM_TYPES, CHAINS, PROTOCOLS, RPC_URLS, SUBGRAPH_URLS } from "./config";
+import { PositionMath } from "./utils/positionMath";
+import { createPublicClient, extractChain, http } from "viem";
+import { linea } from "viem/chains";
+
+
+
+export interface Position {
+    id: string;
+    liquidity: bigint;
+    owner: string;
+    pool: {
+        sqrtPrice: bigint;
+        tick: number;
+        id: string;
+    };
+    tickLower: {
+        tickIdx: number;
+    };
+    tickUpper: {
+        tickIdx: number;
+    };
+
+    token0: {
+        id: string;
+        decimals: number;
+        derivedUSD: number;
+        name: string;
+        symbol: string;
+    };
+    token1: {
+        id: string;
+        decimals: number;
+        derivedUSD: number;
+        name: string;
+        symbol: string;
+    }
+};
+
+
+export interface PositionWithUSDValue extends Position {
+    token0USDValue: string;
+    token1USDValue: string;
+    token0AmountsInWei: bigint;
+    token1AmountsInWei: bigint;
+    token0DecimalValue: number;
+    token1DecimalValue: number;
+}
+
+export const getPositionsForAddressByPoolAtBlock = async (
+    blockNumber: number,
+    address: string,
+    poolId: string,
+    chainId: CHAINS,
+    protocol: PROTOCOLS,
+    ammType: AMM_TYPES
+): Promise<Position[]> => {
+    let subgraphUrl = SUBGRAPH_URLS[chainId][protocol][ammType];
+    let blockQuery = blockNumber !== 0 ? ` block: {number: ${blockNumber}}` : ``;
+    let poolQuery = poolId !== "" ? ` pool_:{id: "${poolId.toLowerCase()}"}` : ``;
+    let ownerQuery = address !== "" ? `owner: "${address.toLowerCase()}"` : ``;
+
+    let whereQuery = ownerQuery !== "" && poolQuery !== "" ? `where: {${ownerQuery} , ${poolQuery}}` : ownerQuery !== "" ? `where: {${ownerQuery}}` : poolQuery !== "" ? `where: {${poolQuery}}` : ``;
+    let skip = 0;
+    let fetchNext = true;
+    let result: Position[] = [];
+    while (fetchNext) {
+        let query = `{
+            bundle( id: 1 ${blockQuery}){
+                ethPriceUSD
+            }
+            positions(${whereQuery} ${blockQuery} orderBy: transaction__timestamp, first:1000,skip:${skip}) {
+            id
+
+                liquidity
+                owner
+                pool {
+                    sqrtPrice
+                    tick
+                    id
+                }
+                tickLower{
+                    tickIdx
+                }
+                tickUpper{
+                    tickIdx
+                }
+                token0 {
+                    id
+                    decimals
+                    derivedETH
+                    name
+                    symbol
+                }
+                token1 {
+                    id
+                    decimals
+                    derivedETH
+                    name
+                    symbol
+                }
+            },
+            _meta{
+                    block{
+                    number
+                }
+            }
+        }`;
+
+        // console.log(query)
+
+        let response = await fetch(subgraphUrl, {
+            method: "POST",
+            body: JSON.stringify({ query }),
+            headers: { "Content-Type": "application/json" },
+        });
+        let data = await response.json();
+        let positions = data.data.positions;
+        let ethPriceUSD = data.data.bundle.ethPriceUSD
+
+        for (let i = 0; i < positions.length; i++) {
+            let position = positions[i];
+            let transformedPosition: Position = {
+                id: position.id,
+                liquidity: BigInt(position.liquidity),
+                owner: position.owner,
+                pool: {
+                    sqrtPrice: BigInt(position.pool.sqrtPrice),
+                    tick: Number(position.pool.tick),
+                    id: position.pool.id,
+                },
+                tickLower: {
+                    tickIdx: Number(position.tickLower.tickIdx),
+                },
+                tickUpper: {
+                    tickIdx: Number(position.tickUpper.tickIdx),
+                },
+                token0: {
+                    id: position.token0.id,
+                    decimals: position.token0.decimals,
+                    derivedUSD: Number(position.token0.derivedETH) * Number(ethPriceUSD),
+                    name: position.token0.name,
+                    symbol: position.token0.symbol,
+                },
+                token1: {
+                    id: position.token1.id,
+                    decimals: position.token1.decimals,
+                    derivedUSD: Number(position.token1.derivedETH) * Number(ethPriceUSD),
+                    name: position.token1.name,
+                    symbol: position.token1.symbol,
+                },
+            };
+            result.push(transformedPosition);
+
+        }
+        if (positions.length < 1000) {
+            fetchNext = false;
+        } else {
+            skip += 1000;
+        }
+    }
+    return result;
+}
+export const getTradeLiquidityForAddressByPoolAtBlock = async (
+    blockNumber: number,
+    address: string,
+    poolId: string,
+    chainId: CHAINS,
+    protocol: PROTOCOLS,
+    ammType: AMM_TYPES
+): Promise<any[]> => {
+    let subgraphUrl = SUBGRAPH_URLS[chainId][protocol][ammType];
+    let blockQuery = blockNumber !== 0 ? ` block: {number: ${blockNumber}}` : ``;
+    let whereQuery = address !== "" ? `where: {user: "${address.toLowerCase()}"}` : `where: {period: "user"}`;
+
+    ;
+    let skip = 0;
+    let fetchNext = true;
+    let result: any[] = [];
+    while (fetchNext) {
+        let query = `{
+            liquidities(${whereQuery} ${blockQuery} orderBy: createTimestamp, first:1000,skip:${skip}) {
+                user
+                asset
+                amountUsd
+                amount
+            },
+            _meta{
+                    block{
+                    number
+                }
+            }
+        }`;
+
+        // console.log(query)
+
+        let response = await fetch(subgraphUrl, {
+            method: "POST",
+            body: JSON.stringify({ query }),
+            headers: { "Content-Type": "application/json" },
+        });
+        let data = await response.json();
+        let liquidities = data.data.liquidities;
+
+        result = result.concat(liquidities)
+        if (liquidities.length < 1000) {
+            fetchNext = false;
+        } else {
+            skip += 1000;
+        }
+    }
+    return result;
+}
+
+export const getPositionAtBlock = async (
+    blockNumber: number,
+    positionId: number,
+    chainId: CHAINS,
+    protocol: PROTOCOLS,
+    ammType: AMM_TYPES
+): Promise<Position> => {
+    let subgraphUrl = SUBGRAPH_URLS[chainId][protocol][ammType];
+    let blockQuery = blockNumber !== 0 ? `, block: {number: ${blockNumber}}` : ``;
+    let query = `{
+        bundle( id: 1 ${blockQuery}){
+            ethPriceUSD
+        }
+        position(id: "${positionId}" ${blockQuery}) {
+            id
+            pool {
+                sqrtPrice
+                tick
+            }
+            tickLower{
+                tickIdx
+            }
+            tickUpper{
+                tickIdx
+            }
+            liquidity
+            token0 {
+                id
+                decimals
+                derivedETH
+                name
+                symbol
+            }
+            token1 {
+                id
+                decimals
+                derivedETH
+                name
+                symbol
+            }
+        },
+        _meta{
+                block{
+                number
+            }
+        }
+    }`;
+    let response = await fetch(subgraphUrl, {
+        method: "POST",
+        body: JSON.stringify({ query }),
+        headers: { "Content-Type": "application/json" },
+    });
+    let data = await response.json();
+    let position = data.data.position;
+    const ethPriceUSD = data.data.bundle.ethPriceUSD
+
+    return {
+        id: position.id,
+        liquidity: BigInt(position.liquidity),
+        owner: position.owner,
+        pool: {
+            sqrtPrice: BigInt(position.pool.sqrtPrice),
+            tick: Number(position.pool.tick),
+            id: position.pool.id,
+        },
+        tickLower: {
+            tickIdx: Number(position.tickLower.tickIdx),
+        },
+        tickUpper: {
+            tickIdx: Number(position.tickUpper.tickIdx),
+        },
+        token0: {
+            id: position.token0.id,
+            decimals: position.token0.decimals,
+            derivedUSD: Number(position.token0.derivedETH) * Number(ethPriceUSD),
+            name: position.token0.name,
+            symbol: position.token0.symbol,
+        },
+        token1: {
+            id: position.token1.id,
+            decimals: position.token1.decimals,
+            derivedUSD: Number(position.token1.derivedETH) * Number(ethPriceUSD),
+            name: position.token1.name,
+            symbol: position.token1.symbol,
+        },
+    };
+
+    // let tickLow = Number(position.tickLower.tickIdx);
+    // let tickHigh = Number(position.tickUpper.tickIdx);
+    // let liquidity = BigInt(position.liquidity);
+    // let sqrtPriceX96 = BigInt(position.pool.sqrtPrice);
+    // let tick = Number(position.pool.tick);
+    // let decimal0 = position.token0.decimals;
+    // let decimal1 = position.token1.decimals;
+    // let token0DerivedUSD = position.token0.derivedUSD;
+    // let token1DerivedUSD = position.token1.derivedUSD;
+    // let token0AmountsInWei = PositionMath.getToken0Amount(tick, tickLow, tickHigh, sqrtPriceX96, liquidity);
+    // let token1AmountsInWei = PositionMath.getToken1Amount(tick, tickLow, tickHigh, sqrtPriceX96, liquidity);
+
+
+    // let token0DecimalValue = Number(token0AmountsInWei) / 10 ** decimal0;
+    // let token1DecimalValue = Number(token1AmountsInWei) / 10 ** decimal1;
+
+    // let token0UsdValue = BigNumber(token0AmountsInWei.toString()).multipliedBy(token0DerivedUSD).div(10 ** decimal0).toFixed(4);
+    // let token1UsdValue = BigNumber(token1AmountsInWei.toString()).multipliedBy(token1DerivedUSD).div(10 ** decimal1).toFixed(4);
+
+
+    // return [position.token0, position.token1,token0AmountsInWei, token1AmountsInWei, token0DecimalValue, token1DecimalValue,token0UsdValue, token1UsdValue,data.data._meta];
+}
+
+export const getPositionDetailsFromPosition = (
+    position: Position
+): PositionWithUSDValue => {
+    let tickLow = position.tickLower.tickIdx;
+    let tickHigh = position.tickUpper.tickIdx;
+    let liquidity = position.liquidity;
+    let sqrtPriceX96 = position.pool.sqrtPrice;
+    let tick = Number(position.pool.tick);
+    let decimal0 = position.token0.decimals;
+    let decimal1 = position.token1.decimals;
+    let token0DerivedUSD = position.token0.derivedUSD;
+    let token1DerivedUSD = position.token1.derivedUSD;
+    let token0AmountsInWei = PositionMath.getToken0Amount(tick, tickLow, tickHigh, sqrtPriceX96, liquidity);
+    let token1AmountsInWei = PositionMath.getToken1Amount(tick, tickLow, tickHigh, sqrtPriceX96, liquidity);
+
+    let token0DecimalValue = Number(token0AmountsInWei) / 10 ** decimal0;
+    let token1DecimalValue = Number(token1AmountsInWei) / 10 ** decimal1;
+
+    let token0UsdValue = BigNumber(token0AmountsInWei.toString()).multipliedBy(token0DerivedUSD).div(10 ** decimal0).toFixed(4);
+    let token1UsdValue = BigNumber(token1AmountsInWei.toString()).multipliedBy(token1DerivedUSD).div(10 ** decimal1).toFixed(4);
+
+
+    return { ...position, token0USDValue: token0UsdValue, token1USDValue: token1UsdValue, token0AmountsInWei, token1AmountsInWei, token0DecimalValue, token1DecimalValue };
+
+}
+
+export const getLPValueByUserAndPoolFromPositions = (
+    positions: Position[]
+): Map<string, Map<string, BigNumber>> => {
+    let result = new Map<string, Map<string, BigNumber>>();
+    for (let i = 0; i < positions.length; i++) {
+        let position = positions[i];
+        let poolId = position.pool.id;
+        let owner = position.owner;
+        let userPositions = result.get(owner);
+        if (userPositions === undefined) {
+            userPositions = new Map<string, BigNumber>();
+            result.set(owner, userPositions);
+        }
+        let poolPositions = userPositions.get(poolId);
+        if (poolPositions === undefined) {
+            poolPositions = BigNumber(0);
+        }
+        let positionWithUSDValue = getPositionDetailsFromPosition(position);
+        poolPositions = poolPositions.plus(BigNumber(positionWithUSDValue.token0USDValue).plus(positionWithUSDValue.token1USDValue));
+        userPositions.set(poolId, poolPositions);
+    }
+    return result;
+}
+
+export const getTimestampAtBlock = async (blockNumber: number) => {
+    const publicClient = createPublicClient({
+        chain: extractChain({ chains: [linea], id: CHAINS.L2_CHAIN_ID }),
+        transport: http(RPC_URLS[CHAINS.L2_CHAIN_ID]),
+    });
+
+    const block = await publicClient.getBlock({
+        blockNumber: BigInt(blockNumber),
+    });
+    return Number(block.timestamp * 1000n);
+};
diff --git a/adapters/metavault/src/sdk/utils/constant.ts b/adapters/metavault/src/sdk/utils/constant.ts
new file mode 100644
index 00000000..375569d6
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/constant.ts
@@ -0,0 +1,38 @@
+// exports for external consumption
+export type BigintIsh = bigint | number | string
+
+export enum TradeType {
+  EXACT_INPUT,
+  EXACT_OUTPUT,
+}
+
+export enum Rounding {
+  ROUND_DOWN,
+  ROUND_HALF_UP,
+  ROUND_UP,
+}
+
+export const MINIMUM_LIQUIDITY = 1000n
+
+// exports for internal consumption
+export const ZERO = 0n
+export const ONE = 1n
+export const TWO = 2n
+export const THREE = 3n
+export const FIVE = 5n
+export const TEN = 10n
+export const _100 = 100n
+export const _9975 = 9975n
+export const _10000 = 10000n
+
+export const MaxUint256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
+
+export enum VMType {
+  uint8 = 'uint8',
+  uint256 = 'uint256',
+}
+
+export const VM_TYPE_MAXIMA = {
+  [VMType.uint8]: BigInt('0xff'),
+  [VMType.uint256]: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
+}
diff --git a/adapters/metavault/src/sdk/utils/fractions/fraction.ts b/adapters/metavault/src/sdk/utils/fractions/fraction.ts
new file mode 100644
index 00000000..3970dd43
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/fractions/fraction.ts
@@ -0,0 +1,159 @@
+import invariant from 'tiny-invariant'
+import _Decimal from 'decimal.js-light'
+import _Big from 'big.js'
+// @ts-ignore
+import toFormat from 'toformat'
+
+import { BigintIsh, Rounding } from '../constant'
+
+const Decimal = toFormat(_Decimal)
+const Big = toFormat(_Big)
+
+const toSignificantRounding = {
+  [Rounding.ROUND_DOWN]: Decimal.ROUND_DOWN,
+  [Rounding.ROUND_HALF_UP]: Decimal.ROUND_HALF_UP,
+  [Rounding.ROUND_UP]: Decimal.ROUND_UP,
+}
+
+const enum RoundingL2_CHAIN_ID {
+  /**
+   * Rounds towards zero.
+   * I.e. truncate, no rounding.
+   */
+  RoundDown = 0,
+  /**
+   * Rounds towards nearest neighbour.
+   * If equidistant, rounds away from zero.
+   */
+  RoundHalfUp = 1,
+  /**
+   * Rounds towards nearest neighbour.
+   * If equidistant, rounds towards even neighbour.
+   */
+  RoundHalfEven = 2,
+  /**
+   * Rounds away from zero.
+   */
+  RoundUp = 3,
+}
+
+const toFixedRounding = {
+  [Rounding.ROUND_DOWN]: RoundingL2_CHAIN_ID.RoundDown,
+  [Rounding.ROUND_HALF_UP]: RoundingL2_CHAIN_ID.RoundHalfUp,
+  [Rounding.ROUND_UP]: RoundingL2_CHAIN_ID.RoundUp,
+}
+
+export class Fraction {
+  public readonly numerator: bigint
+
+  public readonly denominator: bigint
+
+  public constructor(numerator: BigintIsh, denominator: BigintIsh = 1n) {
+    this.numerator = BigInt(numerator)
+    this.denominator = BigInt(denominator)
+  }
+
+  private static tryParseFraction(fractionish: BigintIsh | Fraction): Fraction {
+    if (typeof fractionish === 'bigint' || typeof fractionish === 'number' || typeof fractionish === 'string')
+      return new Fraction(fractionish)
+
+    if ('numerator' in fractionish && 'denominator' in fractionish) return fractionish
+    throw new Error('Could not parse fraction')
+  }
+
+  // performs floor division
+  public get quotient(): bigint {
+    return this.numerator / this.denominator
+  }
+
+  // remainder after floor division
+  public get remainder(): Fraction {
+    return new Fraction(this.numerator % this.denominator, this.denominator)
+  }
+
+  public invert(): Fraction {
+    return new Fraction(this.denominator, this.numerator)
+  }
+
+  public add(other: Fraction | BigintIsh): Fraction {
+    const otherParsed = Fraction.tryParseFraction(other)
+    if (this.denominator === otherParsed.denominator) {
+      return new Fraction(this.numerator + otherParsed.numerator, this.denominator)
+    }
+    return new Fraction(
+      this.numerator * otherParsed.denominator + otherParsed.numerator * this.denominator,
+      this.denominator * otherParsed.denominator
+    )
+  }
+
+  public subtract(other: Fraction | BigintIsh): Fraction {
+    const otherParsed = Fraction.tryParseFraction(other)
+    if (this.denominator === otherParsed.denominator) {
+      return new Fraction(this.numerator - otherParsed.numerator, this.denominator)
+    }
+    return new Fraction(
+      this.numerator * otherParsed.denominator - otherParsed.numerator * this.denominator,
+      this.denominator * otherParsed.denominator
+    )
+  }
+
+  public lessThan(other: Fraction | BigintIsh): boolean {
+    const otherParsed = Fraction.tryParseFraction(other)
+    return this.numerator * otherParsed.denominator < otherParsed.numerator * this.denominator
+  }
+
+  public equalTo(other: Fraction | BigintIsh): boolean {
+    const otherParsed = Fraction.tryParseFraction(other)
+    return this.numerator * otherParsed.denominator === otherParsed.numerator * this.denominator
+  }
+
+  public greaterThan(other: Fraction | BigintIsh): boolean {
+    const otherParsed = Fraction.tryParseFraction(other)
+    return this.numerator * otherParsed.denominator > otherParsed.numerator * this.denominator
+  }
+
+  public multiply(other: Fraction | BigintIsh): Fraction {
+    const otherParsed = Fraction.tryParseFraction(other)
+    return new Fraction(this.numerator * otherParsed.numerator, this.denominator * otherParsed.denominator)
+  }
+
+  public divide(other: Fraction | BigintIsh): Fraction {
+    const otherParsed = Fraction.tryParseFraction(other)
+    return new Fraction(this.numerator * otherParsed.denominator, this.denominator * otherParsed.numerator)
+  }
+
+  public toSignificant(
+    significantDigits: number,
+    format: object = { groupSeparator: '' },
+    rounding: Rounding = Rounding.ROUND_HALF_UP
+  ): string {
+    invariant(Number.isInteger(significantDigits), `${significantDigits} is not an integer.`)
+    invariant(significantDigits > 0, `${significantDigits} is not positive.`)
+
+    Decimal.set({ precision: significantDigits + 1, rounding: toSignificantRounding[rounding] })
+    const quotient = new Decimal(this.numerator.toString())
+      .div(this.denominator.toString())
+      .toSignificantDigits(significantDigits)
+    return quotient.toFormat(quotient.decimalPlaces(), format)
+  }
+
+  public toFixed(
+    decimalPlaces: number,
+    format: object = { groupSeparator: '' },
+    rounding: Rounding = Rounding.ROUND_HALF_UP
+  ): string {
+    invariant(Number.isInteger(decimalPlaces), `${decimalPlaces} is not an integer.`)
+    invariant(decimalPlaces >= 0, `${decimalPlaces} is negative.`)
+
+    Big.DP = decimalPlaces
+    Big.RM = toFixedRounding[rounding]
+    return new Big(this.numerator.toString()).div(this.denominator.toString()).toFormat(decimalPlaces, format)
+  }
+
+  /**
+   * Helper method for converting any super class back to a fraction
+   */
+  public get asFraction(): Fraction {
+    return new Fraction(this.numerator, this.denominator)
+  }
+}
diff --git a/adapters/metavault/src/sdk/utils/fractions/percent.ts b/adapters/metavault/src/sdk/utils/fractions/percent.ts
new file mode 100644
index 00000000..5fcb5d72
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/fractions/percent.ts
@@ -0,0 +1,43 @@
+import { BigintIsh, Rounding } from '../constant'
+import { Fraction } from './fraction'
+
+const ONE_HUNDRED = new Fraction(100n)
+
+/**
+ * Converts a fraction to a percent
+ * @param fraction the fraction to convert
+ */
+function toPercent(fraction: Fraction): Percent {
+  return new Percent(fraction.numerator, fraction.denominator)
+}
+
+export class Percent extends Fraction {
+  /**
+   * This boolean prevents a fraction from being interpreted as a Percent
+   */
+  public readonly isPercent = true as const
+
+  add(other: Fraction | BigintIsh): Percent {
+    return toPercent(super.add(other))
+  }
+
+  subtract(other: Fraction | BigintIsh): Percent {
+    return toPercent(super.subtract(other))
+  }
+
+  multiply(other: Fraction | BigintIsh): Percent {
+    return toPercent(super.multiply(other))
+  }
+
+  divide(other: Fraction | BigintIsh): Percent {
+    return toPercent(super.divide(other))
+  }
+
+  public toSignificant(significantDigits = 5, format?: object, rounding?: Rounding): string {
+    return super.multiply(ONE_HUNDRED).toSignificant(significantDigits, format, rounding)
+  }
+
+  public toFixed(decimalPlaces = 2, format?: object, rounding?: Rounding): string {
+    return super.multiply(ONE_HUNDRED).toFixed(decimalPlaces, format, rounding)
+  }
+}
diff --git a/adapters/metavault/src/sdk/utils/fullMath.ts b/adapters/metavault/src/sdk/utils/fullMath.ts
new file mode 100644
index 00000000..fe84c76b
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/fullMath.ts
@@ -0,0 +1,16 @@
+import { ONE, ZERO } from "./internalConstants"
+
+export abstract class FullMath {
+  /**
+   * Cannot be constructed.
+   */
+  private constructor() {}
+
+  public static mulDivRoundingUp(a: bigint, b: bigint, denominator: bigint): bigint {
+    const product = a * b
+    let result = product / denominator
+    // eslint-disable-next-line operator-assignment
+    if (product % denominator !== ZERO) result = result + ONE
+    return result
+  }
+}
diff --git a/adapters/metavault/src/sdk/utils/internalConstants.ts b/adapters/metavault/src/sdk/utils/internalConstants.ts
new file mode 100644
index 00000000..a9fc9a73
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/internalConstants.ts
@@ -0,0 +1,16 @@
+import { Percent } from "./fractions/percent"
+
+// constants used internally but not expected to be used externally
+export const NEGATIVE_ONE = BigInt(-1)
+export const ZERO = 0n
+export const ONE = 1n
+
+// used in liquidity amount math
+export const Q96 = 2n ** 96n
+export const Q192 = Q96 ** 2n
+
+// used in fee calculation
+export const MAX_FEE = 10n ** 6n
+export const ONE_HUNDRED_PERCENT = new Percent('1')
+export const ZERO_PERCENT = new Percent('0')
+export const Q128 = 2n ** 128n
diff --git a/adapters/metavault/src/sdk/utils/mostSignificantBit.ts b/adapters/metavault/src/sdk/utils/mostSignificantBit.ts
new file mode 100644
index 00000000..c1cb4c31
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/mostSignificantBit.ts
@@ -0,0 +1,20 @@
+import invariant from 'tiny-invariant'
+import { MaxUint256, ZERO } from './constant'
+
+const TWO = 2n
+const POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow: number): [number, bigint] => [pow, TWO ** BigInt(pow)])
+
+export function mostSignificantBit(x: bigint): number {
+  invariant(x > ZERO, 'ZERO')
+  invariant(x <= MaxUint256, 'MAX')
+
+  let msb = 0
+  for (const [power, min] of POWERS_OF_2) {
+    if (x >= min) {
+      // eslint-disable-next-line operator-assignment
+      x = x >> BigInt(power)
+      msb += power
+    }
+  }
+  return msb
+}
diff --git a/adapters/metavault/src/sdk/utils/positionMath.ts b/adapters/metavault/src/sdk/utils/positionMath.ts
new file mode 100644
index 00000000..d20f2b90
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/positionMath.ts
@@ -0,0 +1,50 @@
+import { ZERO } from "./constant"
+import { SqrtPriceMath } from "./squarePriceMath"
+import { TickMath } from "./tickMath"
+
+function getToken0Amount(
+    tickCurrent: number,
+  tickLower: number,
+  tickUpper: number,
+  sqrtRatioX96: bigint,
+  liquidity: bigint
+): bigint {
+  if (tickCurrent < tickLower) {
+    return SqrtPriceMath.getAmount0Delta(
+      TickMath.getSqrtRatioAtTick(tickLower),
+      TickMath.getSqrtRatioAtTick(tickUpper),
+      liquidity,
+      false
+    )
+  }
+  if (tickCurrent < tickUpper) {
+    return SqrtPriceMath.getAmount0Delta(sqrtRatioX96, TickMath.getSqrtRatioAtTick(tickUpper), liquidity, false)
+  }
+  return ZERO
+}
+
+function getToken1Amount(
+    tickCurrent: number,
+  tickLower: number,
+  tickUpper: number,
+  sqrtRatioX96: bigint,
+  liquidity: bigint
+): bigint {
+  if (tickCurrent < tickLower) {
+    return ZERO
+  }
+  if (tickCurrent < tickUpper) {
+    return SqrtPriceMath.getAmount1Delta(TickMath.getSqrtRatioAtTick(tickLower), sqrtRatioX96, liquidity, false)
+  }
+  return SqrtPriceMath.getAmount1Delta(
+    TickMath.getSqrtRatioAtTick(tickLower),
+    TickMath.getSqrtRatioAtTick(tickUpper),
+    liquidity,
+    false
+  )
+}
+
+export const PositionMath = {
+  getToken0Amount,
+  getToken1Amount,
+}
diff --git a/adapters/metavault/src/sdk/utils/squarePriceMath.ts b/adapters/metavault/src/sdk/utils/squarePriceMath.ts
new file mode 100644
index 00000000..02639c62
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/squarePriceMath.ts
@@ -0,0 +1,131 @@
+import invariant from "tiny-invariant"
+import { MaxUint256, ONE, ZERO } from "./constant"
+import { FullMath } from "./fullMath"
+import { Q96 } from "./internalConstants"
+
+const MaxUint160 = 2n ** 160n - ONE
+
+function multiplyIn256(x: bigint, y: bigint): bigint {
+  const product = x * y
+  return product & MaxUint256
+}
+
+function addIn256(x: bigint, y: bigint): bigint {
+  const sum = x + y
+  return sum & MaxUint256
+}
+
+export abstract class SqrtPriceMath {
+  /**
+   * Cannot be constructed.
+   */
+  private constructor() {}
+
+  public static getAmount0Delta(
+    sqrtRatioAX96: bigint,
+    sqrtRatioBX96: bigint,
+    liquidity: bigint,
+    roundUp: boolean
+  ): bigint {
+    if (sqrtRatioAX96 > sqrtRatioBX96) {
+      sqrtRatioAX96 = sqrtRatioBX96
+      sqrtRatioBX96 = sqrtRatioAX96
+    }
+
+    const numerator1 = liquidity << 96n
+    const numerator2 = sqrtRatioBX96 - sqrtRatioAX96
+
+    return roundUp
+      ? FullMath.mulDivRoundingUp(FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), ONE, sqrtRatioAX96)
+      : (numerator1 * numerator2) / sqrtRatioBX96 / sqrtRatioAX96
+  }
+
+  public static getAmount1Delta(
+    sqrtRatioAX96: bigint,
+    sqrtRatioBX96: bigint,
+    liquidity: bigint,
+    roundUp: boolean
+  ): bigint {
+    if (sqrtRatioAX96 > sqrtRatioBX96) {
+      sqrtRatioAX96 = sqrtRatioBX96
+      sqrtRatioBX96 = sqrtRatioAX96
+    }
+
+    return roundUp
+      ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96)
+      : (liquidity * (sqrtRatioBX96 - sqrtRatioAX96)) / Q96
+  }
+
+  public static getNextSqrtPriceFromInput(
+    sqrtPX96: bigint,
+    liquidity: bigint,
+    amountIn: bigint,
+    zeroForOne: boolean
+  ): bigint {
+    invariant(sqrtPX96 > ZERO)
+    invariant(liquidity > ZERO)
+
+    return zeroForOne
+      ? this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
+      : this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true)
+  }
+
+  public static getNextSqrtPriceFromOutput(
+    sqrtPX96: bigint,
+    liquidity: bigint,
+    amountOut: bigint,
+    zeroForOne: boolean
+  ): bigint {
+    invariant(sqrtPX96 > ZERO)
+    invariant(liquidity > ZERO)
+
+    return zeroForOne
+      ? this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
+      : this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false)
+  }
+
+  private static getNextSqrtPriceFromAmount0RoundingUp(
+    sqrtPX96: bigint,
+    liquidity: bigint,
+    amount: bigint,
+    add: boolean
+  ): bigint {
+    if (amount === ZERO) return sqrtPX96
+    const numerator1 = liquidity << 96n
+
+    if (add) {
+      const product = multiplyIn256(amount, sqrtPX96)
+      if (product / amount === sqrtPX96) {
+        const denominator = addIn256(numerator1, product)
+        if (denominator >= numerator1) {
+          return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator)
+        }
+      }
+
+      return FullMath.mulDivRoundingUp(numerator1, ONE, numerator1 / sqrtPX96 + amount)
+    }
+    const product = multiplyIn256(amount, sqrtPX96)
+
+    invariant(product / amount === sqrtPX96)
+    invariant(numerator1 > product)
+    const denominator = numerator1 - product
+    return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator)
+  }
+
+  private static getNextSqrtPriceFromAmount1RoundingDown(
+    sqrtPX96: bigint,
+    liquidity: bigint,
+    amount: bigint,
+    add: boolean
+  ): bigint {
+    if (add) {
+      const quotient = amount <= MaxUint160 ? (amount << 96n) / liquidity : (amount * Q96) / liquidity
+
+      return sqrtPX96 + quotient
+    }
+    const quotient = FullMath.mulDivRoundingUp(amount, Q96, liquidity)
+
+    invariant(sqrtPX96 > quotient)
+    return sqrtPX96 - quotient
+  }
+}
diff --git a/adapters/metavault/src/sdk/utils/tickLibrary.ts b/adapters/metavault/src/sdk/utils/tickLibrary.ts
new file mode 100644
index 00000000..7d59c95e
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/tickLibrary.ts
@@ -0,0 +1,59 @@
+import { ZERO } from "./internalConstants"
+
+interface FeeGrowthOutside {
+  feeGrowthOutside0X128: bigint
+  feeGrowthOutside1X128: bigint
+}
+
+const Q256 = 2n ** 256n
+
+export function subIn256(x: bigint, y: bigint): bigint {
+  const difference = x - y
+
+  if (difference < ZERO) {
+    return Q256 + difference
+  }
+  return difference
+}
+
+export abstract class TickLibrary {
+  /**
+   * Cannot be constructed.
+   */
+  private constructor() {}
+
+  public static getFeeGrowthInside(
+    feeGrowthOutsideLower: FeeGrowthOutside,
+    feeGrowthOutsideUpper: FeeGrowthOutside,
+    tickLower: number,
+    tickUpper: number,
+    tickCurrent: number,
+    feeGrowthGlobal0X128: bigint,
+    feeGrowthGlobal1X128: bigint
+  ) {
+    let feeGrowthBelow0X128: bigint
+    let feeGrowthBelow1X128: bigint
+    if (tickCurrent >= tickLower) {
+      feeGrowthBelow0X128 = feeGrowthOutsideLower.feeGrowthOutside0X128
+      feeGrowthBelow1X128 = feeGrowthOutsideLower.feeGrowthOutside1X128
+    } else {
+      feeGrowthBelow0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideLower.feeGrowthOutside0X128)
+      feeGrowthBelow1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideLower.feeGrowthOutside1X128)
+    }
+
+    let feeGrowthAbove0X128: bigint
+    let feeGrowthAbove1X128: bigint
+    if (tickCurrent < tickUpper) {
+      feeGrowthAbove0X128 = feeGrowthOutsideUpper.feeGrowthOutside0X128
+      feeGrowthAbove1X128 = feeGrowthOutsideUpper.feeGrowthOutside1X128
+    } else {
+      feeGrowthAbove0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideUpper.feeGrowthOutside0X128)
+      feeGrowthAbove1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideUpper.feeGrowthOutside1X128)
+    }
+
+    return [
+      subIn256(subIn256(feeGrowthGlobal0X128, feeGrowthBelow0X128), feeGrowthAbove0X128),
+      subIn256(subIn256(feeGrowthGlobal1X128, feeGrowthBelow1X128), feeGrowthAbove1X128),
+    ]
+  }
+}
diff --git a/adapters/metavault/src/sdk/utils/tickMath.ts b/adapters/metavault/src/sdk/utils/tickMath.ts
new file mode 100644
index 00000000..18a01d96
--- /dev/null
+++ b/adapters/metavault/src/sdk/utils/tickMath.ts
@@ -0,0 +1,115 @@
+import invariant from "tiny-invariant"
+import { MaxUint256, ONE, ZERO } from "./constant"
+import { mostSignificantBit } from "./mostSignificantBit"
+
+
+function mulShift(val: bigint, mulBy: string): bigint {
+  return (val * BigInt(mulBy)) >> 128n
+}
+
+const Q32 = 2n ** 32n
+
+export abstract class TickMath {
+  /**
+   * Cannot be constructed.
+   */
+  private constructor() {}
+
+  /**
+   * The minimum tick that can be used on any pool.
+   */
+  // eslint-disable-next-line @typescript-eslint/no-inferrable-types
+  public static MIN_TICK: number = -887272
+
+  /**
+   * The maximum tick that can be used on any pool.
+   */
+  public static MAX_TICK: number = -TickMath.MIN_TICK
+
+  /**
+   * The sqrt ratio corresponding to the minimum tick that could be used on any pool.
+   */
+  public static MIN_SQRT_RATIO = 4295128739n
+
+  /**
+   * The sqrt ratio corresponding to the maximum tick that could be used on any pool.
+   */
+  public static MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342n
+
+  /**
+   * Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick
+   * @param tick the tick for which to compute the sqrt ratio
+   */
+  public static getSqrtRatioAtTick(tick: number): bigint {
+
+    invariant(tick >= TickMath.MIN_TICK && tick <= TickMath.MAX_TICK && Number.isInteger(tick), 'TICK')
+    const absTick: number = tick < 0 ? tick * -1 : tick
+
+    let ratio: bigint =
+      (absTick & 0x1) != 0
+        ? BigInt('0xfffcb933bd6fad37aa2d162d1a594001')
+        : BigInt('0x100000000000000000000000000000000')
+    if ((absTick & 0x2) != 0) ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a')
+    if ((absTick & 0x4) != 0) ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc')
+    if ((absTick & 0x8) != 0) ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0')
+    if ((absTick & 0x10) != 0) ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644')
+    if ((absTick & 0x20) != 0) ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0')
+    if ((absTick & 0x40) != 0) ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861')
+    if ((absTick & 0x80) != 0) ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053')
+    if ((absTick & 0x100) != 0) ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4')
+    if ((absTick & 0x200) != 0) ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54')
+    if ((absTick & 0x400) != 0) ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3')
+    if ((absTick & 0x800) != 0) ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9')
+    if ((absTick & 0x1000) != 0) ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825')
+    if ((absTick & 0x2000) != 0) ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5')
+    if ((absTick & 0x4000) != 0) ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7')
+    if ((absTick & 0x8000) != 0) ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6')
+    if ((absTick & 0x10000) != 0) ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9')
+    if ((absTick & 0x20000) != 0) ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604')
+    if ((absTick & 0x40000) != 0) ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98')
+    if ((absTick & 0x80000) != 0) ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2')
+
+    if (tick > 0) ratio = MaxUint256 / ratio
+
+    // back to Q96
+    return ratio % Q32 > ZERO ? ratio / Q32 + ONE : ratio / Q32
+  }
+
+  /**
+   * Returns the tick corresponding to a given sqrt ratio, s.t. #getSqrtRatioAtTick(tick) <= sqrtRatioX96
+   * and #getSqrtRatioAtTick(tick + 1) > sqrtRatioX96
+   * @param sqrtRatioX96 the sqrt ratio as a Q64.96 for which to compute the tick
+   */
+  public static getTickAtSqrtRatio(sqrtRatioX96: bigint): number {
+    invariant(sqrtRatioX96 >= TickMath.MIN_SQRT_RATIO && sqrtRatioX96 < TickMath.MAX_SQRT_RATIO, 'SQRT_RATIO')
+
+    const sqrtRatioX128 = sqrtRatioX96 << 32n
+
+    const msb = mostSignificantBit(sqrtRatioX128)
+
+    let r: bigint
+    if (BigInt(msb) >= 128n) {
+      r = sqrtRatioX128 >> BigInt(msb - 127)
+    } else {
+      r = sqrtRatioX128 << BigInt(127 - msb)
+    }
+
+    let log_2: bigint = (BigInt(msb) - 128n) << 64n
+
+    for (let i = 0; i < 14; i++) {
+      r = (r * r) >> 127n
+      const f = r >> 128n
+      // eslint-disable-next-line operator-assignment
+      log_2 = log_2 | (f << BigInt(63 - i))
+      // eslint-disable-next-line operator-assignment
+      r = r >> f
+    }
+
+    const log_sqrt10001 = log_2 * 255738958999603826347141n
+
+    const tickLow = Number((log_sqrt10001 - 3402992956809132418596140100660247210n) >> 128n)
+    const tickHigh = Number((log_sqrt10001 + 291339464771989622907027621153398088495n) >> 128n)
+
+    return tickLow === tickHigh ? tickLow : TickMath.getSqrtRatioAtTick(tickHigh) <= sqrtRatioX96 ? tickHigh : tickLow
+  }
+}
diff --git a/adapters/metavault/tsconfig.json b/adapters/metavault/tsconfig.json
new file mode 100644
index 00000000..9852ff27
--- /dev/null
+++ b/adapters/metavault/tsconfig.json
@@ -0,0 +1,109 @@
+{
+  "compilerOptions": {
+    /* Visit https://aka.ms/tsconfig to read more about this file */
+
+    /* Projects */
+    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
+    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
+    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+
+    /* Language and Environment */
+    "target": "es2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
+    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
+    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
+    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
+
+    /* Modules */
+    "module": "commonjs" /* Specify what module code is generated. */,
+    "rootDir": "src/" /* Specify the root folder within your source files. */,
+    // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
+    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
+    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
+    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
+    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
+    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
+    // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
+    // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */
+    // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */
+    // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
+    "resolveJsonModule": true /* Enable importing .json files. */,
+    // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */
+    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
+
+    /* JavaScript Support */
+    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
+    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+    /* Emit */
+    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
+    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+    "outDir": "dist/" /* Specify an output folder for all emitted files. */,
+    // "removeComments": true,                           /* Disable emitting comments. */
+    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
+    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */
+    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
+    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
+    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
+    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+    /* Interop Constraints */
+    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+    // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
+    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
+    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
+
+    /* Type Checking */
+    "strict": true /* Enable all strict type-checking options. */,
+    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
+    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
+    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
+    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
+    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
+    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
+    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
+    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
+    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
+    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+
+    /* Completeness */
+    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+    "skipLibCheck": true /* Skip type checking all .d.ts files. */
+  }
+}