diff --git a/.registryrc b/.registryrc index a689dace0a..7a2e93dec4 100644 --- a/.registryrc +++ b/.registryrc @@ -1 +1 @@ -d984e8113bb795a01ffe040539a63b1227749d71 +58b181ec6ce4938c15dce9aa966920ff5ef7b3b2 diff --git a/rust/sealevel/client/src/router.rs b/rust/sealevel/client/src/router.rs index 313322a1ea..3ebc3be2fe 100644 --- a/rust/sealevel/client/src/router.rs +++ b/rust/sealevel/client/src/router.rs @@ -8,7 +8,12 @@ use std::{ use solana_client::rpc_client::RpcClient; use solana_program::instruction::Instruction; -use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; +use solana_sdk::{ + account_utils::StateMut, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + commitment_config::CommitmentConfig, + pubkey::Pubkey, +}; use account_utils::DiscriminatorData; use hyperlane_sealevel_connection_client::router::RemoteRouterConfig; @@ -382,12 +387,6 @@ pub(crate) fn deploy_routers< .get(*chain_name) .unwrap_or_else(|| panic!("Chain config not found for chain: {}", chain_name)); - if let Some(configured_owner) = app_config.router_config().ownable.owner { - if configured_owner != ctx.payer_pubkey { - println!("WARNING: Ownership transfer is not yet supported in this deploy tooling, ownership is granted to the payer account"); - } - } - adjust_gas_price_if_needed(chain_name.as_str(), ctx); // Deploy - this is idempotent. @@ -423,6 +422,8 @@ pub(crate) fn deploy_routers< app_config.router_config(), chain_config, ); + + configure_upgrade_authority(ctx, &program_id, app_config.router_config(), chain_config); } // Now enroll all the routers. @@ -540,6 +541,16 @@ fn configure_owner( let expected_owner = Some(router_config.ownable.owner(ctx.payer_pubkey)); if actual_owner != expected_owner { + if actual_owner != Some(ctx.payer_pubkey) { + println!( + "WARNING: Ownership transfer cannot be completed for chain: {} ({}) from {:?} to {:?}, the existing owner is not the payer account", + chain_config.name, + chain_config.domain_id(), + actual_owner, + expected_owner, + ); + return; + } ctx.new_txn() .add_with_description( deployer.set_owner_instruction(&client, program_id, expected_owner), @@ -552,9 +563,109 @@ fn configure_owner( ) .with_client(&client) .send_with_payer(); + + // Sanity check that it was updated! + + // Sleep 5 seconds for the owner to update + std::thread::sleep(std::time::Duration::from_secs(5)); + + let new_owner = deployer.get_owner(&client, program_id); + assert_eq!(new_owner, expected_owner); } } +/// Idempotent. Attempts to set the upgrade authority to the intended owner if +/// the payer can change the upgrade authority. +fn configure_upgrade_authority( + ctx: &mut Context, + program_id: &Pubkey, + router_config: &RouterConfig, + chain_config: &ChainMetadata, +) { + let client = chain_config.client(); + + let actual_upgrade_authority = get_program_upgrade_authority(&client, program_id).unwrap(); + let expected_upgrade_authority = Some(router_config.ownable.owner(ctx.payer_pubkey)); + + // And the upgrade authority is not what we expect... + if actual_upgrade_authority.is_some() && actual_upgrade_authority != expected_upgrade_authority + { + // Flag if we can't change the upgrade authority + if actual_upgrade_authority != Some(ctx.payer_pubkey) { + println!( + "WARNING: Upgrade authority transfer cannot be completed for chain: {} ({}) from {:?} to {:?}, the existing upgrade authority is not the payer account", + chain_config.name, + chain_config.domain_id(), + actual_upgrade_authority, + expected_upgrade_authority, + ); + return; + } + + // Then set the upgrade authority to what we expect. + ctx.new_txn() + .add_with_description( + bpf_loader_upgradeable::set_upgrade_authority( + program_id, + actual_upgrade_authority.as_ref().unwrap(), + expected_upgrade_authority.as_ref(), + ), + format!( + "Setting upgrade authority for chain: {} ({}) to {:?}", + chain_config.name, + chain_config.domain_id(), + expected_upgrade_authority, + ), + ) + .with_client(&client) + .send_with_payer(); + + // Sanity check that it was updated! + + // Sleep 5 seconds for the upgrade authority to update + std::thread::sleep(std::time::Duration::from_secs(5)); + + let new_upgrade_authority = get_program_upgrade_authority(&client, program_id).unwrap(); + assert_eq!(new_upgrade_authority, expected_upgrade_authority); + } +} + +fn get_program_upgrade_authority( + client: &RpcClient, + program_id: &Pubkey, +) -> Result, &'static str> { + let program_account = client.get_account(program_id).unwrap(); + // If the program isn't upgradeable, exit + if program_account.owner != bpf_loader_upgradeable::id() { + return Err("Program is not upgradeable"); + } + + // The program id must actually be a program + let programdata_address = if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = program_account.state() + { + programdata_address + } else { + return Err("Unable to deserialize program account"); + }; + + let program_data_account = client.get_account(&programdata_address).unwrap(); + + // If the program data account somehow isn't deserializable, exit + let actual_upgrade_authority = if let Ok(UpgradeableLoaderState::ProgramData { + upgrade_authority_address, + slot: _, + }) = program_data_account.state() + { + upgrade_authority_address + } else { + return Err("Unable to deserialize program data account"); + }; + + Ok(actual_upgrade_authority) +} + /// For each chain in app_configs_to_deploy, enrolls all the remote routers. /// Idempotent. fn enroll_all_remote_routers< diff --git a/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/program-ids.json index efaac3bc5a..49db45f0e0 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/program-ids.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/program-ids.json @@ -1,10 +1,10 @@ { - "hyperevm": { - "hex": "0x00000000000000000000000096029bcf706fac4176492f4a05f63f7d23ce78fb", - "base58": "11111111111136DQQztgVwcA4ZYDq9QhZhnprvHp" - }, "solanamainnet": { "hex": "0x2f7bbb8b14ccafc48c417e6ba387fa05db8df469156c7a0a923257ad994016cc", "base58": "4CMbJtieJ7EboZZGSbXTQjW5i2sL638jFvE3dWTYG3SK" + }, + "hyperevm": { + "hex": "0x00000000000000000000000096029bcf706fac4176492f4a05f63f7d23ce78fb", + "base58": "11111111111136DQQztgVwcA4ZYDq9QhZhnprvHp" } } \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/token-config.json index 924e873acb..3189e542c4 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/SOL-hyperevm-solanamainnet/token-config.json @@ -9,6 +9,7 @@ "solanamainnet": { "type": "native", "decimals": 9, - "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF" + "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", + "owner": "BNGDJ1h9brgt6FFVd8No1TVAH48Fp44d7jkuydr1URwJ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/SOL-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/SOL-solanamainnet-sonicsvm/token-config.json index 2f13111aed..95556a44d4 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/SOL-solanamainnet-sonicsvm/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/SOL-solanamainnet-sonicsvm/token-config.json @@ -3,11 +3,12 @@ "type": "native", "decimals": 9, "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", - "interchainSecurityModule": "NtVfGz6mMXe17Jy8Mt8pvStgwFbGKHkSvxPeWn1FMNu" + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" }, "sonicsvm": { "type": "native", "decimals": 9, - "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief" + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/program-ids.json index c26f244899..0da1ab661d 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/program-ids.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/program-ids.json @@ -1,10 +1,10 @@ { - "solanamainnet": { - "hex": "0x185ca10cb892c8fbc6857a218f9071ed3d860de9cf81eaf4aac68022f34fe57b", - "base58": "2e6hyJbUpbhqbJzorDZ1m4QVTj5oPhsn2H3KBaMFVXAz" - }, "sonicsvm": { "hex": "0x4857253b685b7aead0442c6566a83b93b28eb0125adeb490a19ef0010e8e34ad", "base58": "5sPRiRLfmohVmtkgiGV6scrzy2C6qEZRGRUiePZf1Fs2" + }, + "solanamainnet": { + "hex": "0x185ca10cb892c8fbc6857a218f9071ed3d860de9cf81eaf4aac68022f34fe57b", + "base58": "2e6hyJbUpbhqbJzorDZ1m4QVTj5oPhsn2H3KBaMFVXAz" } } \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/token-config.json index 5284ecf204..b9308644ac 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/SONIC-solanamainnet-sonicsvm/token-config.json @@ -3,8 +3,8 @@ "type": "collateral", "decimals": 9, "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", - "interchainSecurityModule": "NtVfGz6mMXe17Jy8Mt8pvStgwFbGKHkSvxPeWn1FMNu", - "token": "SonicxvLud67EceaEzCLRnMTBqzYUUYNr93DBkBdDES" + "token": "SonicxvLud67EceaEzCLRnMTBqzYUUYNr93DBkBdDES", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" }, "sonicsvm": { "type": "synthetic", @@ -12,6 +12,7 @@ "name": "Sonic SVM", "symbol": "SONIC", "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/63ae6c0a0415d480c00880e64ec8a9c3724b4e37/deployments/warp_routes/SONIC/metadata.json", - "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief" + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/program-ids.json index ea90925ce6..dfd758fbbb 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/program-ids.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/program-ids.json @@ -1,10 +1,10 @@ { - "solanamainnet": { - "hex": "0x78f010d70282133383abb61fa5d2c35274fceec9485b898ddb4c6bed2eeb61d0", - "base58": "996EsR8a7MC6odE6j7sjsArmDQVqB96qWu84wHdthahm" - }, "sonicsvm": { "hex": "0xa246507f376539e22612cb216b549c958fc9a8eaa470ef9d5320e40493adc81e", "base58": "BvTEYSqCcfMwpAriC1vDpNhzR1JWzasRFfCPCdgsYaCd" + }, + "solanamainnet": { + "hex": "0x78f010d70282133383abb61fa5d2c35274fceec9485b898ddb4c6bed2eeb61d0", + "base58": "996EsR8a7MC6odE6j7sjsArmDQVqB96qWu84wHdthahm" } } \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/token-config.json index 97fd59e3e3..3ac9a0a4b8 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/USDC-solanamainnet-sonicsvm/token-config.json @@ -3,8 +3,8 @@ "type": "collateral", "decimals": 6, "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", - "interchainSecurityModule": "NtVfGz6mMXe17Jy8Mt8pvStgwFbGKHkSvxPeWn1FMNu", - "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" + "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" }, "sonicsvm": { "type": "synthetic", @@ -12,6 +12,7 @@ "name": "USD Coin", "symbol": "USDC", "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/63ae6c0a0415d480c00880e64ec8a9c3724b4e37/deployments/warp_routes/USDC/metadata.json", - "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief" + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/program-ids.json index 6939473da0..2eb84c5b5c 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/program-ids.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/program-ids.json @@ -1,10 +1,10 @@ { - "solanamainnet": { - "hex": "0xa844d77ea1aaa0ec8697646c2d348cc9e843e070f3bf92a3fef4ba976c56bcc5", - "base58": "CKrNt2y1e2H9728mHRVYyF2owy9eKreepRKpTMj2j8JG" - }, "sonicsvm": { "hex": "0x988d8587170da1813da9ce24725953628f7e6fec644e1bde4874774b0f17ed30", "base58": "BGW8geBw12Yyp4rW7Fp97a3CQRA4Czi8PdtuV2Ec3Vdy" + }, + "solanamainnet": { + "hex": "0xa844d77ea1aaa0ec8697646c2d348cc9e843e070f3bf92a3fef4ba976c56bcc5", + "base58": "CKrNt2y1e2H9728mHRVYyF2owy9eKreepRKpTMj2j8JG" } } \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/token-config.json index b488b91d7c..5fca1507c2 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/USDT-solanamainnet-sonicsvm/token-config.json @@ -3,8 +3,8 @@ "type": "collateral", "decimals": 6, "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", - "interchainSecurityModule": "NtVfGz6mMXe17Jy8Mt8pvStgwFbGKHkSvxPeWn1FMNu", - "token": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" + "token": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" }, "sonicsvm": { "type": "synthetic", @@ -12,6 +12,7 @@ "name": "Tether USD", "symbol": "USDT", "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/63ae6c0a0415d480c00880e64ec8a9c3724b4e37/deployments/warp_routes/USDT/metadata.json", - "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief" + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/program-ids.json new file mode 100644 index 0000000000..66babf21ce --- /dev/null +++ b/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/program-ids.json @@ -0,0 +1,10 @@ +{ + "sonicsvm": { + "hex": "0x3cfad3af06f01be3d05923b1ad9446da5c9cb06b229b10626ae224565bccc79f", + "base58": "573J5VSCMCvUVPBBPmr13ovtEmgzU5J1kyLLJ8L3XMJ6" + }, + "solanamainnet": { + "hex": "0xf341c0ab03c8e93493dc3649ec723fc23fc92d09893feeb126137a49b5923694", + "base58": "HNaDuUrtr34tXZApiAMGHG9DgAvGYsY5C6w9M2iHu59u" + } +} \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/token-config.json new file mode 100644 index 0000000000..0b38ee85a5 --- /dev/null +++ b/rust/sealevel/environments/mainnet3/warp-routes/lrtsSOL-solanamainnet-sonicsvm/token-config.json @@ -0,0 +1,18 @@ +{ + "solanamainnet": { + "type": "collateral", + "decimals": 9, + "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", + "token": "4tARAT4ssRYhrENCTxxZrmjL741eE2G23Q1zLPDW2ipf", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" + }, + "sonicsvm": { + "type": "synthetic", + "decimals": 9, + "name": "adraLRT SOL (Solayer)", + "symbol": "lrtsSOL", + "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/0342615816a74737bb5c25d7edc4cb0a691cca21/deployments/warp_routes/lrtsSOL/metadata.json", + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" + } +} diff --git a/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/program-ids.json index 2802500cb0..b5da511c22 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/program-ids.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/program-ids.json @@ -1,10 +1,10 @@ { - "solanamainnet": { - "hex": "0x7c92b922efe079f13c556b637fa1d245ebe52e5ad60d4ec3fc5d55f4ef185759", - "base58": "9PHKQFEDzedHuigSm1ZBojEX4DVF3cincGZwy3k7VHTN" - }, "sonicsvm": { "hex": "0x07d327e3a00042d94b25cb1a910e0a34ccfb68f61dec7f0297d8a07089af2ae1", "base58": "XYbsJQGzZgPDbt9Swd2ao54nhGSq8Wjq23MoogHvEq6" + }, + "solanamainnet": { + "hex": "0x7c92b922efe079f13c556b637fa1d245ebe52e5ad60d4ec3fc5d55f4ef185759", + "base58": "9PHKQFEDzedHuigSm1ZBojEX4DVF3cincGZwy3k7VHTN" } } \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/token-config.json index 491fa2ebd5..a4c9c76926 100644 --- a/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/token-config.json +++ b/rust/sealevel/environments/mainnet3/warp-routes/sSOL-solanamainnet-sonicsvm/token-config.json @@ -3,8 +3,8 @@ "type": "collateral", "decimals": 9, "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", - "interchainSecurityModule": "NtVfGz6mMXe17Jy8Mt8pvStgwFbGKHkSvxPeWn1FMNu", - "token": "sSo14endRuUbvQaJS3dq36Q829a3A6BEfoeeRGJywEh" + "token": "sSo14endRuUbvQaJS3dq36Q829a3A6BEfoeeRGJywEh", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" }, "sonicsvm": { "type": "synthetic", @@ -12,6 +12,7 @@ "name": "Solayer SOL", "symbol": "sSOL", "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/63ae6c0a0415d480c00880e64ec8a9c3724b4e37/deployments/warp_routes/sSOL/metadata.json", - "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief" + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" } } diff --git a/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/program-ids.json b/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/program-ids.json new file mode 100644 index 0000000000..68079d2eec --- /dev/null +++ b/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/program-ids.json @@ -0,0 +1,10 @@ +{ + "solanamainnet": { + "hex": "0xda79c46340361f23add6fad67b75babce6c62b15d39b4d80c10b9b8c71ed7515", + "base58": "Fhqa36L7sFJDiMdu54WUah9stAwRacycqHJYm3b3Geje" + }, + "sonicsvm": { + "hex": "0x989f54126d7fa455b5698b6ddc9a176192a605d6858e3ed16b1829776dd5088a", + "base58": "BGmt6P5djRc3Teo3WLwXfZbEvN9pVJt7wAMgzcCc2idf" + } +} \ No newline at end of file diff --git a/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/token-config.json b/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/token-config.json new file mode 100644 index 0000000000..7cd24f258f --- /dev/null +++ b/rust/sealevel/environments/mainnet3/warp-routes/sonicSOL-solanamainnet-sonicsvm/token-config.json @@ -0,0 +1,18 @@ +{ + "solanamainnet": { + "type": "collateral", + "decimals": 9, + "interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF", + "token": "sonickAJFiVLcYXx25X9vpF293udaWqDMUCiGtk7dg2", + "owner": "9hixEzn9pBzYG1MVWNq3jAuG7RP3vBT5ijN4UFWDVsfD" + }, + "sonicsvm": { + "type": "synthetic", + "decimals": 9, + "name": "Sonic Restaked SOL", + "symbol": "sonicSOL", + "uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/f3462afc9c4f4bb58903608a6890489b29eb5078/deployments/warp_routes/sonicSOL/metadata.json", + "interchainGasPaymaster": "7VResHbw6jRVUa8qfD6e1cbzGmErcLGwgx4o7mLhZief", + "owner": "G8v8LHQw2pWuJiQbbPRHehsNEneMkCzRHz7vSPP2ttiZ" + } +} diff --git a/rust/sealevel/environments/testnet4/warp-routes/SOL-solanatestnet-sonicsvmtestnet/token-config.json b/rust/sealevel/environments/testnet4/warp-routes/SOL-solanatestnet-sonicsvmtestnet/token-config.json index eb345bbc5e..9c3fac3e9f 100644 --- a/rust/sealevel/environments/testnet4/warp-routes/SOL-solanatestnet-sonicsvmtestnet/token-config.json +++ b/rust/sealevel/environments/testnet4/warp-routes/SOL-solanatestnet-sonicsvmtestnet/token-config.json @@ -2,11 +2,13 @@ "solanatestnet": { "type": "native", "decimals": 9, - "interchainGasPaymaster": "hBHAApi5ZoeCYHqDdCKkCzVKmBdwywdT3hMqe327eZB" + "interchainGasPaymaster": "hBHAApi5ZoeCYHqDdCKkCzVKmBdwywdT3hMqe327eZB", + "owner": "6DjHX6Ezjpq3zZMZ8KsqyoFYo1zPSDoiZmLLkxD4xKXS" }, "sonicsvmtestnet": { "type": "native", "decimals": 9, - "interchainGasPaymaster": "9Nq8bJdER4criKNYtkKt3WJDA2LjzHYCH11xKy53fX9" + "interchainGasPaymaster": "9Nq8bJdER4criKNYtkKt3WJDA2LjzHYCH11xKy53fX9", + "owner": "6DjHX6Ezjpq3zZMZ8KsqyoFYo1zPSDoiZmLLkxD4xKXS" } } diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index 02743a6652..1b18c644ca 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -697,7 +697,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'c98b615-20250221-155531', + tag: 'ae8f7c6-20250227-181639', }, blacklist, gasPaymentEnforcement: gasPaymentEnforcement, diff --git a/typescript/infra/config/environments/mainnet3/funding.ts b/typescript/infra/config/environments/mainnet3/funding.ts index 06d2c49139..267d6b660a 100644 --- a/typescript/infra/config/environments/mainnet3/funding.ts +++ b/typescript/infra/config/environments/mainnet3/funding.ts @@ -80,7 +80,7 @@ export const keyFunderConfig: KeyFunderConfig< guru: '100', harmony: '500', hemi: '0.05', - hyperevm: '1', + hyperevm: '5', immutablezkevmmainnet: '25', inevm: '3', ink: '0.05', diff --git a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts index 6ab7476cae..25cb9701ec 100644 --- a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts +++ b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts @@ -70,8 +70,9 @@ export enum WarpRouteIds { SolanaSonicsvmSONIC = 'SONIC/solanamainnet-sonicsvm', SolanaSonicsvmUSDC = 'USDC/solanamainnet-sonicsvm', SolanaSonicsvmUSDT = 'USDT/solanamainnet-sonicsvm', - SolanaSonicsvmUSDStar = 'USDStar/solanamainnet-sonicsvm', SolanaSonicsvmSSOL = 'sSOL/solanamainnet-sonicsvm', + SolanaSonicsvmLrtsSOL = 'lrtsSOL/solanamainnet-sonicsvm', + SolanaSonicsvmSonicSOL = 'sonicSOL/solanamainnet-sonicsvm', ArbitrumEthereumSolanaTreasureSMOL = 'SMOL/arbitrum-ethereum-solanamainnet-treasure', BaseSolanaCDX = 'CDX/base-solanamainnet', HyperevmSolanaSOL = 'SOL/hyperevm-solanamainnet', diff --git a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts index d58af0eac6..0f34fc9b83 100644 --- a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts +++ b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts @@ -43,6 +43,8 @@ async function validateRegistryCommit(commit: string) { async function main() { configureRootLogger(LogFormat.Pretty, LogLevel.Info); const { environment, warpRouteId } = await withWarpRouteId(getArgs()).argv; + const envConfig = getEnvironmentConfig(environment); + const multiProtocolProvider = await envConfig.getMultiProtocolProvider(); let warpRouteIds; if (warpRouteId) { @@ -67,6 +69,7 @@ async function main() { agentConfig.environmentChainNames, registryCommit, ); + await helmManager.runPreflightChecks(multiProtocolProvider); await helmManager.runHelmCommand(HelmCommand.InstallOrUpgrade); }; diff --git a/typescript/infra/src/warp/helm.ts b/typescript/infra/src/warp/helm.ts index e665961447..d17b03d851 100644 --- a/typescript/infra/src/warp/helm.ts +++ b/typescript/infra/src/warp/helm.ts @@ -1,13 +1,39 @@ import { confirm } from '@inquirer/prompts'; import path from 'path'; +import { + ChainMap, + IToken, + MultiProtocolProvider, + SealevelHypTokenAdapter, + TokenStandard, + WarpCore, +} from '@hyperlane-xyz/sdk'; import { difference, rootLogger } from '@hyperlane-xyz/utils'; import { WarpRouteIds } from '../../config/environments/mainnet3/warp/warpIds.js'; +import { + getChainAddresses, + getRegistry, + getWarpCoreConfig, +} from '../../config/registry.js'; import { DeployEnvironment } from '../../src/config/environment.js'; import { HelmManager, removeHelmRelease } from '../../src/utils/helm.js'; import { execCmdAndParseJson, getInfraPath } from '../../src/utils/utils.js'; +// TODO: once we have automated tooling for ATA payer balances and a +// consolidated source of truth, move away from this hardcoded setup. +const ataPayerAlertThreshold: ChainMap = { + eclipsemainnet: 0.01, + solanamainnet: 0.2, + soon: 0.01, + sonicsvm: 0.1, +}; + +// Require the ATA payer balance to be at least this factor of the minimum, +// i.e. 15% higher than the alert threshold. +const minAtaPayerBalanceFactor: number = 1.15; + export class WarpRouteMonitorHelmManager extends HelmManager { static helmReleasePrefix: string = 'hyperlane-warp-route-'; @@ -25,11 +51,33 @@ export class WarpRouteMonitorHelmManager extends HelmManager { super(); } + async runPreflightChecks(multiProtocolProvider: MultiProtocolProvider) { + const warpCoreConfig = getWarpCoreConfig(this.warpRouteId); + if (!warpCoreConfig) { + throw new Error( + `Warp Route ID not found in registry: ${this.warpRouteId}`, + ); + } + + const warpCore = WarpCore.FromConfig(multiProtocolProvider, warpCoreConfig); + + for (const token of warpCore.tokens) { + // If the token is a SealevelHypCollateral or SealevelHypSynthetic, we need to ensure + // the ATA payer is sufficiently funded. + if ( + token.standard === TokenStandard.SealevelHypCollateral || + token.standard === TokenStandard.SealevelHypSynthetic + ) { + await this.ensureAtaPayerBalanceSufficient(warpCore, token); + } + } + } + async helmValues() { return { image: { repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: '52a09c9-20250226-155646', + tag: '83d5ea1-20250227-105909', }, warpRouteId: this.warpRouteId, fullnameOverride: this.helmReleaseName, @@ -107,4 +155,54 @@ export class WarpRouteMonitorHelmManager extends HelmManager { } } } + + async ensureAtaPayerBalanceSufficient(warpCore: WarpCore, token: IToken) { + if (!ataPayerAlertThreshold[token.chainName]) { + rootLogger.warn( + `No ATA payer alert threshold set for chain: ${token.chainName}. Skipping balance check.`, + ); + return; + } + + const registry = getRegistry(); + const chainAddresses = registry.getChainAddresses(token.chainName); + warpCore.multiProvider.metadata[token.chainName] = { + ...warpCore.multiProvider.metadata[token.chainName], + // Hack to get the Mailbox address into the metadata, which WarpCore requires for Sealevel chains. + // This should probably be refactored in the SDK at some point. + // @ts-ignore + mailbox: chainAddresses.mailbox, + }; + + const adapter = token.getAdapter( + warpCore.multiProvider, + ) as SealevelHypTokenAdapter; + const ataPayer = adapter.deriveAtaPayerAccount(); + const provider = adapter.multiProvider.getSolanaWeb3Provider( + token.chainName, + ); + const ataPayerBalanceLamports = await provider.getBalance(ataPayer); + const ataPayerBalance = ataPayerBalanceLamports / 1e9; + + const desiredBalance = + ataPayerAlertThreshold[token.chainName] * minAtaPayerBalanceFactor; + if (ataPayerBalance < desiredBalance) { + rootLogger.warn( + `WARNING: ATA payer balance for ${ + token.chainName + } is below the alert threshold. Desired balance: ${desiredBalance}, current balance: ${ataPayerBalance}. Please fund the ATA payer account: ${ataPayer.toBase58()} on ${ + token.chainName + }`, + ); + await confirm({ + message: 'Continue?', + }); + } else { + rootLogger.info( + `ATA payer balance for ${ + token.chainName + } is sufficient. Current balance: ${ataPayerBalance}, ATA payer: ${ataPayer.toBase58()}`, + ); + } + } }