Skip to content

Instantly share code, notes, and snippets.

@phijfry
Created May 28, 2024 12:20
Show Gist options
  • Save phijfry/649e17a3f90ee2b4d18d20133e6e9335 to your computer and use it in GitHub Desktop.
Save phijfry/649e17a3f90ee2b4d18d20133e6e9335 to your computer and use it in GitHub Desktop.
Get Position Amounts
import { ethers, JsonRpcProvider } from "ethers";
const JSON_RPC = new JsonRpcProvider(process.env.NODE_URL);
const MIN_TICK = -887272;
const MAX_TICK = 887272;
const Q96 = BigInt(1) << BigInt(96); // Represents 1 << 96
const HYPERLOCK_DEPOSIT_CONTRACT = "0xc28EffdfEF75448243c1d9bA972b97e32dF60d06";
const NFP_MANAGER = "0x434575EaEa081b735C985FA9bf63CD7b87e227F9";
const iface = new ethers.Interface(["event Deposit(address pool, address sender, uint256 tokenId)"]);
const fragment = iface.getEvent("Deposit");
const SLOT0_FUNC =
"function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)";
const POSITIONS_FUNC =
"function positions(uint256 tokenId) external view override returns (uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1)";
const nfpManager = new ethers.Contract(NFP_MANAGER, [POSITIONS_FUNC], JSON_RPC);
/** --------------------------------------------------------
*
* Liquidity Helper
* Can also use the Uniswap SDK new Position() class then position.amount0
*
* -------------------------------------------------------- */
const sorted = (arr) => {
return arr.sort((a, b) => {
return a > b ? 1 : a < b ? -1 : 0;
});
};
function liquidityToAmounts(liquidity, tickLower, tickUpper, tickCurrent) {
let tick_lower = Math.max(MIN_TICK, tickLower);
let tick_upper = Math.min(MAX_TICK, tickUpper);
let tick_current = Math.min(MAX_TICK, Math.max(MIN_TICK, tickCurrent));
let sqrt_price_low96 = toSqrtPrice(BigInt(tick_lower));
let sqrt_price_upper96 = toSqrtPrice(BigInt(tick_upper));
let sqrt_price_current96 = toSqrtPrice(BigInt(tick_current));
if (tick_current < tick_lower) {
let amount0 = toAmount0(liquidity, sqrt_price_low96, sqrt_price_upper96);
return [amount0, BigInt(0)];
} else if (tick_current >= tick_upper) {
let amount1 = toAmount1(liquidity, sqrt_price_low96, sqrt_price_upper96);
return [BigInt(0), amount1];
} else {
let amount0 = toAmount0(liquidity, sqrt_price_current96, sqrt_price_upper96);
let amount1 = toAmount1(liquidity, sqrt_price_low96, sqrt_price_current96);
return [amount0, amount1];
}
}
function toAmount0(liquidity, sqrt_price_a96, sqrt_price_b96) {
[sqrt_price_a96, sqrt_price_b96] = sorted([sqrt_price_a96, sqrt_price_b96]);
return (liquidity * Q96 * (sqrt_price_b96 - sqrt_price_a96)) / (sqrt_price_b96 * sqrt_price_a96);
}
function toAmount1(liquidity, sqrt_price_a96, sqrt_price_b96) {
[sqrt_price_a96, sqrt_price_b96] = sorted([sqrt_price_a96, sqrt_price_b96]);
return (liquidity * (sqrt_price_b96 - sqrt_price_a96)) / Q96;
}
function toSqrtPrice(tick) {
return BigInt(Math.trunc(1.0001 ** (Number(tick) / 2) * Number(Q96)));
}
/** --------------------------------------------------------
*
* MAIN
*
* -------------------------------------------------------- */
async function main() {
const logs = await JSON_RPC.getLogs({
address: HYPERLOCK_DEPOSIT_CONTRACT,
topics: [fragment?.topicHash],
fromBlock: 4000000,
toBlock: 4010000,
});
for (const log of logs) {
const { args } = iface.parseLog(log);
const [poolAddress, , tokenId] = args;
const [, , , , , tickLower, tickUpper, liquidity, , , ,] = await nfpManager.positions(tokenId);
const pool = new ethers.Contract(poolAddress, [SLOT0_FUNC], JSON_RPC);
const [, poolTick] = await pool.slot0();
const [amount0, amount1] = liquidityToAmounts(
liquidity,
Number(tickLower),
Number(tickUpper),
Number(poolTick)
);
console.log(poolAddress, amount0, amount1, tokenId);
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment