Ver código fonte

svm/wormhole-core-shims: support non-solana SVM deployments (#4527)

* svm/definitions: use const computation to derive static PDAs

This allows us to only have to specify the program id

* svm/definitions: add feature flag to pick up addresses from env

* svm/definitions: fix path in test

* svm/definitions: error when 'solana' and 'from-env' are both passed

* svm/definitions: small formatting

* svm/definitions: fix *correct* spelling to make spellcheck happy

* svm/definitions: remove bs58 validation

https://docs.rs/const-crypto/latest/src/const_crypto/bs58.rs.html#8-15
already handles this

* svm/definitions: std-finality -> standard-finality

* svm/definitions: mention commitment level in docs
Csongor Kiss 1 mês atrás
pai
commit
cf9a9789b6

+ 17 - 0
svm/wormhole-core-shims/Cargo.lock

@@ -809,6 +809,16 @@ dependencies = [
  "web-sys",
 ]
 
+[[package]]
+name = "const-crypto"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c06f1eb05f06cf2e380fdded278fbf056a38974299d77960555a311dcf91a52"
+dependencies = [
+ "keccak-const",
+ "sha2-const-stable",
+]
+
 [[package]]
 name = "constant_time_eq"
 version = "0.3.1"
@@ -2092,6 +2102,12 @@ dependencies = [
  "cpufeatures",
 ]
 
+[[package]]
+name = "keccak-const"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea"
+
 [[package]]
 name = "lazy_static"
 version = "1.5.0"
@@ -6756,6 +6772,7 @@ dependencies = [
  "base64 0.22.1",
  "borsh 1.5.5",
  "cfg-if",
+ "const-crypto",
  "sha2-const-stable",
  "solana-program",
 ]

+ 17 - 0
svm/wormhole-core-shims/anchor/Cargo.lock

@@ -744,6 +744,16 @@ dependencies = [
  "web-sys",
 ]
 
+[[package]]
+name = "const-crypto"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c06f1eb05f06cf2e380fdded278fbf056a38974299d77960555a311dcf91a52"
+dependencies = [
+ "keccak-const",
+ "sha2-const-stable",
+]
+
 [[package]]
 name = "constant_time_eq"
 version = "0.3.1"
@@ -1167,6 +1177,12 @@ dependencies = [
  "cpufeatures",
 ]
 
+[[package]]
+name = "keccak-const"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea"
+
 [[package]]
 name = "lazy_static"
 version = "1.5.0"
@@ -2703,6 +2719,7 @@ name = "wormhole-svm-definitions"
 version = "0.1.0"
 dependencies = [
  "cfg-if",
+ "const-crypto",
  "sha2-const-stable",
  "solana-program",
 ]

+ 8 - 3
svm/wormhole-core-shims/crates/definitions/Cargo.toml

@@ -12,21 +12,26 @@ version.workspace = true
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [features]
-default = []
+default = [ "standard-finality" ]
 borsh = ["dep:borsh"]
 
 ### Network types
 testnet = []
 localnet = []
+from-env = []
+
+### Standard finality definition
+standard-finality = []
 
 ### Specific networks
-solana = []
+solana = [ "standard-finality" ]
 
 [dependencies]
+const-crypto = "0.3.0"
 borsh = { optional = true, workspace = true }
 cfg-if.workspace = true
 sha2-const-stable.workspace = true
 solana-program.workspace = true
 
 [dev-dependencies]
-base64.workspace = true
+base64.workspace = true

+ 28 - 23
svm/wormhole-core-shims/crates/definitions/README.md

@@ -4,31 +4,36 @@ Definitions relating to Wormhole SVM programs. These definitions include finding
 PDA addresses (and corresponding bump seeds), various consts (like program IDs),
 and other things that define these program accounts and data.
 
-## Cargo Features
-
-There are features that define network types and specific SVM networks.
-
-### Network Types
-
-The default network type is mainnet. There is no feature that defines mainnet.
-But if one of the following features are defined, program IDs and account
-addresses will not use the ones defined for mainnet.
-
-- `localnet`: Wormhole's Tilt devnet. Programs like the Wormhole Core Bridge and
-  its associated PDAs have addresses specific to this local development network.
-- `testnet`: Public devnet or testnet depending on the specific SVM network. For
-  Solana specifically, this feature corresponds to the public Solana devnet.
-
-### Specific Networks
-
-There are no default network features. These feature labels also exist as
-submodules in this crate. By defining a particular SVM network feature, the
-definitions found in this submodule are simply exported into the crate root.
-
-- `solana`
+The crate is parameterized over a set of program IDs (the Wormhole program, the
+post-vaa shim program, and the verify-vaa shim program). Since this crate may be
+used in many different scenarios, and many different SVM networks, we expose
+feature flags to control which program IDs are used to derive the other constants.
+
+For Solana, we have a hardcoded set of addresses for `mainnet`, `devnet` and a
+local testing environment. If the `solana` feature is specified, it will default
+to the mainnet addresses. Otherwise, the `testnet` flag provides the addresses
+for Solana Devnet, and the `localnet` flag provides the addresses for the local
+testing environment.
+
+Alternatively, when using on another SVM chain (or on Solana, but against an
+independent Wormhole deployment) just specify the `from-env` feature flag (and
+don't specify Solana, even if the chain is Solana). In this case, the following
+4 environment variables are needed:
+- `CHAIN_ID`: the Wormhole ID of the chain deployed on. e.g. Solana is 1, Fogo is 51.
+- `BRIDGE_ADDRESS`: program ID of the Wormhole program
+- `POST_MESSAGE_SHIM_PROGRAM_ID`: program ID of the [../../programs/post-message/](post-message shim).
+- `VERIFY_VAA_SHIM_PROGRAM_ID`: program ID of the [../../programs/verify-vaa](verify-vaa shim).
+
+The definitions crate can be compiled without either the `solana` or the
+`from-env` feature flags. In this case, it will not expose any addresses in the top-level crate, for example `crate::CORE_BRIDGE_FEE_COLLECTOR` won't be available. However, the predefined Solana addresses are still available via their qualified paths:
+e.g. `crate::solana::devnet::CORE_BRIDGE_FEE_COLLECTOR`.
+
+A crate wishing to build on top of this crate should pass through the
+`from-env`, `solana`, `testnet`, and `devnet` flags, but may wish to specify
+`from-env` as the default.
 
 ### Other Features
 
 - `borsh`: Accounts and events relating to Wormhole SVM programs that follow
   Borsh serialization. This feature also supports deserializing data with
-  discriminators.
+  discriminators.

+ 6 - 0
svm/wormhole-core-shims/crates/definitions/src/env.rs

@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! env_pubkey {
+    ($name: literal) => {
+        const_crypto::bs58::decode_pubkey(env!($name))
+    };
+}

+ 198 - 5
svm/wormhole-core-shims/crates/definitions/src/lib.rs

@@ -3,16 +3,53 @@
 
 #[cfg(feature = "borsh")]
 pub mod borsh;
+pub mod env;
 pub mod solana;
 pub mod zero_copy;
 
-// NOTE: Expand this conditional as Wormhole supports more SVM networks.
-cfg_if::cfg_if! {
-    if #[cfg(feature = "solana")] {
-        pub use solana::*;
+#[cfg(all(feature = "from-env", feature = "solana"))]
+compile_error!("Features 'from-env' and 'solana' are mutually exclusive.");
+
+// We define the constants (chain id + addresses) here.
+// - For 'solana', we just re-export the definitions in the solana module.
+// - For 'from-env', we pick these up from environment variables and parse (+
+// validate) them into the right types via const functions.
+//
+// Consumers of this crate should mark 'from-env' as the default.
+mod defs {
+    cfg_if::cfg_if! {
+        if #[cfg(feature = "solana")] {
+            pub use crate::solana::*;
+        } else if #[cfg(feature = "from-env")] {
+            #[cfg(any(feature = "testnet"))]
+            panic!("The 'testnet' feature is meaningless without the 'solana' feature.");
+            #[cfg(any(feature = "localnet"))]
+            panic!("The 'localnet' feature is meaningless without the 'solana' feature.");
+
+            use super::*;
+            pub const CHAIN_ID: u16 = match u16::from_str_radix(env!("CHAIN_ID"), 10) {
+                Ok(c) => c,
+                Err(_err) => panic!("CHAIN_ID is not a valid u16")
+            };
+
+            pub const CORE_BRIDGE_PROGRAM_ID_ARRAY: [u8; 32] =
+            // we use the same variable name as the core contracts
+                env_pubkey!("BRIDGE_ADDRESS");
+
+            pub const POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+                env_pubkey!("POST_MESSAGE_SHIM_PROGRAM_ID");
+
+            pub const VERIFY_VAA_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+                env_pubkey!("VERIFY_VAA_SHIM_PROGRAM_ID");
+
+            derive_consts!();
+        }
     }
 }
 
+#[allow(unused_imports)]
+pub use defs::*;
+
 pub use solana_program::keccak::{Hash, HASH_BYTES};
 
 use solana_program::pubkey::Pubkey;
@@ -154,17 +191,173 @@ pub const fn make_anchor_discriminator(input: &[u8]) -> [u8; 8] {
 }
 
 /// Trait to encode and decode the SVM finality of a message.
+/// The byte encoding corresponds to the "commitment level" field in the VAA.
+/// See https://wormhole.com/docs/products/reference/consistency-levels/
+///
+/// Different SVM runtimes may have different finality options, so we just
+/// provide this conversion trait between u8s.
+/// We also define the "standard" finality options ([`standard_finality`]) which are
+/// the available ones on Solana.
+/// If you use this crate with a chain that support different finality modes,
+/// either just use `u8`, or define a a custom enum and an impl of this trait.
 pub trait EncodeFinality: Sized + Copy {
-    /// Encode SVM finality into a byte.
+/// Encode SVM finality into a byte.
     fn encode(&self) -> u8;
 
     /// Decode SVM finality from a byte.
     fn decode(data: u8) -> Option<Self>;
 }
 
+impl EncodeFinality for u8 {
+    fn encode(&self) -> u8 {
+        *self
+    }
+
+    fn decode(data: u8) -> Option<Self> {
+        Some(data)
+    }
+}
+
+pub mod standard_finality {
+    /// Finality of the message (which is when the Wormhole guardians will attest to
+    /// this message's observation).
+    ///
+    /// On Solana, there are only two commitment levels that the Wormhole guardians
+    /// recognize.
+    #[cfg_attr(
+        feature = "borsh",
+        derive(borsh::BorshDeserialize, borsh::BorshSerialize)
+    )]
+    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+    #[repr(u8)]
+    pub enum Finality {
+        /// Equivalent to observing after one slot.
+        Confirmed,
+
+        /// Equivalent to observing after 32 slots.
+        Finalized,
+    }
+
+    impl super::EncodeFinality for Finality {
+        fn encode(&self) -> u8 {
+            *self as u8
+        }
+
+        fn decode(data: u8) -> Option<Self> {
+            match data {
+                0 => Some(Self::Confirmed),
+                1 => Some(Self::Finalized),
+                _ => None,
+            }
+        }
+    }
+}
+
+#[cfg(feature = "standard-finality")]
+pub use standard_finality::*;
+
 /// Trait that defines an arbitrary discriminator for deserializing data. This
 /// discriminator acts as a prefix to identify which kind of data is encoded.
 /// For Anchor accounts and events, this discriminator is 8 bytes long.
 pub trait DataDiscriminator {
     const DISCRIMINATOR: &'static [u8];
 }
