Add zksync deployment files (#450)

This commit is contained in:
Ali Behjati 2023-01-03 17:40:17 +01:00 committed by GitHub
parent c92329c7c4
commit 3b5c159e0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 4431 additions and 3782 deletions

View File

@ -1,5 +1,5 @@
MIGRATIONS_DIR=./migrations/prod-receiver MIGRATIONS_DIR=./migrations/prod-receiver
MIGRATIONS_NETWORK=zksync_testnet MIGRATIONS_NETWORK=zksync_goerli
WORMHOLE_CHAIN_NAME=zksync WORMHOLE_CHAIN_NAME=zksync
CLUSTER=testnet CLUSTER=testnet
VALID_TIME_PERIOD_SECONDS=60 VALID_TIME_PERIOD_SECONDS=60

2
ethereum/.gitignore vendored
View File

@ -5,3 +5,5 @@ cache
.openzeppelin .openzeppelin
*mnemonic* *mnemonic*
!devnet-mnemonic.txt !devnet-mnemonic.txt
cache-zk
artifacts-zk

View File

@ -82,6 +82,8 @@ This is the deployment process:
need to approve the created transactions. Links to the multisig transactions are printed during the need to approve the created transactions. Links to the multisig transactions are printed during the
script execution and you can use them. You need to run the script when the transactions are approved. script execution and you can use them. You need to run the script when the transactions are approved.
If the deployment script runs successfully you should see many ✅s and no ❌s with a successful message. If the deployment script runs successfully you should see many ✅s and no ❌s with a successful message.
Please note that if you need to deploy/upgrade a zkSync network contract, you should deploy/upgrade it manually first
as described below.
7. On first time deployments for a network with Wormhole Receiver contract, run this command: 7. On first time deployments for a network with Wormhole Receiver contract, run this command:
```bash ```bash
npm run receiver-submit-guardian-sets -- --network <network> npm run receiver-submit-guardian-sets -- --network <network>
@ -161,3 +163,17 @@ It will create a new file `PythUpgradable_merged.sol` which you can use in the e
migration. However, if it happens, you can comment out the part that is already ran (you can double check in the explorer), and re-run the migration. migration. However, if it happens, you can comment out the part that is already ran (you can double check in the explorer), and re-run the migration.
You can avoid gas problems by choosing a much higher gas than what is showed on the network gas tracker. Also, you can find other rpc nodes from You can avoid gas problems by choosing a much higher gas than what is showed on the network gas tracker. Also, you can find other rpc nodes from
[here](https://chainlist.org/) [here](https://chainlist.org/)
# Deploy/Upgrade on zkSync networks
Although zkSync is EVM compatible, their binary format is different than solc output. So, we need to use their libraries to
compile it to their binary format (zk-solc) and deploy it. As of this writing they only support hardhat. To deploy a fresh
contract or a new contract do the following steps in addition to the steps described above:
1. Update the [`hardhad.config.ts`](./hardhat.config.ts) file.
2. Add the configuration files to `truffle-config.js` and `.env.prod.<network>` file as described above. Truffle
config is required as the above deployment script still works in changing the contract (except upgrades).
3. Run `npx hardhat compile` to compile the contracts.
4. If you wish to deploy the contract run `npx hardhat deploy-zksync --script deploy/zkSyncDeploy` to deploy it to the new network. Otherwise
run `npx hardhat deploy-zksync --script deploy/zkSyncDeployNewPythImpl.ts` to get a new implementation address. Then put it in
`.<network>.new_impl` file and run the deployment script to handle the rest of the changes.

View File

@ -31,10 +31,13 @@ while [[ $# -ne 0 ]]; do
# If it is a new chain you are deploying to, create a new env file and commit it to the repo. # If it is a new chain you are deploying to, create a new env file and commit it to the repo.
rm -f .env; ln -s .env.prod.$NETWORK .env && set -o allexport && source .env set && set +o allexport rm -f .env; ln -s .env.prod.$NETWORK .env && set -o allexport && source .env set && set +o allexport
if [[ $NETWORK == zksync* ]]; then
echo "Skipping truffle migration on $NETWORK. If you wish to deploy a fresh contract read Deploying.md."
else
echo "Migrating..." echo "Migrating..."
npx truffle migrate --network $MIGRATIONS_NETWORK npx truffle migrate --network $MIGRATIONS_NETWORK
echo "Deployment to $NETWORK finished successfully" echo "Deployment to $NETWORK finished successfully"
fi
echo "=========== Syncing contract state ===========" echo "=========== Syncing contract state ==========="
npx truffle exec scripts/syncPythState.js --network $MIGRATIONS_NETWORK || echo "Syncing failed/incomplete.. skipping" npx truffle exec scripts/syncPythState.js --network $MIGRATIONS_NETWORK || echo "Syncing failed/incomplete.. skipping"

View File

@ -0,0 +1,147 @@
import { utils, Wallet } from "zksync-web3";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import loadEnv from "../scripts/loadEnv";
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
import { assert } from "chai";
import { writeFileSync } from "fs";
loadEnv("./");
function envOrErr(name: string): string {
const res = process.env[name];
if (res === undefined) {
throw new Error(`${name} environment variable is not set.`);
}
return res;
}
export default async function (hre: HardhatRuntimeEnvironment) {
// Initialize the wallet.
const wallet = Wallet.fromMnemonic(envOrErr("MNEMONIC"));
// Create deployer object and load the artifact of the contract we want to deploy.
const deployer = new Deployer(hre, wallet);
// Deposit some funds to L2 in order to be able to perform L2 transactions. Uncomment
// this if the deployment account is unfunded.
//
// const depositAmount = ethers.utils.parseEther("0.005");
// const depositHandle = await deployer.zkWallet.deposit({
// to: deployer.zkWallet.address,
// token: utils.ETH_ADDRESS,
// amount: depositAmount,
// });
// // Wait until the deposit is processed on zkSync
// await depositHandle.wait();
// Deploy WormholeReceiver contract.
const initialSigners = JSON.parse(envOrErr("INIT_SIGNERS"));
const whGovernanceChainId = envOrErr("INIT_GOV_CHAIN_ID");
const whGovernanceContract = envOrErr("INIT_GOV_CONTRACT"); // bytes32
const chainName = envOrErr("WORMHOLE_CHAIN_NAME");
const wormholeReceiverChainId = CHAINS[chainName];
assert(wormholeReceiverChainId !== undefined);
const receiverSetupArtifact = await deployer.loadArtifact("ReceiverSetup");
const receiverImplArtifact = await deployer.loadArtifact(
"ReceiverImplementation"
);
const wormholeReceiverArtifact = await deployer.loadArtifact(
"WormholeReceiver"
);
const receiverSetupContract = await deployer.deploy(receiverSetupArtifact);
// deploy implementation
const receiverImplContract = await deployer.deploy(receiverImplArtifact);
// encode initialisation data
const whInitData = receiverSetupContract.interface.encodeFunctionData(
"setup",
[
receiverImplContract.address,
initialSigners,
wormholeReceiverChainId,
whGovernanceChainId,
whGovernanceContract,
]
);
// deploy proxy
const wormholeReceiverContract = await deployer.deploy(
wormholeReceiverArtifact,
[receiverSetupContract.address, whInitData]
);
console.log(
`Deployed WormholeReceiver on ${wormholeReceiverContract.address}`
);
// Deploy Pyth contract.
const emitterChainIds = [
envOrErr("SOLANA_CHAIN_ID"),
envOrErr("PYTHNET_CHAIN_ID"),
];
const emitterAddresses = [
envOrErr("SOLANA_EMITTER"),
envOrErr("PYTHNET_EMITTER"),
];
const governanceChainId = envOrErr("GOVERNANCE_CHAIN_ID");
const governanceEmitter = envOrErr("GOVERNANCE_EMITTER");
// Default value for this field is 0
const governanceInitialSequence = Number(
process.env.GOVERNANCE_INITIAL_SEQUENCE ?? "0"
);
const validTimePeriodSeconds = Number(envOrErr("VALID_TIME_PERIOD_SECONDS"));
const singleUpdateFeeInWei = Number(envOrErr("SINGLE_UPDATE_FEE_IN_WEI"));
const pythImplArtifact = await deployer.loadArtifact("PythUpgradable");
const pythProxyArtifact = await deployer.loadArtifact("ERC1967Proxy");
const pythImplContract = await deployer.deploy(pythImplArtifact);
const pythInitData = pythImplContract.interface.encodeFunctionData(
"initialize",
[
wormholeReceiverContract.address,
emitterChainIds,
emitterAddresses,
governanceChainId,
governanceEmitter,
governanceInitialSequence,
validTimePeriodSeconds,
singleUpdateFeeInWei,
]
);
const pythProxyContract = await deployer.deploy(pythProxyArtifact, [
pythImplContract.address,
pythInitData,
]);
console.log(`Deployed Pyth contract on ${pythProxyContract.address}`);
const networkId = hre.network.config.chainId;
const registryPath = `networks/${networkId}.json`;
console.log(`Saving addresses in ${registryPath}`);
writeFileSync(
registryPath,
JSON.stringify(
[
{
contractName: "WormholeReceiver",
address: wormholeReceiverContract.address,
},
{
contractName: "PythUpgradable",
address: pythProxyContract.address,
},
],
null,
2
)
);
}

View File

@ -0,0 +1,48 @@
import { utils, Wallet } from "zksync-web3";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import loadEnv from "../scripts/loadEnv";
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
import { assert } from "chai";
import { writeFileSync } from "fs";
import { ethers } from "ethers";
loadEnv("./");
function envOrErr(name: string): string {
const res = process.env[name];
if (res === undefined) {
throw new Error(`${name} environment variable is not set.`);
}
return res;
}
export default async function (hre: HardhatRuntimeEnvironment) {
// Initialize the wallet.
const wallet = Wallet.fromMnemonic(envOrErr("MNEMONIC"));
// Create deployer object and load the artifact of the contract we want to deploy.
const deployer = new Deployer(hre, wallet);
// Deposit some funds to L2 in order to be able to perform L2 transactions. Uncomment
// this if the deployment account is unfunded.
//
// const depositAmount = ethers.utils.parseEther("0.005");
// const depositHandle = await deployer.zkWallet.deposit({
// to: deployer.zkWallet.address,
// token: utils.ETH_ADDRESS,
// amount: depositAmount,
// });
// // Wait until the deposit is processed on zkSync
// await depositHandle.wait();
const pythImplArtifact = await deployer.loadArtifact("PythUpgradable");
const pythImplContract = await deployer.deploy(pythImplArtifact);
console.log(
`Deployed Pyth implementation contract on ${pythImplContract.address}`
);
console.log(
"Please use this address as the candidate new implementation in the deployment script."
);
}

View File

@ -0,0 +1,32 @@
require("@matterlabs/hardhat-zksync-deploy");
require("@matterlabs/hardhat-zksync-solc");
module.exports = {
zksolc: {
version: "1.2.0",
compilerSource: "binary",
settings: {
optimizer: {
enabled: true,
},
},
},
defaultNetwork: "zkTestnet",
networks: {
zkTestnet: {
url: "https://zksync2-testnet.zksync.dev", // URL of the zkSync network RPC
ethNetwork: "goerli", // Can also be the RPC URL of the Ethereum network (e.g. `https://goerli.infura.io/v3/<API_KEY>`)
zksync: true,
chainId: 280,
},
},
solidity: {
version: "0.8.4",
settings: {
optimizer: {
enabled: true,
runs: 10000,
},
},
},
};

View File

@ -0,0 +1,10 @@
[
{
"contractName": "WormholeReceiver",
"address": "0x02C404128Ba4b83f4Ea8c134Ca30A7Aa07aac535"
},
{
"contractName": "PythUpgradable",
"address": "0xF532F2C1bB7b67E08f7D8B76f9fF804D0831725e"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -30,20 +30,26 @@
"dependencies": { "dependencies": {
"@certusone/wormhole-sdk": "^0.8.0", "@certusone/wormhole-sdk": "^0.8.0",
"@certusone/wormhole-sdk-wasm": "^0.0.1", "@certusone/wormhole-sdk-wasm": "^0.0.1",
"@matterlabs/hardhat-zksync-deploy": "^0.6.1",
"@matterlabs/hardhat-zksync-solc": "^0.3.13",
"@openzeppelin/contracts": "^4.5.0", "@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/contracts-upgradeable": "^4.5.2", "@openzeppelin/contracts-upgradeable": "^4.5.2",
"@pythnetwork/pyth-sdk-solidity": "^2.2.0", "@pythnetwork/pyth-sdk-solidity": "^2.2.0",
"@pythnetwork/xc-governance-sdk": "file:../third_party/pyth/xc-governance-sdk-js", "@pythnetwork/xc-governance-sdk": "file:../third_party/pyth/xc-governance-sdk-js",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"elliptic": "^6.5.2", "elliptic": "^6.5.2",
"ethers": "^5.6.8", "ethers": "^5.7.2",
"ganache-cli": "^6.12.1", "ganache-cli": "^6.12.1",
"hardhat": "^2.12.5",
"jsonfile": "^4.0.0", "jsonfile": "^4.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"solc": "^0.8.4", "solc": "^0.8.4",
"truffle-contract-size": "^2.0.1", "truffle-contract-size": "^2.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.9.4",
"web3": "^1.2.2", "web3": "^1.2.2",
"web3-eth-abi": "^1.2.2", "web3-eth-abi": "^1.2.2",
"web3-utils": "^1.2.2" "web3-utils": "^1.2.2",
"zksync-web3": "^0.12.3"
} }
} }

View File

@ -215,7 +215,18 @@ async function upgradeContract(proxy, desiredVersion) {
); );
} else { } else {
console.log("Deploying a new implementation..."); console.log("Deploying a new implementation...");
const newImplementation = await PythUpgradable.new();
let newImplementation;
try {
newImplementation = await PythUpgradable.new();
} catch (e) {
console.error(
"Could not deploy the new contract. Please try again. If this is a zkSync " +
"network truffle cannot it and you need to deploy it manually (as described in Deploying.md) "`and store the address on ${implCachePath} file. Then rerun the script.`
);
throw e;
}
console.log(`Tx hash: ${newImplementation.transactionHash}`); console.log(`Tx hash: ${newImplementation.transactionHash}`);
console.log(`New implementation address: ${newImplementation.address}`); console.log(`New implementation address: ${newImplementation.address}`);
fs.writeFileSync(implCachePath, newImplementation.address); fs.writeFileSync(implCachePath, newImplementation.address);

View File

@ -261,7 +261,7 @@ module.exports = {
}, },
network_id: 324, network_id: 324,
}, },
zksync_testnet: { zksync_goerli: {
provider: () => { provider: () => {
return new HDWalletProvider( return new HDWalletProvider(
process.env.MNEMONIC, process.env.MNEMONIC,