Skip to content

Instantly share code, notes, and snippets.

@niettcat
Forked from BlockmanCodes/01_deployContracts.js
Created August 17, 2023 07:16
Show Gist options
  • Select an option

  • Save niettcat/169d366ae64d4cd18a1c946752eae448 to your computer and use it in GitHub Desktop.

Select an option

Save niettcat/169d366ae64d4cd18a1c946752eae448 to your computer and use it in GitHub Desktop.
Uniswap V3: protocol fees
const { ContractFactory, utils } = require("ethers")
const WETH9 = require("../WETH9.json")
const fs = require('fs');
const { promisify } = require('util');
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,
};
const linkLibraries = ({ bytecode, linkReferences }, libraries) => {
Object.keys(linkReferences).forEach((fileName) => {
Object.keys(linkReferences[fileName]).forEach((contractName) => {
if (!libraries.hasOwnProperty(contractName)) {
throw new Error(`Missing link library name ${contractName}`)
}
const address = utils
.getAddress(libraries[contractName])
.toLowerCase()
.slice(2)
linkReferences[fileName][contractName].forEach(
({ start, length }) => {
const start2 = 2 + start * 2
const length2 = length * 2
bytecode = bytecode
.slice(0, start2)
.concat(address)
.concat(bytecode.slice(start2 + length2, bytecode.length))
}
)
})
})
return bytecode
}
async function main() {
const [owner] = await ethers.getSigners();
Weth = new ContractFactory(artifacts.WETH9.abi, artifacts.WETH9.bytecode, owner);
weth = await Weth.deploy();
Factory = new ContractFactory(artifacts.UniswapV3Factory.abi, artifacts.UniswapV3Factory.bytecode, owner);
factory = await Factory.deploy();
SwapRouter = new ContractFactory(artifacts.SwapRouter.abi, artifacts.SwapRouter.bytecode, owner);
swapRouter = await SwapRouter.deploy(factory.address, weth.address);
NFTDescriptor = new ContractFactory(artifacts.NFTDescriptor.abi, artifacts.NFTDescriptor.bytecode, owner);
nftDescriptor = await NFTDescriptor.deploy();
const linkedBytecode = linkLibraries(
{
bytecode: artifacts.NonfungibleTokenPositionDescriptor.bytecode,
linkReferences: {
"NFTDescriptor.sol": {
NFTDescriptor: [
{
length: 20,
start: 1681,
},
],
},
},
},
{
NFTDescriptor: nftDescriptor.address,
}
);
NonfungibleTokenPositionDescriptor = new ContractFactory(artifacts.NonfungibleTokenPositionDescriptor.abi, linkedBytecode, owner);
const nativeCurrencyLabelBytes = utils.formatBytes32String('WETH')
nonfungibleTokenPositionDescriptor = await NonfungibleTokenPositionDescriptor.deploy(weth.address, nativeCurrencyLabelBytes);
NonfungiblePositionManager = new ContractFactory(artifacts.NonfungiblePositionManager.abi, artifacts.NonfungiblePositionManager.bytecode, owner);
nonfungiblePositionManager = await NonfungiblePositionManager.deploy(factory.address, weth.address, nonfungibleTokenPositionDescriptor.address);
let addresses = [
`WETH_ADDRESS=${weth.address}`,
`FACTORY_ADDRESS=${factory.address}`,
`SWAP_ROUTER_ADDRESS=${swapRouter.address}`,
`NFT_DESCRIPTOR_ADDRESS=${nftDescriptor.address}`,
`POSITION_DESCRIPTOR_ADDRESS=${nonfungibleTokenPositionDescriptor.address}`,
`POSITION_MANAGER_ADDRESS=${nonfungiblePositionManager.address}`,
]
const data = addresses.join('\n')
const writeFile = promisify(fs.writeFile);
const filePath = '.env';
return writeFile(filePath, data)
.then(() => {
console.log('Addresses recorded.');
})
.catch((error) => {
console.error('Error logging addresses:', error);
throw error;
});
}
/*
npx hardhat run --network localhost scripts/01_deployContracts.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
const fs = require('fs');
const { promisify } = require('util');
async function main() {
const [owner, signer2] = await ethers.getSigners();
const Tether = await ethers.getContractFactory('Tether', owner);
const tether = await Tether.deploy();
const Usdc = await ethers.getContractFactory('UsdCoin', owner);
const usdc = await Usdc.deploy();
const WrappedBitcoin = await ethers.getContractFactory('WrappedBitcoin', owner);
const wrappedBitcoin = await WrappedBitcoin.deploy();
await tether.connect(owner).mint(
signer2.address,
ethers.utils.parseEther('100000')
)
await usdc.connect(owner).mint(
signer2.address,
ethers.utils.parseEther('100000')
)
await wrappedBitcoin.connect(owner).mint(
signer2.address,
ethers.utils.parseEther('100000')
)
let addresses = [
`USDC_ADDRESS=${usdc.address}`,
`TETHER_ADDRESS=${tether.address}`,
`WRAPPED_BITCOIN_ADDRESS=${wrappedBitcoin.address}`,
]
const data = '\n' + addresses.join('\n')
const writeFile = promisify(fs.appendFile);
const filePath = '.env';
return writeFile(filePath, data)
.then(() => {
console.log('Addresses recorded.');
})
.catch((error) => {
console.error('Error logging addresses:', error);
throw error;
});
}
/*
npx hardhat run --network localhost scripts/02_deployTokens.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
require('dotenv').config()
TETHER_ADDRESS = process.env.TETHER_ADDRESS
USDC_ADDRESS = process.env.USDC_ADDRESS
FACTORY_ADDRESS = process.env.FACTORY_ADDRESS
POSITION_MANAGER_ADDRESS = process.env.POSITION_MANAGER_ADDRESS
const artifacts = {
UniswapV3Factory: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"),
NonfungiblePositionManager: require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"),
UniswapV3Pool: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"),
};
const { Contract, BigNumber } = require("ethers")
const bn = require('bignumber.js')
const {promisify} = require("util");
const fs = require("fs");
bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 })
const provider = ethers.provider
function encodePriceSqrt(reserve1, reserve0) {
return BigNumber.from(
new bn(reserve1.toString())
.div(reserve0.toString())
.sqrt()
.multipliedBy(new bn(2).pow(96))
.integerValue(3)
.toString()
)
}
const nonfungiblePositionManager = new Contract(
POSITION_MANAGER_ADDRESS,
artifacts.NonfungiblePositionManager.abi,
provider
)
const factory = new Contract(
FACTORY_ADDRESS,
artifacts.UniswapV3Factory.abi,
provider
)
async function deployPool(token0, token1, fee, price) {
const [owner] = await ethers.getSigners();
await nonfungiblePositionManager.connect(owner).createAndInitializePoolIfNecessary(
token0,
token1,
fee,
price,
{ gasLimit: 5000000 }
)
const poolAddress = await factory.connect(owner).getPool(
token0,
token1,
fee,
)
return poolAddress
}
async function main() {
const [owner] = await ethers.getSigners();
const poolAddress = await deployPool(TETHER_ADDRESS, USDC_ADDRESS,10000, encodePriceSqrt(1, 1))
const poolContract = new Contract(poolAddress, artifacts.UniswapV3Pool.abi, provider)
const feeProtocol0 = 4
const feeProtocol1 = 4
await poolContract.connect(owner).setFeeProtocol(feeProtocol0, feeProtocol1)
let addresses = [
`USDT_USDC_500=${poolAddress}`
]
const data = '\n' + addresses.join('\n')
const writeFile = promisify(fs.appendFile);
const filePath = '.env';
return writeFile(filePath, data)
.then(() => {
console.log('Addresses recorded.');
})
.catch((error) => {
console.error('Error logging addresses:', error);
throw error;
});
}
/*
npx hardhat run --network localhost scripts/03_deployPools.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
require('dotenv').config()
TETHER_ADDRESS = process.env.TETHER_ADDRESS
USDC_ADDRESS = process.env.USDC_ADDRESS
POSITION_MANAGER_ADDRESS = process.env.POSITION_MANAGER_ADDRESS
USDT_USDC_500 = process.env.USDT_USDC_500
const artifacts = {
NonfungiblePositionManager: require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"),
Usdt: require("../artifacts/contracts/Tether.sol/Tether.json"),
Usdc: require("../artifacts/contracts/UsdCoin.sol/UsdCoin.json"),
UniswapV3Pool: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"),
};
const { Contract } = require("ethers")
const { Token } = require('@uniswap/sdk-core')
const { Pool, Position, nearestUsableTick } = require('@uniswap/v3-sdk')
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,
sqrtPriceX96: slot0[0],
tick: slot0[1],
}
}
async function main() {
const [_owner, signer2] = await ethers.getSigners();
const provider = ethers.provider
const usdtContract = new Contract(TETHER_ADDRESS,artifacts.Usdt.abi,provider)
const usdcContract = new Contract(USDC_ADDRESS,artifacts.Usdc.abi,provider)
await usdtContract.connect(signer2).approve(POSITION_MANAGER_ADDRESS, ethers.utils.parseEther('10000'))
await usdcContract.connect(signer2).approve(POSITION_MANAGER_ADDRESS, ethers.utils.parseEther('10000'))
const poolContract = new Contract(USDT_USDC_500, artifacts.UniswapV3Pool.abi, provider)
const poolData = await getPoolData(poolContract)
const UsdtToken = new Token(31337, TETHER_ADDRESS, 18, 'USDT', 'Tether')
const UsdcToken = new Token(31337, USDC_ADDRESS, 18, 'USDC', 'UsdCoin')
const pool = new Pool(
UsdtToken,
UsdcToken,
poolData.fee,
poolData.sqrtPriceX96.toString(),
poolData.liquidity.toString(),
poolData.tick
)
const position = new Position({
pool: pool,
liquidity: ethers.utils.parseEther('100000'),
tickLower: nearestUsableTick(poolData.tick, poolData.tickSpacing) - poolData.tickSpacing * 2,
tickUpper: nearestUsableTick(poolData.tick, poolData.tickSpacing) + poolData.tickSpacing * 2,
})
const { amount0: amount0Desired, amount1: amount1Desired} = position.mintAmounts
const params = {
token0: TETHER_ADDRESS,
token1: USDC_ADDRESS,
fee: poolData.fee,
tickLower: nearestUsableTick(poolData.tick, poolData.tickSpacing) - poolData.tickSpacing * 2,
tickUpper: nearestUsableTick(poolData.tick, poolData.tickSpacing) + poolData.tickSpacing * 2,
amount0Desired: amount0Desired.toString(),
amount1Desired: amount1Desired.toString(),
amount0Min: 0,
amount1Min: 0,
recipient: signer2.address,
deadline: Math.floor(Date.now() / 1000) + (60 * 10)
}
const nonfungiblePositionManager = new Contract(
POSITION_MANAGER_ADDRESS,
artifacts.NonfungiblePositionManager.abi,
provider
)
const tx = await nonfungiblePositionManager.connect(signer2).mint(
params,
{ gasLimit: '1000000' }
)
await tx.wait()
}
/*
npx hardhat run --network localhost scripts/04_addLiquidity.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
require('dotenv').config()
USDT_USDC_500 = process.env.USDT_USDC_500
const { Contract } = require("ethers")
const UniswapV3Pool = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json")
async function getPoolData(poolContract) {
const [tickSpacing, fee, liquidity, slot0, protocolFees] = await Promise.all([
poolContract.tickSpacing(),
poolContract.fee(),
poolContract.liquidity(),
poolContract.slot0(),
poolContract.protocolFees(),
])
return {
tickSpacing: tickSpacing,
fee: fee,
liquidity: liquidity.toString(),
sqrtPriceX96: slot0[0],
tick: slot0[1],
protocolFees: protocolFees,
}
}
async function main() {
const provider = ethers.provider
const poolContract = new Contract(USDT_USDC_500, UniswapV3Pool.abi, provider)
const poolData = await getPoolData(poolContract)
console.log('poolData', poolData)
}
/*
npx hardhat run --network localhost scripts/05_poolData.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
const { Contract } = require("ethers")
require('dotenv').config()
TETHER_ADDRESS = process.env.TETHER_ADDRESS
USDC_ADDRESS = process.env.USDC_ADDRESS
SWAP_ROUTER_ADDRESS = process.env.SWAP_ROUTER_ADDRESS
USDT_USDC_500 = process.env.USDT_USDC_500
const artifacts = {
SwapRouter: require("@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"),
Usdt: require("../artifacts/contracts/Tether.sol/Tether.json"),
Usdc: require("../artifacts/contracts/UsdCoin.sol/UsdCoin.json"),
UniswapV3Pool: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"),
};
async function getPoolData(poolContract) {
const [token0, token1, fee] = await Promise.all([
poolContract.token0(),
poolContract.token1(),
poolContract.fee(),
])
return {
token0: token0,
token1: token1,
fee: fee,
}
}
async function main() {
const provider = ethers.provider;
const [_owner, signer2] = await ethers.getSigners();
const usdtContract = new Contract(TETHER_ADDRESS,artifacts.Usdt.abi,provider)
const usdcContract = new Contract(USDC_ADDRESS,artifacts.Usdc.abi,provider)
const poolContract = new ethers.Contract(
USDT_USDC_500,
artifacts.UniswapV3Pool.abi,
provider
);
const poolData = await getPoolData(poolContract)
const swapRouterContract = new ethers.Contract(
SWAP_ROUTER_ADDRESS,
artifacts.SwapRouter.abi,
provider
)
const amountIn = ethers.utils.parseUnits('100')
const params = {
tokenIn: poolData.token0,
tokenOut: poolData.token1,
fee: poolData.fee,
recipient: signer2.address,
deadline: Math.floor(Date.now() / 1000) + (60 * 10),
amountIn: amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0,
}
await usdtContract.connect(signer2).approve(SWAP_ROUTER_ADDRESS, amountIn)
await usdcContract.connect(signer2).approve(SWAP_ROUTER_ADDRESS, amountIn)
const tx = await swapRouterContract.connect(signer2).exactInputSingle(
params,
{ gasLimit: ethers.utils.hexlify(1000000) }
)
await tx.wait()
}
/*
npx hardhat run --network localhost scripts/06_swapTokens.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
require('dotenv').config()
USDT_USDC_500 = process.env.USDT_USDC_500
const artifacts = {
UniswapV3Pool: require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json"),
};
const { Contract } = require("ethers")
async function main() {
const [owner] = await ethers.getSigners();
const provider = ethers.provider
const poolContract = new Contract(USDT_USDC_500, artifacts.UniswapV3Pool.abi, provider)
const withdrawAmount = ethers.utils.parseEther('100000')
await poolContract.connect(owner).collectProtocol(
owner.address,
withdrawAmount,
withdrawAmount,
)
}
/*
npx hardhat run --network localhost scripts/07_withdrawProtocolFees.js
*/
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import "@openzeppelin/contracts/access/Ownable.sol";
contract Tether is ERC20, Ownable {
constructor() ERC20('Tether', 'USDT') {}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import "@openzeppelin/contracts/access/Ownable.sol";
contract UsdCoin is ERC20, Ownable {
constructor() ERC20('UsdCoin', 'USDC') {}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import "@openzeppelin/contracts/access/Ownable.sol";
contract WrappedBitcoin is ERC20, Ownable {
constructor() ERC20('WrappedBitcoin', 'WBTC') {}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
require("@nomicfoundation/hardhat-toolbox")
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
version: "0.8.18",
settings: {
optimizer: {
enabled: true,
runs: 5000,
details: { yul: false },
},
}
},
};
{
"name": "local-deploy-uniswap-v3-updated",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^1.0.6",
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@openzeppelin/contracts": "^4.8.3",
"@typechain/ethers-v5": "^10.2.1",
"@typechain/hardhat": "^6.1.6",
"@types/chai": "^4.3.5",
"@types/mocha": "^10.0.1",
"@uniswap/v3-periphery": "^1.4.3",
"@uniswap/v3-sdk": "^3.9.0",
"bignumber.js": "^9.1.1",
"chai": "^4.3.7",
"dotenv": "^16.0.3",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^1.0.9",
"solidity-coverage": "^0.8.2",
"ts-node": "^10.9.1",
"typechain": "^8.1.1",
"typescript": "^5.0.4"
},
"devDependencies": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment