Skip to content
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

zkSync era #1

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,7 @@ dist
.tern-port

.nvmrc

# hardhat
artifacts-zk/
cache-zk/
42 changes: 42 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import '@matterlabs/hardhat-zksync-solc'
import 'hardhat-dependency-compiler'

export default {
networks: {
hardhat: {
allowUnlimitedContractSize: false,
zksync: true,
},
zkSyncTestnet: {
url: "https://testnet.era.zksync.dev",
ethNetwork: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
zksync: true,
},
zkSyncLocalhost: {
url: "http://localhost:3050",
ethNetwork: "http://localhost:8545",
zksync: true,
}
},
solidity: {
version: '0.7.6',
settings: {
optimizer: {
enabled: true,
},
metadata: {
bytecodeHash: 'none',
},
},
},
zksolc: {
version: "1.3.9",
compilerSource: "binary",
settings: {},
},
dependencyCompiler: {
paths: [
'v3-core/contracts/UniswapV3Factory.sol',
],
},
}
106 changes: 22 additions & 84 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,101 +1,38 @@
import { program } from 'commander'
import { Wallet } from '@ethersproject/wallet'
import { JsonRpcProvider, TransactionReceipt } from '@ethersproject/providers'
import { Wallet, Provider } from 'zksync-web3'
import { TransactionResponse } from '@ethersproject/providers'
import { AddressZero } from '@ethersproject/constants'
import { getAddress } from '@ethersproject/address'
import fs from 'fs'
import deploy from './src/deploy'
import { MigrationState } from './src/migrations'
import { asciiStringToBytes32 } from './src/util/asciiStringToBytes32'
import { version } from './package.json'

program
.requiredOption('-pk, --private-key <string>', 'Private key used to deploy all contracts')
.requiredOption('-j, --json-rpc <url>', 'JSON RPC URL where the program should be deployed')
.requiredOption('-w9, --weth9-address <address>', 'Address of the WETH9 contract on this chain')
.requiredOption('-ncl, --native-currency-label <string>', 'Native currency label, e.g. ETH')
.requiredOption(
'-o, --owner-address <address>',
'Contract address that will own the deployed artifacts after the script runs'
)
.option('-s, --state <path>', 'Path to the JSON file containing the migrations state (optional)', './state.json')
.option('-v2, --v2-core-factory-address <address>', 'The V2 core factory address used in the swap router (optional)')
.option('-g, --gas-price <number>', 'The gas price to pay in GWEI for each transaction (optional)')
.option('-c, --confirmations <number>', 'How many confirmations to wait for after each transaction (optional)', '2')

program.name('npx @uniswap/deploy-v3').version(version).parse(process.argv)

if (!/^0x[a-zA-Z0-9]{64}$/.test(program.privateKey)) {
console.error('Invalid private key!')
process.exit(1)
}
const hre = require("hardhat")

let url: URL
try {
url = new URL(program.jsonRpc)
} catch (error) {
console.error('Invalid JSON RPC URL', (error as Error).message)
process.exit(1)
}
// TODO: think how to pass args
AntonD3 marked this conversation as resolved.
Show resolved Hide resolved
const privateKey: string = '0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3'

let gasPrice: number | undefined
try {
gasPrice = program.gasPrice ? parseInt(program.gasPrice) : undefined
} catch (error) {
console.error('Failed to parse gas price', (error as Error).message)
process.exit(1)
}
// TODO: think how to sync url with hardhat env
const url: URL = new URL('http://localhost:3050')

let confirmations: number
try {
confirmations = parseInt(program.confirmations)
} catch (error) {
console.error('Failed to parse confirmations', (error as Error).message)
process.exit(1)
}
const gasPrice: number | undefined = undefined

let nativeCurrencyLabelBytes: string
try {
nativeCurrencyLabelBytes = asciiStringToBytes32(program.nativeCurrencyLabel)
} catch (error) {
console.error('Invalid native currency label', (error as Error).message)
process.exit(1)
}
const nativeCurrencyLabelBytes: string = asciiStringToBytes32('ETH')

