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

Upgrade the package to ethers v6 #404

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v15.6.0
v20
2 changes: 1 addition & 1 deletion artifacts/bytecode.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3
0x604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3
12 changes: 6 additions & 6 deletions deploy/compile-zk.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { utils, Wallet, Provider, EIP712Signer, types } from "zksync-web3";
import * as ethers from "ethers";
import * as ethers from "ethers-v5";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import dotenv from "dotenv";
Expand Down Expand Up @@ -83,11 +83,11 @@ export default async function signDeployFactoryContractTX(hre: HardhatRuntimeEnv
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
fs.writeFileSync(path.join(dir, "deployment.json"), JSON.stringify({
gasPrice: factoryTx.gasPrice.toNumber(),
gasLimit: factoryTx.gasLimit.toNumber(),
signerAddress: factoryTx.from,
transaction: rawTx,
fs.writeFileSync(path.join(dir, "deployment.json"), JSON.stringify({
gasPrice: factoryTx.gasPrice.toNumber(),
gasLimit: factoryTx.gasLimit.toNumber(),
signerAddress: factoryTx.from,
transaction: rawTx,
address: contractAddress
}, null, 4));
}
23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,19 @@
"@matterlabs/hardhat-zksync-deploy": "^0.6.1",
"@matterlabs/hardhat-zksync-solc": "^0.3.16",
"@matterlabs/zksync-contracts": "^0.6.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.21",
"@types/yargs": "^15.0.10",
"argv": "^0.0.2",
"axios": "^0.21.1",
"dotenv": "^8.0.0",
"ethers": "^5.7.0",
"hardhat": "^2.12.0",
"@types/mocha": "^10.0.6",
"@types/node": "^20.11.30",
"@types/yargs": "^17.0.32",
"argv": "^0.0.3",
"axios": "^1.6.8",
"dotenv": "^16.4.5",
"ethers": "^6.11.1",
"ethers-v5": "npm:[email protected]",
"hardhat": "^2.22.2",
"solc": "0.5.8",
"ts-node": "^9.1.1",
"typescript": "^4.1.3",
"yargs": "^17.3.1",
"ts-node": "^10.9.2",
"typescript": "^5.4.3",
"yargs": "^17.7.2",
"zksync-web3": "^0.14.3"
}
}
126 changes: 71 additions & 55 deletions scripts/common.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,97 @@
import { ethers } from 'ethers';
import * as path from 'path'
import { promises as filesystem } from 'fs'
import { CompilerOutputContract } from 'solc'
import { arrayFromHexString, compileContracts } from './utils';
import { ethers } from "ethers"
import * as path from "path"
import { promises as filesystem } from "fs"
import { CompilerOutputContract } from "solc"
import {compileContracts, hexPrefix} from "./utils"

const signer = "0xE1CB04A0fA36DdD16a06ea828007E35e1a3cBC37";
const signer = "0xE1CB04A0fA36DdD16a06ea828007E35e1a3cBC37"

export interface DeploymentEstimation {
chainId: number
gasLimit: ethers.BigNumber
gasPrice: ethers.BigNumber
chainId: bigint
gasLimit: ethers.BigNumberish
gasPrice: ethers.BigNumberish
}

export async function ensureDirectoryExists(absoluteDirectoryPath: string) {
try {
await filesystem.mkdir(absoluteDirectoryPath)
} catch (error) {
if (error.code === 'EEXIST') return
throw error
}
try {
await filesystem.mkdir(absoluteDirectoryPath)
} catch (error) {
if (error != null && typeof error === "object" && "code" in error && error.code === "EEXIST")
return
throw error
}
}

async function writeBytecode(bytecode: string) {
const filePath = path.join(__dirname, '..', 'artifacts', `bytecode.txt`)
await filesystem.writeFile(filePath, bytecode, { encoding: 'utf8', flag: 'w' })
const filePath = path.join(__dirname, "..", "artifacts", `bytecode.txt`)
await filesystem.writeFile(filePath, bytecode, { encoding: "utf8", flag: "w" })
}

async function writeFactoryDeployerTransaction(contract: CompilerOutputContract, chainId: number, overwrites?: { gasPrice?: number, gasLimit?: number, nonce?: number}) {
const deploymentBytecode = contract.evm.bytecode.object
async function writeFactoryDeployerTransaction(deploymentBytecode: string,
chainId: bigint,
overwrites?: { gasPrice?: ethers.BigNumberish; gasLimit?: ethers.BigNumberish; nonce?: number }
) {
const nonce = overwrites?.nonce || 0
const gasPrice = overwrites?.gasPrice != undefined ? overwrites.gasPrice : 100 * 10 ** 9
// actual gas costs last measure: 59159; we don't want to run too close though because gas costs can change in forks and we want our address to be retained
const gasLimit = overwrites?.gasLimit || 100000
const value = 0

const nonce = overwrites?.nonce || 0
const gasPrice = overwrites?.gasPrice != undefined ? overwrites.gasPrice : 100*10**9
// actual gas costs last measure: 59159; we don't want to run too close though because gas costs can change in forks and we want our address to be retained
const gasLimit = overwrites?.gasLimit || 100000
const value = 0
const data = arrayFromHexString(deploymentBytecode)
if (!process.env.MNEMONIC) throw Error("MNEMONIC is required")
const signer = ethers.HDNodeWallet.fromPhrase(process.env.MNEMONIC!!)
const signedEncodedTransaction = await signer.signTransaction({
nonce,
gasPrice,
gasLimit,
value,
data: deploymentBytecode,
chainId,
})
const signerAddress = await signer.getAddress()
const contractAddress = ethers.getCreateAddress({ from: signerAddress, nonce })

if (!process.env.MNEMONIC) throw Error("MNEMONIC is required")
const signer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC!!)
const signedEncodedTransaction = await signer.signTransaction({
nonce, gasPrice, gasLimit, value, data, chainId
})
const signerAddress = await signer.getAddress()
const contractAddress = ethers.utils.getContractAddress({ from: signerAddress, nonce } )

const filePath = path.join(__dirname, "..", "artifacts", `${chainId}`, "deployment.json")
const fileContents = `{
const filePath = path.join(__dirname, "..", "artifacts", `${chainId}`, "deployment.json")
const fileContents = `{
"gasPrice": ${gasPrice},
"gasLimit": ${gasLimit},
"signerAddress": "${signerAddress}",
"transaction": "${signedEncodedTransaction}",
"address": "${contractAddress}"
}
`
await filesystem.writeFile(filePath, fileContents, { encoding: 'utf8', flag: 'w' })
await filesystem.writeFile(filePath, fileContents, { encoding: "utf8", flag: "w" })
}

export async function estimateDeploymentTransaction(rpcUrl: string): Promise<DeploymentEstimation> {
const provider = new ethers.providers.JsonRpcProvider(rpcUrl)
const chainId = (await provider.getNetwork()).chainId
console.log({chainId})
const compilerOutput = await compileContracts()
const contract = compilerOutput.contracts['deterministic-deployment-proxy.yul']['Proxy']
const data = "0x" + contract.evm.bytecode.object
const gasLimit = await provider.estimateGas({ data, from: signer })
console.log({estimate: gasLimit.toString() })
const gasPrice = await provider.getGasPrice()
console.log({gasPriceGwei: ethers.utils.formatUnits(gasPrice, "gwei"), gasPrice: gasPrice.toString() })
console.log({requiredFunds: ethers.utils.formatUnits(gasPrice.mul(gasLimit), "ether") })
return { chainId, gasLimit, gasPrice }
const provider = new ethers.JsonRpcProvider(rpcUrl)
const chainId = (await provider.getNetwork()).chainId
console.log({ chainId })
const compilerOutput = await compileContracts()
const contract = compilerOutput.contracts["deterministic-deployment-proxy.yul"]["Proxy"]
const data = "0x" + contract.evm.bytecode.object
const gasLimit = await provider.estimateGas({ data, from: signer })
console.log({ estimate: gasLimit.toString() })
const { gasPrice } = await provider.getFeeData()

if (!gasPrice) throw Error("Couldn't fetch the gas price")

console.log({
gasPriceGwei: ethers.formatUnits(gasPrice, "gwei"),
gasPrice: gasPrice.toString(),
})
console.log({ requiredFunds: ethers.formatUnits(gasPrice * gasLimit, "ether") })
return { chainId, gasLimit, gasPrice }
}

export async function createDeploymentTransaction(chainId: number, options?: { gasPrice?: number, gasLimit?: number, nonce?: number}) {
const compilerOutput = await compileContracts()
const contract = compilerOutput.contracts['deterministic-deployment-proxy.yul']['Proxy']
await ensureDirectoryExists(path.join(__dirname, '..', 'artifacts'))
await ensureDirectoryExists(path.join(__dirname, '..', 'artifacts', `${chainId}`))
await writeBytecode(contract.evm.bytecode.object)
await writeFactoryDeployerTransaction(contract, chainId, options)
export async function createDeploymentTransaction(
chainId: bigint,
options?: { gasPrice?: ethers.BigNumberish; gasLimit?: ethers.BigNumberish; nonce?: number }
) {
const compilerOutput = await compileContracts()
const contract = compilerOutput.contracts["deterministic-deployment-proxy.yul"]["Proxy"]
await ensureDirectoryExists(path.join(__dirname, "..", "artifacts"))
await ensureDirectoryExists(path.join(__dirname, "..", "artifacts", `${chainId}`))
const hexPrefixedBytecode = hexPrefix(contract.evm.bytecode.object)
await writeBytecode(hexPrefixedBytecode)
await writeFactoryDeployerTransaction(hexPrefixedBytecode, chainId, options)
}
23 changes: 11 additions & 12 deletions scripts/compile.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@

import dotenv from "dotenv";
import yargs from 'yargs/yargs';
import { runScript } from './utils';
import { createDeploymentTransaction } from "./common";
import dotenv from "dotenv"
import yargs from "yargs/yargs"
import { runScript } from "./utils"
import { createDeploymentTransaction } from "./common"

dotenv.config()

async function runCreateDeploymentTransaction() {
const chainId: number = parseInt(process.argv[2])
const options = yargs(process.argv.slice(3)).options({
"gasPrice": { type: "number" },
"gasLimit": { type: "number" },
"nonce": { type: "number" }
}).argv
await createDeploymentTransaction(chainId, options)
const chainId: number = parseInt(process.argv[2])
const options = await yargs(process.argv.slice(3)).options({
gasPrice: { type: "number" },
gasLimit: { type: "number" },
nonce: { type: "number" },
}).argv
await createDeploymentTransaction(chainId, options)
}

runScript(runCreateDeploymentTransaction)
6 changes: 3 additions & 3 deletions scripts/estimate-compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ async function runEstimateAndCompile() {
if (rpcUrl === undefined) throw "RPC environment variable must be defined"
const deploymentEstimation: DeploymentEstimation = await estimateDeploymentTransaction(rpcUrl)
const options = {
gasPrice: deploymentEstimation.gasPrice.toNumber(),
gasLimit: Math.round(deploymentEstimation.gasLimit.toNumber() * 1.4),
gasPrice: deploymentEstimation.gasPrice,
gasLimit: BigInt(deploymentEstimation.gasLimit) * 14n / 10n,
nonce: 0
}
await createDeploymentTransaction(deploymentEstimation.chainId, options)
}

runScript(runEstimateAndCompile)
runScript(runEstimateAndCompile)
2 changes: 1 addition & 1 deletion scripts/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dotenv.config()

async function checkDeploymentStatus() {
const rpcUrl = process.env.RPC
const provider = new ethers.providers.JsonRpcProvider(rpcUrl)
const provider = new ethers.JsonRpcProvider(rpcUrl)
const chainId = (await provider.getNetwork()).chainId
console.log({chainId})
const filePath = path.join(__dirname, "..", "artifacts", `${chainId}`, "deployment.json")
Expand Down
4 changes: 2 additions & 2 deletions scripts/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ dotenv.config()

async function submitDeploymentTransaction() {
const rpcUrl = process.env.RPC
const provider = new ethers.providers.JsonRpcProvider(rpcUrl)
const provider = new ethers.JsonRpcProvider(rpcUrl)
const chainId = (await provider.getNetwork()).chainId
console.log({chainId})
const filePath = path.join(__dirname, "..", "artifacts", `${chainId}`, "deployment.json")
const deploymentData = JSON.parse(await filesystem.readFile(filePath, { encoding: 'utf8' }))

const submittedTx = await provider.send("eth_sendRawTransaction", [deploymentData.transaction])
console.log("Transaction Hash", submittedTx)
}
Expand Down
11 changes: 3 additions & 8 deletions scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ export function runScript(script: () => Promise<any>) {
})
}

export function arrayFromHexString(value: string): Uint8Array {
const normalized = (value.length % 2) ? `0${value}` : value
const bytes: number[] = []
for (let i = 0; i < normalized.length; i += 2) {
bytes.push(Number.parseInt(`${normalized[i]}${normalized[i+1]}`, 16))
}
return new Uint8Array(bytes)
}
export function hexPrefix(value: string): string {
return value.startsWith("0x") ? value : `0x${value}`
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es2018",
"target": "es2020",
"module": "commonjs",
"lib": ["es2020"],
"declaration": true,
Expand Down
Loading