aptos: tooling for mainnet upgrades (#3338)

* aptos: update upgrade script to support mainnet

Also factor out named_addresses into a separate helper script

* scripts: aptos support for gov proposal generation

* sdk/js: add aptos nft_bridge mainnet address
This commit is contained in:
Csongor Kiss 2023-09-29 11:11:43 -04:00 committed by GitHub
parent e71c4776ee
commit 3adce639fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 276 additions and 73 deletions

View File

@ -11,21 +11,17 @@ EOF
exit 1
}
# cd to script directory so that we can run this script from anywhere
cd "$(dirname "$0")"
NETWORK=$1 || usage
if [ "$NETWORK" = mainnet ]; then
DEPLOYER_ADDR=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b
GUARDIAN_ADDR=0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5
elif [ "$NETWORK" = testnet ]; then
DEPLOYER_ADDR=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b
GUARDIAN_ADDR=0x13947Bd48b18E53fdAeEe77F3473391aC727C638
elif [ "$NETWORK" = devnet ]; then
DEPLOYER_ADDR=0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b
DOTENV=$(dirname $0)/../.env
[[ -f "$DOTENV" ]] && . "$DOTENV"
@ -36,28 +32,28 @@ else
usage
fi
WORMHOLE_ADDR=$(worm info contract "$NETWORK" aptos Core)
TOKEN_BRIDGE_ADDR=$(worm info contract "$NETWORK" aptos TokenBridge)
NFT_BRIDGE_ADDR=$(worm info contract "$NETWORK" aptos NFTBridge)
NAMED_ADDRS="wormhole=$WORMHOLE_ADDR,deployer=$DEPLOYER_ADDR,token_bridge=$TOKEN_BRIDGE_ADDR"
NAMED_ADDRS="$(./named_addresses $NETWORK)"
NAMED_ADDRS="wormhole=$WORMHOLE_ADDR,deployer=$DEPLOYER_ADDR,token_bridge=$TOKEN_BRIDGE_ADDR,nft_bridge=$NFT_BRIDGE_ADDR"
echo "Addresses: $NAMED_ADDRS"
# NOTE: this always succeeds, even if the deployer contact is already deployed
echo "[1/6] Deploying deployer contract for creating resource accounts..."
worm aptos deploy --network "$NETWORK" ../deployer --named-addresses "$NAMED_ADDRS"
echo "[2/6] Deploying wormhole contract at $WORMHOLE_ADDR..."
echo "[2/6] Deploying wormhole contract..."
worm aptos deploy-resource wormhole --network "$NETWORK" ../wormhole --named-addresses "$NAMED_ADDRS"
echo "[3/6] Initialising wormhole with guardian(s) $GUARDIAN_ADDR..."
worm aptos init-wormhole --network "$NETWORK" -g $GUARDIAN_ADDR
echo "[4/6] Deploying token bridge contract at $TOKEN_BRIDGE_ADDR..."
echo "[4/6] Deploying token bridge contract..."
worm aptos deploy-resource token_bridge --network "$NETWORK" ../token_bridge --named-addresses "$NAMED_ADDRS"
echo "[5/6] Initialising token bridge..."
worm aptos init-token-bridge --network "$NETWORK"
echo "[6/6] Deploying (& initialising) NFT bridge contract at $NFT_BRIDGE_ADDR..."
echo "[6/6] Deploying (& initialising) NFT bridge contract..."
worm aptos deploy-resource nft_bridge --network "$NETWORK" ../nft_bridge --named-addresses "$NAMED_ADDRS"
if [ "$NETWORK" = devnet ]; then

