Browse Source

solana/Makefile: fogo deployment support

scripts: add fogo to contract-upgrade-governance.sh
hernandp 1 tháng trước cách đây
mục cha
commit
854a1079a1
5 tập tin đã thay đổi với 153 bổ sung78 xóa
  1. 1 3
      .gitignore
  2. 12 7
      scripts/contract-upgrade-governance.sh
  3. 81 42
      solana/Makefile
  4. 26 17
      solana/README.md
  5. 33 9
      solana/verify

+ 1 - 3
.gitignore

@@ -24,9 +24,7 @@ devnet-consts.json
 !/terra/artifacts/cw20_base.wasm
 /cosmwasm/artifacts/
 !/cosmwasm/artifacts/cw20_base.wasm
-/solana/artifacts-testnet/
-/solana/artifacts-devnet/
-/solana/artifacts-mainnet/
+/solana/artifacts-*
 /ethereum/out/
 /ethereum/cache/
 sui.log.*

+ 12 - 7
scripts/contract-upgrade-governance.sh

@@ -143,6 +143,11 @@ case "$chain_name" in
     explorer="https://explorer.solana.com/address/"
     extra=""
     ;;
+  fogo)
+    chain=51
+    explorer="https://explorer.fogo.io/address/"
+    extra=""
+    ;;
   pythnet)
     chain=26
     explorer="https://explorer.solana.com/address/"
@@ -307,13 +312,13 @@ function evm_artifact() {
 function solana_artifact() {
   case "$module" in
   bridge|core)
-    echo "artifacts-mainnet/bridge.so"
+    echo "artifacts-$chain_name-mainnet/bridge.so"
     ;;
   token_bridge)
-    echo "artifacts-mainnet/token_bridge.so"
+    echo "artifacts-$chain_name-mainnet/token_bridge.so"
     ;;
   nft_bridge)
-    echo "artifacts-mainnet/nft_bridge.so"
+    echo "artifacts-$chain_name-mainnet/nft_bridge.so"
     ;;
   *) echo "unknown module $module" >&2
      usage
@@ -455,15 +460,15 @@ if [ "$evm" = true ]; then
 	\`\`\`
 
 EOF
-elif [ "$chain_name" = "solana" ] || [ "$chain_name" = "pythnet" ]; then
+elif [ "$chain_name" = "solana" ] || [ "$chain_name" = "fogo" ] || [ "$chain_name" = "pythnet" ]; then
   cat <<-EOF >> "$instructions_file"
 	## Build
 	\`\`\`shell
 	wormhole/solana $ make clean
-	wormhole/solana $ make NETWORK=mainnet artifacts
+	wormhole/solana $ make NETWORK=mainnet SVM=$chain_name artifacts
 	\`\`\`
 
-	This command will compile all the contracts into the \`artifacts-mainnet\` directory using Docker to ensure that the build artifacts are deterministic.
+	This command will compile all the contracts into the \`artifacts-$chain_name-mainnet\` directory using Docker to ensure that the build artifacts are deterministic.
 
 	## Verify
 	Contract at [$explorer$address]($explorer$address)
@@ -474,7 +479,7 @@ elif [ "$chain_name" = "solana" ] || [ "$chain_name" = "pythnet" ]; then
 
 	\`\`\`shell
 	# $module
-	wormhole/solana$ ./verify -n mainnet $(solana_artifact) $address
+	wormhole/solana$ ./verify -n mainnet -s $chain_name $(solana_artifact) $address
 	\`\`\`
 EOF
 elif [ "$chain_name" = "near" ]; then

+ 81 - 42
solana/Makefile

@@ -1,28 +1,52 @@
+# Solana addresses
+# ----------------
+
 # Mainnet buffer authority is the "upgrade" PDA
-bridge_ADDRESS_mainnet=worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
-bridge_AUTHORITY_mainnet=2rCAC1VKz5YP1jZTHcVfWDhHMs2iEruUaATdeZe5Fjk5
-token_bridge_ADDRESS_mainnet=wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
-token_bridge_AUTHORITY_mainnet=DHyAcRbFpRWTkcsAsfwQpbABXvtjs6bQ1dq5ScNhRDoQ
-nft_bridge_ADDRESS_mainnet=WnFt12ZrnzZrFZkt2xsNsaNWoQribnuQ5B5FrDbwDhD
-nft_bridge_AUTHORITY_mainnet=3cVZHphy4QUYnU1hYFyvHF9joeZJ6ZTxpWx1nzavaUa8
+bridge_ADDRESS_solana_mainnet=worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
+bridge_AUTHORITY_solana_mainnet=2rCAC1VKz5YP1jZTHcVfWDhHMs2iEruUaATdeZe5Fjk5
+token_bridge_ADDRESS_solana_mainnet=wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
+token_bridge_AUTHORITY_solana_mainnet=DHyAcRbFpRWTkcsAsfwQpbABXvtjs6bQ1dq5ScNhRDoQ
+nft_bridge_ADDRESS_solana_mainnet=WnFt12ZrnzZrFZkt2xsNsaNWoQribnuQ5B5FrDbwDhD
+nft_bridge_AUTHORITY_solana_mainnet=3cVZHphy4QUYnU1hYFyvHF9joeZJ6ZTxpWx1nzavaUa8
 
 # Testnet buffer authority is the deployer public key
-bridge_ADDRESS_testnet=3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5
-bridge_AUTHORITY_testnet=J8am6SkUHRTtLPJpnfUd6Uy38U7Yh17fa7ZtiqaLoJcV
-token_bridge_ADDRESS_testnet=DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe
-token_bridge_AUTHORITY_testnet=FQAHqBcVHiiiLP8qXKPDQGr3mEXLv7RSdvfHJ3ZLugBV
-nft_bridge_ADDRESS_testnet=2rHhojZ7hpu1zA91nvZmT8TqWWvMcKmmNBCr2mKTtMq4
-nft_bridge_AUTHORITY_testnet=9r6q2iEg4MBevjC8reaLmQUDxueF3vabUoqDkZ2LoAYe
+bridge_ADDRESS_solana_testnet=3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5
+bridge_AUTHORITY_solana_testnet=J8am6SkUHRTtLPJpnfUd6Uy38U7Yh17fa7ZtiqaLoJcV
+token_bridge_ADDRESS_solana_testnet=DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe
+token_bridge_AUTHORITY_solana_testnet=FQAHqBcVHiiiLP8qXKPDQGr3mEXLv7RSdvfHJ3ZLugBV
+nft_bridge_ADDRESS_solana_testnet=2rHhojZ7hpu1zA91nvZmT8TqWWvMcKmmNBCr2mKTtMq4
+nft_bridge_AUTHORITY_solana_testnet=9r6q2iEg4MBevjC8reaLmQUDxueF3vabUoqDkZ2LoAYe
 
 # Devnet buffer authority is the devnet public key
-bridge_ADDRESS_devnet=Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o
-bridge_AUTHORITY_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
-token_bridge_ADDRESS_devnet=B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE
-token_bridge_AUTHORITY_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
-nft_bridge_ADDRESS_devnet=NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA
-nft_bridge_AUTHORITY_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
-
-SOURCE_FILES=$(shell find . -name "*.rs" -or -name "*.lock" -or -name "*.toml" | grep -v "target") Dockerfile
+bridge_ADDRESS_solana_devnet=Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o
+bridge_AUTHORITY_solana_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
+token_bridge_ADDRESS_solana_devnet=B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE
+token_bridge_AUTHORITY_solana_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
+nft_bridge_ADDRESS_solana_devnet=NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA
+nft_bridge_AUTHORITY_solana_devnet=6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J
+
+# Fogo SVM addresses
+# -------------------
+
+# Testnet
+bridge_ADDRESS_fogo_testnet=BhnQyKoQQgpuRTRo6D8Emz93PvXCYfVgHhnrR4T3qhw4
+bridge_AUTHORITY_fogo_testnet=34NzRtyigDRthGuWTCcaVRN6sHjkJc86fFNkqjvtghXs
+token_bridge_ADDRESS_fogo_testnet=78HdStBqCMioGii9D8mF3zQaWDqDZBQWTUwjjpdmbJKX
+token_bridge_AUTHORITY_fogo_testnet=CDZR3RgCs21mJS2uYKFmof24iiryxJAb8R2Wk9Rgg3Pw
+
+# Mainnet
+bridge_ADDRESS_fogo_mainnet=worm2mrQkG1B1KTz37erMfWN8anHkSK24nzca7UD8BB
+bridge_AUTHORITY_fogo_mainnet=CAb6rWkJAMMX4feJQgJZvBg2sK5Z5Tn2i48njRhSL9sw
+token_bridge_ADDRESS_fogo_mainnet=wormQuCVWSSmPdjVmEzAWxAXViVyTSWnLyhff5hVYGS
+token_bridge_AUTHORITY_fogo_mainnet=BAaVJ8fzpw8WJJqER9LK5ezTvxmG5VvFRgAWh21jJchz
+
+# Fogo specific RPC URLs.
+# for testnet we use the alt endpoint because of solana-cli issues with certs
+# at the time of writing.
+FOGO_RPC_URL_MAINNET=https://mainnet.fogo.io
+FOGO_RPC_URL_TESTNET=https://testnet-alt.fogo.io
+
+SOURCE_FILES:=$(shell find . -name "*.rs" -or -name "*.lock" -or -name "*.toml" | grep -v "target") Dockerfile
 
 .PHONY: clean all help artifacts deploy/bridge deploy/token_bridge deploy/nft_bridge .FORCE fmt check clippy test
 
@@ -31,43 +55,52 @@ SOURCE_FILES=$(shell find . -name "*.rs" -or -name "*.lock" -or -name "*.toml" |
 .FORCE:
 
 ## Build contracts.
-artifacts: check-network artifacts-$(NETWORK)
+artifacts: check-svmchain-name check-network artifacts-$(SVM)-$(NETWORK)
 
 .PHONY: check-network
 check-network:
-ifndef bridge_ADDRESS_$(NETWORK)
-	$(error Invalid or missing NETWORK. Please call with `$(MAKE) $(MAKECMDGOALS) NETWORK=[mainnet | testnet | devnet]`)
+ifndef bridge_ADDRESS_$(SVM)_$(NETWORK)
+	$(error Invalid or missing NETWORK and/or SVM. Please call with `$(MAKE) $(MAKECMDGOALS) SVM=[solana | fogo] NETWORK=[mainnet | testnet | devnet]`)
 endif
 
-artifacts-$(NETWORK): $(SOURCE_FILES)
+check-svmchain-name:
+	@if [ -z "$(SVM)" ] || [ "$(filter $(SVM), solana fogo)" != "$(SVM)" ]; then \
+		echo "Error: Invalid or missing SVM. Valid options are 'solana' and 'fogo'"; \
+		exit 1; \
+	fi
+
+artifacts-$(SVM)-$(NETWORK): $(SOURCE_FILES)
 	echo $@
-	@echo "Building artifacts for ${NETWORK} (${bridge_ADDRESS_${NETWORK}})"
-	DOCKER_BUILDKIT=1 docker build -f Dockerfile --build-arg BRIDGE_ADDRESS=${bridge_ADDRESS_${NETWORK}} -o $@ .
+	@echo "Building artifacts for ${SVM} ${NETWORK} (${bridge_ADDRESS_$${SVM}_${NETWORK}})"
+	DOCKER_BUILDKIT=1 docker build -f Dockerfile --build-arg BRIDGE_ADDRESS=${bridge_ADDRESS_${SVM}_${NETWORK}} -o $@ .
 	cd $@ && ls | xargs sha256sum > checksums.txt
 
-payer-$(NETWORK).json:
-	$(error Missing private key in payer-$(NETWORK).json)
+payer-$(SVM)-$(NETWORK).json:
+	$(error Missing private key in payer-$(SVM)-$(NETWORK).json)
 
-%-buffer-$(NETWORK).txt: payer-$(NETWORK).json check-network
-	$(eval FLAG := $(shell echo 	$(if $(filter mainnet,$(NETWORK)),	m,\
-				   	$(if $(filter testnet,$(NETWORK)),	d,\
-										l\
-			))))
-	solana -k payer-${NETWORK}.json program write-buffer artifacts-$(NETWORK)/$*.so -u $(FLAG) | cut -f2 -d' ' > $@
-	solana -k payer-${NETWORK}.json program set-buffer-authority $$(cat $@) --new-buffer-authority $($*_AUTHORITY_$(NETWORK)) -u $(FLAG)
+%-buffer-$(SVM)-$(NETWORK).txt: payer-$(SVM)-$(NETWORK).json check-network
+	$(eval FLAG := $(shell echo 	$(if $(filter fogo,$(SVM)),\
+						$(if $(filter mainnet,$(NETWORK)),	$(FOGO_RPC_URL_MAINNET),\
+						$(if $(filter testnet,$(NETWORK)),	$(FOGO_RPC_URL_TESTNET),\
+													l)),\
+					$(if $(filter mainnet,$(NETWORK)),	m,\
+					$(if $(filter testnet,$(NETWORK)),	d,\
+									l)))))
+	solana -k payer-${SVM}-${NETWORK}.json program write-buffer artifacts-$(SVM)-$(NETWORK)/$*.so -u $(FLAG) | cut -f2 -d' ' > $@
+	solana -k payer-${SVM}-${NETWORK}.json program set-buffer-authority $$(cat $@) --new-buffer-authority $($*_AUTHORITY_$(SVM)_$(NETWORK)) -u $(FLAG)
 
 ## Deploy core bridge program.
-deploy/bridge: bridge-buffer-$(NETWORK).txt
+deploy/bridge: bridge-buffer-$(SVM)-$(NETWORK).txt
 	@echo Deployed core bridge contract at:
 	@cat $<
 
 ## Deploy token bridge program.
-deploy/token_bridge: token_bridge-buffer-$(NETWORK).txt
+deploy/token_bridge: token_bridge-buffer-$(SVM)-$(NETWORK).txt
 	@echo Deployed token bridge contract at:
 	@cat $<
 
 ## Deploy nft bridge program.
-deploy/nft_bridge: nft_bridge-buffer-$(NETWORK).txt
+deploy/nft_bridge: nft_bridge-buffer-$(SVM)-$(NETWORK).txt
 	@echo Deployed nft bridge contract at:
 	@cat $<
 
@@ -88,13 +121,19 @@ clippy: $(SOURCE_FILES)
 	cargo clippy --workspace --tests --manifest-path Cargo.toml \
 		--features "nft-bridge/instructions token-bridge/instructions wormhole-bridge-solana/instructions"
 
-test: $(SOURCE_FILES)
-	DOCKER_BUILDKIT=1 docker build -f Dockerfile --build-arg BRIDGE_ADDRESS=${bridge_ADDRESS_devnet} \
+test: $(SOURCE_FILES) check-svmchain-name
+	DOCKER_BUILDKIT=1 docker build -f Dockerfile --build-arg BRIDGE_ADDRESS=${bridge_ADDRESS_${SVM}_devnet} \
 		--build-arg EMITTER_ADDRESS=CiByUvEcx7w2HA4VHcPCBUAFQ73Won9kB36zW9VjirSr -o target/deploy .
 	BPF_OUT_DIR=$(realpath $(dir $(firstword $(MAKEFILE_LIST))))/target/deploy \
 		cargo test --workspace \
 			--features "nft-bridge/instructions token-bridge/instructions wormhole-bridge-solana/instructions"
 
-clean:
-	rm -rf artifacts-mainnet artifacts-testnet artifacts-devnet *-buffer-*.txt
+.PHONY: build
+# Build for local use (not for deployment)
+build: check-network check-svmchain-name
+	BRIDGE_ADDRESS=${bridge_ADDRESS_${SVM}_${NETWORK}} \
+	EMITTER_ADDRESS=11111111111111111111111111111115 \
+	cargo build
 
+clean: check-svmchain-name
+	rm -rf artifacts-$(SVM)-mainnet artifacts-$(SVM)-testnet artifacts-$(SVM)-devnet *-buffer-*.txt

+ 26 - 17
solana/README.md

@@ -1,17 +1,19 @@
-# Solana Wormhole Contract Deployment
+# SVM (Solana and Fogo) Wormhole Contract Deployment
 
-This readme describes the steps for building, verifying, and deploying Solana smart contracts for Wormhole.
+This readme describes the steps for building, verifying, and deploying SVM (Solana and Fogo) smart contracts for Wormhole.
 
 **WARNING**: *This process is only Linux host compatible at this time.*
 
 ## Verify Tilt
 
-Before building Solana contracts, ensure that the specific commit you will be building from passes in tilt.  This ensures the basic functionality of the Solana smart contracts that you are about to build and deploy.
+Before building SVM contracts, ensure that the specific commit you will be building from passes in tilt.  This ensures the basic functionality of the SVM smart contracts that you are about to build and deploy.
 
 
 ## Build Contracts
 
-The following command can be used to build contracts for Solana contracts via Docker.
+The following command can be used to build contracts for SVM contracts via Docker.
+
+SVM Options: [`fogo | solana`]
 
 Build Target Options: [`mainnet`|`testnet`|`devnet`]
 
@@ -19,39 +21,44 @@ These network names correspond to the naming convention used by wormhole
 elsewhere. This means that `mainnet` corresponds to Solana `mainnet-beta`,
 `testnet` corresponds to Solana `devnet`, and `devnet` is Solana `localhost`.
 
+Fogo follows the same conventions.
+
 ```console
