-
Notifications
You must be signed in to change notification settings - Fork 34
feat: uniswap v3 deployment and liquidity commands #295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 17 commits
9b9d630
3d4725e
5c52248
2209951
ba4ae4b
dc308ae
9fd0071
442977d
50362ab
fe543e4
691b2fb
f6a7c28
2f6a239
f49f222
28cad95
3ea1b78
c6bfb85
d16debf
b15c2db
27a0062
0234c46
6f1553b
2985c00
e09172a
4904414
1aa83e7
6907609
4bc23f3
653ad1f
cfea79d
cfb9973
8b6e857
4dc7f2c
1fd27fd
583a152
dff4ad9
d26804c
1795013
228b66d
01acd19
a3d96c5
439a441
de14ad5
cf8946f
b8e2bd3
16bca71
01757b2
e01d06f
4cfa442
66e1330
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,15 @@ | ||
| import { Command } from "commander"; | ||
|
|
||
| import { accountsCommand } from "./accounts"; | ||
| import { poolsCommand } from "./pools/"; | ||
| import { solanaEncodeCommand } from "./solanaEncode"; | ||
|
|
||
| export const toolkitCommand = new Command("toolkit") | ||
| .description("Local development environment") | ||
| .helpCommand(false); | ||
|
|
||
| toolkitCommand.addCommand(solanaEncodeCommand); | ||
| toolkitCommand.addCommand(accountsCommand); | ||
| toolkitCommand | ||
| .addCommand(solanaEncodeCommand) | ||
| .addCommand(poolsCommand) | ||
| .addCommand(solanaEncodeCommand) | ||
| .addCommand(accountsCommand); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export const DEFAULT_RPC = | ||
| "https://zetachain-athens.g.allthatnode.com/archive/evm"; | ||
| export const DEFAULT_FACTORY = "0x7E032E349853178C233a2560d9Ea434ac82228e0"; | ||
| export const DEFAULT_WZETA = "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"; | ||
| export const DEFAULT_FEE = 3000; // 0.3% | ||
| export const DEFAULT_POSITION_MANAGER = | ||
| "0xFc5D90f650cf46Cecf96C66a4993f97D2a49f93B"; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,106 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as UniswapV3Factory from "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as UniswapV3Pool from "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Command } from "commander"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Contract, ethers, JsonRpcProvider, Wallet } from "ethers"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type CreatePoolOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createPoolOptionsSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PoolCreationError, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "../../../../types/pools"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { DEFAULT_FACTORY, DEFAULT_FEE, DEFAULT_RPC } from "./constants"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const main = async (options: CreatePoolOptions): Promise<void> => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validate options | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedOptions = createPoolOptionsSchema.parse(options); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (validatedOptions.tokens.length !== 2) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Exactly 2 token addresses must be provided"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Initialize provider and signer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const provider = new JsonRpcProvider(validatedOptions.rpc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const signer = new Wallet(validatedOptions.privateKey, provider); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Creating Uniswap V3 pool..."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Signer address:", await signer.getAddress()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Balance:", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ethers.formatEther(await provider.getBalance(await signer.getAddress())), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "ZETA" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Initialize factory contract | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const uniswapV3FactoryInstance = new Contract( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedOptions.factory, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UniswapV3Factory.abi, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| signer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create the pool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("\nCreating pool..."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fee = validatedOptions.fee; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const createPoolTx = (await uniswapV3FactoryInstance.createPool( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedOptions.tokens[0], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedOptions.tokens[1], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fee | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) as ethers.TransactionResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Pool creation transaction hash:", createPoolTx.hash); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await createPoolTx.wait(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create the pool | |
| console.log("\nCreating pool..."); | |
| const fee = validatedOptions.fee; | |
| const createPoolTx = (await uniswapV3FactoryInstance.createPool( | |
| validatedOptions.tokens[0], | |
| validatedOptions.tokens[1], | |
| fee | |
| )) as ethers.TransactionResponse; | |
| console.log("Pool creation transaction hash:", createPoolTx.hash); | |
| await createPoolTx.wait(); | |
| // Create the pool | |
| console.log("\nCreating pool..."); | |
| const fee = validatedOptions.fee; | |
| // Check if pool already exists | |
| const existingPoolAddress = await uniswapV3FactoryInstance.getPool( | |
| validatedOptions.tokens[0], | |
| validatedOptions.tokens[1], | |
| fee | |
| ); | |
| if (existingPoolAddress !== "0x0000000000000000000000000000000000000000") { | |
| console.log("Pool already exists at:", existingPoolAddress); | |
| return existingPoolAddress; | |
| } | |
| const createPoolTx = (await uniswapV3FactoryInstance.createPool( | |
| validatedOptions.tokens[0], | |
| validatedOptions.tokens[1], | |
| fee | |
| )) as ethers.TransactionResponse; | |
| console.log("Pool creation transaction hash:", createPoolTx.hash); | |
| await createPoolTx.wait(); |
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| import * as UniswapV3Factory from "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"; | ||
| import * as NonfungiblePositionManager from "@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"; | ||
| import * as SwapRouter from "@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"; | ||
| import { Command } from "commander"; | ||
| import { ContractFactory, ethers, JsonRpcProvider, Wallet } from "ethers"; | ||
|
|
||
| import { | ||
| DeploymentError, | ||
| type DeployOptions, | ||
| deployOptionsSchema, | ||
| } from "../../../../types/pools"; | ||
| import { DEFAULT_RPC, DEFAULT_WZETA } from "./constants"; | ||
|
|
||
| const deployOpts = { | ||
| gasLimit: 8000000, | ||
| }; | ||
|
|
||
| const estimateGas = async ( | ||
| contractFactory: ContractFactory, | ||
| args: unknown[] = [] | ||
| ): Promise<bigint | null> => { | ||
| try { | ||
| const deployment = await contractFactory.getDeployTransaction(...args); | ||
| const gasEstimate = await contractFactory.runner?.provider?.estimateGas( | ||
| deployment | ||
| ); | ||
| console.log("Estimated gas:", gasEstimate?.toString()); | ||
| return gasEstimate ?? null; | ||
| } catch (error) { | ||
| console.error("Gas estimation failed:", error); | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| const main = async (options: DeployOptions): Promise<void> => { | ||
| try { | ||
| // Validate options | ||
| const validatedOptions = deployOptionsSchema.parse(options); | ||
|
|
||
| // Initialize provider and signer | ||
| const provider = new JsonRpcProvider(validatedOptions.rpc); | ||
| const signer = new Wallet(validatedOptions.privateKey, provider); | ||
|
|
||
| console.log("Deploying Uniswap V3 contracts..."); | ||
| console.log("Deployer address:", await signer.getAddress()); | ||
| console.log("Network:", (await provider.getNetwork()).name); | ||
| console.log( | ||
| "Balance:", | ||
| ethers.formatEther(await provider.getBalance(await signer.getAddress())), | ||
| "ZETA" | ||
| ); | ||
|
|
||
| // Deploy Uniswap V3 Factory | ||
| console.log("\nDeploying Uniswap V3 Factory..."); | ||
| const uniswapV3Factory = new ContractFactory( | ||
| UniswapV3Factory.abi, | ||
| UniswapV3Factory.bytecode, | ||
| signer | ||
| ); | ||
|
|
||
| // Estimate gas for factory deployment | ||
| const factoryGasEstimate = await estimateGas(uniswapV3Factory); | ||
| if (factoryGasEstimate) { | ||
| deployOpts.gasLimit = Number(factoryGasEstimate * 2n); | ||
| } | ||
|
|
||
| console.log("Using gas limit:", deployOpts.gasLimit.toString()); | ||
|
|
||
| const uniswapV3FactoryInstance = await uniswapV3Factory.deploy(deployOpts); | ||
| console.log( | ||
| "Factory deployment transaction hash:", | ||
| uniswapV3FactoryInstance.deploymentTransaction()?.hash | ||
| ); | ||
|
|
||
| await uniswapV3FactoryInstance.waitForDeployment(); | ||
| console.log( | ||
| "Uniswap V3 Factory deployed at:", | ||
| await uniswapV3FactoryInstance.getAddress() | ||
| ); | ||
|
|
||
| // Deploy Swap Router | ||
| console.log("\nDeploying Swap Router..."); | ||
| const swapRouter = new ContractFactory( | ||
| SwapRouter.abi, | ||
| SwapRouter.bytecode, | ||
| signer | ||
| ); | ||
|
|
||
| // Estimate gas for router deployment | ||
| const routerGasEstimate = await estimateGas(swapRouter, [ | ||
| await uniswapV3FactoryInstance.getAddress(), | ||
| validatedOptions.wzeta, | ||
| ]); | ||
| if (routerGasEstimate) { | ||
| deployOpts.gasLimit = Number(routerGasEstimate * 2n); | ||
| } | ||
|
|
||
| console.log("Using gas limit:", deployOpts.gasLimit.toString()); | ||
|
|
||
| const swapRouterInstance = await swapRouter.deploy( | ||
| await uniswapV3FactoryInstance.getAddress(), | ||
| validatedOptions.wzeta, | ||
| deployOpts | ||
| ); | ||
| console.log( | ||
| "Router deployment transaction hash:", | ||
| swapRouterInstance.deploymentTransaction()?.hash | ||
| ); | ||
|
|
||
| await swapRouterInstance.waitForDeployment(); | ||
| console.log( | ||
| "Swap Router deployed at:", | ||
| await swapRouterInstance.getAddress() | ||
| ); | ||
|
|
||
| // Deploy Nonfungible Position Manager | ||
| console.log("\nDeploying Nonfungible Position Manager..."); | ||
| const nonfungiblePositionManager = new ContractFactory( | ||
| NonfungiblePositionManager.abi, | ||
| NonfungiblePositionManager.bytecode, | ||
| signer | ||
| ); | ||
|
|
||
| // Estimate gas for position manager deployment | ||
| const positionManagerGasEstimate = await estimateGas( | ||
| nonfungiblePositionManager, | ||
| [ | ||
| await uniswapV3FactoryInstance.getAddress(), | ||
| validatedOptions.wzeta, | ||
| await swapRouterInstance.getAddress(), | ||
| ] | ||
| ); | ||
| if (positionManagerGasEstimate) { | ||
| deployOpts.gasLimit = Number(positionManagerGasEstimate * 2n); | ||
| } | ||
|
|
||
| console.log("Using gas limit:", deployOpts.gasLimit.toString()); | ||
|
|
||
| const nonfungiblePositionManagerInstance = | ||
| await nonfungiblePositionManager.deploy( | ||
| await uniswapV3FactoryInstance.getAddress(), | ||
| validatedOptions.wzeta, | ||
| await swapRouterInstance.getAddress(), | ||
| deployOpts | ||
| ); | ||
| console.log( | ||
| "Position Manager deployment transaction hash:", | ||
| nonfungiblePositionManagerInstance.deploymentTransaction()?.hash | ||
| ); | ||
|
|
||
| await nonfungiblePositionManagerInstance.waitForDeployment(); | ||
| console.log( | ||
| "Nonfungible Position Manager deployed at:", | ||
| await nonfungiblePositionManagerInstance.getAddress() | ||
| ); | ||
|
|
||
| console.log("\nDeployment completed successfully!"); | ||
| console.log("\nContract addresses:"); | ||
| console.log( | ||
| "Uniswap V3 Factory:", | ||
| await uniswapV3FactoryInstance.getAddress() | ||
| ); | ||
| console.log("Swap Router:", await swapRouterInstance.getAddress()); | ||
| console.log( | ||
| "Nonfungible Position Manager:", | ||
| await nonfungiblePositionManagerInstance.getAddress() | ||
| ); | ||
| } catch (error) { | ||
| const deploymentError = error as DeploymentError; | ||
| console.error("\nDeployment failed with error:"); | ||
| console.error("Error message:", deploymentError.message); | ||
| if (deploymentError.receipt) { | ||
| console.error("Transaction receipt:", deploymentError.receipt); | ||
| } | ||
| if (deploymentError.transaction) { | ||
| console.error("Transaction details:", deploymentError.transaction); | ||
| } | ||
| process.exit(1); | ||
| } | ||
| }; | ||
|
|
||
| export const deployCommand = new Command("deploy") | ||
| .description("Deploy Uniswap V3 contracts") | ||
| .requiredOption("--private-key <privateKey>", "Private key for deployment") | ||
| .option("--rpc <rpc>", "RPC URL for the network", DEFAULT_RPC) | ||
| .option("--wzeta <wzeta>", "WZETA token address", DEFAULT_WZETA) | ||
| .action(main); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { Command } from "commander"; | ||
|
|
||
| import { createCommand } from "./create"; | ||
| import { deployCommand } from "./deploy"; | ||
| import { liquidityCommand } from "./liquidity"; | ||
| import { showCommand } from "./show"; | ||
|
|
||
| export const poolsCommand = new Command("pools") | ||
| .description("Manage Uniswap V3 pools") | ||
| .addCommand(deployCommand) | ||
| .addCommand(createCommand) | ||
| .addCommand(showCommand) | ||
| .addCommand(liquidityCommand); |
Uh oh!
There was an error while loading. Please reload this page.