Skip to content

Instantly share code, notes, and snippets.

@0xhammadali
Last active October 28, 2025 19:59
Show Gist options
  • Select an option

  • Save 0xhammadali/375ba0fc2aef890377872f0ddae6f9de to your computer and use it in GitHub Desktop.

Select an option

Save 0xhammadali/375ba0fc2aef890377872f0ddae6f9de to your computer and use it in GitHub Desktop.
const { Contract, ContractFactory, utils } = require("ethers")
const WETH9 = require("../artifacts/contracts/WETH9.sol/WETH9.json");
//Token
const {Token, CurrencyAmount} = require("@uniswap/sdk-core");
const { Pool, Position, nearestUsableTick } = require("@uniswap/v3-sdk");
const bn = require("bignumber.js");
const JSBI = require('jsbi');
bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 });
const artifacts = {
UniswapV3Factory: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"),
SwapRouter: require("@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"),
NFTDescriptor: require("@uniswap/v3-periphery/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json"),
NonfungibleTokenPositionDescriptor: require("@uniswap/v3-periphery/artifacts/contracts/NonfungibleTokenPositionDescriptor.sol/NonfungibleTokenPositionDescriptor.json"),
NonfungiblePositionManager: require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"),
WETH9,
UniswapV3Pool: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"),
ERC20: require("@openzeppelin/contracts/build/contracts/ERC20.json"),
};
const KoryntiaYieldVaultV3Import = require("../KoryntiaYieldVaultV3_ABI/KoryntiaYieldVaultV3.json");
const KoryntiaYieldPriceOracleV3Import = require("../KoryntiaYieldVaultV3_ABI/KoryntiaYieldPriceOracleV3.json");
function linkLibraries(artifact, libraries) {
let { bytecode, linkReferences } = artifact;
for (const [fileName, fileReferences] of Object.entries(linkReferences)) {
for (const [libName, fixups] of Object.entries(fileReferences)) {
const address = libraries[libName];
if (!address) {
throw new Error(`Missing address for library ${libName}`);
}
// Remove 0x prefix
const addressHex = address.replace(/^0x/, "");
for (const fixup of fixups) {
const start = 2 + fixup.start * 2;
const length = fixup.length * 2;
bytecode =
bytecode.slice(0, start) +
addressHex +
bytecode.slice(start + length);
}
}
}
// ensure prefixed
if (!bytecode.startsWith("0x")) {
bytecode = "0x" + bytecode;
}
return bytecode;
}
function encodePriceSqrt(reserve1, reserve0) {
const Q96 = 2n ** 96n; // Uniswap Q96 factor
const ratio = (BigInt(reserve1) * Q96) / BigInt(reserve0); // multiply only once
return sqrtBigInt(ratio); // returns sqrtPriceX96
}
// Integer sqrt for BigInt
function sqrtBigInt(value) {
if (value < 2n) return value;
let x0 = value / 2n;
let x1 = (x0 + value / x0) / 2n;
while (x1 < x0) {
x0 = x1;
x1 = (x0 + value / x0) / 2n;
}
return x0;
}
async function getPoolData(poolContract) {
const [tickSpacing, fee, liquidity, slot0] = await Promise.all([
poolContract.tickSpacing(),
poolContract.fee(),
poolContract.liquidity(),
poolContract.slot0(),
])
return {
tickSpacing: tickSpacing,
fee: fee,
liquidity: liquidity.toString(),
sqrtPriceX96: slot0[0],
tick: slot0[1],
}
}
async function main() {
const [owner] = await ethers.getSigners();
const wethAddress = "0xe14b648606bE573f31937d2734C6C10cAdd57516";
const weth = new Contract(wethAddress, artifacts.WETH9.abi, owner);
const factoryAddress = "0x9EBDbA331d1E7C4Bd2aDa1bd0A156518d454a798";
const factory = new Contract(factoryAddress, artifacts.UniswapV3Factory.abi, owner);
const swapRouterAddress = "0xdE30101a2E5870927fa7BeDf048A268971Bd9014";
const swapRouter = new Contract(swapRouterAddress, artifacts.SwapRouter.abi, owner);
const nftDescriptorAddress = "0xa1f8797652C32FEd56C6d7Ac6b23499DBcacA08F";
const nftDescriptor = new Contract(nftDescriptorAddress, artifacts.NFTDescriptor.abi, owner);
const linkedBytecode = linkLibraries(
artifacts.NonfungibleTokenPositionDescriptor,
{ NFTDescriptor: nftDescriptor.target }
);
const nonfungibleTokenPositionDescriptorAddress = "0x6285F678D8799c89a3b59D6589787DeF01deeaA8";
const nonfungibleTokenPositionDescriptor = new Contract(nonfungibleTokenPositionDescriptorAddress, artifacts.NonfungibleTokenPositionDescriptor.abi, owner);
const nonfungiblePositionManagerAddress = "0x64E947214B8BBC4437d0d4Fa02B446e3DBc10540";
const nonfungiblePositionManager = new Contract(nonfungiblePositionManagerAddress, artifacts.NonfungiblePositionManager.abi, owner);
const FakeERC20 = await hre.ethers.getContractFactory("FakeERC20");
const WETHADDRESS = "0xae4b22C890E5ea53912DDf185761740930EAe19e";
const WETH = new Contract(WETHADDRESS, FakeERC20.interface, owner);
const WBTCADDRESS = "0x1D728DF7d0734117617f0C8c80f73f3B68e6920b";
const WBTC = new Contract(WBTCADDRESS, FakeERC20.interface, owner);
console.log("hi");
const fee = 500;
let token0 = WETH;
let token1 = WBTC;
// Sort tokens by address first
if (token0.target.toLowerCase() > token1.target.toLowerCase()) {
console.log("swapping tokens");
[token0, token1] = [token1, token0];
}
console.log("token0 address:", token0.target);
// Get decimals after sorting
const token0Decimals = await token0.decimals();
const token1Decimals = await token1.decimals();
console.log("token0Decimals:", token0Decimals);
console.log("token1Decimals:", token1Decimals);
// Calculate desired amounts
const amount0Desired = ethers.parseUnits("1", token0Decimals);
const amount1Desired = ethers.parseUnits("1", token1Decimals);
// Amounts already match sorted tokens
const sortedAmount0 = amount0Desired;
const sortedAmount1 = amount1Desired;
// Encode price for pool initialization
const price = encodePriceSqrt(
ethers.parseUnits("1", token1Decimals), // token1
ethers.parseUnits("1", token0Decimals) // token0
);
console.log("price", price);
const existingPool = await factory.getPool(token0.target, token1.target, fee);
console.log("existingPool:", existingPool);
const poolAddress = await factory.connect(owner).getPool(token0.target, token1.target, fee);
// const poolAddress="";
const poolContract = new Contract(poolAddress, artifacts.UniswapV3Pool.abi, owner);
// console.log("pool contract address:", poolContract.target);
const poolData = await getPoolData(poolContract);
// console.log("pool data:", poolData);
const tickNumber = Number(poolData.tick);
const tickSpacing = Number(poolData.tickSpacing);
const tickCurrent = nearestUsableTick(tickNumber, tickSpacing);
let tickLower = nearestUsableTick(tickCurrent - tickSpacing * 10, tickSpacing);
let tickUpper = nearestUsableTick(tickCurrent + tickSpacing * 10, tickSpacing);
const MIN_TICK = -887272;
const MAX_TICK = 887272;
// Clamp within min/max ticks
tickLower = Math.max(tickLower, MIN_TICK);
tickUpper = Math.min(tickUpper, MAX_TICK);
console.log("tickLower:", tickLower, "tickUpper:", tickUpper);
console.log("Pool current tick:", poolData.tick.toString());
// Approve position manager to spend both tokens
await token0.connect(owner).approve(nonfungiblePositionManager.target, sortedAmount0);
await token1.connect(owner).approve(nonfungiblePositionManager.target, sortedAmount1);
console.log("Approved position manager to spend tokens");
const mintParams = {
token0: token0.target,
token1: token1.target,
fee: poolData.fee,
tickLower,
tickUpper,
amount0Desired: sortedAmount0,
amount1Desired: sortedAmount1,
amount0Min: 0,
amount1Min: 0,
recipient: owner.address,
deadline: Math.floor(Date.now() / 1000) + 60 * 3600
};
console.log("Mint Parameters:", mintParams);
const tx = await nonfungiblePositionManager.connect(owner).mint(mintParams, { gasLimit: 8000000 });
const receipt = await tx.wait();
console.log("Position minted:", receipt.hash);
// Get the tokenId of the minted position
const events = receipt.logs.filter(
(log) => log.address === nonfungiblePositionManager.target
);
const mintEvent = nonfungiblePositionManager.interface.parseLog(events[events.length - 1]);
const tokenId = mintEvent.args.tokenId;
console.log("Minted token ID:", tokenId.toString());
//TODO: Bilal changes
const Oracle = new ContractFactory(KoryntiaYieldPriceOracleV3Import.abi, KoryntiaYieldPriceOracleV3Import.bytecode, owner);
const oracle = await Oracle.connect(owner).deploy();
console.log("oracle address", oracle.target);
// const oracleAddress="";
// const oracle = new Contract(oracleAddress, KoryntiaYieldPriceOracleV3Import.abi, owner);
const upatdatePriceFeed = await oracle.connect(owner).updatePrice(114564 * 10 ** 6);
console.log("price updated", upatdatePriceFeed.hash);
const KoryntiaYieldVaultV3 = new ContractFactory(KoryntiaYieldVaultV3Import.abi, KoryntiaYieldVaultV3Import.bytecode, owner);
const koryntiaYieldVaultV3 = await KoryntiaYieldVaultV3.connect(owner).deploy(
WBTC.target,
WETH.target,
swapRouter.target,
factory.target,
nonfungiblePositionManager.target,
oracle.target,
owner.address
);
console.log("KoryntiaYieldVaultV3 deployed at:", koryntiaYieldVaultV3.target);
//const koryntiaYieldVaultV3Address="";
//const koryntiaYieldVaultV3 = new Contract(koryntiaYieldVaultV3Address, KoryntiaYieldVaultV3Import.abi, owner);
//create pool
let createPoolTx = await koryntiaYieldVaultV3.connect(owner).initializePool();
let createPoolReceipt = await createPoolTx.wait();
console.log("create pool tx", createPoolReceipt.hash);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment