EVM deployment scripts and documentation (#141)

* Make Migrations contract Ownable

* Add prod deployment migrations

* Add BSC Testnet deployment configuration

* Add documentation for deploying contracts to production

* Fix test environment script for deployment to development network

* Fix tilt issues + refactor

Co-authored-by: Ali Behjati <bahjatia@gmail.com>
This commit is contained in:
Tom Pointon 2022-05-13 09:25:35 +01:00 committed by GitHub
parent 941017de4b
commit 4f4bec508e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 170 additions and 31 deletions

View File

@ -73,9 +73,9 @@ spec:
command:
- /bin/sh
- -c
- "npm run migrate &&
npx truffle test test/pyth.js 2>&1 &&
nc -lkp 2000 0.0.0.0"
- "npm run migrate --network development &&
npx truffle test test/pyth.js 2>&1 &&
nc -lkp 2000 0.0.0.0"
readinessProbe:
periodSeconds: 1
failureThreshold: 300

View File

@ -1,2 +1,5 @@
node_modules
build
.openzeppelin
networks
.env

View File

@ -0,0 +1,7 @@
MIGRATIONS_DIR=./migrations/prod
MIGRATIONS_NETWORK=binance_testnet
#Pyth
WORMHOME_BRIDGE_ADDRESS=0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D
PYTH_TO_WORMHOLE_CHAIN_ID=0x1
PYTH_TO_WORMHOLE_EMITTER=0xf346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0

View File

@ -0,0 +1,8 @@
# Migrations Metadata
MIGRATIONS_DIR=./migrations/prod
MIGRATIONS_NETWORK=development
#Pyth
WORMHOME_BRIDGE_ADDRESS=0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D
PYTH_TO_WORMHOLE_CHAIN_ID=0x1
PYTH_TO_WORMHOLE_EMITTER=0x6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25

View File

@ -14,6 +14,6 @@ BRIDGE_INIT_GOV_CHAIN_ID=0x1
BRIDGE_INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
BRIDGE_INIT_WETH=0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E
#Pyth Migrations
#Pyth
PYTH_TO_WORMHOLE_CHAIN_ID=0x1
PYTH_TO_WORMHOLE_EMITTER=8fuAZUxHecYLMC76ZNjYzwRybUiDv9LhkRQsAccEykLr
PYTH_TO_WORMHOLE_EMITTER=0x71f8dcb863d176e2c420ad6610cf687359612b6fb392e0642b0ca6b1f186aa3b

30
ethereum/Deploying.md Normal file
View File

@ -0,0 +1,30 @@
# Deploying Contracts to Production
Running the Truffle migrations in [`migrations/prod`](migrations/prod) will deploy the contracts to production. Truffle stores the address of the deployed contracts in the build artifacts, which can make local development difficult. We use [`truffle-deploy-registry`](https://github.com/MedXProtocol/truffle-deploy-registry) to store the addresses separately from the artifacts, in the [`networks`](networks) directory. When we need to perform operations on the deployed contracts, such as performing additional migrations, we can run `apply-registry -n networks/$NETWORK` to populate the artifacts with the correct addresses.
An example deployment process, for deploying to Binance Smart Chain Testnet:
```bash
# Load the configuration environment variables for deploying to BSC Testnet.
rm -f .env; ln -s .env.prod.binance_testnet .env && set -o allexport && source .env set && set +o allexport
# The Secret Recovery Phrase for the wallet the contract will be deployed from.
export MNEMONIC=...
# Ensure that we deploy a fresh build with up-to-date dependencies.
rm -rf build .openzeppelin node_modules && npm install && npx truffle compile --all
# Merge the network addresses into the artifacts, if some contracts are already deployed.
npx apply-registry -n networks/$MIGRATIONS_NETWORK
# Perform the migration
npx truffle migrate --network $MIGRATIONS_NETWORK
# Running the migration will cause a JSON file to be written to the networks/
# directory, with a filename like 1648198934288.json (the Truffle network ID).
# To make it more obvious which network this corresponds to, move this file
# to networks/$MIGRATIONS_NETWORK.
mkdir -p networks/$MIGRATIONS_NETWORK && mv networks/NETWORK__ID.json networks/$MIGRATIONS_NETWORK
```
As a sanity check, it is recommended to deploy the migrations in `migrations/prod` to the Truffle `development` network first. You can do this by using the configuration values in [`.env.prod.development`](.env.prod.development).

View File

@ -1,19 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract Migrations {
address public owner = msg.sender;
import "@openzeppelin/contracts/access/Ownable.sol";
// Needed for truffle migrate to work correctly.
// Simply stores the last completed migration.
contract Migrations is Ownable {
uint public last_completed_migration;
modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}
function setCompleted(uint completed) public restricted {
function setCompleted(uint completed) public onlyOwner {
last_completed_migration = completed;
}
}
}

View File

@ -0,0 +1,12 @@
const Migrations = artifacts.require("Migrations");
const tdr = require('truffle-deploy-registry');
module.exports = async function (deployer, network) {
await deployer.deploy(Migrations);
let migrationsInstance = await Migrations.deployed();
if (!tdr.isDryRunNetworkName(network)) {
await tdr.appendInstance(migrationsInstance);
}
};

View File

@ -0,0 +1,35 @@
require('dotenv').config({ path: "../.env" });
const bs58 = require("bs58");
const PythUpgradable = artifacts.require("PythUpgradable");
const wormholeBridgeAddress = process.env.WORMHOME_BRIDGE_ADDRESS;
const pyth2WormholeChainId = process.env.PYTH_TO_WORMHOLE_CHAIN_ID;
const pyth2WormholeEmitter = process.env.PYTH_TO_WORMHOLE_EMITTER;
const { deployProxy } = require("@openzeppelin/truffle-upgrades");
const tdr = require('truffle-deploy-registry');
console.log("Wormhole bridge address: " + wormholeBridgeAddress)
console.log("pyth2WormholeEmitter: " + pyth2WormholeEmitter)
console.log("pyth2WormholeChainId: " + pyth2WormholeChainId)
module.exports = async function (deployer, network) {
// Deploy the proxy. This will return an instance of PythUpgradable,
// with the address field corresponding to the fronting ERC1967Proxy.
let proxyInstance = await deployProxy(PythUpgradable,
[
wormholeBridgeAddress,
pyth2WormholeChainId,
pyth2WormholeEmitter
],
{ deployer });
// Add the ERC1967Proxy address to the PythUpgradable contract's
// entry in the registry. This allows us to call upgradeProxy
// functions with the value of PythUpgradable.deployed().address:
// e.g. upgradeProxy(PythUpgradable.deployed().address, NewImplementation)
if (!tdr.isDryRunNetworkName(network)) {
await tdr.appendInstance(proxyInstance);
}
};

View File

@ -5,7 +5,7 @@ const PythUpgradable = artifacts.require("PythUpgradable");
const Wormhole = artifacts.require("Wormhole");
const pyth2WormholeChainId = process.env.PYTH_TO_WORMHOLE_CHAIN_ID;
const pyth2WormholeEmitter = bs58.decode(process.env.PYTH_TO_WORMHOLE_EMITTER); // base58, must fit into bytes32
const pyth2WormholeEmitter = process.env.PYTH_TO_WORMHOLE_EMITTER;
const { deployProxy } = require("@openzeppelin/truffle-upgrades");
@ -17,7 +17,7 @@ module.exports = async function (deployer) {
[
(await Wormhole.deployed()).address,
pyth2WormholeChainId,
"0x" + pyth2WormholeEmitter.toString("hex")
pyth2WormholeEmitter
],
{ deployer });
};

View File

@ -9,7 +9,9 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/contracts-upgradeable": "^4.5.2",
"@pythnetwork/pyth-sdk-solidity": "0.0.3",
"dotenv": "^10.0.0",
"elliptic": "^6.5.2",
"ganache-cli": "^6.12.1",
@ -19,7 +21,6 @@
"devDependencies": {
"@chainsafe/truffle-plugin-abigen": "0.0.1",
"@openzeppelin/cli": "^2.8.2",
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/test-environment": "^0.1.9",
"@openzeppelin/test-helpers": "^0.5.15",
"@openzeppelin/truffle-upgrades": "^1.14.0",
@ -29,6 +30,7 @@
"mocha": "^8.2.1",
"truffle": "^5.5.5",
"truffle-assertions": "^0.9.2",
"truffle-deploy-registry": "^0.5.1",
"truffle-plugin-verify": "^0.5.11"
}
},
@ -2030,8 +2032,7 @@
"node_modules/@openzeppelin/contracts": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz",
"integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==",
"dev": true
"integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA=="
},
"node_modules/@openzeppelin/contracts-upgradeable": {
"version": "4.5.2",
@ -3672,6 +3673,11 @@
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
"dev": true
},
"node_modules/@pythnetwork/pyth-sdk-solidity": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.0.3.tgz",
"integrity": "sha512-4FaoGD4Sizvdm0+8KuQsYzARHa+myNwmFE2GBYxmMcw3zMtwvD7PH0RWM8nK9UyExJ+vyAAth7SbVzyLfN4Yow=="
},
"node_modules/@redux-saga/core": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
@ -32672,6 +32678,27 @@
"node": ">=4"
}
},
"node_modules/truffle-deploy-registry": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/truffle-deploy-registry/-/truffle-deploy-registry-0.5.1.tgz",
"integrity": "sha512-ZvyRpn67J67cWTfN5Z+sIryOirzxOuvpS7WO1WJYx3V1GcJR0gWWEM38KTBoPQ5L98/n7XxWC8+TtkOypKEp6A==",
"dev": true,
"dependencies": {
"chalk": "^2.4.2",
"commander": "^2.19.0",
"mkdirp": "^0.5.1",
"rimraf": "^2.6.3"
},
"bin": {
"apply-registry": "lib/command.js"
}
},
"node_modules/truffle-deploy-registry/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"node_modules/truffle-error": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/truffle-error/-/truffle-error-0.0.5.tgz",
@ -38580,8 +38607,7 @@
"@openzeppelin/contracts": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz",
"integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==",
"dev": true
"integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA=="
},
"@openzeppelin/contracts-upgradeable": {
"version": "4.5.2",
@ -39972,9 +39998,9 @@
"dev": true
},
"@pythnetwork/pyth-sdk-solidity": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.0.2.tgz",
"integrity": "sha512-/nxo+HqikNFDbi2dW/GQFJQYLjbe/PZL9x3ILxT4AdM1Nd76ykd+AK5aq08Giz6H4FGGrjsjJH4TtmgPJsUpDw=="
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.0.3.tgz",
"integrity": "sha512-4FaoGD4Sizvdm0+8KuQsYzARHa+myNwmFE2GBYxmMcw3zMtwvD7PH0RWM8nK9UyExJ+vyAAth7SbVzyLfN4Yow=="
},
"@redux-saga/core": {
"version": "1.1.3",
@ -66512,6 +66538,26 @@
}
}
},
"truffle-deploy-registry": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/truffle-deploy-registry/-/truffle-deploy-registry-0.5.1.tgz",
"integrity": "sha512-ZvyRpn67J67cWTfN5Z+sIryOirzxOuvpS7WO1WJYx3V1GcJR0gWWEM38KTBoPQ5L98/n7XxWC8+TtkOypKEp6A==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"commander": "^2.19.0",
"mkdirp": "^0.5.1",
"rimraf": "^2.6.3"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
}
}
},
"truffle-error": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/truffle-error/-/truffle-error-0.0.5.tgz",