+
+/// Derive constants from the defined addresses. We use const functions here so
+/// we only need to define the program ids, and PDAs are derived at compile time
+/// and made available as consts.
+///
+/// We expose this as a macro, so that it can be invoked in multiple different scopes.
+/// Alternatively, we could just simply define the below constants at the
+/// top-level, but then they would only be available to the network that's
+/// specified as the feature flag.
+///
+/// This way, we can derive these constants within the solana network modules,
+/// such as 'solana::mainnet' and 'solana::devnet', and have both of them
+/// available, even when not compiling for solana mainnet or solana devnet.
+/// The network flags just define which of these is available at the top-level.
+#[macro_export]
+macro_rules! derive_consts {
+    () => {
+        pub const CORE_BRIDGE_PROGRAM_ID: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(CORE_BRIDGE_PROGRAM_ID_ARRAY);
+
+        pub const CORE_BRIDGE_FEE_COLLECTOR_PDA: ([u8; 32], u8) =
+            const_crypto::ed25519::derive_program_address(&[crate::FEE_COLLECTOR_SEED], &CORE_BRIDGE_PROGRAM_ID_ARRAY);
+
+        pub const CORE_BRIDGE_FEE_COLLECTOR: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(CORE_BRIDGE_FEE_COLLECTOR_PDA.0);
+
+        pub const CORE_BRIDGE_FEE_COLLECTOR_BUMP: u8 = CORE_BRIDGE_FEE_COLLECTOR_PDA.1;
+
+        pub const CORE_BRIDGE_CONFIG_PDA: ([u8; 32], u8) =
+            const_crypto::ed25519::derive_program_address(
+                &[crate::CORE_BRIDGE_CONFIG_SEED],
+                &CORE_BRIDGE_PROGRAM_ID_ARRAY,
+            );
+
+        pub const CORE_BRIDGE_CONFIG: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(CORE_BRIDGE_CONFIG_PDA.0);
+
+        pub const CORE_BRIDGE_CONFIG_BUMP: u8 = CORE_BRIDGE_CONFIG_PDA.1;
+
+        pub const POST_MESSAGE_SHIM_PROGRAM_ID: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY);
+
+        const POST_MESSAGE_SHIM_EVENT_AUTHORITY_PDA: ([u8; 32], u8) =
+            const_crypto::ed25519::derive_program_address(
+                &[crate::EVENT_AUTHORITY_SEED],
+                &POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY,
+            );
+
+        pub const POST_MESSAGE_SHIM_EVENT_AUTHORITY: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(POST_MESSAGE_SHIM_EVENT_AUTHORITY_PDA.0);
+
+        pub const POST_MESSAGE_SHIM_EVENT_AUTHORITY_BUMP: u8 =
+            POST_MESSAGE_SHIM_EVENT_AUTHORITY_PDA.1;
+
+        pub const VERIFY_VAA_SHIM_PROGRAM_ID: solana_program::pubkey::Pubkey =
+            solana_program::pubkey::Pubkey::new_from_array(VERIFY_VAA_SHIM_PROGRAM_ID_ARRAY);
+    };
+}
+
+#[allow(dead_code)]
+/// A test to make sure the expected IDs are available.
+fn available_ids() {
+    let _ = crate::solana::mainnet::CORE_BRIDGE_PROGRAM_ID;
+    let _ = crate::solana::devnet::CORE_BRIDGE_PROGRAM_ID;
+    let _ = crate::solana::localnet::CORE_BRIDGE_PROGRAM_ID;
+    // defaults to mainnet (for backwards compatibility)
+    let _ = crate::solana::CORE_BRIDGE_PROGRAM_ID;
+    #[cfg(any(feature = "solana", feature = "from-env"))]
+    let _ = crate::CORE_BRIDGE_PROGRAM_ID;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_core_bridge_fee_collector() {
+        let (expected, _) = crate::find_fee_collector_address(&CORE_BRIDGE_PROGRAM_ID);
+        assert_eq!(CORE_BRIDGE_FEE_COLLECTOR, expected);
+    }
+
+    #[test]
+    fn test_core_bridge_config() {
+        let (expected, _) = crate::find_core_bridge_config_address(&CORE_BRIDGE_PROGRAM_ID);
+        assert_eq!(CORE_BRIDGE_CONFIG, expected);
+    }
+
+    #[test]
+    fn test_post_message_shim_event_authority() {
+        let expected = crate::find_event_authority_address(&POST_MESSAGE_SHIM_PROGRAM_ID);
+        assert_eq!(
+            (
+                POST_MESSAGE_SHIM_EVENT_AUTHORITY,
+                POST_MESSAGE_SHIM_EVENT_AUTHORITY_BUMP
+            ),
+            expected
+        );
+    }
+}