-wormhole/solana $ make NETWORK=BUILD_TARGET artifacts
+wormhole/solana $ make NETWORK=BUILD_TARGET SVM=<fogo | solana> artifacts
 ```
-Example: `make NETWORK=testnet artifacts`
+Example: `make NETWORK=testnet SVM=solana artifacts`
 
 
-Upon completion, the compiled bytecode for the Solana contracts will be placed into an artifacts directory with a convention of `artifacts-BUILD_TARGET` (eg. `artifacts-testnet`)
+Upon completion, the compiled bytecode for the selected SVM contracts will be placed into an artifacts directory with a convention of `artifacts-SVM-BUILD_TARGET` (eg. `artifacts-solana-testnet`)
 
 The contract addresses are compiled into the binaries, which is why these build
 outputs are kept separate. The deploy script below makes sure that only the
 right binaries can be deployed to each network.
 
-You may set the build target in the `NETWORK` environment variable, and then
+You may set the SVM and build target in the `NETWORK` and `SVM` environment variables, and then
 omit it from all of the subsequent commands.
 Example:
 ```console
 export NETWORK=testnet
+export SVM=solana
 make artifacts
 ```
 
 ## Verify Checksums
 
-Now that you have built the Solana Contracts, you should ask a peer to build using the same process and compare the equivalent checksums.txt files to make sure the contract bytecode(s) are deterministic.
+Now that you have built the SVM Contracts, you should ask a peer to build using the same process and compare the equivalent checksums.txt files to make sure the contract bytecode(s) are deterministic.
 
 Verify Target Options: [`mainnet`|`testnet`|`devnet`]
 
+SVM Options: [`fogo | solana`]
+
 ```console