View File

@ -6,7 +6,6 @@
"devDependencies": {
"@chainsafe/truffle-plugin-abigen": "0.0.1",
"@openzeppelin/cli": "^2.8.2",
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/test-environment": "^0.1.9",
"@openzeppelin/test-helpers": "^0.5.15",
"@openzeppelin/truffle-upgrades": "^1.14.0",
@ -16,6 +15,7 @@
"mocha": "^8.2.1",
"truffle": "^5.5.5",
"truffle-assertions": "^0.9.2",
"truffle-deploy-registry": "^0.5.1",
"truffle-plugin-verify": "^0.5.11"
},
"scripts": {
@ -30,6 +30,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/contracts-upgradeable": "^4.5.2",
"@pythnetwork/pyth-sdk-solidity": "0.0.3",
"dotenv": "^10.0.0",

View File

@ -59,11 +59,13 @@ module.exports = {
binance_testnet: {
provider: () => new HDWalletProvider(
process.env.MNEMONIC,
"https://data-seed-prebsc-1-s1.binance.org:8545/"
"https://data-seed-prebsc-1-s1.binance.org:8545"
),
network_id: "97",
gas: 70000000,
gasPrice: 8000000000,
confirmations: 10,
networkCheckTimeout: 1000000,
timeoutBlocks: 1000,
skipDryRun: true,
},
polygon: {
provider: () => {