+ 51 - 79
svm/wormhole-core-shims/crates/definitions/src/solana.rs

@@ -2,96 +2,68 @@
 /// devnet.
 pub const CHAIN_ID: u16 = 1;
 
-use solana_program::{pubkey, pubkey::Pubkey};
+pub mod mainnet {
+    use const_crypto::bs58;
 
-pub const POST_MESSAGE_SHIM_PROGRAM_ID: Pubkey =
-    pubkey!("EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX");
-pub const POST_MESSAGE_SHIM_EVENT_AUTHORITY: Pubkey =
-    pubkey!("HQS31aApX3DDkuXgSpV9XyDUNtFgQ31pUn5BNWHG2PSp");
-pub const POST_MESSAGE_SHIM_EVENT_AUTHORITY_BUMP: u8 = 255;
+    /// Core Bridge program ID on Solana mainnet.
+    pub const CORE_BRIDGE_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth");
 
-pub const VERIFY_VAA_SHIM_PROGRAM_ID: Pubkey =
-    pubkey!("EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at");
+    /// Post message shim program ID on Solana mainnet.
+    pub const POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX");
 
-cfg_if::cfg_if! {
-    if #[cfg(feature = "testnet")] {
-        /// Core Bridge program ID on Solana devnet.
-        pub const CORE_BRIDGE_PROGRAM_ID: Pubkey = pubkey!("3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5");
-        pub const CORE_BRIDGE_FEE_COLLECTOR: Pubkey = pubkey!("7s3a1ycs16d6SNDumaRtjcoyMaTDZPavzgsmS3uUZYWX");
-        pub const CORE_BRIDGE_CONFIG: Pubkey = pubkey!("6bi4JGDoRwUs9TYBuvoA7dUVyikTJDrJsJU1ew6KVLiu");
-    } else if #[cfg(feature = "localnet")] {
-        /// Core Bridge program ID on Wormhole's Tilt (dev) network.
-        pub const CORE_BRIDGE_PROGRAM_ID: Pubkey = pubkey!("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o");
-        pub const CORE_BRIDGE_FEE_COLLECTOR: Pubkey = pubkey!("GXBsgBD3LDn3vkRZF6TfY5RqgajVZ4W5bMAdiAaaUARs");
-        pub const CORE_BRIDGE_CONFIG: Pubkey = pubkey!("FKoMTctsC7vJbEqyRiiPskPnuQx2tX1kurmvWByq5uZP");
-    }
-    // Default to mainnet.
-    else {
-        /// Core Bridge program ID on Solana mainnet.
-        pub const CORE_BRIDGE_PROGRAM_ID: Pubkey = pubkey!("worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth");
-        pub const CORE_BRIDGE_FEE_COLLECTOR: Pubkey = pubkey!("9bFNrXNb2WTx8fMHXCheaZqkLZ3YCCaiqTftHxeintHy");
-        pub const CORE_BRIDGE_CONFIG: Pubkey = pubkey!("2yVjuQwpsvdsrywzsJJVs9Ueh4zayyo5DYJbBNc3DDpn");
-    }
-}
+    /// Verify VAA shim program ID on Solana mainnet.
+    pub const VERIFY_VAA_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at");
 
