Skip to content

Commit 3b5c159

Browse files
authored
Add zksync deployment files (#450)
1 parent c92329c commit 3b5c159

File tree

12 files changed

+4675
-4026
lines changed

12 files changed

+4675
-4026
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
MIGRATIONS_DIR=./migrations/prod-receiver
2-
MIGRATIONS_NETWORK=zksync_testnet
2+
MIGRATIONS_NETWORK=zksync_goerli
33
WORMHOLE_CHAIN_NAME=zksync
44
CLUSTER=testnet
55
VALID_TIME_PERIOD_SECONDS=60

ethereum/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ cache
55
.openzeppelin
66
*mnemonic*
77
!devnet-mnemonic.txt
8+
cache-zk
9+
artifacts-zk

ethereum/Deploying.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ This is the deployment process:
8282
need to approve the created transactions. Links to the multisig transactions are printed during the
8383
script execution and you can use them. You need to run the script when the transactions are approved.
8484
If the deployment script runs successfully you should see many ✅s and no ❌s with a successful message.
85+
Please note that if you need to deploy/upgrade a zkSync network contract, you should deploy/upgrade it manually first
86+
as described below.
8587
7. On first time deployments for a network with Wormhole Receiver contract, run this command:
8688
```bash
8789
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
161163
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.
162164
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
163165
[here](https://chainlist.org/)
166+
167+
# Deploy/Upgrade on zkSync networks
168+
169+
Although zkSync is EVM compatible, their binary format is different than solc output. So, we need to use their libraries to
170+
compile it to their binary format (zk-solc) and deploy it. As of this writing they only support hardhat. To deploy a fresh
171+
contract or a new contract do the following steps in addition to the steps described above:
172+
173+
1. Update the [`hardhad.config.ts`](./hardhat.config.ts) file.
174+
2. Add the configuration files to `truffle-config.js` and `.env.prod.<network>` file as described above. Truffle
175+
config is required as the above deployment script still works in changing the contract (except upgrades).
176+
3. Run `npx hardhat compile` to compile the contracts.
177+
4. If you wish to deploy the contract run `npx hardhat deploy-zksync --script deploy/zkSyncDeploy` to deploy it to the new network. Otherwise
178+
run `npx hardhat deploy-zksync --script deploy/zkSyncDeployNewPythImpl.ts` to get a new implementation address. Then put it in
179+
`.<network>.new_impl` file and run the deployment script to handle the rest of the changes.

ethereum/deploy.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ while [[ $# -ne 0 ]]; do
3131
# If it is a new chain you are deploying to, create a new env file and commit it to the repo.
3232
rm -f .env; ln -s .env.prod.$NETWORK .env && set -o allexport && source .env set && set +o allexport
3333

34-
echo "Migrating..."
35-
npx truffle migrate --network $MIGRATIONS_NETWORK
36-
37-
echo "Deployment to $NETWORK finished successfully"
34+
if [[ $NETWORK == zksync* ]]; then
35+
echo "Skipping truffle migration on $NETWORK. If you wish to deploy a fresh contract read Deploying.md."
36+
else
37+
echo "Migrating..."
38+
npx truffle migrate --network $MIGRATIONS_NETWORK
39+
echo "Deployment to $NETWORK finished successfully"
40+
fi
3841

3942
echo "=========== Syncing contract state ==========="
4043
npx truffle exec scripts/syncPythState.js --network $MIGRATIONS_NETWORK || echo "Syncing failed/incomplete.. skipping"

ethereum/deploy/zkSyncDeploy.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { utils, Wallet } from "zksync-web3";
2+
import { HardhatRuntimeEnvironment } from "hardhat/types";
3+
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
4+
import loadEnv from "../scripts/loadEnv";
5+
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
6+
import { assert } from "chai";
7+
import { writeFileSync } from "fs";
8+
9+
loadEnv("./");
10+
11+
function envOrErr(name: string): string {
12+
const res = process.env[name];
13+
if (res === undefined) {
14+
throw new Error(`${name} environment variable is not set.`);
15+
}
16+
return res;
17+
}
18+
19+
export default async function (hre: HardhatRuntimeEnvironment) {
20+
// Initialize the wallet.
21+
const wallet = Wallet.fromMnemonic(envOrErr("MNEMONIC"));
22+
23+
// Create deployer object and load the artifact of the contract we want to deploy.
24+
const deployer = new Deployer(hre, wallet);
25+
26+
// Deposit some funds to L2 in order to be able to perform L2 transactions. Uncomment
27+
// this if the deployment account is unfunded.
28+
//
29+
// const depositAmount = ethers.utils.parseEther("0.005");
30+
// const depositHandle = await deployer.zkWallet.deposit({
31+
// to: deployer.zkWallet.address,
32+
// token: utils.ETH_ADDRESS,
33+
// amount: depositAmount,
34+
// });
35+
// // Wait until the deposit is processed on zkSync
36+
// await depositHandle.wait();
37+
38+
// Deploy WormholeReceiver contract.
39+
const initialSigners = JSON.parse(envOrErr("INIT_SIGNERS"));
40+
const whGovernanceChainId = envOrErr("INIT_GOV_CHAIN_ID");
41+
const whGovernanceContract = envOrErr("INIT_GOV_CONTRACT"); // bytes32
42+
43+
const chainName = envOrErr("WORMHOLE_CHAIN_NAME");
44+
const wormholeReceiverChainId = CHAINS[chainName];
45+
assert(wormholeReceiverChainId !== undefined);
46+
47+
const receiverSetupArtifact = await deployer.loadArtifact("ReceiverSetup");
48+
const receiverImplArtifact = await deployer.loadArtifact(
49+
"ReceiverImplementation"
50+
);
51+
const wormholeReceiverArtifact = await deployer.loadArtifact(
52+
"WormholeReceiver"
53+
);
54+
55+
const receiverSetupContract = await deployer.deploy(receiverSetupArtifact);
56+
57+
// deploy implementation
58+
const receiverImplContract = await deployer.deploy(receiverImplArtifact);
59+
60+
// encode initialisation data
61+
const whInitData = receiverSetupContract.interface.encodeFunctionData(
62+
"setup",
63+
[
64+
receiverImplContract.address,
65+
initialSigners,
66+
wormholeReceiverChainId,
67+
whGovernanceChainId,
68+
whGovernanceContract,
69+
]
70+
);
71+
72+
// deploy proxy
73+
const wormholeReceiverContract = await deployer.deploy(
74+
wormholeReceiverArtifact,
75+
[receiverSetupContract.address, whInitData]
76+
);
77+
78+
console.log(
79+
`Deployed WormholeReceiver on ${wormholeReceiverContract.address}`
80+
);
81+
82+
// Deploy Pyth contract.
83+
const emitterChainIds = [
84+
envOrErr("SOLANA_CHAIN_ID"),
85+
envOrErr("PYTHNET_CHAIN_ID"),
86+
];
87+
const emitterAddresses = [
88+
envOrErr("SOLANA_EMITTER"),
89+
envOrErr("PYTHNET_EMITTER"),
90+
];
91+
const governanceChainId = envOrErr("GOVERNANCE_CHAIN_ID");
92+
const governanceEmitter = envOrErr("GOVERNANCE_EMITTER");
93+
// Default value for this field is 0
94+
const governanceInitialSequence = Number(
95+
process.env.GOVERNANCE_INITIAL_SEQUENCE ?? "0"
96+
);
97+
98+
const validTimePeriodSeconds = Number(envOrErr("VALID_TIME_PERIOD_SECONDS"));
99+
const singleUpdateFeeInWei = Number(envOrErr("SINGLE_UPDATE_FEE_IN_WEI"));
100+
101+
const pythImplArtifact = await deployer.loadArtifact("PythUpgradable");
102+
const pythProxyArtifact = await deployer.loadArtifact("ERC1967Proxy");
103+
104+
const pythImplContract = await deployer.deploy(pythImplArtifact);
105+
106+
const pythInitData = pythImplContract.interface.encodeFunctionData(
107+
"initialize",
108+
[
109+
wormholeReceiverContract.address,
110+
emitterChainIds,
111+
emitterAddresses,
112+
governanceChainId,
113+
governanceEmitter,
114+
governanceInitialSequence,
115+
validTimePeriodSeconds,
116+
singleUpdateFeeInWei,
117+
]
118+
);
119+
120+
const pythProxyContract = await deployer.deploy(pythProxyArtifact, [
121+
pythImplContract.address,
122+
pythInitData,
123+
]);
124+
125+
console.log(`Deployed Pyth contract on ${pythProxyContract.address}`);
126+
127+
const networkId = hre.network.config.chainId;
128+
const registryPath = `networks/${networkId}.json`;
129+
console.log(`Saving addresses in ${registryPath}`);
130+
writeFileSync(
131+
registryPath,
132+
JSON.stringify(
133+
[
134+
{
135+
contractName: "WormholeReceiver",
136+
address: wormholeReceiverContract.address,
137+
},
138+
{
139+
contractName: "PythUpgradable",
140+
address: pythProxyContract.address,
141+
},
142+
],
143+
null,
144+
2
145+
)
146+
);
147+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { utils, Wallet } from "zksync-web3";
2+
import { HardhatRuntimeEnvironment } from "hardhat/types";
3+
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
4+
import loadEnv from "../scripts/loadEnv";
5+
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
6+
import { assert } from "chai";
7+
import { writeFileSync } from "fs";
8+
import { ethers } from "ethers";
9+
10+
loadEnv("./");
11+
12+
function envOrErr(name: string): string {
13+
const res = process.env[name];
14+
if (res === undefined) {
15+
throw new Error(`${name} environment variable is not set.`);
16+
}
17+
return res;
18+
}
19+
20+
export default async function (hre: HardhatRuntimeEnvironment) {
21+
// Initialize the wallet.
22+
const wallet = Wallet.fromMnemonic(envOrErr("MNEMONIC"));
23+
24+
// Create deployer object and load the artifact of the contract we want to deploy.
25+
const deployer = new Deployer(hre, wallet);
26+
27+
// Deposit some funds to L2 in order to be able to perform L2 transactions. Uncomment
28+
// this if the deployment account is unfunded.
29+
//
30+
// const depositAmount = ethers.utils.parseEther("0.005");
31+
// const depositHandle = await deployer.zkWallet.deposit({
32+
// to: deployer.zkWallet.address,
33+
// token: utils.ETH_ADDRESS,
34+
// amount: depositAmount,
35+
// });
36+
// // Wait until the deposit is processed on zkSync
37+
// await depositHandle.wait();
38+
39+
const pythImplArtifact = await deployer.loadArtifact("PythUpgradable");
40+
const pythImplContract = await deployer.deploy(pythImplArtifact);
41+
42+
console.log(
43+
`Deployed Pyth implementation contract on ${pythImplContract.address}`
44+
);
45+
console.log(
46+
"Please use this address as the candidate new implementation in the deployment script."
47+
);
48+
}

ethereum/hardhat.config.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
require("@matterlabs/hardhat-zksync-deploy");
2+
require("@matterlabs/hardhat-zksync-solc");
3+
4+
module.exports = {
5+
zksolc: {
6+
version: "1.2.0",
7+
compilerSource: "binary",
8+
settings: {
9+
optimizer: {
10+
enabled: true,
11+
},
12+
},
13+
},
14+
defaultNetwork: "zkTestnet",
15+
networks: {
16+
zkTestnet: {
17+
url: "https://zksync2-testnet.zksync.dev", // URL of the zkSync network RPC
18+
ethNetwork: "goerli", // Can also be the RPC URL of the Ethereum network (e.g. `https://goerli.infura.io/v3/<API_KEY>`)
19+
zksync: true,
20+
chainId: 280,
21+
},
22+
},
23+
solidity: {
24+
version: "0.8.4",
25+
settings: {
26+
optimizer: {
27+
enabled: true,
28+
runs: 10000,
29+
},
30+
},
31+
},
32+
};

ethereum/networks/280.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"contractName": "WormholeReceiver",
4+
"address": "0x02C404128Ba4b83f4Ea8c134Ca30A7Aa07aac535"
5+
},
6+
{
7+
"contractName": "PythUpgradable",
8+
"address": "0xF532F2C1bB7b67E08f7D8B76f9fF804D0831725e"
9+
}
10+
]

0 commit comments

Comments
 (0)