-wormhole/solana $ cat artifacts-VERIFY_TARGET/checksums.txt
+wormhole/solana $ cat artifacts-SVM-VERIFY_TARGET/checksums.txt
 ```
-Example: `cat artifacts-testnet/checksums.txt`
+Example: `cat artifacts-solana-testnet/checksums.txt`
 
 
-Once you have verified the Solana contracts are deterministic with a peer, you can now move to the deploy step.
+Once you have verified the SVM contracts are deterministic with a peer, you can now move to the deploy step.
 
 ## Deploy Contracts
 
@@ -59,14 +66,16 @@ Now that you have built and verified checksums, you can now deploy one or more r
 
 Deploy Target Options: [`mainnet`|`testnet`|`devnet`]
 
-You will need to define a `payer-DEPLOY_TARGET.json` for the relevant deploy target (eg. `payer-testnet.json`).  This will contain the relevant wallet private key that you will be using to deploy the contracts.
+SVM Options: [`fogo | solana`]
+
+You will need to define a `payer-SVM-DEPLOY_TARGET.json` for the relevant deploy target (eg. `payer-solana-testnet.json`).  This will contain the relevant wallet private key that you will be using to deploy the contracts.
 
 ```console
-wormhole/solana $ make NETWORK=DEPLOY_TARGET deploy/bridge
-wormhole/solana $ make NETWORK=DEPLOY_TARGET deploy/token_bridge
-wormhole/solana $ make NETWORK=DEPLOY_TARGET deploy/nft_bridge
+wormhole/solana $ make NETWORK=DEPLOY_TARGET SVM=<fogo | solana>   deploy/bridge
+wormhole/solana $ make NETWORK=DEPLOY_TARGET SVM=<fogo | solana>   deploy/token_bridge
+wormhole/solana $ make NETWORK=DEPLOY_TARGET SVM=<fogo | solana>   deploy/nft_bridge
 ```
-Example: `make NETWORK=testnet deploy/bridge`
+Example: `make NETWORK=testnet SVM=solana deploy/bridge`
 
 For each deployed contract, you will get an account address for that relevant account address for the deployment, make note of these so you can use them in the next step for on-chain verification.
 

+ 33 - 9
solana/verify

@@ -5,25 +5,32 @@ set -euo pipefail
 function usage() {
 cat<<-EOF >&2
 	Usage:
-	  $(basename "$0") [-h] [-n network] <.so file> <account address> -- Verify that the deployed on-chain bytecode matches the local object file
+	  $(basename "$0") [-h] [-n network] [-s svm] <.so file> <account address> -- Verify that the deployed on-chain bytecode matches the local object file
 
 	  where:
 	      -h  show this help text
 	      -n  set the network (mainnet, testnet, devnet. defaults to \$NETWORK if set)
+	      -s  set the svm (solana, fogo. defaults to \$SVM if set)
 EOF
 exit 1
 }
 
 network=""
-if [[ -n $NETWORK ]]; then
-  network=$NETWORK
+if [[ -n "${NETWORK:-}" ]]; then
+  network="$NETWORK"
 fi
-while getopts ':hn:' option; do
+svm=""
+if [[ -n "${SVM:-}" ]]; then
+  svm="$SVM"
+fi
+while getopts ':n:s:h' option; do
   case "$option" in
     h) usage
        ;;
     n) network=$OPTARG
        ;;
+    s) svm=$OPTARG
+       ;;
     :) printf "missing argument for -%s\n" "$OPTARG" >&2
        usage
        ;;
@@ -34,11 +41,28 @@ while getopts ':hn:' option; do
 done
 shift $((OPTIND - 1))
 
-case "$network" in
-  mainnet) moniker="m";;
-  testnet) moniker="d";;
-  devnet)  moniker="l";;
-  *) printf "Network not set. Specify with -n\n" >&2
+# Set moniker based on SVM and network
+case "$svm" in
+  solana)
+    case "$network" in
+      mainnet) moniker="m";;
+      testnet) moniker="d";;
+      devnet)  moniker="l";;
+      *) printf "Network not set. Specify with -n\n" >&2
+         usage
+         ;;
+    esac
+    ;;
+  fogo)
+    case "$network" in
+      mainnet) moniker="https://mainnet.fogo.io";;
+      testnet) moniker="https://testnet-alt.fogo.io";;
+      *) printf "Fogo only supports mainnet and testnet. Specify with -n\n" >&2
+         usage
+         ;;
+    esac
+    ;;
+  *) printf "SVM not set. Specify with -s\n" >&2
      usage
      ;;
 esac