let weth9Address: string
try {
weth9Address = getAddress(program.weth9Address)
} catch (error) {
console.error('Invalid WETH9 address', (error as Error).message)
process.exit(1)
}
const weth9Address: string = getAddress('0xa61464658AfeAf65CccaaFD3a512b69A83B77618')

let v2CoreFactoryAddress: string
if (typeof program.v2CoreFactoryAddress === 'undefined') {
v2CoreFactoryAddress = AddressZero
} else {
try {
v2CoreFactoryAddress = getAddress(program.v2CoreFactoryAddress)
} catch (error) {
console.error('Invalid V2 factory address', (error as Error).message)
process.exit(1)
}
}
const v2CoreFactoryAddress: string = AddressZero

const ownerAddress: string = getAddress('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049')

const statePath: string = './state.json'

let ownerAddress: string
try {
ownerAddress = getAddress(program.ownerAddress)
} catch (error) {
console.error('Invalid owner address', (error as Error).message)
process.exit(1)
}

const wallet = new Wallet(program.privateKey, new JsonRpcProvider({ url: url.href }))
const wallet = new Wallet(privateKey, new Provider({ url: url.href }))

let state: MigrationState
if (fs.existsSync(program.state)) {
if (fs.existsSync(statePath)) {
try {
state = JSON.parse(fs.readFileSync(program.state, { encoding: 'utf8' }))
state = JSON.parse(fs.readFileSync(statePath, { encoding: 'utf8' }))
} catch (error) {
console.error('Failed to load and parse migration state file', (error as Error).message)
process.exit(1)
Expand All @@ -106,7 +43,7 @@ if (fs.existsSync(program.state)) {

let finalState: MigrationState
const onStateChange = async (newState: MigrationState): Promise<void> => {
fs.writeFileSync(program.state, JSON.stringify(newState))
fs.writeFileSync(statePath, JSON.stringify(newState))
finalState = newState
}

Expand All @@ -131,9 +68,10 @@ async function run() {
// wait 15 minutes for any transactions sent in the step
await Promise.all(
result.map(
(stepResult): Promise<TransactionReceipt | true> => {
async (stepResult): Promise<TransactionResponse | true> => {
// TODO: think about confirmations
if (stepResult.hash) {
return wallet.provider.waitForTransaction(stepResult.hash, confirmations, /* 15 minutes */ 1000 * 60 * 15)
return await wallet._providerL2().getTransaction(stepResult.hash);
} else {
return Promise.resolve(true)
}
Expand Down
2 changes: 2 additions & 0 deletions init_submodule.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
yarn --cwd v3-periphery-1_3_0 install --frozen-lockfile
yarn --cwd v3-periphery-1_3_0 hardhat compile --network zkSyncTestnet
25 changes: 13 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
},
"main": "dist/index.js",
"scripts": {
"test": "mocha",
"build": "ncc build index.ts -o dist -m",
"postbuild": "cat shebang.txt dist/index.js > dist/index.cmd.js && mv dist/index.cmd.js dist/index.js",
"prestart": "yarn build",
"start": "node dist/index.js",
"prepublishOnly": "yarn build"
"test": "mocha"
},
"files": [
"dist/"
Expand Down Expand Up @@ -43,24 +38,30 @@
"@ethersproject/contracts": "^5.5.0",
"@ethersproject/providers": "^5.5.1",
"@ethersproject/wallet": "^5.5.0",
"@openzeppelin/contracts": "3.4.1-solc-0.7-2",
"@matterlabs/hardhat-zksync-deploy": "^0.6.3",
"@matterlabs/hardhat-zksync-solc": "^0.3.16",
"@types/chai": "^4.2.12",
"@types/mocha": "^8.0.3",
"@types/node": "^14.6.3",
"@uniswap/sdk-core": "^1.0.8",
"@uniswap/swap-router-contracts": "1.1.0",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "1.1.1",
"@uniswap/v3-staker": "1.0.2",
"@vercel/ncc": "^0.33.1",
"chai": "^4.2.0",
"commander": "^6.1.0",
"ethers": "5",
"ganache-cli": "^6.10.1",
"hardhat": "^2.14.0",
"hardhat-dependency-compiler": "^1.1.3",
"immer": "^7.0.8",
"mocha": "^8.1.3",
"openzeppelin-contracts": "https://github.com/AntonD3/openzeppelin-contracts.git#v3.4.1-solc-0.7-2-zksync-era",
"prettier": "^2.1.1",
"swap-router-contracts": "https://github.com/AntonD3/swap-router-contracts.git#v1.1.0-zksync-era",
"ts-node": "^9.0.0",
"typescript": "^4.0.2",
"v3-periphery-1_3_0": "npm:@uniswap/v3-periphery@1.3.0"
"v3-core": "https://github.com/AntonD3/v3-core.git#v1.0.0-zksync-era",
"v3-periphery": "https://github.com/AntonD3/v3-periphery.git#v1.1.1-zksync-era",
"v3-periphery-1_3_0": "https://github.com/AntonD3/v3-periphery.git#v1.3.0-zksync-era",
"v3-staker": "https://github.com/AntonD3/v3-staker.git#v1.0.2-zksync-era",
"zksync-web3": "^0.14.3"
}
}
4 changes: 2 additions & 2 deletions src/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Signer } from '@ethersproject/abstract-signer'
import { Wallet } from 'zksync-web3'
import { BigNumber } from '@ethersproject/bignumber'
import { migrate } from './migrate'
import { MigrationState, MigrationStep, StepOutput } from './migrations'
Expand Down Expand Up @@ -47,7 +47,7 @@ export default function deploy({
v2CoreFactoryAddress,
ownerAddress,
}: {
signer: Signer
signer: Wallet
gasPrice: number | undefined
weth9Address: string
nativeCurrencyLabelBytes: string
Expand Down
4 changes: 2 additions & 2 deletions src/migrations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Signer } from '@ethersproject/abstract-signer'
import { Wallet } from 'zksync-web3'
import { BigNumber } from '@ethersproject/bignumber'
import { GenericMigrationStep } from './migrate'

Expand All @@ -20,7 +20,7 @@ export interface MigrationState {
export type StepOutput = { message: string; hash?: string; address?: string }

export type MigrationConfig = {
signer: Signer
signer: Wallet
gasPrice: BigNumber | undefined
weth9Address: string
nativeCurrencyLabelBytes: string
Expand Down
4 changes: 2 additions & 2 deletions src/steps/add-1bp-fee-tier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import UniswapV3Factory from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
import { Contract } from '@ethersproject/contracts'
import UniswapV3Factory from 'v3-core/artifacts-zk/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
import { Contract } from 'zksync-web3'
import { MigrationStep } from '../migrations'

const ONE_BP_FEE = 100
Expand Down
7 changes: 5 additions & 2 deletions src/steps/deploy-multicall2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import UniswapInterfaceMulticall from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
import UniswapInterfaceMulticall from 'v3-periphery/artifacts-zk/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
import createDeployContractStep from './meta/createDeployContractStep'
import {ZkSyncArtifact} from "@matterlabs/hardhat-zksync-deploy/src/types";

export const DEPLOY_MULTICALL2 = createDeployContractStep({
key: 'multicall2Address',
artifact: UniswapInterfaceMulticall,
async computeArtifact() {
return UniswapInterfaceMulticall as ZkSyncArtifact
}
})
2 changes: 1 addition & 1 deletion src/steps/deploy-nft-descriptor-library-v1_3_0.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import NFTDescriptor from 'v3-periphery-1_3_0/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json'
import NFTDescriptor from 'v3-periphery-1_3_0/artifacts-zk/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json'
import createDeployLibraryStep from './meta/createDeployLibraryStep'

export const DEPLOY_NFT_DESCRIPTOR_LIBRARY_V1_3_0 = createDeployLibraryStep({
Expand Down
14 changes: 9 additions & 5 deletions src/steps/deploy-nft-position-descriptor-v1_3_0.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import NonfungibleTokenPositionDescriptor from 'v3-periphery-1_3_0/artifacts/contracts/NonfungibleTokenPositionDescriptor.sol/NonfungibleTokenPositionDescriptor.json'
import createDeployContractStep from './meta/createDeployContractStep'
const hre = require("hardhat")

export const DEPLOY_NFT_POSITION_DESCRIPTOR_V1_3_0 = createDeployContractStep({
key: 'nonfungibleTokenPositionDescriptorAddressV1_3_0',
artifact: NonfungibleTokenPositionDescriptor,
computeLibraries(state) {
async computeArtifact(state) {
if (state.nftDescriptorLibraryAddressV1_3_0 === undefined) {
throw new Error('NFTDescriptor library missing')
}
return {
NFTDescriptor: state.nftDescriptorLibraryAddressV1_3_0,
hre.config.zksolc.settings.libraries = {
"v3-periphery-1_3_0/contracts/libraries/NFTDescriptor.sol": {
NFTDescriptor: state.nftDescriptorLibraryAddressV1_3_0,
},
}
hre.config.dependencyCompiler.paths = ['v3-periphery-1_3_0/contracts/NonfungibleTokenPositionDescriptor.sol']
await hre.run("compile")
return hre.artifacts.readArtifactSync('NonfungibleTokenPositionDescriptor')
},
computeArguments(_, { weth9Address, nativeCurrencyLabelBytes }) {
return [weth9Address, nativeCurrencyLabelBytes]
Expand Down
7 changes: 5 additions & 2 deletions src/steps/deploy-nonfungible-position-manager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import NonfungiblePositionManager from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import NonfungiblePositionManager from 'v3-periphery/artifacts-zk/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import createDeployContractStep from './meta/createDeployContractStep'
import {ZkSyncArtifact} from "@matterlabs/hardhat-zksync-deploy/src/types";

export const DEPLOY_NONFUNGIBLE_POSITION_MANAGER = createDeployContractStep({
key: 'nonfungibleTokenPositionManagerAddress',
artifact: NonfungiblePositionManager,
async computeArtifact() {
return NonfungiblePositionManager as ZkSyncArtifact
},
computeArguments(state, config) {
if (state.v3CoreFactoryAddress === undefined) {
throw new Error('Missing V3 Core Factory')
Expand Down
7 changes: 5 additions & 2 deletions src/steps/deploy-proxy-admin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import ProxyAdmin from '@openzeppelin/contracts/build/contracts/ProxyAdmin.json'
import ProxyAdmin from 'openzeppelin-contracts/artifacts-zk/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json'
import createDeployContractStep from './meta/createDeployContractStep'
import {ZkSyncArtifact} from "@matterlabs/hardhat-zksync-deploy/src/types";

export const DEPLOY_PROXY_ADMIN = createDeployContractStep({
key: 'proxyAdminAddress',
artifact: ProxyAdmin,
async computeArtifact() {
return ProxyAdmin as ZkSyncArtifact
},
})
7 changes: 5 additions & 2 deletions src/steps/deploy-quoter-v2.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import QuoterV2 from '@uniswap/swap-router-contracts/artifacts/contracts/lens/QuoterV2.sol/QuoterV2.json'
import QuoterV2 from 'swap-router-contracts/artifacts-zk/contracts/lens/QuoterV2.sol/QuoterV2.json'
import createDeployContractStep from './meta/createDeployContractStep'
import {ZkSyncArtifact} from "@matterlabs/hardhat-zksync-deploy/src/types";

export const DEPLOY_QUOTER_V2 = createDeployContractStep({
key: 'quoterV2Address',
artifact: QuoterV2,
async computeArtifact() {
return QuoterV2 as ZkSyncArtifact
},
computeArguments(state, config) {
if (state.v3CoreFactoryAddress === undefined) {
throw new Error('Missing V3 Core Factory')
Expand Down
7 changes: 5 additions & 2 deletions src/steps/deploy-tick-lens.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import TickLens from '@uniswap/v3-periphery/artifacts/contracts/lens/TickLens.sol/TickLens.json'
import TickLens from 'v3-periphery/artifacts-zk/contracts/lens/TickLens.sol/TickLens.json'
import createDeployContractStep from './meta/createDeployContractStep'
import {ZkSyncArtifact} from "@matterlabs/hardhat-zksync-deploy/src/types";

export const DEPLOY_TICK_LENS = createDeployContractStep({
key: 'tickLensAddress',
artifact: TickLens,
async computeArtifact() {
return TickLens as ZkSyncArtifact
},
})
Loading