Last active
October 28, 2025 19:59
-
-
Save 0xhammadali/375ba0fc2aef890377872f0ddae6f9de to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 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