-/// Finality of the message (which is when the Wormhole guardians will attest to
-/// this message's observation).
-///
-/// On Solana, there are only two commitment levels that the Wormhole guardians
-/// recognize.
-#[cfg_attr(
-    feature = "borsh",
-    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
-)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-#[repr(u8)]
-pub enum Finality {
-    /// Equivalent to observing after one slot.
-    Confirmed,
-
-    /// Equivalent to observing after 32 slots.
-    Finalized,
+    crate::derive_consts!();
 }
 
-impl super::EncodeFinality for Finality {
-    fn encode(&self) -> u8 {
-        *self as u8
-    }
+pub mod devnet {
+    use const_crypto::bs58;
 
-    fn decode(data: u8) -> Option<Self> {
-        match data {
-            0 => Some(Self::Confirmed),
-            1 => Some(Self::Finalized),
-            _ => None,
-        }
-    }
+    /// Core Bridge program ID on Solana devnet.
+    pub const CORE_BRIDGE_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5");
+
+    /// Post message shim program ID on Solana devnet.
+    pub const POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX");
+
+    /// Verify VAA shim program ID on Solana devnet.
+    pub const VERIFY_VAA_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at");
+
+    crate::derive_consts!();
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
+pub mod localnet {
+    use const_crypto::bs58;
 
-    #[test]
-    fn test_core_bridge_fee_collector() {
-        let (expected, _) = crate::find_fee_collector_address(&CORE_BRIDGE_PROGRAM_ID);
-        assert_eq!(CORE_BRIDGE_FEE_COLLECTOR, expected);
-    }
+    /// Core Bridge program ID on Wormhole's Tilt (dev) network.
+    pub const CORE_BRIDGE_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o");
 
-    #[test]
-    fn test_core_bridge_config() {
-        let (expected, _) = crate::find_core_bridge_config_address(&CORE_BRIDGE_PROGRAM_ID);
-        assert_eq!(CORE_BRIDGE_CONFIG, expected);
-    }
+    /// Post message shim program ID on Wormhole's Tilt (dev) network.
+    pub const POST_MESSAGE_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX");
+
+    /// Verify VAA shim program ID on Wormhole's Tilt (dev) network.
+    pub const VERIFY_VAA_SHIM_PROGRAM_ID_ARRAY: [u8; 32] =
+        bs58::decode_pubkey("EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at");
+
+    crate::derive_consts!();
+}
 
-    #[test]
-    fn test_post_message_shim_event_authority() {
-        let expected = crate::find_event_authority_address(&POST_MESSAGE_SHIM_PROGRAM_ID);
-        assert_eq!(
-            (
-                POST_MESSAGE_SHIM_EVENT_AUTHORITY,
-                POST_MESSAGE_SHIM_EVENT_AUTHORITY_BUMP
-            ),
-            expected
-        );
+cfg_if::cfg_if! {
+    if #[cfg(feature = "testnet")] {
+        pub use devnet::*;
+    } else if #[cfg(feature = "localnet")] {
+        pub use localnet::*;
+    }
+    // Default to mainnet.
+    else {
+        pub use mainnet::*;
     }
 }

+ 4 - 2
svm/wormhole-core-shims/programs/post-message/Cargo.toml

@@ -13,7 +13,7 @@ version.workspace = true
 crate-type = ["cdylib", "lib"]
 
 [features]
-default = []
+default = [ "from-env" ]
 no-entrypoint = []
 
 ### Network types
@@ -23,6 +23,8 @@ localnet = ["wormhole-svm-definitions/localnet"]
 ### Specific networks
 solana = ["wormhole-svm-definitions/solana"]
 
+from-env = ["wormhole-svm-definitions/from-env"]
+
 [dependencies]
 solana-program.workspace = true
 wormhole-svm-definitions.workspace = true
@@ -30,4 +32,4 @@ wormhole-svm-shim.workspace = true
 
 [dev-dependencies]
 solana-program-test.workspace = true
-solana-sdk.workspace = true
+solana-sdk.workspace = true

+ 4 - 2
svm/wormhole-core-shims/programs/verify-vaa/Cargo.toml

@@ -13,7 +13,7 @@ version.workspace = true
 crate-type = ["cdylib", "lib"]
 
 [features]
-default = []
+default = [ "from-env" ]
 no-entrypoint = []
 
 ### Network types
@@ -23,6 +23,8 @@ localnet = ["wormhole-svm-definitions/localnet"]
 ### Specific networks
 solana = ["wormhole-svm-definitions/solana"]
 
+from-env = ["wormhole-svm-definitions/from-env"]
+
 [dependencies]
 solana-program.workspace = true
 wormhole-svm-definitions.workspace = true
@@ -33,4 +35,4 @@ base64.workspace = true
 borsh.workspace = true
 solana-program-test.workspace = true
 solana-sdk.workspace = true
-wormhole-svm-definitions = { workspace = true, features = ["borsh"]}
+wormhole-svm-definitions = { workspace = true, features = ["borsh"]}