diff --git a/aptos/scripts/deploy b/aptos/scripts/deploy index 65bb81ead..9205b9b94 100755 --- a/aptos/scripts/deploy +++ b/aptos/scripts/deploy @@ -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 diff --git a/aptos/scripts/named_addresses b/aptos/scripts/named_addresses new file mode 100755 index 000000000..1aa50ac5f --- /dev/null +++ b/aptos/scripts/named_addresses @@ -0,0 +1,42 @@ +#!/bin/bash + +set -eo pipefail + +usage() { + cat <<-EOF >&2 + Usage: ${0##*/} + + 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" diff --git a/aptos/scripts/upgrade b/aptos/scripts/upgrade index b34fccbbd..f3aa8c6fc 100755 --- a/aptos/scripts/upgrade +++ b/aptos/scripts/upgrade @@ -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 <&2 -Usage: +usage() { + cat <<-EOF >&2 + Usage: ${0##*/} [OPTIONS] - $(basename "$0") -- Perform a contract upgrade + Perform a contract upgrade. + + Positional arguments: + Network to deploy to (devnet, testnet, mainnet) + 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" diff --git a/scripts/contract-upgrade-governance.sh b/scripts/contract-upgrade-governance.sh index 0ed798c18..5c0eb8fe3 100755 --- a/scripts/contract-upgrade-governance.sh +++ b/scripts/contract-upgrade-governance.sh @@ -28,20 +28,22 @@ set -euo pipefail -function usage() { -cat <&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 Specify the module (bridge, token_bridge, nft_bridge) + -c, --chain Specify the chain name + -a, --address
Specify the new code address (e.g., 0x3f1a6729bb27350748f0a0bd85ca641a100bf0a1) + -o, --output 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 diff --git a/sdk/js/src/utils/consts.ts b/sdk/js/src/utils/consts.ts index 2a6e0b909..f8cb2d128 100644 --- a/sdk/js/src/utils/consts.ts +++ b/sdk/js/src/utils/consts.ts @@ -396,7 +396,8 @@ const TESTNET = { core: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625", token_bridge: "0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f", - nft_bridge: undefined, + nft_bridge: + "0x1bdffae984043833ed7fe223f7af7a3f8902d04129b14f801823e64827da7130", }, sui: { core: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",