42
aptos/scripts/named_addresses Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
set -eo pipefail
usage() {
cat <<-EOF >&2
Usage: ${0##*/} <network>
Print the named addresses for the given network.
EOF
exit 1
}
if [ $# -lt 1 ]; then
usage
fi
NETWORK="$1"
case "$NETWORK" in
testnet)
DEPLOYER=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b
;;
devnet)
DEPLOYER=0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b
;;
mainnet)
DEPLOYER=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b
;;
*)
echo "Unknown network $NETWORK" >&2
usage
;;
esac
WORMHOLE=$(worm info contract "$NETWORK" aptos Core)
TOKEN_BRIDGE=$(worm info contract "$NETWORK" aptos TokenBridge)
NFT_BRIDGE=$(worm info contract "$NETWORK" aptos NFTBridge)
NAMED_ADDRS="wormhole=$WORMHOLE,deployer=$DEPLOYER,token_bridge=$TOKEN_BRIDGE,nft_bridge=$NFT_BRIDGE"
echo "$NAMED_ADDRS"

View File

@ -1,56 +1,156 @@
#!/bin/bash
# This is a script for upgrading contracts on the Aptos network.
# It supports all of devnet (localhost), testnet, and mainnet.
#
# A VAA may be provided, in which case the script uses that.
# Otherwise, in devnet, it generates a VAA using the devnet guardian secret.
# In testnet, it generates a VAA using the testnet guardian secret as long as
# it's set in the environment variable GUARDIAN_SECRET.
# In mainnet, a VAA is required.
set -eo pipefail
function usage() {
cat <<EOF >&2
Usage:
usage() {
cat <<-EOF >&2
Usage: ${0##*/} <network> <module> [OPTIONS]
$(basename "$0") <devnet|testnet> <Core|TokenBridge> -- Perform a contract upgrade
Perform a contract upgrade.
Positional arguments:
<network> Network to deploy to (devnet, testnet, mainnet)
<module> Module to upgrade (Core, TokenBridge, NFTBridge)
Options:
--vaa VAA to submit (required for mainnet)
--yes Skip confirmation prompt
EOF
exit 1
exit 1
}
NETWORK=$1 || usage
MODULE=$2 || usage
# cd to script directory so that we can run this script from anywhere
cd "$(dirname "$0")"
if [ "$NETWORK" = testnet ]; then
# This script upgrades the core bridge in local devnet by generating a
# governance VAA and submitting it
DEPLOYER_ADDR=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b
[ -z "$GUARDIAN_SECRET" ] && echo "GUARDIAN_SECRET unset" >&2 && exit 1
elif [ "$NETWORK" = devnet ]; then
GUARDIAN_SECRET=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
DEPLOYER_ADDR=0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b
else
usage
# Check if the jq binary is available.
if ! command -v jq >/dev/null; then
echo "jq not found, please install it"
exit 1
fi
WORMHOLE_ADDR=$(worm info contract "$NETWORK" aptos Core)
TOKEN_BRIDGE_ADDR=$(worm info contract "$NETWORK" aptos TokenBridge)
NFT_BRIDGE_ADDR=$(worm info contract "$NETWORK" aptos NFTBridge)
# If positional args are missing, print help message and exit
if [ $# -lt 2 ]; then
usage
fi
NAMED_ADDRS="wormhole=$WORMHOLE_ADDR,deployer=$DEPLOYER_ADDR,token_bridge=$TOKEN_BRIDGE_ADDR,nft_bridge=$NFT_BRIDGE_ADDR"
# Get positional arguments
NETWORK="$1"
shift
MODULE="$1"
shift
yes=false
# Parse options
while [[ $# -gt 0 ]]; do
case "$1" in
--vaa)
VAA="$2"
shift 2
;;
--yes)
yes=true
shift
;;
--) # end of options
shift
break
;;
-*)
echo "Error: Unsupported option $1" >&2
usage
;;
*) # anything else
echo "Error: Unsupported argument $1" >&2
usage
;;
esac
done
case "$MODULE" in
Core)
DIR="../wormhole"
LOWER_MODULE="wormhole"
;;
TokenBridge)
DIR="../token_bridge"
LOWER_MODULE="token_bridge"
;;
NFTBridge)
DIR="../nft_bridge"
LOWER_MODULE="nft_bridge"
;;
*) echo "unsupported module $MODULE" >&2
usage
;;
esac
NAMED_ADDRS="$(./named_addresses $NETWORK)"
HASH=$(worm aptos hash-contracts $DIR --named-addresses "$NAMED_ADDRS")
VAA=$(worm generate upgrade -c aptos -a "$HASH" -m "$MODULE" -g $GUARDIAN_SECRET)
if [ "$NETWORK" = testnet ]; then
[ -z "$GUARDIAN_SECRET" ] && echo "GUARDIAN_SECRET unset" >&2 && exit 1
elif [ "$NETWORK" = devnet ]; then
GUARDIAN_SECRET=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
elif [ "$NETWORK" = mainnet ]; then
# VAA is required for mainnet
if [ -z "$VAA" ]; then
echo "VAA required for mainnet. Pass it in with the --vaa flag." >&2
echo "To generate a draft governance proposal, run" >&2
echo " ../../scripts/contract-upgrade-governance.sh -c aptos --address $HASH --module $LOWER_MODULE" >&2
exit 1
fi
else
usage
fi
# if VAA is not set, generate it
[ -z "$VAA" ] && VAA=$(worm generate upgrade -c aptos -a "$HASH" -m "$MODULE" -g $GUARDIAN_SECRET)
# parse VAA
VAA_JSON=$(worm parse "$VAA")
# sanity check VAA
check_payload_value() {
key="$1"
expected_value="$2"
payload_value=$(echo "$VAA_JSON" | jq -r ".payload.$key")
if [ "$payload_value" != "$expected_value" ]; then
echo "VAA payload: expected $key $expected_value, got $payload_value" >&2
exit 1
fi
}
# here we make sure the VAA is for the hash we expect
check_payload_value "type" "ContractUpgrade"
check_payload_value "chain" "$(worm info chain-id aptos)"
check_payload_value "module" "$MODULE"
check_payload_value "address" "0x$HASH"
echo "VAA is a valid ContractUpgrade VAA for $MODULE"
# Ask for confirmation
if [ "$yes" = false ]; then
read -p "Upgrade $MODULE to $HASH? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborting"
exit 1
fi
fi
echo "Submitting VAA: $VAA"
@ -59,3 +159,8 @@ CONTRACT_ADDR=$(worm info contract "$NETWORK" aptos "$MODULE")
worm submit --network "$NETWORK" "$VAA" --contract-address "$CONTRACT_ADDR"
worm aptos upgrade $DIR --network "$NETWORK" --contract-address "$CONTRACT_ADDR" --named-addresses "$NAMED_ADDRS"
worm aptos migrate --network "$NETWORK" --contract-address "$CONTRACT_ADDR"
echo "Successfully upgraded $MODULE to $HASH"
# if network is mainnet or testnet, print explorer link
[ "$NETWORK" = mainnet ] || [ "$NETWORK" = testnet ] &&
echo "Check it out at https://explorer.aptoslabs.com/account/$CONTRACT_ADDR?network=$NETWORK"

View File

@ -28,20 +28,22 @@
set -euo pipefail
function usage() {
cat <<EOF >&2
Usage:
usage() {
cat <<-EOF >&2
Usage: $(basename "$0") [OPTIONS]
$(basename "$0") [-h] [-m s] [-c s] [-a s] [-o d] -- Generate governance proposal for a given module to be upgraded to a given address
Generate governance proposal for a module to be upgraded to a given address.
Options:
-h, --help Show this help message
-m, --module <module> Specify the module (bridge, token_bridge, nft_bridge)
-c, --chain <chain_name> Specify the chain name
-a, --address <address> Specify the new code address (e.g., 0x3f1a6729bb27350748f0a0bd85ca641a100bf0a1)
-o, --output <output_dir> Specify the multi-mode output directory
-f, --force Force: bypass dirty git repo check
where:
-h show this help text
-m module (bridge, token_bridge, nft_bridge)
-c chain name
-a new code address (example: 0x3f1a6729bb27350748f0a0bd85ca641a100bf0a1)
-o multi-mode output directory
EOF
exit 1
exit 1
}
# Check if guardiand command exists. It's needed for generating the protoxt and
@ -51,39 +53,74 @@ if ! command -v guardiand >/dev/null 2>&1; then
exit 1
fi
# Check if the worm command exists. It's needed for computing the digest.
if ! command -v worm >/dev/null 2>&1; then
echo "ERROR: worm binary not found" >&2
exit 1
fi
### Parse command line options
address=""
module=""
chain_name=""
multi_mode=false
out_dir=""
while getopts ':hm:c:a:o:' option; do
case "$option" in
h) usage
;;
m) module=$OPTARG
;;
c) chain_name=$OPTARG
;;
a) address=$OPTARG
;;
o) multi_mode=true
out_dir=$OPTARG
;;
:) printf "missing argument for -%s\n" "$OPTARG" >&2
usage
;;
\?) printf "illegal option: -%s\n" "$OPTARG" >&2
usage
;;
allow_dirty=false
while (( "$#" )); do
case "$1" in
-h|--help)
usage
;;
-m|--module)
module="$2"
shift 2
;;
-c|--chain)
chain_name="$2"
shift 2
;;
-a|--address)
address="$2"
shift 2
;;
-o|--output)
multi_mode=true
out_dir="$2"
shift 2
;;
-f|--force)
allow_dirty=true
shift
;;
--) # end of options
shift
break
;;
-*)
echo "Error: Unsupported option $1" >&2
usage
;;
*) # anything else
echo "Error: Unsupported argument $1" >&2
usage
;;
esac
done
shift $((OPTIND - 1))
[ -z "$address" ] && usage
[ -z "$chain_name" ] && usage
[ -z "$module" ] && usage
# Check if the git tree is dirty
if [ "$allow_dirty" = false ]; then
if ! git diff-index --quiet HEAD --; then
echo "ERROR: git tree is dirty. Commit or stash your changes first." >&2
echo "If you are sure you want to proceed, use the --force flag." >&2
exit 1
fi
fi
### The script constructs the governance proposal in two different steps. First,
### the governance prototxt (for VAA injection by the guardiand tool), then the voting/verification instructions.
gov_msg_file=""
@ -190,13 +227,17 @@ case "$chain_name" in
explorer="https://optimistic.etherscan.io/address/"
evm=true
;;
aptos)
chain=22
explorer="https://explorer.aptoslabs.com/account/"
;;
base)
echo "Need to specify the base explorer URL!"
exit 1
exit 1
chain=30
explorer="??/address/"
evm=true
;;
;;
*)
echo "Unknown chain: $chain_name" >&2
exit 1
@ -429,7 +470,7 @@ elif [ "$chain_name" = "solana" ] || [ "$chain_name" = "pythnet" ]; then
## Verify
Contract at [$explorer$address]($explorer$address)
$extra
Next, use the \`verify\` script to verify that the deployed bytecodes we are upgrading to match the build artifacts:
@ -486,13 +527,31 @@ elif [ "$chain_name" = "terra" ]; then
wormhole/terra$ ./verify -n mainnet -c $chain_name -w $(terra_artifact) -i $terra_code_id
\`\`\`
EOF
elif [ "$chain_name" = "aptos" ]; then
cat <<-EOF >> "$instructions_file"
## Build
\`\`\`shell
wormhole/aptos $ docker build -f Dockerfile --target aptos -t aptos-build .
\`\`\`
This command will build a docker image that can compile the contracts reproducibly.
## Verify
Next, run the following command to check that the contract hash matches the expected value ($address):
\`\`\`shell
# $module
wormhole/aptos$ docker run -it aptos-build
wormhole/aptos$ worm aptos hash-contracts /tmp/$module --named-addresses wormhole=0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625,deployer=0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b,token_bridge=0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f,nft_bridge=0x1bdffae984043833ed7fe223f7af7a3f8902d04129b14f801823e64827da7130
wormhole/aptos$ exit
\`\`\`
EOF
else
echo "ERROR: no verification instructions for chain $chain_name" >&2
exit 1
fi
cat <<-EOF >> "$instructions_file"
## Create governance
\`\`\`shell

View File

@ -396,7 +396,8 @@ const TESTNET = {
core: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625",
token_bridge:
"0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f",
nft_bridge: undefined,
nft_bridge:
"0x1bdffae984043833ed7fe223f7af7a3f8902d04129b14f801823e64827da7130",
},
sui: {
core: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",