Created
August 1, 2024 07:38
-
-
Save elmariachi111/dc633daf6b5d6143d9570afe7fcb3c2b to your computer and use it in GitHub Desktop.
Provide UniV3 Liquidity between IPTs / ETH
This file contains 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
// SPDX-License-Identifier: BUSL-1.1 | |
pragma solidity ^0.8.0; | |
/// @title Creates and initializes V3 Pools | |
/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that | |
/// require the pool to exist. | |
interface IPoolInitializer { | |
/// @notice Creates a new pool if it does not exist, then initializes if not initialized | |
/// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool | |
/// @param token0 The contract address of token0 of the pool | |
/// @param token1 The contract address of token1 of the pool | |
/// @param fee The fee amount of the v3 pool for the specified token pair | |
/// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value | |
/// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary | |
function createAndInitializePoolIfNecessary( | |
address token0, | |
address token1, | |
uint24 fee, | |
uint160 sqrtPriceX96 | |
) external payable returns (address pool); | |
} | |
interface INonfungiblePositionManager is IPoolInitializer { | |
struct MintParams { | |
address token0; | |
address token1; | |
uint24 fee; | |
int24 tickLower; | |
int24 tickUpper; | |
uint256 amount0Desired; | |
uint256 amount1Desired; | |
uint256 amount0Min; | |
uint256 amount1Min; | |
address recipient; | |
uint256 deadline; | |
} | |
function mint(MintParams calldata params) | |
external | |
payable | |
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); | |
struct IncreaseLiquidityParams { | |
uint256 tokenId; | |
uint256 amount0Desired; | |
uint256 amount1Desired; | |
uint256 amount0Min; | |
uint256 amount1Min; | |
uint256 deadline; | |
} | |
function increaseLiquidity(IncreaseLiquidityParams calldata params) | |
external | |
payable | |
returns (uint128 liquidity, uint256 amount0, uint256 amount1); | |
struct DecreaseLiquidityParams { | |
uint256 tokenId; | |
uint128 liquidity; | |
uint256 amount0Min; | |
uint256 amount1Min; | |
uint256 deadline; | |
} | |
function decreaseLiquidity(DecreaseLiquidityParams calldata params) | |
external | |
payable | |
returns (uint256 amount0, uint256 amount1); | |
struct CollectParams { | |
uint256 tokenId; | |
address recipient; | |
uint128 amount0Max; | |
uint128 amount1Max; | |
} | |
function collect(CollectParams calldata params) | |
external | |
payable | |
returns (uint256 amount0, uint256 amount1); | |
} |
This file contains 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.25; | |
import { Test } from "forge-std/Test.sol"; | |
import "forge-std/console.sol"; | |
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | |
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import { Address } from "@openzeppelin/contracts/utils/Address.sol"; | |
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; | |
import { IWETH9 } from "../../src/lib/IWETH9.sol"; | |
import { LinearCurve } from "../../src/curves/LinearCurve.sol"; | |
import { IIPSeedCurve } from "../../src/curves/IIPSeedCurve.sol"; | |
import { INonfungiblePositionManager } from "../../src/lib/uni/INonfungiblePositionManager.sol"; | |
import { IUniswapV3Factory } from "../../src/lib/uni/IUniswapV3Factory.sol"; | |
import { | |
IPSeed, MarketData, MarketState, MarketParameters, BASIS_POINTS | |
} from "../../src/IPSeed.sol"; | |
error OwnableUnauthorizedAccount(address account); | |
contract LiquidityForkTest is Test { | |
IPSeed ipSeed = IPSeed(0x1545dAbD87Bd880F4c03Bc4e5BC59d8C7711222d); | |
IERC20 ipts = IERC20(0x2854e2ACC2530165a76623B99c2F5b4915484BdC); | |
uint256 tokenId = 71608873548347908551806579327355212747937605875372970477748660726076739061303; | |
//https://docs.uniswap.org/contracts/v3/reference/deployments/base-deployments | |
INonfungiblePositionManager positionManager = | |
INonfungiblePositionManager(0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2); | |
IWETH9 weth9 = IWETH9(0x4200000000000000000000000000000000000006); | |
int24 private constant MIN_TICK = -887272; | |
int24 private constant MAX_TICK = -MIN_TICK; | |
int24 private constant TICK_SPACING = 60; | |
IUniswapV3Factory uniV3Factory = IUniswapV3Factory(0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24); | |
function setUp() public { | |
uint256 baseSepoliaFork = vm.createFork(vm.envString("BASE_SEPOLIA_RPC_URL"), 13085032); | |
vm.selectFork(baseSepoliaFork); | |
} | |
function testCheckPrices() public { | |
MarketParameters memory parameters = ipSeed.getMarketParams(tokenId); | |
address beneficiary = parameters.beneficiary; | |
assertEq(beneficiary.balance, 0.031085914 ether); | |
assertEq(ipts.balanceOf(beneficiary), 67_942.161866091752 ether); | |
uint256 closingPrice = IIPSeedCurve(parameters.priceCurve).getBuyPrice( | |
ipSeed.totalSupply(tokenId), 1 ether, parameters.curveParameters | |
); | |
uint256 mediumPrice = IIPSeedCurve(parameters.priceCurve).getBuyPrice( | |
ipSeed.totalSupply(tokenId) / 2, 1 ether, parameters.curveParameters | |
); | |
assertEq(mediumPrice, 0.000036998396980146 ether); | |
assertEq(closingPrice, 0.000079808151300778 ether); | |
} | |
//GPT knows how to do this: https://chatgpt.com/c/67d584e5-c249-4b3d-bbd6-ae532b1a345a | |
function testCreatePoolPosition() public { | |
MarketParameters memory parameters = ipSeed.getMarketParams(tokenId); | |
address beneficiary = parameters.beneficiary; | |
vm.startPrank(beneficiary); | |
weth9.deposit{ value: beneficiary.balance }(); | |
assertEq(weth9.balanceOf(address(beneficiary)), 0.031085914 ether); | |
// input tokens must be ordered "alphabetically" | |
// token0 (UNDER the line): IPT (0x28...) | |
// token1 WETH (0x42...) | |
// lets just use the current token ratio be the price, because it feels so natural! | |
// compute tick price: https://blog.uniswap.org/uniswap-v3-math-primer#how-does-tick-and-tick-spacing-relate-to-sqrtpricex96 | |
uint256 decPrice = (weth9.balanceOf(beneficiary) * 1e18) / ipts.balanceOf(beneficiary); | |
uint160 sqrtPriceX96 = uint160(((Math.sqrt(decPrice) * 2 ** 96)) / 1e18); | |
console.log("PRICE dec %s sqrt96 %s", decPrice, sqrtPriceX96); | |
ipts.approve(address(positionManager), ipts.balanceOf(beneficiary)); | |
weth9.approve(address(positionManager), weth9.balanceOf(beneficiary)); | |
//under the hood: | |
// address pool = uniV3Factory.createPool(address(ipts), address(weth9), 3000); | |
// IUniswapV3Pool(pool).initialize(sqrtPriceX96); // sqrtPriceX96 is the square root of the initial price ratio | |
// console.log(pool); | |
address pool = positionManager.createAndInitializePoolIfNecessary( | |
address(ipts), address(weth9), 3000, sqrtPriceX96 | |
); | |
uint256 amount0ToAdd = ipts.balanceOf(beneficiary); | |
uint256 amount1ToAdd = weth9.balanceOf(beneficiary); | |
// https://docs.uniswap.org/contracts/v3/guides/providing-liquidity/mint-a-position#calling-mint | |
INonfungiblePositionManager.MintParams memory positionParams = INonfungiblePositionManager | |
.MintParams({ | |
token0: address(ipts), | |
token1: address(weth9), | |
fee: 3000, //0.3% fee | |
tickLower: (MIN_TICK / TICK_SPACING) * TICK_SPACING, | |
tickUpper: (MAX_TICK / TICK_SPACING) * TICK_SPACING, | |
amount0Desired: amount0ToAdd, | |
amount1Desired: amount1ToAdd, | |
amount0Min: 0, | |
amount1Min: 0, | |
recipient: beneficiary, | |
deadline: block.timestamp + 1000 | |
}); | |
// //console.logBytes(abi.encodeCall(positionManager.mint, positionParams)); | |
(uint256 positionTokenId, uint128 liquidity, uint256 amount0, uint256 amount1) = | |
positionManager.mint(positionParams); | |
console.log("POSITION", liquidity, amount0, amount1); | |
console.log( | |
"POOL %s ipts %s weth %s", address(pool), ipts.balanceOf(pool), weth9.balanceOf(pool) | |
); | |
} | |
} |
This file contains 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
[PASS] testCreatePoolPosition() (gas: 5298751) | |
Logs: | |
PRICE dec 457534955412 sqrt96 53590959090761083 | |
POSITION 45956961534 67942161865605776840284 1 | |
POOL 0xaaCEaa92d3eC529E34631e74499e479acD8515ff ipts 67942161865605776840284 weth 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment