Add zksync deployment files (#450)
This commit is contained in:
parent
c92329c7c4
commit
3b5c159e0b
|
@ -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
|
|
@ -5,3 +5,5 @@ cache
|
||||||
.openzeppelin
|
.openzeppelin
|
||||||
*mnemonic*
|
*mnemonic*
|
||||||
!devnet-mnemonic.txt
|
!devnet-mnemonic.txt
|
||||||
|
cache-zk
|
||||||
|
artifacts-zk
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
|
@ -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."
|
||||||
|
);
|
||||||
|
}
|
|
@ -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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"contractName": "WormholeReceiver",
|
||||||
|
"address": "0x02C404128Ba4b83f4Ea8c134Ca30A7Aa07aac535"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"contractName": "PythUpgradable",
|
||||||
|
"address": "0xF532F2C1bB7b67E08f7D8B76f9fF804D0831725e"
|
||||||
|
}
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue