From 794c56f7701f9cf1948da01614183e3609578fa6 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 29 Apr 2025 14:00:32 +0200 Subject: [PATCH 01/59] feat: add skeleton flow Signed-off-by: Guilherme Felipe da Silva --- solana/cli/.gitignore | 2 + solana/cli/Cargo.toml | 53 +++++++ solana/cli/devnet-amplifier.json | 1 + solana/cli/mainnet.json | 1 + solana/cli/src/broadcast.rs | 166 ++++++++++++++++++++ solana/cli/src/combine.rs | 149 ++++++++++++++++++ solana/cli/src/config.rs | 36 +++++ solana/cli/src/error.rs | 93 ++++++++++++ solana/cli/src/generate.rs | 199 ++++++++++++++++++++++++ solana/cli/src/main.rs | 253 +++++++++++++++++++++++++++++++ solana/cli/src/send.rs | 38 +++++ solana/cli/src/sign.rs | 118 ++++++++++++++ solana/cli/src/types.rs | 163 ++++++++++++++++++++ solana/cli/src/utils.rs | 133 ++++++++++++++++ solana/cli/testnet.json | 1 + 15 files changed, 1406 insertions(+) create mode 100644 solana/cli/.gitignore create mode 100644 solana/cli/Cargo.toml create mode 120000 solana/cli/devnet-amplifier.json create mode 120000 solana/cli/mainnet.json create mode 100644 solana/cli/src/broadcast.rs create mode 100644 solana/cli/src/combine.rs create mode 100644 solana/cli/src/config.rs create mode 100644 solana/cli/src/error.rs create mode 100644 solana/cli/src/generate.rs create mode 100644 solana/cli/src/main.rs create mode 100644 solana/cli/src/send.rs create mode 100644 solana/cli/src/sign.rs create mode 100644 solana/cli/src/types.rs create mode 100644 solana/cli/src/utils.rs create mode 120000 solana/cli/testnet.json diff --git a/solana/cli/.gitignore b/solana/cli/.gitignore new file mode 100644 index 000000000..f9dbd91f3 --- /dev/null +++ b/solana/cli/.gitignore @@ -0,0 +1,2 @@ +target/ +output/ diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml new file mode 100644 index 000000000..ba24e6d14 --- /dev/null +++ b/solana/cli/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +axelar-solana-gateway = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ + "no-entrypoint", +] } +axelar-solana-gas-service = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ + "no-entrypoint", +] } +axelar-solana-governance = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ + "no-entrypoint", +] } +axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ + "no-entrypoint" +] } +axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } +axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } + +axelar-wasm-std = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec" } +voting-verifier = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ + "library", +] } +multisig-prover = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ + "library", +] } + +anyhow = "1.0.98" +bincode = { version = "2.0.1", features = ["serde"] } +bs58 = "0.5.1" +clap = { version = "3.2", features = ["derive", "env"] } +cosmrs = { version = "0.16", features = ["cosmwasm", "rpc", "grpc"] } +cosmwasm-schema = "2" +cosmwasm-std = "1.5" +eyre = "0.6.12" +flate2 = { version = "1.1.1", default-features = false, features = ["zlib"] } +hex = { version = "0.4.3", features = ["serde"] } +rand = "0.9.1" +reqwest = { version = "0.12", features = ["json", "stream"] } +rust_decimal = "1.37.1" +rust_decimal_macros = "1.37.1" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" +solana-clap-v3-utils = "2.2.7" +solana-cli-config = "2.2.7" +solana-client = "2.2.7" +solana-sdk = "2.2.2" +tar = "0.4.44" +thiserror = "2.0.12" +tokio = { version = "1", features = ["full"] } +walkdir = "2.5.0" diff --git a/solana/cli/devnet-amplifier.json b/solana/cli/devnet-amplifier.json new file mode 120000 index 000000000..b01c8bbfa --- /dev/null +++ b/solana/cli/devnet-amplifier.json @@ -0,0 +1 @@ +../../axelar-chains-config/info/devnet-amplifier.json \ No newline at end of file diff --git a/solana/cli/mainnet.json b/solana/cli/mainnet.json new file mode 120000 index 000000000..9be267eff --- /dev/null +++ b/solana/cli/mainnet.json @@ -0,0 +1 @@ +../../axelar-chains-config/info/mainnet.json \ No newline at end of file diff --git a/solana/cli/src/broadcast.rs b/solana/cli/src/broadcast.rs new file mode 100644 index 000000000..33d90b07d --- /dev/null +++ b/solana/cli/src/broadcast.rs @@ -0,0 +1,166 @@ +use crate::config::Config; +use crate::error::{AppError, Result}; +use crate::types::{BroadcastArgs, NetworkType, SignedSolanaTransaction}; +use crate::utils; +use solana_client::rpc_client::RpcClient; +use solana_sdk::{ + commitment_config::CommitmentConfig, hash::Hash, instruction::Instruction as SolanaInstruction, + message::Message, pubkey::Pubkey, signature::Signature, transaction::Transaction, +}; +use std::collections::HashMap; +use std::str::FromStr; + +fn submit_solana_transaction( + url: &str, + signed_tx_data: &SignedSolanaTransaction, +) -> Result { + println!( + "Reconstructing Solana transaction for broadcasting via RPC: {}", + url + ); + + let fee_payer = Pubkey::from_str(&signed_tx_data.unsigned_tx_data.params.fee_payer)?; + let recent_blockhash = + Hash::from_str(&signed_tx_data.unsigned_tx_data.params.blockhash_for_message)?; + let sdk_instructions: Vec = signed_tx_data + .unsigned_tx_data + .instructions + .iter() + .map(SolanaInstruction::try_from) + .collect::>>()?; + + let message = Message::new(&sdk_instructions, Some(&fee_payer)); + + let mut signatures_map: HashMap = signed_tx_data + .signatures + .iter() + .map(|ps| { + Ok(( + Pubkey::from_str(&ps.signer_pubkey)?, + Signature::from_str(&ps.signature)?, + )) + }) + .collect::>>()?; + + let mut ordered_signatures: Vec = + Vec::with_capacity(message.header.num_required_signatures as usize); + let mut missing_sig_for_required_signer = false; + for (index, key) in message.account_keys.iter().enumerate() { + if message.is_signer(index) { + match signatures_map.remove(key) { + Some(signature) => { + ordered_signatures.push(signature); + } + None => { + eprintln!( + "Critical Error during broadcast reconstruction: Missing signature for required signer {} (index {}).", + key, index + ); + ordered_signatures.push(Signature::default()); + missing_sig_for_required_signer = true; + } + } + } + } + + if missing_sig_for_required_signer { + return Err(AppError::BroadcastError( + "Cannot broadcast: Missing signature for one or more required signers during final reconstruction.".to_string() + )); + } + + if !signatures_map.is_empty() { + println!( + "Warning: The following signatures were provided but not required by the transaction message: {:?}", + signatures_map + .keys() + .map(|pk| pk.to_string()) + .collect::>() + ); + } + + let mut transaction = Transaction::new_unsigned(message); + + if ordered_signatures.len() != transaction.signatures.len() { + return Err(AppError::InconsistentState(format!( + "Signature count mismatch during reconstruction: Expected {} based on message header, but gathered {}.", + transaction.signatures.len(), + ordered_signatures.len() + ))); + } + transaction.signatures = ordered_signatures; + transaction.message.recent_blockhash = recent_blockhash; + + println!( + "Transaction reconstructed with blockhash: {}", + recent_blockhash + ); + + if let Err(e) = transaction.verify() { + return Err(AppError::BroadcastError(format!( + "Constructed transaction failed structural verification: {}", + e + ))); + } + + println!("Connecting to RPC client at {}", url); + let rpc_client = RpcClient::new_with_commitment(url.to_string(), CommitmentConfig::confirmed()); + + println!("Broadcasting transaction..."); + match rpc_client.send_and_confirm_transaction_with_spinner(&transaction) { + Ok(tx_signature) => { + println!("Transaction broadcast and confirmed!"); + Ok(tx_signature) + } + Err(client_err) => { + eprintln!("Error during RPC broadcast/confirmation: {}", client_err); + if let solana_client::client_error::ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { data: solana_client::rpc_request::RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), .. } + ) = client_err.kind() { + eprintln!(" -> Preflight Simulation Failure Result: {:?}", sim_result); + } else if let solana_client::client_error::ClientErrorKind::TransactionError(tx_err) = client_err.kind() { + eprintln!(" -> Transaction Error Detail: {:?}", tx_err); + } + Err(AppError::from(client_err)) + } + } +} + +pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Result<()> { + println!("Starting Solana transaction broadcast..."); + + let signed_tx_data = utils::load_signed_solana_transaction(&args.signed_tx_path)?; + println!( + "Loaded combined signed transaction data from: {}", + args.signed_tx_path.display() + ); + + match submit_solana_transaction(&config.url, &signed_tx_data) { + Ok(tx_signature) => { + println!("------------------------------------------"); + println!("✅ Solana Transaction successfully broadcast and confirmed!"); + println!(" Transaction Signature (ID): {}", tx_signature); + println!(" RPC Endpoint: {}", config.url); + let explorer_base_url = "https://explorer.solana.com/tx/"; + let cluster_param = match config.network_type { + NetworkType::Mainnet => "", + NetworkType::Testnet => "?cluster=testnet", + NetworkType::Devnet => "?cluster=devnet", + NetworkType::Localnet => "?cluster=custom", + }; + println!( + " Explorer Link: {}{}{}", + explorer_base_url, tx_signature, cluster_param + ); + println!("------------------------------------------"); + } + Err(e) => { + eprintln!("------------------------------------------"); + eprintln!("❌ Solana Transaction broadcast failed."); + eprintln!("------------------------------------------"); + return Err(e); + } + } + + Ok(()) +} diff --git a/solana/cli/src/combine.rs b/solana/cli/src/combine.rs new file mode 100644 index 000000000..34784a227 --- /dev/null +++ b/solana/cli/src/combine.rs @@ -0,0 +1,149 @@ +use crate::config::Config; +use crate::error::{AppError, Result}; +use crate::types::{CombineArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; +use crate::utils; +use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; +use std::collections::{HashMap, HashSet}; +use std::str::FromStr; + +fn get_required_signers_from_instructions( + instructions: &[crate::types::SerializableInstruction], + fee_payer: &Pubkey, + nonce_authority: Option<&Pubkey>, +) -> Result> { + let mut signers = HashSet::new(); + signers.insert(*fee_payer); + if let Some(na) = nonce_authority { + signers.insert(*na); + } + for ix in instructions { + for acc_meta in &ix.accounts { + if acc_meta.is_signer { + signers.insert(Pubkey::from_str(&acc_meta.pubkey)?); + } + } + } + Ok(signers) +} + +pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result<()> { + println!("Starting Solana signature combination..."); + + let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; + println!( + "Loaded unsigned transaction data from: {}", + args.unsigned_tx_path.display() + ); + + let fee_payer = Pubkey::from_str(&unsigned_tx.params.fee_payer)?; + let nonce_authority_pubkey: Option = unsigned_tx + .params + .nonce_authority + .as_ref() + .map(|s| Pubkey::from_str(s)) + .transpose()?; + let required_signers = get_required_signers_from_instructions( + &unsigned_tx.instructions, + &fee_payer, + nonce_authority_pubkey.as_ref(), + )?; + println!( + "Required signers determined from unsigned data: {:?}", + required_signers + .iter() + .map(|pk| pk.to_string()) + .collect::>() + ); + + let mut signatures_map: HashMap = HashMap::new(); + let mut loaded_paths = HashSet::new(); + + for sig_path in &args.signature_paths { + if !loaded_paths.insert(sig_path.clone()) { + println!( + "Skipping duplicate signature file path: {}", + sig_path.display() + ); + continue; + } + let partial_sig = utils::load_partial_signature(sig_path)?; + println!("Loaded signature from path: {}", sig_path.display()); + let signer_pubkey = Pubkey::from_str(&partial_sig.signer_pubkey)?; + let signature = SolanaSignature::from_str(&partial_sig.signature)?; + println!(" -> Signer: {}, Signature: {}", signer_pubkey, signature); + + if !required_signers.contains(&signer_pubkey) { + println!( + "Warning: Signature provided by {} who is not listed as a required signer. Including it anyway.", + signer_pubkey + ); + } + if let Some(existing_sig) = signatures_map.insert(signer_pubkey, signature) { + if existing_sig != signature { + return Err(AppError::CombinationError(format!( + "Conflicting signatures provided for the same signer: {}.", + signer_pubkey + ))); + } + } + } + + if signatures_map.is_empty() { + return Err(AppError::CombinationError( + "No valid signatures were loaded from the provided paths.".to_string(), + )); + } + println!("Loaded {} unique signatures.", signatures_map.len()); + + let mut missing_signers = Vec::new(); + for required_signer in &required_signers { + if !signatures_map.contains_key(required_signer) { + missing_signers.push(required_signer.to_string()); + } + } + + if !missing_signers.is_empty() { + return Err(AppError::CombinationError(format!( + "Missing required signatures for: {:?}", + missing_signers + ))); + } + println!("Validation OK: All required signers have provided signatures."); + + let message_bytes = hex::decode(&unsigned_tx.signable_message_hex)?; + for (signer_pubkey, signature) in &signatures_map { + if !signature.verify(signer_pubkey.as_ref(), &message_bytes) { + return Err(AppError::CombinationError(format!( + "Signature verification failed for signer: {}", + signer_pubkey + ))); + } + } + + let partial_signatures_vec: Vec = signatures_map + .into_iter() + .map(|(pubkey, sig)| PartialSignature { + signer_pubkey: pubkey.to_string(), + signature: sig.to_string(), + }) + .collect(); + + let signed_tx = SignedSolanaTransaction { + unsigned_tx_data: unsigned_tx, + signatures: partial_signatures_vec, + }; + + utils::save_signed_solana_transaction(&signed_tx, &args.output_signed_tx_path)?; + println!( + "Combined signed Solana transaction data saved to: {}", + args.output_signed_tx_path.display() + ); + + if config.network_type == NetworkType::Mainnet { + println!( + "-> Combined transaction file should be transferred to an online machine for broadcasting." + ); + } + + Ok(()) +} diff --git a/solana/cli/src/config.rs b/solana/cli/src/config.rs new file mode 100644 index 000000000..7c11a11db --- /dev/null +++ b/solana/cli/src/config.rs @@ -0,0 +1,36 @@ +use std::path::PathBuf; +use std::{fs, str::FromStr}; + +use crate::{ + error::{AppError, Result}, + types::NetworkType, +}; + +#[derive(Debug, Clone)] +pub struct Config { + pub url: String, + pub output_dir: PathBuf, + pub network_type: NetworkType, +} + +impl Config { + pub fn new(url: String, output_dir: PathBuf) -> Result { + if !output_dir.exists() { + fs::create_dir_all(&output_dir).map_err(|e| AppError::IoError(e))?; + println!("Created output directory: {}", output_dir.display()); + } else if !output_dir.is_dir() { + return Err(AppError::ConfigError(format!( + "Specified output path exists but is not a directory: {}", + output_dir.display() + ))); + } + + let network_type = NetworkType::from_str(&url)?; + + Ok(Self { + url, + output_dir, + network_type, + }) + } +} diff --git a/solana/cli/src/error.rs b/solana/cli/src/error.rs new file mode 100644 index 000000000..914271f25 --- /dev/null +++ b/solana/cli/src/error.rs @@ -0,0 +1,93 @@ +use solana_sdk::{hash::ParseHashError, transaction::TransactionError}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum AppError { + #[error("Configuration Error: {0}")] + ConfigError(String), + + #[error("I/O Error: {0}")] + IoError(#[from] std::io::Error), + + #[error("Serialization Error (JSON): {0}")] + JsonError(#[from] serde_json::Error), + + #[error("Serialization Error (Hex): {0}")] + HexError(#[from] hex::FromHexError), + + #[error("Serialization Error (Base58): {0}")] + Base58Error(#[from] bs58::decode::Error), + + #[error("Serialization Error (Bincode): {0}")] + BincodeError(#[from] bincode::error::EncodeError), + + #[error("Packaging Error: {0}")] + PackagingError(String), + + #[error("Signing Error: {0}")] + SigningError(String), + + #[error("Hardware Wallet Error: {0}")] + HardwareWalletError(String), + + #[error("Key Not Found: {0}")] + KeyNotFoundError(String), + + #[error("Signature Combination Error: {0}")] + CombinationError(String), + + #[error("Broadcasting Error: {0}")] + BroadcastError(String), + + #[error("Sending error: {0}")] + SendError(String), + + #[error("Invalid Input: {0}")] + InvalidInput(String), + + #[error("Blockchain Interaction Error: {0}")] + ChainError(String), + + #[error("Invalid Network Type: {0}")] + InvalidNetworkType(String), + + #[error("Solana RPC Client Error: {0}")] + SolanaClientError(#[from] solana_client::client_error::ClientError), + + #[error("Solana Program/SDK Error: {0}")] + SolanaProgSdkError(String), + + #[error("Inconsistent State: {0}")] + InconsistentState(String), + + #[error("Feature Not Implemented: {0}")] + NotImplemented(String), + + #[error("Failed to parse hash: {0}")] + ParseHashError(#[from] ParseHashError), + + #[error("Transaction error: {0}")] + TransactionError(#[from] TransactionError), + + #[error("Unknown Error: {0}")] + Unknown(String), +} + +impl From for AppError { + fn from(err: solana_sdk::pubkey::ParsePubkeyError) -> Self { + AppError::InvalidInput(format!("Invalid Solana Pubkey: {}", err)) + } +} +impl From for AppError { + fn from(err: solana_sdk::signature::ParseSignatureError) -> Self { + AppError::InvalidInput(format!("Invalid Solana Signature: {}", err)) + } +} + +impl From for AppError { + fn from(err: solana_sdk::program_error::ProgramError) -> Self { + AppError::SolanaProgSdkError(format!("Solana Program Error: {}", err)) + } +} + +pub type Result = std::result::Result; diff --git a/solana/cli/src/generate.rs b/solana/cli/src/generate.rs new file mode 100644 index 000000000..02dca389d --- /dev/null +++ b/solana/cli/src/generate.rs @@ -0,0 +1,199 @@ +use crate::config::Config; +use crate::error::{AppError, Result}; +use crate::types::{ + GenerateArgs, NetworkType, SerializableInstruction, SolanaTransactionParams, + UnsignedSolanaTransaction, +}; +use crate::utils; +use solana_client::rpc_client::RpcClient; +use solana_sdk::{ + account::Account, hash::Hash, instruction::Instruction as SolanaInstruction, message::Message, + nonce::state::State as NonceState, pubkey::Pubkey, system_instruction, system_program, +}; +use std::fs::File; +use std::path::Path; +use std::str::FromStr; + +fn fetch_latest_blockhash(rpc_url: &str) -> Result { + let rpc_client = RpcClient::new(rpc_url.to_string()); + rpc_client.get_latest_blockhash().map_err(AppError::from) +} + +fn fetch_nonce_data_and_verify( + rpc_url: &str, + nonce_account_pubkey: &Pubkey, + expected_nonce_authority: &Pubkey, +) -> Result { + let rpc_client = RpcClient::new(rpc_url.to_string()); + let nonce_account: Account = rpc_client.get_account(nonce_account_pubkey)?; + + if !system_program::check_id(&nonce_account.owner) { + return Err(AppError::InvalidInput(format!( + "Nonce account {} is not owned by the system program ({}), owner is {}", + nonce_account_pubkey, + system_program::id(), + nonce_account.owner + ))); + } + + let (nonce_state, _size): (NonceState, usize) = + bincode::serde::decode_from_slice(&nonce_account.data, bincode::config::legacy()).map_err( + |e| { + AppError::ChainError(format!( + "Failed to borsh deserialize nonce account state ({}): {}", + nonce_account_pubkey, e + )) + }, + )?; + + match nonce_state { + NonceState::Initialized(data) => { + println!("Nonce account is initialized."); + println!(" -> Stored Nonce (Blockhash): {}", data.blockhash()); + println!(" -> Authority: {}", data.authority); + println!( + " -> Fee Lamports/Signature: {}", + data.fee_calculator.lamports_per_signature + ); + + if data.authority != *expected_nonce_authority { + return Err(AppError::InvalidInput(format!( + "Nonce account authority mismatch. Expected: {}, Found in account: {}", + expected_nonce_authority, data.authority + ))); + } + Ok(data.blockhash()) + } + NonceState::Uninitialized => Err(AppError::InvalidInput(format!( + "Nonce account {} is uninitialized", + nonce_account_pubkey + ))), + } +} + +pub fn generate_unsigned_solana_transaction( + args: &GenerateArgs, + config: &Config, + instruction: SolanaInstruction, +) -> Result<()> { + println!("Starting unsigned Solana transaction generation..."); + println!("Network Type: {:?}", config.network_type); + + println!("Fee Payer: {}", args.fee_payer); + + let mut sdk_instructions: Vec; + let blockhash_for_message: Hash; + let mut params = SolanaTransactionParams { + fee_payer: args.fee_payer.to_string(), + recent_blockhash: None, + nonce_account: None, + nonce_authority: None, + blockhash_for_message: Hash::default().to_string(), + }; + + match (&args.nonce_account, &args.nonce_authority) { + (Some(nonce_account), Some(nonce_authority)) => { + println!("Using Durable Nonce flow."); + if args.recent_blockhash.is_some() { + println!("Warning: --recent-blockhash is ignored when using --nonce-account."); + } + + blockhash_for_message = + fetch_nonce_data_and_verify(&config.url, &nonce_account, &nonce_authority)?; + println!( + "Using Nonce (Blockhash) from account {}: {}", + nonce_account, blockhash_for_message + ); + + params.nonce_account = Some(nonce_account.to_string()); + params.nonce_authority = Some(nonce_authority.to_string()); + + let advance_nonce_ix = + system_instruction::advance_nonce_account(&nonce_account, &nonce_authority); + println!("Prepending AdvanceNonceAccount instruction."); + + sdk_instructions = vec![advance_nonce_ix]; + sdk_instructions.push(instruction); + } + (None, None) => { + println!("Using latest blockhash flow."); + blockhash_for_message = match &args.recent_blockhash { + Some(bh_str) => Hash::from_str(bh_str)?, + None => fetch_latest_blockhash(&config.url)?, + }; + println!("Using Recent Blockhash: {}", blockhash_for_message); + params.recent_blockhash = Some(blockhash_for_message.to_string()); + sdk_instructions = vec![instruction]; + } + _ => { + return Err(AppError::InconsistentState( + "Internal Error: CLI parser should have prevented providing only one nonce argument.".to_string(), + )); + } + } + + params.blockhash_for_message = blockhash_for_message.to_string(); + + let message = Message::new_with_blockhash( + &sdk_instructions, + Some(&args.fee_payer), + &blockhash_for_message, + ); + + let message_bytes = message.serialize(); + let signable_message_hex = hex::encode(&message_bytes); + let unsigned_tx = UnsignedSolanaTransaction { + params, + instructions: sdk_instructions + .iter() + .map(SerializableInstruction::from) + .collect(), + signable_message_hex, + }; + + let unsigned_tx_filename = format!("{}.unsigned.solana.json", args.output_file); + let unsigned_tx_path = config.output_dir.join(&unsigned_tx_filename); + utils::save_unsigned_solana_transaction(&unsigned_tx, &unsigned_tx_path)?; + println!( + "Unsigned Solana transaction saved to: {}", + unsigned_tx_path.display() + ); + + if config.network_type == NetworkType::Mainnet { + println!("Mainnet detected. Packaging dependencies for offline signing..."); + let mut files_to_include = Vec::new(); + files_to_include.push(("unsigned_tx.solana.json", unsigned_tx_path.as_path())); + files_to_include.push(("Cargo.toml", Path::new("./Cargo.toml"))); + files_to_include.push(("Cargo.lock", Path::new("./Cargo.lock"))); + files_to_include.push(("README.md", Path::new("./README.md"))); + files_to_include.push(("src", Path::new("./src"))); + + std::fs::create_dir_all(".cargo").unwrap(); + let config_toml = File::create(".cargo/config.toml").unwrap(); + + let mut cmd = std::process::Command::new("cargo") + .arg("vendor") + .stdout(config_toml) + .spawn() + .unwrap(); + cmd.wait().unwrap(); + + files_to_include.push(("vendor", Path::new("./vendor"))); + files_to_include.push((".cargo/config.toml", Path::new("./.cargo/config.toml"))); + + println!("OK {}", line!()); + let bundle_name = format!("{}.solana.bundle", args.output_file); + let bundle_path = + utils::create_offline_bundle(&bundle_name, &config.output_dir, &files_to_include) + .unwrap(); + println!( + "Offline bundle created for Mainnet: {}", + bundle_path.display() + ); + println!("-> This bundle should be securely transferred to each signer's offline machine."); + } else { + println!("Testnet/Devnet detected. No offline dependency packaging needed."); + } + + Ok(()) +} diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs new file mode 100644 index 000000000..a4d29c82d --- /dev/null +++ b/solana/cli/src/main.rs @@ -0,0 +1,253 @@ +mod broadcast; +mod combine; +mod config; +mod error; +mod generate; +mod send; +mod sign; +mod types; +mod utils; + +use clap::{ArgGroup, Parser, Subcommand}; +use send::build_and_send_solana_transaction; +use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; +use solana_sdk::instruction::Instruction; +use solana_sdk::pubkey::Pubkey; +use std::path::PathBuf; +use std::process::exit; +use types::SendArgs; + +use crate::broadcast::broadcast_solana_transaction; +use crate::combine::combine_solana_signatures; +use crate::config::Config; +use crate::generate::generate_unsigned_solana_transaction; +use crate::sign::sign_solana_transaction; +use crate::types::{BroadcastArgs, CombineArgs, GenerateArgs, SignArgs}; + +#[derive(Parser, Debug)] +#[clap( + author, + version, + about = "Solana Key Management Tool for Offline/Multisig Workflows", + long_about = "A CLI tool to generate, sign (offline/Ledger), combine, and broadcast Solana transactions, supporting durable nonces for delayed signing scenarios." +)] +struct Cli { + #[clap(subcommand)] + command: Command, + + #[clap( + short, + long, + env = "URL_OR_MONIKER", + value_parser = parse_url_or_moniker, + help = "URL for Solana's JSON RPC or moniker (or their first letter): \ + [mainnet-beta, testnet, devnet, localhost]", + )] + url: String, + + /// Directory to store output files (unsigned tx, signatures, bundles) + #[clap( + short = 'o', + long = "output-dir", + default_value = "./output", + parse(from_os_str), + help = "Directory for output files" + )] + output_dir: PathBuf, +} + +#[derive(Subcommand, Debug)] +enum Command { + #[clap(long_about = "")] + Send(SendCommandArgs), + + #[clap(long_about = "Generates an unsigned Solana transaction JSON file. \ + Use --nonce-account and --nonce-authority for durable nonces, otherwise fetches the latest blockhash. \ + On mainnet, also creates a *.tar.gz bundle for offline signing.")] + Generate(GenerateCommandArgs), + + /// Sign an unsigned transaction using a local keypair file or Ledger. + #[clap( + long_about = "Signs the message bytes from an unsigned transaction JSON file. \ + Requires a keypair file path (for testnet/devnet) or the signer's public key (for mainnet/Ledger). \ + Outputs a partial signature JSON file." + )] + Sign(SignCommandArgs), + + /// Combine multiple partial signatures into a single file. + #[clap( + long_about = "Combines multiple partial signature JSON files corresponding to an unsigned transaction. \ + Validates that all required signers (including fee payer and nonce authority if applicable) have provided signatures. \ + Outputs a combined signed transaction JSON file." + )] + Combine(CombineCommandArgs), + + /// Broadcast a combined signed transaction to the Solana network. + #[clap( + long_about = "Reconstructs a Solana transaction from a combined signed transaction JSON file \ + and broadcasts it to the specified network via RPC. Waits for confirmation." + )] + Broadcast(BroadcastCommandArgs), +} + +#[derive(Parser, Debug)] +struct SendCommandArgs { + /// Fee Payer Pubkey (Base58 encoded string) + #[clap(long)] + fee_payer: Pubkey, + + #[clap(long, help = "List of signers (Base58 encoded strings)")] + signer_keys: Vec, + + #[clap(subcommand)] + instruction: InstructionSubcommand, +} + +#[derive(Parser, Debug)] +#[clap(group(ArgGroup::new("blockhash_source").required(false).args(&["nonce-account", "recent-blockhash"])))] +struct GenerateCommandArgs { + /// Fee Payer Pubkey (Base58 encoded string) + #[clap(long)] + fee_payer: Pubkey, + + /// Nonce account Pubkey (Base58). Requires --nonce-authority. + #[clap(long, requires = "nonce-authority")] + nonce_account: Option, + + /// Nonce authority Pubkey (Base58). Must sign the transaction. + #[clap(long, requires = "nonce-account")] + nonce_authority: Option, + + /// Specify a recent blockhash (Base58) instead of fetching or using a nonce. + #[clap(long, global = true)] + recent_blockhash: Option, + + /// Base name for output files (e.g., 'my_tx' -> my_tx.unsigned.solana.json) + #[clap(long = "output-name")] + output_file: String, + + #[clap(subcommand)] + instruction: InstructionSubcommand, +} + +#[derive(Subcommand, Debug)] +enum InstructionSubcommand { +} + +#[derive(Parser, Debug)] +struct SignCommandArgs { + /// Path to the unsigned Solana transaction JSON file (*.unsigned.solana.json) + #[clap(parse(from_os_str))] + unsigned_tx_path: PathBuf, + + /// Signing key identifier (path for keypair file or usb ledger) + #[clap(long = "signer", short = 'k')] + signer_key: String, + + /// Output file path for the generated partial signature JSON (*.sig.json) + #[clap(long = "output-sig", short = 's', parse(from_os_str))] + // Changed from arg(value_parser = ...) + output_signature_path: PathBuf, +} + +#[derive(Parser, Debug)] +struct CombineCommandArgs { + /// Path to the original unsigned Solana transaction JSON file (*.unsigned.solana.json) + #[clap(long, parse(from_os_str))] + unsigned_tx_path: PathBuf, + + /// Paths to the partial signature JSON files (*.sig.json) to combine (provide at least one) + #[clap( + long = "signatures", + short = 's', + required = true, + multiple_values = true, + min_values = 1, + parse(from_os_str) + )] + signature_paths: Vec, + + /// Output file path for the combined signed transaction JSON (*.signed.solana.json) + #[clap(long = "output-signed", short = 'f', parse(from_os_str))] + output_signed_tx_path: PathBuf, +} + +#[derive(Parser, Debug)] +struct BroadcastCommandArgs { + /// Path to the combined signed Solana transaction JSON file (*.signed.solana.json) + #[clap(parse(from_os_str))] + signed_tx_path: PathBuf, +} + +#[tokio::main] +async fn main() { + if let Err(e) = run().await { + eprintln!("\nError: {}", e); + exit(1); + } +} + +async fn run() -> eyre::Result<()> { + let cli = Cli::parse(); + + let config = Config::new(cli.url, cli.output_dir)?; + + match cli.command { + Command::Send(args) => { + let send_args = SendArgs { + fee_payer: args.fee_payer, + signers: args.signer_keys, + }; + let instruction = + build_instruction(&send_args.fee_payer, args.instruction, &config).await?; + build_and_send_solana_transaction(&send_args, &config, instruction)?; + } + Command::Generate(args) => { + let gen_args = GenerateArgs { + fee_payer: args.fee_payer, + nonce_account: args.nonce_account, + nonce_authority: args.nonce_authority, + recent_blockhash: args.recent_blockhash, + output_file: args.output_file, + }; + let instruction = + build_instruction(&gen_args.fee_payer, args.instruction, &config).await?; + println!("Generating..."); + generate_unsigned_solana_transaction(&gen_args, &config, instruction)?; + } + Command::Sign(args) => { + let sign_args = SignArgs { + unsigned_tx_path: args.unsigned_tx_path, + signer_key: args.signer_key, + output_signature_path: args.output_signature_path, + }; + sign_solana_transaction(&sign_args)?; + } + Command::Combine(args) => { + let combine_args = CombineArgs { + unsigned_tx_path: args.unsigned_tx_path, + signature_paths: args.signature_paths, + output_signed_tx_path: args.output_signed_tx_path, + }; + combine_solana_signatures(&combine_args, &config)?; + } + Command::Broadcast(args) => { + let broadcast_args = BroadcastArgs { + signed_tx_path: args.signed_tx_path, + }; + broadcast_solana_transaction(&broadcast_args, &config)?; + } + } + Ok(()) +} + +async fn build_instruction( + fee_payer: &Pubkey, + instruction: InstructionSubcommand, + config: &Config, +) -> eyre::Result { + let serializable_ix = match instruction { + }; + + Ok(serializable_ix) +} diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs new file mode 100644 index 000000000..bb49b03fe --- /dev/null +++ b/solana/cli/src/send.rs @@ -0,0 +1,38 @@ +use solana_clap_v3_utils::keypair::signer_from_path; +use solana_client::rpc_client::RpcClient; +use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::instruction::Instruction; +use solana_sdk::message::Message; +use solana_sdk::transaction::Transaction; + +use crate::config::Config; +use crate::error::{AppError, Result}; +use crate::types::SendArgs; + +pub(crate) fn build_and_send_solana_transaction( + send_args: &SendArgs, + config: &Config, + instruction: Instruction, +) -> Result<()> { + let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); + let message = Message::new(&[instruction], Some(&send_args.fee_payer)); + + let mut transaction = Transaction::new_unsigned(message); + let mut signers = Vec::with_capacity(transaction.signatures.len()); + let signer_context = clap::ArgMatches::default(); // Dummy context + + for signer in send_args.signers.iter() { + let signer = + signer_from_path(&signer_context, signer, "signer", &mut None).map_err(|e| { + AppError::SigningError(format!("Failed to load signer '{}': {}", signer, e)) + })?; + + signers.push(signer); + } + + let blockhash = rpc_client.get_latest_blockhash()?; + transaction.sign(&signers, blockhash); + rpc_client.send_and_confirm_transaction(&transaction)?; + + Ok(()) +} diff --git a/solana/cli/src/sign.rs b/solana/cli/src/sign.rs new file mode 100644 index 000000000..2b73fe9ff --- /dev/null +++ b/solana/cli/src/sign.rs @@ -0,0 +1,118 @@ +use crate::error::{AppError, Result}; +use crate::types::{PartialSignature, SignArgs}; // Removed NetworkType import +use crate::utils; +use solana_clap_v3_utils::keypair::signer_from_path; +use solana_sdk::{pubkey::Pubkey, signer::Signer}; +use std::collections::HashSet; +use std::str::FromStr; + +fn get_required_signers_from_instructions( + instructions: &[crate::types::SerializableInstruction], + fee_payer: &Pubkey, + nonce_authority: Option<&Pubkey>, +) -> Result> { + let mut signers = HashSet::new(); + signers.insert(*fee_payer); + + if let Some(na) = nonce_authority { + signers.insert(*na); + } + + for ix in instructions { + for acc_meta in &ix.accounts { + if acc_meta.is_signer { + signers.insert(Pubkey::from_str(&acc_meta.pubkey)?); + } + } + } + Ok(signers) +} + +pub fn sign_solana_transaction(args: &SignArgs) -> Result<()> { + println!("Starting Solana transaction signing..."); + + let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; + println!( + "Loaded unsigned Solana transaction from: {}", + args.unsigned_tx_path.display() + ); + + let message_bytes = hex::decode(&unsigned_tx.signable_message_hex).map_err(|e| { + AppError::SigningError(format!( + "Failed to decode signable_message_hex from unsigned tx file: {}", + e + )) + })?; + println!( + "Decoded message bytes ({} bytes) to sign.", + message_bytes.len() + ); + + println!("Loading signer from: {}", args.signer_key); + let signer_context = clap::ArgMatches::default(); // Dummy context + let signer = + signer_from_path(&signer_context, &args.signer_key, "signer", &mut None).map_err(|e| { + AppError::SigningError(format!( + "Failed to load signer '{}': {}", + args.signer_key, e + )) + })?; + + let signer_pubkey = signer.pubkey(); + println!("Signer loaded successfully. Pubkey: {}", signer_pubkey); + + println!("Signing message with loaded signer..."); + let signature = signer.try_sign_message(&message_bytes).map_err(|e| { + AppError::SigningError(format!( + "Failed to sign message using '{}': {}", + args.signer_key, e + )) + })?; + println!("Generated signature: {}", signature); + + let partial_signature = PartialSignature { + signer_pubkey: signer_pubkey.to_string(), + signature: signature.to_string(), + }; + + let fee_payer = Pubkey::from_str(&unsigned_tx.params.fee_payer)?; + let nonce_authority_pubkey: Option = unsigned_tx + .params + .nonce_authority + .as_ref() + .map(|s| Pubkey::from_str(s)) + .transpose()?; + + let required_signers = get_required_signers_from_instructions( + &unsigned_tx.instructions, + &fee_payer, + nonce_authority_pubkey.as_ref(), + )?; + + if !required_signers.contains(&signer_pubkey) { + println!( + "Warning: Signer {} provided a signature, but is not found in the list of required signers (Fee Payer, Nonce Authority, or Instruction Signers).", + signer_pubkey + ); + // Consider making this an error: + // return Err(AppError::SigningError(format!("Signer {} is not required by the transaction", signer_pubkey))); + } else { + println!( + "Validation OK: Signer {} is required by the transaction.", + signer_pubkey + ); + } + + println!("Signature generated successfully:"); + println!(" Signer Pubkey: {}", partial_signature.signer_pubkey); + println!(" Signature: {}", partial_signature.signature); + + utils::save_partial_signature(&partial_signature, &args.output_signature_path)?; + + println!( + "Partial signature saved to: {}", + args.output_signature_path.display() + ); + + Ok(()) +} diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs new file mode 100644 index 000000000..b82358e3b --- /dev/null +++ b/solana/cli/src/types.rs @@ -0,0 +1,163 @@ +use crate::error::{AppError, Result}; +use clap::ArgEnum; +use serde::{Deserialize, Serialize}; +use solana_sdk::{instruction::Instruction as SolanaInstruction, pubkey::Pubkey}; +use std::path::PathBuf; +use std::str::FromStr; + +#[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] +pub enum NetworkType { + Mainnet, + Testnet, + Devnet, + Localnet, +} + +impl FromStr for NetworkType { + type Err = AppError; + + fn from_str(s: &str) -> Result { + s.contains("mainnet") + .then_some(NetworkType::Mainnet) + .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) + .or_else(|| s.contains("devnet").then_some(NetworkType::Devnet)) + .or_else(|| s.contains("localhost").then_some(NetworkType::Localnet)) + .ok_or_else(|| AppError::InvalidNetworkType(s.to_string())) + } +} + +pub struct ChainNameOnAxelar(pub String); + +impl From for ChainNameOnAxelar { + fn from(value: NetworkType) -> Self { + match value { + NetworkType::Mainnet => Self("solana-mainnet".to_owned()), + NetworkType::Testnet => Self("solana-testnet".to_owned()), + NetworkType::Devnet => Self("solana-devnet".to_owned()), + NetworkType::Localnet => Self("solana-localnet".to_owned()), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SolanaTransactionParams { + pub fee_payer: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub recent_blockhash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub nonce_account: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub nonce_authority: Option, + pub blockhash_for_message: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SerializableInstruction { + pub program_id: String, + pub accounts: Vec, + #[serde(with = "hex::serde")] + pub data: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SerializableAccountMeta { + pub pubkey: String, + pub is_signer: bool, + pub is_writable: bool, +} + +impl TryFrom<&SerializableInstruction> for SolanaInstruction { + type Error = AppError; + + fn try_from(si: &SerializableInstruction) -> Result { + let program_id = Pubkey::from_str(&si.program_id)?; + let accounts = si + .accounts + .iter() + .map(|sa| { + Ok(solana_sdk::instruction::AccountMeta { + pubkey: Pubkey::from_str(&sa.pubkey)?, + is_signer: sa.is_signer, + is_writable: sa.is_writable, + }) + }) + .collect::>>()?; + + Ok(SolanaInstruction { + program_id, + accounts, + data: si.data.clone(), + }) + } +} + +impl From<&SolanaInstruction> for SerializableInstruction { + fn from(instruction: &SolanaInstruction) -> Self { + Self { + program_id: instruction.program_id.to_string(), + accounts: instruction + .accounts + .iter() + .map(|am| SerializableAccountMeta { + pubkey: am.pubkey.to_string(), + is_signer: am.is_signer, + is_writable: am.is_writable, + }) + .collect(), + data: instruction.data.clone(), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UnsignedSolanaTransaction { + pub params: SolanaTransactionParams, + pub instructions: Vec, + pub signable_message_hex: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PartialSignature { + pub signer_pubkey: String, + pub signature: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SignedSolanaTransaction { + pub unsigned_tx_data: UnsignedSolanaTransaction, + pub signatures: Vec, +} + +#[derive(Debug, Clone)] +pub struct SendArgs { + pub fee_payer: Pubkey, + pub signers: Vec, +} + +#[derive(Debug, Clone)] +pub struct GenerateArgs { + pub fee_payer: Pubkey, + pub nonce_account: Option, + pub nonce_authority: Option, + pub recent_blockhash: Option, + pub output_file: String, +} + +#[derive(Debug, Clone)] +pub struct SignArgs { + pub unsigned_tx_path: PathBuf, + pub signer_key: String, + pub output_signature_path: PathBuf, +} + +#[derive(Debug, Clone)] +pub struct CombineArgs { + pub unsigned_tx_path: PathBuf, + pub signature_paths: Vec, + pub output_signed_tx_path: PathBuf, +} + +#[derive(Debug, Clone)] +pub struct BroadcastArgs { + pub signed_tx_path: PathBuf, +} diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs new file mode 100644 index 000000000..397df7b1d --- /dev/null +++ b/solana/cli/src/utils.rs @@ -0,0 +1,133 @@ +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::sync::LazyLock; + +use crate::error::{AppError, Result}; +use crate::types::{ + NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, +}; + +const DEVNET_AMPLIFIER_CONFIG: &'static str = include_str!("../devnet-amplifier.json"); +const TESTNET_AMPLIFIER_CONFIG: &'static str = include_str!("../testnet.json"); +const MAINNET_AMPLIFIER_CONFIG: &'static str = include_str!("../mainnet.json"); + +static MAINNET_INFO: LazyLock = + LazyLock::new(|| serde_json::from_str(MAINNET_AMPLIFIER_CONFIG).unwrap()); + +static TESTNET_INFO: LazyLock = + LazyLock::new(|| serde_json::from_str(TESTNET_AMPLIFIER_CONFIG).unwrap()); + +static DEVNET_INFO: LazyLock = + LazyLock::new(|| serde_json::from_str(DEVNET_AMPLIFIER_CONFIG).unwrap()); + +pub fn chains_info(network: NetworkType) -> &'static serde_json::Value { + match network { + NetworkType::Mainnet => &*MAINNET_INFO, + NetworkType::Testnet => &*TESTNET_INFO, + NetworkType::Devnet => &*DEVNET_INFO, + NetworkType::Localnet => panic!( + "Cannot automatically load chains info for Localnet. \ + Please pass the required arguments to the CLI." + ), + } +} + +pub fn save_chains_info(network: NetworkType, info: serde_json::Value, output_dir: &Path) { + let path = match network { + NetworkType::Mainnet => "mainnet.json", + NetworkType::Testnet => "testnet.json", + NetworkType::Devnet => "devnet-amplifier.json", + NetworkType::Localnet => panic!("Cannot save chains info for Localnet."), + }; + + let file = std::fs::File::create(output_dir.join(path)).expect("Unable to create file"); + serde_json::to_writer_pretty(file, &info).expect("Unable to write data"); +} + +pub fn read_json_file(path: &Path) -> Result { + let file = File::open(path).map_err(|e| AppError::IoError(e))?; + let reader = std::io::BufReader::new(file); + serde_json::from_reader(reader).map_err(|e| AppError::JsonError(e)) +} + +pub fn write_json_file(data: &T, path: &Path) -> Result<()> { + let file = File::create(path).map_err(|e| AppError::IoError(e))?; + let writer = std::io::BufWriter::new(file); + serde_json::to_writer_pretty(writer, data).map_err(|e| AppError::JsonError(e)) +} + +pub fn load_unsigned_solana_transaction(path: &Path) -> Result { + read_json_file(path) +} + +pub fn save_unsigned_solana_transaction(tx: &UnsignedSolanaTransaction, path: &Path) -> Result<()> { + write_json_file(tx, path) +} + +pub fn load_partial_signature(path: &Path) -> Result { + read_json_file(path) +} + +pub fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Result<()> { + write_json_file(sig, path) +} + +pub fn load_signed_solana_transaction(path: &Path) -> Result { + read_json_file(path) +} + +pub fn save_signed_solana_transaction(tx: &SignedSolanaTransaction, path: &Path) -> Result<()> { + write_json_file(tx, path) +} + +pub fn create_offline_bundle( + bundle_name: &str, + output_dir: &Path, + files_to_include: &[(&str, &Path)], +) -> Result { + let target_path = output_dir.join(format!("{}.tar.gz", bundle_name)); + let tar_gz_file = File::create(&target_path).unwrap(); + let gz_encoder = flate2::write::GzEncoder::new(tar_gz_file, flate2::Compression::default()); + let mut tar_builder = tar::Builder::new(gz_encoder); + tar_builder.follow_symlinks(true); + + for (name_in_archive, path_on_disk) in files_to_include { + if !path_on_disk.exists() { + return Err(AppError::PackagingError(format!( + "File specified for packaging not found: {}", + path_on_disk.display() + ))); + } + if path_on_disk.is_file() { + println!( + "Adding file to bundle: {} (from {})", + name_in_archive, + path_on_disk.display() + ); + tar_builder + .append_path_with_name(path_on_disk, name_in_archive) + .unwrap(); + } else if path_on_disk.is_dir() { + println!( + "Adding directory to bundle: {} (from {})", + name_in_archive, + path_on_disk.display() + ); + tar_builder + .append_dir_all(name_in_archive, path_on_disk) + .unwrap(); + } else { + return Err(AppError::PackagingError(format!( + "Path specified for packaging is not a file or directory: {}", + path_on_disk.display() + ))); + } + } + + let gz_encoder = tar_builder.into_inner().unwrap(); + gz_encoder.finish().unwrap(); + + Ok(target_path) +} diff --git a/solana/cli/testnet.json b/solana/cli/testnet.json new file mode 120000 index 000000000..2f2d28d24 --- /dev/null +++ b/solana/cli/testnet.json @@ -0,0 +1 @@ +../../axelar-chains-config/info/testnet.json \ No newline at end of file From c0ad70d46f975afc21fd1574fec14888dc7c052b Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 29 Apr 2025 14:01:44 +0200 Subject: [PATCH 02/59] feat: add first gateway instructions Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 10976 ++++++++++++++++++++++++++++++++++++ solana/cli/src/gateway.rs | 250 + solana/cli/src/main.rs | 6 + 3 files changed, 11232 insertions(+) create mode 100644 solana/cli/Cargo.lock create mode 100644 solana/cli/src/gateway.rs diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock new file mode 100644 index 000000000..d05ce2e25 --- /dev/null +++ b/solana/cli/Cargo.lock @@ -0,0 +1,10976 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "agave-feature-set" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973a83d0d66d1f04647d1146a07736864f0742300b56bf2a5aadf5ce7b22fe47" +dependencies = [ + "ahash 0.8.11", + "solana-epoch-schedule", + "solana-feature-set-interface", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.16", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 0.99.20", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand 0.8.5", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" +dependencies = [ + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck 0.5.0", + "indexmap 2.9.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rayon", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", + "rayon", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "axelar-executable" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-sol-types", + "axelar-solana-encoding", + "axelar-solana-gateway", + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "axelar-message-primitives" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "bnum 0.10.0", + "borsh 1.5.7", + "bytemuck", + "hex", + "rkyv", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "axelar-solana-encoding" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "arrayref", + "borsh 1.5.7", + "bs58", + "hex", + "rkyv", + "rs_merkle", + "sha3", + "solana-program", + "thiserror 1.0.69", + "udigest", +] + +[[package]] +name = "axelar-solana-gas-service" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "axelar-solana-gas-service-events", + "borsh 1.5.7", + "bytemuck", + "program-utils", + "solana-program", + "spl-token 6.0.0", + "spl-token-2022 8.0.1", +] + +[[package]] +name = "axelar-solana-gas-service-events" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "event-utils", + "solana-program", +] + +[[package]] +name = "axelar-solana-gateway" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "axelar-message-primitives", + "axelar-solana-encoding", + "bincode 1.3.3", + "bitvec", + "borsh 1.5.7", + "bytemuck", + "ed25519-dalek 2.1.1", + "event-utils", + "hex", + "itertools 0.12.1", + "libsecp256k1", + "num-derive 0.4.2", + "num-traits", + "program-utils", + "role-management", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "axelar-solana-governance" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-sol-types", + "axelar-executable", + "axelar-solana-encoding", + "axelar-solana-gateway", + "base64 0.21.7", + "borsh 1.5.7", + "governance-gmp", + "program-utils", + "role-management", + "solana-program", +] + +[[package]] +name = "axelar-solana-its" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "axelar-executable", + "axelar-message-primitives", + "axelar-solana-encoding", + "axelar-solana-gas-service", + "axelar-solana-gateway", + "bitflags 2.9.0", + "borsh 1.5.7", + "event-utils", + "interchain-token-transfer-gmp", + "itertools 0.12.1", + "mpl-token-metadata", + "program-utils", + "role-management", + "solana-program", + "spl-associated-token-account", + "spl-token-2022 8.0.1", + "typed-builder", +] + +[[package]] +name = "axelar-wasm-std" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "alloy-primitives", + "axelar-wasm-std-derive", + "bech32 0.11.0", + "bs58", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "flagset", + "into-inner-derive", + "itertools 0.14.0", + "lazy_static", + "num-traits", + "regex", + "report", + "schemars", + "semver 1.0.26", + "serde", + "serde_json", + "serde_with", + "sha3", + "starknet-checked-felt", + "stellar-xdr", + "strum 0.25.0", + "sui-types", + "thiserror 1.0.69", + "valuable", +] + +[[package]] +name = "axelar-wasm-std-derive" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "cosmwasm-std 2.2.2", + "error-stack", + "heck 0.5.0", + "itertools 0.14.0", + "proc-macro2", + "quote", + "report", + "semver 1.0.26", + "syn 2.0.101", + "thiserror 1.0.69", +] + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 0.1.2", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bcs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" +dependencies = [ + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bip32" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "secp256k1", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" +dependencies = [ + "serde", + "serde-big-array", +] + +[[package]] +name = "bnum" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive 1.5.7", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf19e729cdbd51af9a397fb9ef8ac8378007b797f8273cfbfdf45dcaa316167b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.8", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror 1.0.69", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.26", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cc" +version = "1.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width 0.1.14", + "vec_map", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap 0.16.2", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "axelar-executable", + "axelar-solana-encoding", + "axelar-solana-gas-service", + "axelar-solana-gateway", + "axelar-solana-governance", + "axelar-solana-its", + "axelar-wasm-std", + "bincode 2.0.1", + "bs58", + "clap 3.2.25", + "cosmrs", + "cosmwasm-schema", + "cosmwasm-std 1.5.11", + "eyre", + "flate2", + "hex", + "multisig-prover", + "rand 0.9.1", + "reqwest 0.12.15", + "rust_decimal", + "rust_decimal_macros", + "serde", + "serde_json", + "solana-clap-v3-utils", + "solana-cli-config", + "solana-client", + "solana-sdk", + "tar", + "thiserror 2.0.12", + "tokio", + "voting-verifier", + "walkdir", +] + +[[package]] +name = "client" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "cosmwasm-std 2.2.2", + "error-stack", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "const-hex" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "coordinator" +version = "1.1.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "itertools 0.14.0", + "msgs-derive", + "multisig", + "report", + "router-api", + "semver 1.0.26", + "service-registry-api", + "thiserror 1.0.69", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cosmos-sdk-proto" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e23f6ab56d5f031cde05b8b82a5fefd3a1a223595c79e32317a97189e612bc" +dependencies = [ + "prost", + "prost-types", + "tendermint-proto", + "tonic", +] + +[[package]] +name = "cosmrs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d184abb7b0039cc64f282dfa5b34165e4c5a7410ab46804636d53f4d09aee44" +dependencies = [ + "bip32", + "cosmos-sdk-proto", + "ecdsa", + "eyre", + "k256", + "rand_core 0.6.4", + "serde", + "serde_json", + "signature 2.2.0", + "subtle-encoding", + "tendermint", + "tendermint-rpc", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-core" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b6dc17e7fd89d0a0a58f12ef33f0bbdf09a6a14c3dfb383eae665e5889250e" + +[[package]] +name = "cosmwasm-crypto" +version = "1.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c82e56962f0f18c9a292aa59940e03a82ce15ef79b93679d5838bb8143f0df" +dependencies = [ + "digest 0.10.7", + "ed25519-zebra 3.1.0", + "k256", + "rand_core 0.6.4", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-crypto" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2f53285517db3e33d825b3e46301efe845135778527e1295154413b2f0469e" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "cosmwasm-core", + "curve25519-dalek 4.1.3", + "digest 0.10.7", + "ecdsa", + "ed25519-zebra 4.0.3", + "k256", + "num-traits", + "p256", + "rand_core 0.6.4", + "rayon", + "sha2 0.10.8", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b804ff15a0e059c88f85ae0e868cf8c7aba9d61221e46f1ad7250f270628c7" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-derive" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a782b93fae93e57ca8ad3e9e994e784583f5933aeaaa5c80a545c4b437be2047" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "cosmwasm-schema" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6984ab21b47a096e17ae4c73cea2123a704d4b6686c39421247ad67020d76f95" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01c9214319017f6ebd8e299036e1f717fa9bb6724e758f7d6fb2477599d1a29" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "cosmwasm-std" +version = "1.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763340055b84e5482ed90fec8194ff7d59112267a09bbf5819c9e3edca8c052e" +dependencies = [ + "base64 0.21.7", + "bech32 0.9.1", + "bnum 0.10.0", + "cosmwasm-crypto 1.5.11", + "cosmwasm-derive 1.5.11", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm 0.5.2", + "sha2 0.10.8", + "static_assertions", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-std" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf82335c14bd94eeb4d3c461b7aa419ecd7ea13c2efe24b97cd972bdb8044e7d" +dependencies = [ + "base64 0.22.1", + "bech32 0.11.0", + "bnum 0.11.0", + "cosmwasm-core", + "cosmwasm-crypto 2.2.2", + "cosmwasm-derive 2.2.2", + "derive_more 1.0.0", + "hex", + "rand_core 0.6.4", + "rmp-serde", + "schemars", + "serde", + "serde-json-wasm 1.0.1", + "sha2 0.10.8", + "static_assertions", + "thiserror 1.0.69", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crate-git-revision" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version 0.4.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "cw-storage-macro" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90e7828ea0175c45743178f8b0290513752e949b2fdfa5bda52a7389d732610" +dependencies = [ + "syn 2.0.101", +] + +[[package]] +name = "cw-storage-plus" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" +dependencies = [ + "cosmwasm-std 2.2.2", + "cw-storage-macro", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07dfee7f12f802431a856984a32bce1cb7da1e6c006b5409e3981035ce562dec" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "schemars", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "cw2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "schemars", + "semver 1.0.26", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.101", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.101", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "unicode-xid", +] + +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.2.0", + "spki", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek 1.0.1", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "hashbrown 0.14.5", + "hex", + "rand_core 0.6.4", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-display-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "error-stack" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a72baa257b5e0e2de241967bc5ee8f855d6072351042688621081d66b2a76b" +dependencies = [ + "anyhow", + "eyre", + "rustc_version 0.4.1", +] + +[[package]] +name = "escape-bytes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror 1.0.69", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.101", + "toml 0.8.22", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.101", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum 0.26.3", + "syn 2.0.101", + "tempfile", + "thiserror 1.0.69", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "event-macros" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "keccak-const", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "event-utils" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "axelar-message-primitives", + "base64 0.21.7", + "event-macros", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "evm-gateway" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "cosmwasm-std 2.2.2", + "error-stack", + "ethers-contract", + "ethers-core", + "k256", + "multisig", + "router-api", + "sha3", + "thiserror 1.0.69", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "flagset" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" +dependencies = [ + "serde", +] + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gateway" +version = "1.1.1" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "gateway-api", + "itertools 0.14.0", + "report", + "router-api", + "semver 1.0.26", + "serde", + "serde_json", + "thiserror 1.0.69", + "voting-verifier", +] + +[[package]] +name = "gateway-api" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "error-stack", + "msgs-derive", + "router-api", + "thiserror 1.0.69", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "governance-gmp" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "hex", +] + +[[package]] +name = "governor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.9.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap 2.9.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hidapi" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "pkg-config", + "windows-sys 0.48.0", +] + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.9", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.3.1", + "hyper 1.6.0", + "hyper-util", + "rustls 0.23.26", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.2", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.32", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width 0.2.0", + "web-time", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "interchain-token-transfer-gmp" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "hex", +] + +[[package]] +name = "into-inner-derive" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "error-stack", + "quote", + "report", + "syn 2.0.101", + "thiserror 1.0.69", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.2", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + +[[package]] +name = "lambdaworks-crypto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2 0.10.8", + "sha3", +] + +[[package]] +name = "lambdaworks-math" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1bd2632acbd9957afc5aeec07ad39f078ae38656654043bf16e046fa2730e23" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libm" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "mpl-token-metadata" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6a3000e761d3b2d685662a3a9ee99826f9369fb033bd1bc7011b1cf02ed9" +dependencies = [ + "borsh 0.10.4", + "num-derive 0.3.3", + "num-traits", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "msgs-derive" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "cosmwasm-std 2.2.2", + "error-stack", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "multisig" +version = "1.1.1" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-crypto 2.2.2", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw-utils", + "cw2", + "ed25519-dalek 2.1.1", + "enum-display-derive", + "error-stack", + "getrandom 0.2.16", + "itertools 0.11.0", + "k256", + "msgs-derive", + "report", + "rewards", + "router-api", + "semver 1.0.26", + "serde", + "serde_json", + "sha3", + "signature-verifier-api", + "thiserror 1.0.69", +] + +[[package]] +name = "multisig-prover" +version = "1.1.1" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "bcs", + "client", + "coordinator", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw-utils", + "cw2", + "error-stack", + "ethers-contract", + "ethers-core", + "evm-gateway", + "gateway", + "gateway-api", + "hex", + "itertools 0.11.0", + "k256", + "msgs-derive", + "multisig", + "report", + "router-api", + "semver 1.0.26", + "serde_json", + "service-registry", + "service-registry-api", + "sha3", + "stellar", + "stellar-xdr", + "sui-gateway", + "thiserror 1.0.69", + "voting-verifier", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "peg" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9928cfca101b36ec5163e70049ee5368a8a1c3c6efc9ca9c5f9cc2f816152477" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6298ab04c202fa5b5d52ba03269fb7b74550b150323038878fe6c372d8280f71" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "132dca9b868d927b35b5dd728167b2dee150eb1ad686008fc71ccb298b776fca" + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy 0.8.25", +] + +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn 2.0.101", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "program-utils" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "rkyv", + "solana-program", +] + +[[package]] +name = "proptest" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.9.0", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quanta" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls 0.23.26", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +dependencies = [ + "bytes", + "getrandom 0.3.2", + "rand 0.9.1", + "ring", + "rustc-hash 2.1.1", + "rustls 0.23.26", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "report" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "error-stack", + "eyre", + "itertools 0.14.0", + "thiserror 1.0.69", + "valuable", +] + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.9", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-rustls 0.27.5", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower 0.5.2", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "windows-registry", +] + +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http 0.2.12", + "reqwest 0.11.27", + "serde", + "task-local-extensions", + "thiserror 1.0.69", +] + +[[package]] +name = "rewards" +version = "1.2.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "itertools 0.11.0", + "msgs-derive", + "report", + "router-api", + "semver 1.0.26", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "role-management" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "bincode 1.3.3", + "bitflags 2.9.0", + "borsh 1.5.7", + "program-utils", + "solana-program", +] + +[[package]] +name = "router-api" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "error-stack", + "flagset", + "msgs-derive", + "report", + "schemars", + "serde", + "serde_json", + "sha3", + "thiserror 1.0.69", + "valuable", +] + +[[package]] +name = "rpassword" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.59.0", +] + +[[package]] +name = "rs_merkle" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" +dependencies = [ + "sha2 0.10.8", +] + +[[package]] +name = "rtoolbox" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ruint" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a46eb779843b2c4f21fac5773e25d6d5b7c8f0922876c91541790d2ca27eef" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.1", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rust_decimal" +version = "1.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" +dependencies = [ + "arrayvec", + "borsh 1.5.7", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6268b74858287e1a062271b988a0c534bf85bbeb567fe09331bf40ed78113d5" +dependencies = [ + "quote", + "syn 2.0.101", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.26", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4937d110d34408e9e5ad30ba0b0ca3b6a8a390f8db3636db60144ac4fa792750" +dependencies = [ + "core-foundation 0.10.0", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.26", + "rustls-native-certs 0.8.1", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.1", + "security-framework 3.2.0", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" +dependencies = [ + "cfg-if", + "derive_more 1.0.0", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.101", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9213a07d53faa0b8dd81e767a54a8188a242fdb9be99ab75ec576a774bfdd7" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.9.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "service-registry" +version = "1.1.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "coordinator", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "itertools 0.14.0", + "msgs-derive", + "report", + "router-api", + "schemars", + "semver 1.0.26", + "serde", + "service-registry-api", + "thiserror 1.0.69", +] + +[[package]] +name = "service-registry-api" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "error-stack", + "msgs-derive", + "report", + "router-api", + "schemars", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature-verifier-api" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "error-stack", + "thiserror 1.0.69", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "size-of" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e36eca171fddeda53901b0a436573b3f2391eaa9189d439b2bd8ea8cebd7e3" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "bincode 1.3.3", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c5d7d0f1581d98a869f2569122ded67e0735f3780d787b3e7653bdcd1708a2" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" +dependencies = [ + "bincode 1.3.3", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode 1.3.3", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode 1.3.3", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-bn254" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", +] + +[[package]] +name = "solana-clap-utils" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3c210e89742f6c661eb4e7549eb779dbc56cab4b700a1fd761cd7c9b2de6e6" +dependencies = [ + "chrono", + "clap 2.34.0", + "rpassword", + "solana-clock", + "solana-cluster-type", + "solana-commitment-config", + "solana-derivation-path", + "solana-hash", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-presigner", + "solana-pubkey", + "solana-remote-wallet", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "thiserror 2.0.12", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-clap-v3-utils" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f945634dcb7b4db6d39bbee568e3549a0b4501e1375e94be93f01a9393f0122" +dependencies = [ + "chrono", + "clap 3.2.25", + "rpassword", + "solana-clock", + "solana-cluster-type", + "solana-commitment-config", + "solana-derivation-path", + "solana-hash", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-presigner", + "solana-pubkey", + "solana-remote-wallet", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "solana-zk-token-sdk", + "thiserror 2.0.12", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-cli-config" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cdb4a08bb852494082cd115e3b654b5505af4d2c0e9d24e602553d36dc2f1f5" +dependencies = [ + "dirs-next", + "lazy_static", + "serde", + "serde_derive", + "serde_yaml", + "solana-clap-utils", + "solana-commitment-config", + "url", +] + +[[package]] +name = "solana-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32a6ae5a74f13425eb0f8503b9a2c0bf59581e98deeee2d0555dfe6f05502c9" +dependencies = [ + "async-trait", + "bincode 1.3.3", + "dashmap", + "futures", + "futures-util", + "indexmap 2.9.0", + "indicatif", + "log", + "quinn", + "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-measure", + "solana-message", + "solana-pubkey", + "solana-pubsub-client", + "solana-quic-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-signature", + "solana-signer", + "solana-streamer", + "solana-thin-client", + "solana-time-utils", + "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", + "solana-udp-client", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-client-traits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f0071874e629f29e0eb3dab8a863e98502ac7aba55b7e0df1803fc5cac72a7" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-clock" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c2177a1b9fe8326004f1151a5acd124420b737811080b1035df31349e4d892" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cluster-type" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", +] + +[[package]] +name = "solana-commitment-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac49c4dde3edfa832de1697e9bcdb7c3b3f7cb7a1981b7c62526c8bb6700fb73" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5df17b195d312b66dccdde9beec6709766d8230cb4718c4c08854f780d0309" +dependencies = [ + "borsh 1.5.7", + "serde", + "serde_derive", + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-connection-cache" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240bc217ca05f3e1d1d88f1cfda14b785a02288a630419e4a0ecd6b4fa5094b7" +dependencies = [ + "async-trait", + "bincode 1.3.3", + "crossbeam-channel", + "futures-util", + "indexmap 2.9.0", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-time-utils", + "solana-transaction-error", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cf33066cc9a741ff4cc4d171a4a816ea06f9826516b7360d997179a1b3244f" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-define-syscall", + "subtle", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-decode-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a6a6383af236708048f8bd8d03db8ca4ff7baf4a48e5d580f4cce545925470" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf784bb2cb3e02cac9801813c30187344228d2ae952534902108f6150573a33d" + +[[package]] +name = "solana-derivation-path" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-ed25519-program" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0fc717048fdbe5d2ee7d673d73e6a30a094002f4a29ca7630ac01b6bddec04" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "ed25519-dalek 1.0.1", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-epoch-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ef6f0b449290b0b9f32973eefd95af35b01c5c0c34c569f936c34c5b20d77b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" +dependencies = [ + "siphasher", + "solana-hash", + "solana-pubkey", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9c7fbf3e58b64a667c5f35e90af580538a95daea7001ff7806c0662d301bdf" +dependencies = [ + "bincode 1.3.3", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-feature-set" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92f6c09cc41059c0e03ccbee7f5d4cc0a315d68ef0d59b67eb90246adfd8cc35" +dependencies = [ + "ahash 0.8.11", + "lazy_static", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-feature-set-interface" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02007757246e40f10aa936dae4fa27efbf8dbd6a59575a12ccc802c1aea6e708" +dependencies = [ + "ahash 0.8.11", + "solana-pubkey", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f45f94a88efdb512805563181dfa1c85c60a21b6e6d602bf24a2ea88f9399d6e" +dependencies = [ + "serde", + "serde_derive", + "solana-message", + "solana-native-token", +] + +[[package]] +name = "solana-genesis-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968dabd2b92d57131473eddbd475339da530e14f54397386abf303de3a2595a2" +dependencies = [ + "bincode 1.3.3", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-logger", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-shred-version", + "solana-signer", + "solana-time-utils", +] + +[[package]] +name = "solana-hard-forks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c28371f878e2ead55611d8ba1b5fb879847156d04edea13693700ad1a28baf" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" +dependencies = [ + "borsh 1.5.7", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23eef6a09eb8e568ce6839573e4966850e85e9ce71e6ae1a6c930c1c43947de3" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaac98c150932bba4bfbef5b52fae9ef445f767d66ded2f1398382149bc94f69" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" +dependencies = [ + "bincode 1.3.3", + "borsh 1.5.7", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427f2d0d6dc0bb49f16cef5e7f975180d2e80aab9bdd3b2af68e2d029ec63f43" +dependencies = [ + "bitflags 2.9.0", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-keypair" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dbb7042c2e0c561afa07242b2099d55c57bd1b1da3b6476932197d84e15e3e4" +dependencies = [ + "bs58", + "ed25519-dalek 1.0.1", + "ed25519-dalek-bip32", + "rand 0.7.3", + "solana-derivation-path", + "solana-pubkey", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-logger" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8e777ec1afd733939b532a42492d888ec7c88d8b4127a5d867eb45c6eb5cd5" +dependencies = [ + "env_logger", + "lazy_static", + "libc", + "log", + "signal-hook", +] + +[[package]] +name = "solana-measure" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9566e754d9b9bcdee7b4aae38e425d47abf8e4f00057208868cb3ab9bee7feae" + +[[package]] +name = "solana-message" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268486ba8a294ed22a4d7c1ec05f540c3dbe71cfa7c6c54b6d4d13668d895678" +dependencies = [ + "bincode 1.3.3", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-metrics" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02311660a407de41df2d5ef4e4118dac7b51cfe81a52362314ea51b091ee4150" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest 0.11.27", + "solana-clock", + "solana-cluster-type", + "solana-sha256-hasher", + "solana-time-utils", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" + +[[package]] +name = "solana-net-utils" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27f0e0bbb972456ed255f81135378ecff3a380252ced7274fa965461ab99977" +dependencies = [ + "anyhow", + "bincode 1.3.3", + "bytes", + "crossbeam-channel", + "itertools 0.12.1", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-serde", + "tokio", + "url", +] + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-nonce-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde971a20b8dbf60144d6a84439dda86b5466e00e2843091fe731083cda614da" +dependencies = [ + "solana-account", + "solana-hash", + "solana-nonce", + "solana-sdk-ids", +] + +[[package]] +name = "solana-offchain-message" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b526398ade5dea37f1f147ce55dae49aa017a5d7326606359b0445ca8d946581" +dependencies = [ + "num_enum", + "solana-hash", + "solana-packet", + "solana-pubkey", + "solana-sanitize", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-packet" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" +dependencies = [ + "bincode 1.3.3", + "bitflags 2.9.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97222a3fda48570754ce114e43ca56af34741098c357cb8d3cb6695751e60330" +dependencies = [ + "ahash 0.8.11", + "bincode 1.3.3", + "bv", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash", + "solana-message", + "solana-metrics", + "solana-packet", + "solana-pubkey", + "solana-rayon-threadlimit", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-time-utils", +] + +[[package]] +name = "solana-poh-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d650c3b4b9060082ac6b0efbbb66865089c58405bfb45de449f3f2b91eccee75" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-precompile-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff64daa2933c22982b323d88d0cdf693201ef56ac381ae16737fd5f579e07d6" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-precompiles" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a460ab805ec063802105b463ecb5eb02c3ffe469e67a967eea8a6e778e0bc06" +dependencies = [ + "lazy_static", + "solana-ed25519-program", + "solana-feature-set", + "solana-message", + "solana-precompile-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-secp256k1-program", + "solana-secp256r1-program", +] + +[[package]] +name = "solana-presigner" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a57a24e6a4125fc69510b6774cd93402b943191b6cddad05de7281491c90fe" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" +dependencies = [ + "bincode 1.3.3", + "blake3", + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-address-lookup-table-interface", + "solana-atomic-u64", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", + "solana-msg", + "solana-native-token", + "solana-nonce", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-stake-interface", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-vote-interface", + "thiserror 2.0.12", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ae2c1a8d0d4ae865882d5770a7ebca92bab9c685e43f0461682c6c05a35bfa" +dependencies = [ + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-pubkey" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40db1ff5a0f8aea2c158d78ab5f2cf897848964251d1df42fef78efd3c85b863" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9633402b60b93f903d37c940a8ce0c1afc790b5a8678aaa8304f9099adf108b" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest 0.11.27", + "semver 1.0.26", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826ec34b8d4181f0c46efaa84c6b7992a459ca129f21506656d79a1e62633d4b" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.26", + "solana-connection-cache", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-pubkey", + "solana-quic-definitions", + "solana-rpc-client-api", + "solana-signer", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-quic-definitions" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e606feac5110eb5d8afaa43ccaeea3ec49ccec36773387930b5ba545e745aea2" +dependencies = [ + "solana-keypair", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "423c912a1a68455fe4ed5175cf94eb8965e061cd257973c9a5659e2bf4ea8371" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-remote-wallet" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71f9dfc6f2a5df04c3fed2b90b0fbf0da3939f3383a9bf24a5c0bcf994f2b10" +dependencies = [ + "console", + "dialoguer", + "hidapi", + "log", + "num-derive 0.4.2", + "num-traits", + "parking_lot", + "qstring", + "semver 1.0.26", + "solana-derivation-path", + "solana-offchain-message", + "solana-pubkey", + "solana-signature", + "solana-signer", + "thiserror 2.0.12", + "uriparse", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-rent-collector" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c1e19f5d5108b0d824244425e43bc78bbb9476e2199e979b0230c9f632d3bf4" +dependencies = [ + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-epoch-schedule", + "solana-genesis-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", +] + +[[package]] +name = "solana-rent-debits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f6f9113c6003492e74438d1288e30cffa8ccfdc2ef7b49b9e816d8034da18cd" +dependencies = [ + "solana-pubkey", + "solana-reward-info", +] + +[[package]] +name = "solana-reserved-account-keys" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b293f4246626c0e0a991531f08848a713ada965612e99dc510963f04d12cae7" +dependencies = [ + "lazy_static", + "solana-feature-set", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-reward-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18205b69139b1ae0ab8f6e11cdcb627328c0814422ad2482000fa2ca54ae4a2f" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-rpc-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3313bc969e1a8681f19a74181d301e5f91e5cc5a60975fb42e793caa9768f22e" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode 1.3.3", + "bs58", + "indicatif", + "log", + "reqwest 0.11.27", + "reqwest-middleware", + "semver 1.0.26", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-epoch-info", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-hash", + "solana-instruction", + "solana-message", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc3276b526100d0f55a7d1db2366781acdc75ce9fe4a9d1bc9c85a885a503f8" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest 0.11.27", + "reqwest-middleware", + "semver 1.0.26", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-fee-calculator", + "solana-inflation", + "solana-inline-spl", + "solana-pubkey", + "solana-signer", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "294874298fb4e52729bb0229e0cdda326d4393b7122b92823aa46e99960cb920" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-hash", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-rpc-client", + "solana-sdk-ids", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sdk" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8af90d2ce445440e0548fa4a5f96fe8b265c22041a68c942012ffadd029667d" +dependencies = [ + "bincode 1.3.3", + "bs58", + "getrandom 0.1.16", + "js-sys", + "serde", + "serde_json", + "solana-account", + "solana-bn254", + "solana-client-traits", + "solana-cluster-type", + "solana-commitment-config", + "solana-compute-budget-interface", + "solana-decode-error", + "solana-derivation-path", + "solana-ed25519-program", + "solana-epoch-info", + "solana-epoch-rewards-hasher", + "solana-feature-set", + "solana-fee-structure", + "solana-genesis-config", + "solana-hard-forks", + "solana-inflation", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-nonce-account", + "solana-offchain-message", + "solana-packet", + "solana-poh-config", + "solana-precompile-error", + "solana-precompiles", + "solana-presigner", + "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-quic-definitions", + "solana-rent-collector", + "solana-rent-debits", + "solana-reserved-account-keys", + "solana-reward-info", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-program", + "solana-secp256k1-recover", + "solana-secp256r1-program", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-serde", + "solana-serde-varint", + "solana-short-vec", + "solana-shred-version", + "solana-signature", + "solana-signer", + "solana-system-transaction", + "solana-time-utils", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "solana-validator-exit", + "thiserror 2.0.12", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "solana-secp256k1-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" +dependencies = [ + "bincode 1.3.3", + "digest 0.10.7", + "libsecp256k1", + "serde", + "serde_derive", + "sha3", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "borsh 1.5.7", + "libsecp256k1", + "solana-define-syscall", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-secp256r1-program" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cda2aa1bbaceda14763c4f142a00b486f2f262cfd901bd0410649ad0404d5f7" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "sha2 0.10.8", +] + +[[package]] +name = "solana-serde" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1931484a408af466e14171556a47adaa215953c7f48b24e5f6b0282763818b04" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-shred-version" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afd3db0461089d1ad1a78d9ba3f15b563899ca2386351d38428faa5350c60a98" +dependencies = [ + "solana-hard-forks", + "solana-hash", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-signature" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d251c8f3dc015f320b4161daac7f108156c837428e5a8cc61136d25beb11d6" +dependencies = [ + "bs58", + "ed25519-dalek 1.0.1", + "rand 0.8.5", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-streamer" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaf5b216717d1d551716f3190878d028c689dabac40c8889767cead7e447481" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap 2.9.0", + "itertools 0.12.1", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.26", + "smallvec", + "socket2", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-packet", + "solana-perf", + "solana-pubkey", + "solana-quic-definitions", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-tls-utils", + "solana-transaction-error", + "solana-transaction-metrics-tracker", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-system-transaction" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd98a25e5bcba8b6be8bcbb7b84b24c2a6a8178d7fb0e3077a916855ceba91a" +dependencies = [ + "solana-hash", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signer", + "solana-system-interface", + "solana-transaction", +] + +[[package]] +name = "solana-sysvar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" +dependencies = [ + "base64 0.22.1", + "bincode 1.3.3", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-thin-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "255bda447fbff4526b6b19b16b3652281ec2b7c4952d019b369a5f4a9dba4e5c" +dependencies = [ + "bincode 1.3.3", + "log", + "rayon", + "solana-account", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-time-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" + +[[package]] +name = "solana-tls-utils" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f227b3813b6c26c8ed38910b90a0b641baedb2ad075ea51ccfbff1992ee394" +dependencies = [ + "rustls 0.23.26", + "solana-keypair", + "solana-pubkey", + "solana-signer", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc74ecb664add683a18bb9f484a30ca8c9d71f3addcd3a771eaaaaec12125fd" +dependencies = [ + "async-trait", + "bincode 1.3.3", + "futures-util", + "indexmap 2.9.0", + "indicatif", + "log", + "rayon", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-measure", + "solana-message", + "solana-net-utils", + "solana-pubkey", + "solana-pubsub-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-transaction" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abec848d081beb15a324c633cd0e0ab33033318063230389895cae503ec9b544" +dependencies = [ + "bincode 1.3.3", + "serde", + "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-precompiles", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-transaction-context" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5022de04cbba05377f68bf848c8c1322ead733f88a657bf792bb40f3257b8218" +dependencies = [ + "bincode 1.3.3", + "serde", + "serde_derive", + "solana-account", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-signature", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4c03abfcb923aaf71c228e81b54a804aa224a48577477d8e1096c3a1429d21b" +dependencies = [ + "base64 0.22.1", + "bincode 1.3.3", + "lazy_static", + "log", + "rand 0.8.5", + "solana-packet", + "solana-perf", + "solana-short-vec", + "solana-signature", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaef59e8a54fc3a2dabfd85c32e35493c5e228f9d1efbcdcdc3c0819dddf7fd" +dependencies = [ + "base64 0.22.1", + "bincode 1.3.3", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-message", + "solana-reward-info", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-udp-client" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3e085a6adf81d51f678624934ffe266bd45a1c105849992b1af933c80bbf19" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-keypair", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-validator-exit" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" + +[[package]] +name = "solana-version" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a58e01912dc3d5ff4391fe49476461b3b9ebc4215f3713d2fe3ffcfeda7f8e2" +dependencies = [ + "agave-feature-set", + "semver 1.0.26", + "serde", + "serde_derive", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f039b0788337bedc6c5450d2f237718f938defb5ce0e0ad8ef507e78dcd370" +dependencies = [ + "bincode 1.3.3", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c757a8d8b66af3e150c29e961310bafa9d8c91ad826f96fb88b2bface31ba2" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode 1.3.3", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "merlin", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.12", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d91b7c7651e776b848b67b6b58f032566be4cd554e6f6283bdf415e3a70b61" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode 1.3.3", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "lazy_static", + "merlin", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-curve25519", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.12", + "zeroize", +] + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spl-associated-token-account" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" +dependencies = [ + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-associated-token-account-client" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f8349dbcbe575f354f9a533a21f272f3eb3808a49e2fdc1c34393b88ba76cb" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.101", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.101", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction 0.2.1", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65edfeed09cd4231e595616aa96022214f9c9d2be02dea62c2b30d5695a6833a" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", + "solana-sysvar", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction 0.3.0", +] + +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-pod" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "num-derive 0.4.2", + "num-traits", + "serde", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive 0.4.1", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdebc8b42553070b75aa5106f071fef2eb798c64a7ec63375da4b1f058688c6" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-program-error-derive 0.5.0", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.101", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2539e259c66910d78593475540e8072f0b10f0f61d7607bbf7593899ed52d0" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.101", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error 0.6.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1408e961215688715d5a1063cbdcf982de225c45f99c82b4f7d7e1dd22b998d7" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error 0.7.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053067c6a82c705004f91dae058b11b4780407e9ccd6799dc9e7d0fab5f242da" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sysvar", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-2022" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry 0.1.1", + "spl-memo", + "spl-pod", + "spl-token 7.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1", + "spl-token-confidential-transfer-proof-extraction 0.2.1", + "spl-token-confidential-transfer-proof-generation 0.2.0", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface 0.9.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f0dfbb079eebaee55e793e92ca5f433744f4b71ee04880bfd6beefba5973e5" +dependencies = [ + "arrayref", + "base64 0.22.1", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "serde", + "serde_with", + "solana-account-info", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-security-txt", + "solana-system-interface", + "solana-sysvar", + "solana-zk-sdk", + "spl-elgamal-registry 0.2.0", + "spl-memo", + "spl-pod", + "spl-token 8.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.3.0", + "spl-token-confidential-transfer-proof-extraction 0.3.0", + "spl-token-confidential-transfer-proof-generation 0.4.0", + "spl-token-group-interface 0.6.0", + "spl-token-metadata-interface 0.7.0", + "spl-transfer-hook-interface 0.10.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94ab20faf7b5edaa79acd240e0f21d5a2ef936aa99ed98f698573a2825b299c4" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2629860ff04c17bafa9ba4bed8850a404ecac81074113e1f840dbd0ebb7bd6" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-curve25519", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8627184782eec1894de8ea26129c61303f1f0adeed65c20e0b10bc584f09356d" +dependencies = [ + "curve25519-dalek 4.1.3", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae5b124840d4aed474cef101d946a798b806b46a509ee4df91021e1ab1cef3ef" +dependencies = [ + "curve25519-dalek 4.1.3", + "solana-zk-sdk", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5597b4cd76f85ce7cd206045b7dc22da8c25516573d42d267c8d1fd128db5129" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304d6e06f0de0c13a621464b1fd5d4b1bebf60d15ca71a44d3839958e0da16ee" +dependencies = [ + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value 0.8.0", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error 0.6.0", + "spl-tlv-account-resolution 0.9.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e905b849b6aba63bde8c4badac944ebb6c8e6e14817029cbe1bc16829133bd" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error 0.7.0", + "spl-tlv-account-resolution 0.10.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-type-length-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d417eb548214fa822d93f84444024b4e57c13ed6719d4dcc68eec24fb481e9f5" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 2.0.12", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "starknet-checked-felt" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "alloy-primitives", + "error-stack", + "hex", + "serde", + "starknet-types-core", + "thiserror 1.0.69", +] + +[[package]] +name = "starknet-types-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4037bcb26ce7c508448d221e570d075196fd4f6912ae6380981098937af9522a" +dependencies = [ + "lambdaworks-crypto", + "lambdaworks-math", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "serde", + "size-of", + "zeroize", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stellar" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "cosmwasm-std 2.2.2", + "error-stack", + "hex", + "multisig", + "router-api", + "serde", + "serde_json", + "sha3", + "stellar-strkey 0.0.10", + "stellar-xdr", + "thiserror 1.0.69", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12d2bf45e114117ea91d820a846fd1afbe3ba7d717988fee094ce8227a3bf8bd" +dependencies = [ + "base32", + "crate-git-revision", + "thiserror 1.0.69", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecda1f64c0a1427563b0b35aa771b66c6ce508f02b18effcae1d0ab1261d014" +dependencies = [ + "crate-git-revision", + "data-encoding", + "thiserror 1.0.69", +] + +[[package]] +name = "stellar-xdr" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2675a71212ed39a806e415b0dbf4702879ff288ec7f5ee996dda42a135512b50" +dependencies = [ + "crate-git-revision", + "escape-bytes", + "hex", + "stellar-strkey 0.0.8", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "sui-gateway" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "bcs", + "cosmwasm-std 2.2.2", + "error-stack", + "hex", + "multisig", + "router-api", + "serde", + "serde_json", + "sha3", + "sui-types", + "thiserror 1.0.69", +] + +[[package]] +name = "sui-types" +version = "1.0.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "error-stack", + "hex", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +dependencies = [ + "fastrand", + "getrandom 0.3.2", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "tendermint" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f8a10105d0a7c4af0a242e23ed5a12519afe5cc0e68419da441bb5981a6802" +dependencies = [ + "bytes", + "digest 0.10.7", + "ed25519 2.2.3", + "ed25519-consensus", + "flex-error", + "futures", + "k256", + "num-traits", + "once_cell", + "prost", + "prost-types", + "ripemd", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.10.8", + "signature 2.2.0", + "subtle", + "subtle-encoding", + "tendermint-proto", + "time", + "zeroize", +] + +[[package]] +name = "tendermint-config" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6bf36c613bb113737c333e3c1d6dfd3c99f8ac679e84feb58dd6456d77fb2e" +dependencies = [ + "flex-error", + "serde", + "serde_json", + "tendermint", + "toml 0.8.22", + "url", +] + +[[package]] +name = "tendermint-proto" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff525d5540a9fc535c38dc0d92a98da3ee36fcdfbda99cecb9f3cce5cd4d41d7" +dependencies = [ + "bytes", + "flex-error", + "num-derive 0.4.2", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-rpc" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8fe61b1772cd50038bdeeadf53773bb37a09e639dd8e6d996668fd220ddb29" +dependencies = [ + "async-trait", + "bytes", + "flex-error", + "futures", + "getrandom 0.2.16", + "peg", + "pin-project", + "rand 0.8.5", + "reqwest 0.11.27", + "semver 1.0.26", + "serde", + "serde_bytes", + "serde_json", + "subtle", + "subtle-encoding", + "tendermint", + "tendermint-config", + "tendermint-proto", + "thiserror 1.0.69", + "time", + "tokio", + "tracing", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width 0.1.14", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash 1.1.0", + "sha2 0.9.9", + "thiserror 1.0.69", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.26", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap 2.9.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + +[[package]] +name = "tonic" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.21.7", + "bytes", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.12", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "typed-builder" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "udigest" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cd61fa9fb78569e9fe34acf0048fd8cb9ebdbacc47af740745487287043ff0" +dependencies = [ + "digest 0.10.7", + "udigest-derive", +] + +[[package]] +name = "udigest-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603329303137e0d59238ee4d6b9c085eada8e2a9d20666f3abd9dadf8f8543f4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +dependencies = [ + "valuable-derive", +] + +[[package]] +name = "valuable-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3a32a9bcc0f6c6ccfd5b27bcf298c58e753bcc9eeff268157a303393183a6d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "voting-verifier" +version = "1.1.0" +source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +dependencies = [ + "axelar-wasm-std", + "client", + "cosmwasm-schema", + "cosmwasm-std 2.2.2", + "cw-storage-plus", + "cw2", + "error-stack", + "itertools 0.14.0", + "msgs-derive", + "multisig", + "report", + "rewards", + "router-api", + "semver 1.0.26", + "serde_json", + "service-registry", + "service-registry-api", + "thiserror 1.0.69", +] + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180d2741b6115c3d906577e6533ad89472d48d96df00270fccb78233073d77f7" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings 0.4.0", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "xattr" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive 0.8.25", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs new file mode 100644 index 000000000..75becb845 --- /dev/null +++ b/solana/cli/src/gateway.rs @@ -0,0 +1,250 @@ +use std::collections::BTreeMap; +use std::str::FromStr; + +use axelar_solana_encoding::hasher::NativeHasher; +use axelar_solana_encoding::types::pubkey::PublicKey; +use axelar_solana_encoding::types::verifier_set::VerifierSet; +use axelar_solana_gateway::state::config::RotationDelaySecs; +use clap::{Parser, Subcommand}; +use cosmrs::proto::cosmwasm::wasm::v1::query_client; +use serde::Deserialize; +use serde_json::json; +use solana_sdk::instruction::Instruction; +use solana_sdk::pubkey::Pubkey; + +use crate::config::Config; +use crate::types::ChainNameOnAxelar; +use crate::utils; + +const CHAINS_KEY: &str = "chains"; +const AXELAR_KEY: &str = "axelar"; +const MULTISIG_PROVER_KEY: &str = "MultisigProver"; +const GRPC_KEY: &str = "grpc"; +const CONTRACTS_KEY: &str = "contracts"; +const ADDRESS_KEY: &str = "address"; +const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; +const GATEWAY_KEY: &str = "gateway"; + +#[derive(Subcommand, Debug)] +pub(crate) enum Commands { + #[clap(long_about = "Initialize the Gateway program")] + Init(InitArgs), + + #[clap(long_about = "Call contract on an Axelar enabled destination chain")] + CallContract(CallContractArgs), + + #[clap(long_about = "Transfer operatorship of the Gateway program")] + TransferOperatorship(TransferOperatorshipArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct InitArgs { + #[clap(short = 'r', long)] + previous_signers_retention: u128, + + #[clap(short, long)] + minimum_rotation_delay: RotationDelaySecs, + + #[clap(short, long)] + axelar_grpc_endpoint: Option, + + #[clap(short = 'p', long)] + multisig_prover_address: Option, + + #[clap(long)] + operator: Pubkey, + + #[clap(short, long)] + domain_separator: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct CallContractArgs { + #[clap(short = 'd', long)] + destination_chain: String, + + #[clap(short = 'a', long)] + destination_contract_address: String, + + #[clap(short, long)] + payload: String, +} + +#[derive(Parser, Debug)] +pub(crate) struct TransferOperatorshipArgs { + /// Current operator OR upgrade authority + #[clap(short, long)] + authority: Pubkey, + + /// Address of the new operator + #[clap(short, long)] + new_operator: Pubkey, +} + +pub(crate) async fn build_instruction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result { + match command { + Commands::Init(init_args) => init(fee_payer, init_args, config).await, + Commands::CallContract(call_contract_args) => { + call_contract(fee_payer, call_contract_args).await + } + Commands::TransferOperatorship(transfer_operatorship_args) => { + transfer_operatorship(fee_payer, transfer_operatorship_args).await + } + } +} + +async fn query( + mut endpoint: String, + address: cosmrs::AccountId, + query_data: Vec, +) -> eyre::Result { + if !endpoint.starts_with("https://") { + endpoint = format!("https://{}", endpoint); + } + let mut c = query_client::QueryClient::connect(endpoint).await?; + + let res = c + .smart_contract_state( + cosmrs::proto::cosmwasm::wasm::v1::QuerySmartContractStateRequest { + address: address.to_string(), + query_data, + }, + ) + .await? + .into_inner() + .data; + + let result = serde_json::from_slice::(res.as_ref())?; + + Ok(result) +} + +async fn init( + fee_payer: &Pubkey, + init_args: InitArgs, + config: &Config, +) -> eyre::Result { + let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); + let multisig_prover_address = { + let address = match init_args.multisig_prover_address { + Some(address) => address, + None => String::deserialize( + &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY] + [MULTISIG_PROVER_KEY][ChainNameOnAxelar::from(config.network_type).0] + [ADDRESS_KEY], + )?, + }; + + cosmrs::AccountId::from_str(&address).unwrap() + }; + + let axelar_grpc_endpoint = { + match init_args.axelar_grpc_endpoint { + Some(endpoint) => endpoint, + None => { + String::deserialize(&utils::chains_info(config.network_type)[AXELAR_KEY][GRPC_KEY])? + } + } + }; + + let multisig_prover_response = query::( + axelar_grpc_endpoint, + multisig_prover_address, + serde_json::to_vec(&multisig_prover::msg::QueryMsg::CurrentVerifierSet {})?, + ) + .await?; + + let mut signers = BTreeMap::new(); + for signer in multisig_prover_response.verifier_set.signers.values() { + let pubkey = PublicKey::Secp256k1(signer.pub_key.as_ref().try_into()?); + let weight = signer.weight.u128(); + signers.insert(pubkey, weight); + } + let verifier_set = VerifierSet { + nonce: multisig_prover_response.verifier_set.created_at, + signers, + quorum: multisig_prover_response.verifier_set.threshold.u128(), + }; + + let domain_separator = { + match init_args.domain_separator { + Some(domain_separator) => domain_separator, + None => String::deserialize( + &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY] + [MULTISIG_PROVER_KEY][ChainNameOnAxelar::from(config.network_type).0] + [DOMAIN_SEPARATOR_KEY], + )?, + } + }; + + let mut domain_separator_bytes = [0_u8; 32]; + hex::decode_to_slice(&domain_separator, &mut domain_separator_bytes)?; + + let verifier_set_hash = axelar_solana_encoding::types::verifier_set::verifier_set_hash::< + NativeHasher, + >(&verifier_set, &domain_separator_bytes)?; + + let (init_tracker_pda, _bump) = + axelar_solana_gateway::get_verifier_set_tracker_pda(verifier_set_hash); + let payer = *fee_payer; + let upgrade_authority = payer; + + let mut updated_chains_info = utils::chains_info(config.network_type).clone(); + updated_chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0] + [CONTRACTS_KEY][GATEWAY_KEY] = json!({ + "address": bs58::encode(axelar_solana_gateway::id()).into_string(), + "deployer": fee_payer, + "operator": init_args.operator, + "minimumRotationDelay": init_args.minimum_rotation_delay, + "previousSignersRetention": init_args.previous_signers_retention, + "domainSeparator": domain_separator, + }); + + utils::save_chains_info(config.network_type, updated_chains_info, &config.output_dir); + + Ok(axelar_solana_gateway::instructions::initialize_config( + payer, + upgrade_authority, + domain_separator_bytes, + vec![(verifier_set_hash, init_tracker_pda)], + init_args.minimum_rotation_delay, + init_args.operator, + init_args.previous_signers_retention.into(), + gateway_config_pda, + )?) +} + +async fn call_contract( + fee_payer: &Pubkey, + call_contract_args: CallContractArgs, +) -> eyre::Result { + let (signing_pda, signing_pda_bump) = + axelar_solana_gateway::get_call_contract_signing_pda(*fee_payer); + let payload = hex::decode(call_contract_args.payload)?; + + Ok(axelar_solana_gateway::instructions::call_contract( + axelar_solana_gateway::id(), + axelar_solana_gateway::get_gateway_root_config_pda().0, + *fee_payer, + signing_pda, + signing_pda_bump, + call_contract_args.destination_chain, + call_contract_args.destination_contract_address, + payload, + )?) +} + +async fn transfer_operatorship( + fee_payer: &Pubkey, + transfer_operatorship_args: TransferOperatorshipArgs, +) -> eyre::Result { + Ok(axelar_solana_gateway::instructions::transfer_operatorship( + *fee_payer, + transfer_operatorship_args.authority, + transfer_operatorship_args.new_operator, + )?) +} diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index a4d29c82d..993ed7e3b 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -2,6 +2,7 @@ mod broadcast; mod combine; mod config; mod error; +mod gateway; mod generate; mod send; mod sign; @@ -132,6 +133,8 @@ struct GenerateCommandArgs { #[derive(Subcommand, Debug)] enum InstructionSubcommand { + #[clap(long_about = "Commands for Gateway program", subcommand)] + Gateway(gateway::Commands), } #[derive(Parser, Debug)] @@ -247,6 +250,9 @@ async fn build_instruction( config: &Config, ) -> eyre::Result { let serializable_ix = match instruction { + InstructionSubcommand::Gateway(command) => { + gateway::build_instruction(fee_payer, command, config).await? + } }; Ok(serializable_ix) From e276999e3b24983f159001295e322fea2ab3b824 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 29 Apr 2025 15:13:43 +0200 Subject: [PATCH 03/59] feat: add gas_service initialization Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gas_service.rs | 44 +++++++++++++++++++++++++++++++++++ solana/cli/src/main.rs | 7 ++++++ 2 files changed, 51 insertions(+) create mode 100644 solana/cli/src/gas_service.rs diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs new file mode 100644 index 000000000..4b2364320 --- /dev/null +++ b/solana/cli/src/gas_service.rs @@ -0,0 +1,44 @@ +use clap::{Parser, Subcommand}; +use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; + +use crate::config::Config; + +#[derive(Subcommand, Debug)] +pub(crate) enum Commands { + #[clap(long_about = "Initialize the Gateway program")] + Init(InitArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct InitArgs { + #[clap(short, long)] + authority: Pubkey, + + #[clap(short, long)] + salt: String, +} + +pub(crate) async fn build_instruction( + fee_payer: &Pubkey, + command: Commands, + _config: &Config, +) -> eyre::Result { + match command { + Commands::Init(init_args) => init(fee_payer, init_args).await, + } +} + +async fn init(fee_payer: &Pubkey, init_args: InitArgs) -> eyre::Result { + let program_id = axelar_solana_gas_service::id(); + let salt_hash = solana_sdk::keccak::hashv(&[init_args.salt.as_bytes()]).0; + let (config_pda, _bump) = + axelar_solana_gas_service::get_config_pda(&program_id, &salt_hash, &init_args.authority); + + Ok(axelar_solana_gas_service::instructions::init_config( + &program_id, + fee_payer, + &init_args.authority, + &config_pda, + salt_hash, + )?) +} diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 993ed7e3b..69ac5ae4c 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -2,6 +2,7 @@ mod broadcast; mod combine; mod config; mod error; +mod gas_service; mod gateway; mod generate; mod send; @@ -135,6 +136,9 @@ struct GenerateCommandArgs { enum InstructionSubcommand { #[clap(long_about = "Commands for Gateway program", subcommand)] Gateway(gateway::Commands), + + #[clap(long_about = "Commands for GasService program", subcommand)] + GasService(gas_service::Commands), } #[derive(Parser, Debug)] @@ -253,6 +257,9 @@ async fn build_instruction( InstructionSubcommand::Gateway(command) => { gateway::build_instruction(fee_payer, command, config).await? } + InstructionSubcommand::GasService(command) => { + gas_service::build_instruction(fee_payer, command, config).await? + } }; Ok(serializable_ix) From 6d6c10eb632723e23b28ebb397ab6dd1a6b633b6 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 08:51:15 +0200 Subject: [PATCH 04/59] refactor: move json keys to utils These keys will be used in other modules as well. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gateway.rs | 14 ++++---------- solana/cli/src/utils.rs | 10 ++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 75becb845..6b42aa425 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -14,16 +14,10 @@ use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::ChainNameOnAxelar; -use crate::utils; - -const CHAINS_KEY: &str = "chains"; -const AXELAR_KEY: &str = "axelar"; -const MULTISIG_PROVER_KEY: &str = "MultisigProver"; -const GRPC_KEY: &str = "grpc"; -const CONTRACTS_KEY: &str = "contracts"; -const ADDRESS_KEY: &str = "address"; -const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; -const GATEWAY_KEY: &str = "gateway"; +use crate::utils::{ + self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, + GRPC_KEY, MULTISIG_PROVER_KEY, +}; #[derive(Subcommand, Debug)] pub(crate) enum Commands { diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 397df7b1d..4c7d60484 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -13,6 +13,16 @@ const DEVNET_AMPLIFIER_CONFIG: &'static str = include_str!("../devnet-amplifier. const TESTNET_AMPLIFIER_CONFIG: &'static str = include_str!("../testnet.json"); const MAINNET_AMPLIFIER_CONFIG: &'static str = include_str!("../mainnet.json"); +pub(crate) const CHAINS_KEY: &str = "chains"; +pub(crate) const AXELAR_KEY: &str = "axelar"; +pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; +pub(crate) const GRPC_KEY: &str = "grpc"; +pub(crate) const CONTRACTS_KEY: &str = "contracts"; +pub(crate) const ADDRESS_KEY: &str = "address"; +pub(crate) const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; +pub(crate) const GATEWAY_KEY: &str = "gateway"; +pub(crate) const ITS_KEY: &str = "InterchainTokenService"; + static MAINNET_INFO: LazyLock = LazyLock::new(|| serde_json::from_str(MAINNET_AMPLIFIER_CONFIG).unwrap()); From 2aa5c71e34a557ed71e040e3e6b1e47242eb4959 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 08:51:47 +0200 Subject: [PATCH 05/59] feat: add its initialization Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ solana/cli/src/main.rs | 7 ++++++ 2 files changed, 56 insertions(+) create mode 100644 solana/cli/src/its.rs diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs new file mode 100644 index 000000000..d68d46a6a --- /dev/null +++ b/solana/cli/src/its.rs @@ -0,0 +1,49 @@ +use clap::{Parser, Subcommand}; +use serde::Deserialize; +use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; + +use crate::{ + config::Config, + types::ChainNameOnAxelar, + utils::{self, ADDRESS_KEY, AXELAR_KEY, CONTRACTS_KEY, ITS_KEY}, +}; + +#[derive(Subcommand, Debug)] +pub(crate) enum Commands { + #[clap(long_about = "Initialize the Gateway program")] + Init(InitArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct InitArgs { + #[clap(short, long)] + operator: Pubkey, +} + +pub(crate) async fn build_instruction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result { + match command { + Commands::Init(init_args) => init(fee_payer, init_args, config).await, + } +} + +async fn init( + fee_payer: &Pubkey, + init_args: InitArgs, + config: &Config, +) -> eyre::Result { + let its_hub_address = String::deserialize( + &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY], + )?; + + Ok(axelar_solana_its::instruction::initialize( + *fee_payer, + axelar_solana_gateway::get_gateway_root_config_pda().0, + init_args.operator, + ChainNameOnAxelar::from(config.network_type).0, + its_hub_address, + )?) +} diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 69ac5ae4c..e2ab87265 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -5,6 +5,7 @@ mod error; mod gas_service; mod gateway; mod generate; +mod its; mod send; mod sign; mod types; @@ -139,6 +140,9 @@ enum InstructionSubcommand { #[clap(long_about = "Commands for GasService program", subcommand)] GasService(gas_service::Commands), + + #[clap(long_about = "Commands for InterchainTokenService program", subcommand)] + Its(its::Commands), } #[derive(Parser, Debug)] @@ -260,6 +264,9 @@ async fn build_instruction( InstructionSubcommand::GasService(command) => { gas_service::build_instruction(fee_payer, command, config).await? } + InstructionSubcommand::Its(command) => { + its::build_instruction(fee_payer, command, config).await? + } }; Ok(serializable_ix) From f6246f4780e2b2ebe80e10322843ced981634130 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 08:59:21 +0200 Subject: [PATCH 06/59] feat: add its set-pause-status Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index d68d46a6a..3ebe109ac 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -10,8 +10,11 @@ use crate::{ #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the Gateway program")] + #[clap(long_about = "Initialize the ITS program")] Init(InitArgs), + + #[clap(long_about = "Set the pause status of the ITS program")] + SetPauseStatus(SetPauseStatusArgs), } #[derive(Parser, Debug)] @@ -20,6 +23,12 @@ pub(crate) struct InitArgs { operator: Pubkey, } +#[derive(Parser, Debug)] +pub(crate) struct SetPauseStatusArgs { + #[clap(short, long)] + paused: bool, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, @@ -27,6 +36,9 @@ pub(crate) async fn build_instruction( ) -> eyre::Result { match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await, + Commands::SetPauseStatus(set_pause_args) => { + set_pause_status(fee_payer, set_pause_args).await + } } } @@ -47,3 +59,13 @@ async fn init( its_hub_address, )?) } + +async fn set_pause_status( + fee_payer: &Pubkey, + set_pause_args: SetPauseStatusArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::set_pause_status( + *fee_payer, + set_pause_args.paused, + )?) +} From 94cf5aefe115c9189dc08102dbde8ce3dac610b9 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 09:07:59 +0200 Subject: [PATCH 07/59] feat: its trusted chain add/remove Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index 3ebe109ac..d3c4416a9 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -15,6 +15,12 @@ pub(crate) enum Commands { #[clap(long_about = "Set the pause status of the ITS program")] SetPauseStatus(SetPauseStatusArgs), + + #[clap(long_about = "Add a new trusted chain to ITS")] + SetTrustedChain(TrustedChainArgs), + + #[clap(long_about = "Remove an existing trusted chain from ITS")] + RemoveTrustedChain(TrustedChainArgs), } #[derive(Parser, Debug)] @@ -29,6 +35,12 @@ pub(crate) struct SetPauseStatusArgs { paused: bool, } +#[derive(Parser, Debug)] +pub(crate) struct TrustedChainArgs { + #[clap(short, long)] + chain_name: String, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, @@ -39,6 +51,12 @@ pub(crate) async fn build_instruction( Commands::SetPauseStatus(set_pause_args) => { set_pause_status(fee_payer, set_pause_args).await } + Commands::SetTrustedChain(set_trusted_chain_args) => { + set_trusted_chain(fee_payer, set_trusted_chain_args).await + } + Commands::RemoveTrustedChain(remove_trusted_chain_args) => { + remove_trusted_chain(fee_payer, remove_trusted_chain_args).await + } } } @@ -69,3 +87,23 @@ async fn set_pause_status( set_pause_args.paused, )?) } + +async fn set_trusted_chain( + fee_payer: &Pubkey, + set_trusted_chain_args: TrustedChainArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::set_trusted_chain( + *fee_payer, + set_trusted_chain_args.chain_name, + )?) +} + +async fn remove_trusted_chain( + fee_payer: &Pubkey, + remove_trusted_chain_args: TrustedChainArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::remove_trusted_chain( + *fee_payer, + remove_trusted_chain_args.chain_name, + )?) +} From ae19a9fcab0a24d8a78ec3c68ce73daea945efeb Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 12:16:24 +0200 Subject: [PATCH 08/59] feat: add gas service related keys to utils Since we're here, fix the visibility of the functions. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/utils.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 4c7d60484..2606eb333 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -13,15 +13,18 @@ const DEVNET_AMPLIFIER_CONFIG: &'static str = include_str!("../devnet-amplifier. const TESTNET_AMPLIFIER_CONFIG: &'static str = include_str!("../testnet.json"); const MAINNET_AMPLIFIER_CONFIG: &'static str = include_str!("../mainnet.json"); -pub(crate) const CHAINS_KEY: &str = "chains"; +pub(crate) const ADDRESS_KEY: &str = "address"; pub(crate) const AXELAR_KEY: &str = "axelar"; -pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; -pub(crate) const GRPC_KEY: &str = "grpc"; +pub(crate) const CHAINS_KEY: &str = "chains"; +pub(crate) const CHAIN_TYPE_KEY: &str = "chainType"; pub(crate) const CONTRACTS_KEY: &str = "contracts"; -pub(crate) const ADDRESS_KEY: &str = "address"; pub(crate) const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; -pub(crate) const GATEWAY_KEY: &str = "gateway"; +pub(crate) const GAS_CONFIG_ACCOUNT: &str = "configAccount"; +pub(crate) const GAS_SERVICE_KEY: &str = "AxelarGasService"; +pub(crate) const GATEWAY_KEY: &str = "AxelarGateway"; +pub(crate) const GRPC_KEY: &str = "grpc"; pub(crate) const ITS_KEY: &str = "InterchainTokenService"; +pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; static MAINNET_INFO: LazyLock = LazyLock::new(|| serde_json::from_str(MAINNET_AMPLIFIER_CONFIG).unwrap()); @@ -32,7 +35,7 @@ static TESTNET_INFO: LazyLock = static DEVNET_INFO: LazyLock = LazyLock::new(|| serde_json::from_str(DEVNET_AMPLIFIER_CONFIG).unwrap()); -pub fn chains_info(network: NetworkType) -> &'static serde_json::Value { +pub(crate) fn chains_info(network: NetworkType) -> &'static serde_json::Value { match network { NetworkType::Mainnet => &*MAINNET_INFO, NetworkType::Testnet => &*TESTNET_INFO, @@ -44,7 +47,7 @@ pub fn chains_info(network: NetworkType) -> &'static serde_json::Value { } } -pub fn save_chains_info(network: NetworkType, info: serde_json::Value, output_dir: &Path) { +pub(crate) fn save_chains_info(network: NetworkType, info: serde_json::Value, output_dir: &Path) { let path = match network { NetworkType::Mainnet => "mainnet.json", NetworkType::Testnet => "testnet.json", @@ -56,43 +59,49 @@ pub fn save_chains_info(network: NetworkType, info: serde_json::Value, output_di serde_json::to_writer_pretty(file, &info).expect("Unable to write data"); } -pub fn read_json_file(path: &Path) -> Result { +pub(crate) fn read_json_file(path: &Path) -> Result { let file = File::open(path).map_err(|e| AppError::IoError(e))?; let reader = std::io::BufReader::new(file); serde_json::from_reader(reader).map_err(|e| AppError::JsonError(e)) } -pub fn write_json_file(data: &T, path: &Path) -> Result<()> { +pub(crate) fn write_json_file(data: &T, path: &Path) -> Result<()> { let file = File::create(path).map_err(|e| AppError::IoError(e))?; let writer = std::io::BufWriter::new(file); serde_json::to_writer_pretty(writer, data).map_err(|e| AppError::JsonError(e)) } -pub fn load_unsigned_solana_transaction(path: &Path) -> Result { +pub(crate) fn load_unsigned_solana_transaction(path: &Path) -> Result { read_json_file(path) } -pub fn save_unsigned_solana_transaction(tx: &UnsignedSolanaTransaction, path: &Path) -> Result<()> { +pub(crate) fn save_unsigned_solana_transaction( + tx: &UnsignedSolanaTransaction, + path: &Path, +) -> Result<()> { write_json_file(tx, path) } -pub fn load_partial_signature(path: &Path) -> Result { +pub(crate) fn load_partial_signature(path: &Path) -> Result { read_json_file(path) } -pub fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Result<()> { +pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Result<()> { write_json_file(sig, path) } -pub fn load_signed_solana_transaction(path: &Path) -> Result { +pub(crate) fn load_signed_solana_transaction(path: &Path) -> Result { read_json_file(path) } -pub fn save_signed_solana_transaction(tx: &SignedSolanaTransaction, path: &Path) -> Result<()> { +pub(crate) fn save_signed_solana_transaction( + tx: &SignedSolanaTransaction, + path: &Path, +) -> Result<()> { write_json_file(tx, path) } -pub fn create_offline_bundle( +pub(crate) fn create_offline_bundle( bundle_name: &str, output_dir: &Path, files_to_include: &[(&str, &Path)], From 02964f670f98f88ab02cc2f80cf0252b0bc43580 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 12:17:28 +0200 Subject: [PATCH 09/59] feat: add more its instructions Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 3 + solana/cli/Cargo.toml | 3 + solana/cli/src/its.rs | 742 +++++++++++++++++++++++++++++++++++++++- solana/cli/src/utils.rs | 21 +- 4 files changed, 761 insertions(+), 8 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index d05ce2e25..b7b6c2940 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -1419,6 +1419,9 @@ dependencies = [ "solana-cli-config", "solana-client", "solana-sdk", + "spl-associated-token-account", + "spl-token 8.0.0", + "spl-token-2022 8.0.1", "tar", "thiserror 2.0.12", "tokio", diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index ba24e6d14..5be2ad595 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -51,3 +51,6 @@ tar = "0.4.44" thiserror = "2.0.12" tokio = { version = "1", features = ["full"] } walkdir = "2.5.0" +spl-token = { version = "8.0.0", features = ["no-entrypoint"] } +spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } +spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index d3c4416a9..a0b2d6e7d 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -1,11 +1,15 @@ +use std::{fs::File, io::Write, time::SystemTime}; + +use axelar_solana_its::state; use clap::{Parser, Subcommand}; use serde::Deserialize; -use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; +use solana_sdk::instruction::Instruction; +use solana_sdk::pubkey::Pubkey; -use crate::{ - config::Config, - types::ChainNameOnAxelar, - utils::{self, ADDRESS_KEY, AXELAR_KEY, CONTRACTS_KEY, ITS_KEY}, +use crate::config::Config; +use crate::types::ChainNameOnAxelar; +use crate::utils::{ + self, ADDRESS_KEY, AXELAR_KEY, CONTRACTS_KEY, GAS_CONFIG_ACCOUNT, GAS_SERVICE_KEY, ITS_KEY, }; #[derive(Subcommand, Debug)] @@ -21,6 +25,123 @@ pub(crate) enum Commands { #[clap(long_about = "Remove an existing trusted chain from ITS")] RemoveTrustedChain(TrustedChainArgs), + + #[clap(long_about = "Approve deploying a remote interchain token with a specific minter")] + ApproveDeployRemoteInterchainToken(ApproveDeployRemoteInterchainTokenArgs), + + #[clap(long_about = "Revoke approval for deploying a remote interchain token")] + RevokeDeployRemoteInterchainToken(RevokeDeployRemoteInterchainTokenArgs), + + #[clap(long_about = "Register a canonical token as an interchain token")] + RegisterCanonicalInterchainToken(RegisterCanonicalInterchainTokenArgs), + + #[clap(long_about = "Deploy a canonical interchain token on a remote chain")] + DeployRemoteCanonicalInterchainToken(DeployRemoteCanonicalInterchainTokenArgs), + + #[clap(long_about = "Deploy a new interchain token")] + DeployInterchainToken(DeployInterchainTokenArgs), + + #[clap(long_about = "Deploy an existing interchain token to a remote chain")] + DeployRemoteInterchainToken(DeployRemoteInterchainTokenArgs), + + #[clap( + long_about = "Deploy an existing interchain token to a remote chain with a specific minter" + )] + DeployRemoteInterchainTokenWithMinter(DeployRemoteInterchainTokenWithMinterArgs), + + #[clap(long_about = "Register token metadata with the ITS hub")] + RegisterTokenMetadata(RegisterTokenMetadataArgs), + + #[clap(long_about = "Register a custom token with ITS")] + RegisterCustomToken(RegisterCustomTokenArgs), + + #[clap(long_about = "Link a local token to a remote token")] + LinkToken(LinkTokenArgs), + + #[clap(long_about = "Transfer interchain tokens to a remote chain")] + InterchainTransfer(InterchainTransferArgs), + + #[clap(long_about = "Transfer interchain tokens and call a contract on the remote chain")] + CallContractWithInterchainToken(CallContractWithInterchainTokenArgs), + + #[clap( + long_about = "Transfer interchain tokens and call a contract on the remote chain using offchain data" + )] + CallContractWithInterchainTokenOffchainData(CallContractWithInterchainTokenOffchainDataArgs), + + #[clap(long_about = "Set the flow limit for a token manager")] + SetFlowLimit(SetFlowLimitArgs), + + #[clap(long_about = "Transfer ITS operatorship")] + TransferOperatorship(TransferOperatorshipArgs), + + #[clap(long_about = "Propose ITS operatorship transfer")] + ProposeOperatorship(TransferOperatorshipArgs), // Uses same args as transfer + + #[clap(long_about = "Accept ITS operatorship transfer")] + AcceptOperatorship(AcceptOperatorshipArgs), +} + +// Helper functions for parsing CLI arguments +fn hash_salt(s: &str) -> eyre::Result<[u8; 32]> { + Ok(solana_sdk::keccak::hash(s.as_bytes()).0) +} + +fn parse_hex_vec(s: &str) -> Result, hex::FromHexError> { + hex::decode(s.strip_prefix("0x").unwrap_or(s)) +} + +fn parse_token_program(s: &str) -> Result { + match s.to_lowercase().as_str() { + "spl_token" => Ok(spl_token::id()), + "spl_token_2022" => Ok(spl_token_2022::id()), + _ => Err(format!("Invalid token program: {}", s)), + } +} + +fn parse_token_manager_type(s: &str) -> Result { + match s.to_lowercase().as_str() { + "lockunlock" | "lock_unlock" => Ok(state::token_manager::Type::LockUnlock), + "mintburn" | "mint_burn" => Ok(state::token_manager::Type::MintBurn), + _ => Err(format!("Invalid token manager type: {}", s)), + } +} + +fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre::Result { + match maybe_arg { + Some(id) => Ok(id), + None => { + let id = Pubkey::deserialize( + &utils::chains_info(config.network_type) + [ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][ADDRESS_KEY], + ).map_err(|_| eyre::eyre!( + "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-service"))?; + + Ok(id) + } + } +} + +fn try_infer_gas_service_config_account( + maybe_arg: Option, + config: &Config, +) -> eyre::Result { + match maybe_arg { + Some(id) => Ok(id), + None => { + let id = Pubkey::deserialize( + &utils::chains_info(config.network_type) + [ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][GAS_CONFIG_ACCOUNT], + ).map_err(|_| eyre::eyre!( + "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-config-account"))?; + + Ok(id) + } + } } #[derive(Parser, Debug)] @@ -41,6 +162,265 @@ pub(crate) struct TrustedChainArgs { chain_name: String, } +#[derive(Parser, Debug)] +pub(crate) struct ApproveDeployRemoteInterchainTokenArgs { + #[clap(long)] + deployer: Pubkey, + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long)] + destination_minter: String, +} + +#[derive(Parser, Debug)] +pub(crate) struct RevokeDeployRemoteInterchainTokenArgs { + #[clap(long)] + deployer: Pubkey, + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + destination_chain: String, +} + +#[derive(Parser, Debug)] +pub(crate) struct RegisterCanonicalInterchainTokenArgs { + #[clap(long)] + mint: Pubkey, + + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct DeployRemoteCanonicalInterchainTokenArgs { + #[clap(long)] + mint: Pubkey, + #[clap(long)] + destination_chain: String, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct DeployInterchainTokenArgs { + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + name: String, + #[clap(long)] + symbol: String, + #[clap(long)] + decimals: u8, + #[clap(long)] + initial_supply: u64, + #[clap(long)] + minter: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct DeployRemoteInterchainTokenArgs { + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct DeployRemoteInterchainTokenWithMinterArgs { + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + minter: Pubkey, + #[clap(long)] + destination_chain: String, + #[clap(long)] + destination_minter: String, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct RegisterTokenMetadataArgs { + #[clap(long)] + mint: Pubkey, + + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct RegisterCustomTokenArgs { + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + mint: Pubkey, + #[clap(long, value_parser = parse_token_manager_type)] + token_manager_type: state::token_manager::Type, + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + operator: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct LinkTokenArgs { + #[clap(long, value_parser = hash_salt)] + salt: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long, value_parser = parse_hex_vec)] + destination_token_address: Vec, + #[clap(long, value_parser = parse_token_manager_type)] + token_manager_type: state::token_manager::Type, + #[clap(long, value_parser = parse_hex_vec)] + link_params: Vec, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, +} + +#[derive(Parser, Debug)] +pub(crate) struct InterchainTransferArgs { + #[clap(long)] + source_account: Pubkey, + #[clap(long)] + authority: Option, // If None, uses TokenManager PDA + #[clap(long, value_parser = hash_salt)] + token_id: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long)] + destination_address: String, + #[clap(long)] + amount: u64, + #[clap(long)] + mint: Pubkey, + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, + #[clap(long)] + timestamp: Option, // Defaults to current time if not provided +} + +#[derive(Parser, Debug)] +pub(crate) struct CallContractWithInterchainTokenArgs { + #[clap(long)] + source_account: Pubkey, + #[clap(long)] + authority: Option, // If None, uses TokenManager PDA + #[clap(long, value_parser = hash_salt)] + token_id: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long)] + destination_address: String, + #[clap(long)] + amount: u64, + #[clap(long)] + mint: Pubkey, + #[clap(long, value_parser = parse_hex_vec)] + data: Vec, + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, + #[clap(long)] + timestamp: Option, // Defaults to current time if not provided +} + +#[derive(Parser, Debug)] +pub(crate) struct CallContractWithInterchainTokenOffchainDataArgs { + #[clap(long)] + source_account: Pubkey, + #[clap(long)] + authority: Option, // If None, uses TokenManager PDA + #[clap(long, value_parser = hash_salt)] + token_id: [u8; 32], + #[clap(long)] + destination_chain: String, + #[clap(long)] + destination_address: String, + #[clap(long)] + amount: u64, + #[clap(long)] + mint: Pubkey, + + /// Hex string with the calldata to be sent to the contract. + #[clap(long, value_parser = parse_hex_vec)] + data: Vec, + + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + gas_value: u64, + #[clap(long)] + gas_service: Option, + #[clap(long)] + gas_config_account: Option, + #[clap(long)] + timestamp: Option, // Defaults to current time if not provided +} + +#[derive(Parser, Debug)] +pub(crate) struct SetFlowLimitArgs { + #[clap(long, value_parser = hash_salt)] + token_id: [u8; 32], + #[clap(long)] + flow_limit: u64, +} + +#[derive(Parser, Debug)] +pub(crate) struct TransferOperatorshipArgs { + #[clap(long)] + to: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct AcceptOperatorshipArgs { + #[clap(long)] + from: Pubkey, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, @@ -54,12 +434,49 @@ pub(crate) async fn build_instruction( Commands::SetTrustedChain(set_trusted_chain_args) => { set_trusted_chain(fee_payer, set_trusted_chain_args).await } - Commands::RemoveTrustedChain(remove_trusted_chain_args) => { - remove_trusted_chain(fee_payer, remove_trusted_chain_args).await + Commands::RemoveTrustedChain(args) => remove_trusted_chain(fee_payer, args).await, + Commands::ApproveDeployRemoteInterchainToken(args) => { + approve_deploy_remote_interchain_token(fee_payer, args, config).await + } + Commands::RevokeDeployRemoteInterchainToken(args) => { + revoke_deploy_remote_interchain_token(fee_payer, args).await + } + Commands::RegisterCanonicalInterchainToken(args) => { + register_canonical_interchain_token(fee_payer, args).await + } + Commands::DeployRemoteCanonicalInterchainToken(args) => { + deploy_remote_canonical_interchain_token(fee_payer, args, config).await + } + Commands::DeployInterchainToken(args) => deploy_interchain_token(fee_payer, args).await, + Commands::DeployRemoteInterchainToken(args) => { + deploy_remote_interchain_token(fee_payer, args, config).await + } + Commands::DeployRemoteInterchainTokenWithMinter(args) => { + deploy_remote_interchain_token_with_minter(fee_payer, args, config).await + } + Commands::RegisterTokenMetadata(args) => { + register_token_metadata(fee_payer, args, config).await + } + Commands::RegisterCustomToken(args) => register_custom_token(fee_payer, args).await, + Commands::LinkToken(args) => link_token(fee_payer, args, config).await, + Commands::InterchainTransfer(args) => interchain_transfer(fee_payer, args, config).await, + Commands::CallContractWithInterchainToken(args) => { + call_contract_with_interchain_token(fee_payer, args, config).await } + Commands::CallContractWithInterchainTokenOffchainData(args) => { + call_contract_with_interchain_token_offchain_data(fee_payer, args, config).await + } + Commands::SetFlowLimit(args) => set_flow_limit(fee_payer, args).await, + Commands::TransferOperatorship(args) => transfer_operatorship(fee_payer, args).await, + Commands::ProposeOperatorship(args) => propose_operatorship(fee_payer, args).await, + Commands::AcceptOperatorship(args) => accept_operatorship(fee_payer, args).await, } } +// Note: The `call_contract_with_interchain_token_offchain_data` instruction builder +// returns a tuple `(Instruction, Vec)`. This CLI currently only handles the +// `Instruction`. The offchain data needs separate handling (e.g., storing or logging). + async fn init( fee_payer: &Pubkey, init_args: InitArgs, @@ -107,3 +524,314 @@ async fn remove_trusted_chain( remove_trusted_chain_args.chain_name, )?) } + +async fn approve_deploy_remote_interchain_token( + fee_payer: &Pubkey, + args: ApproveDeployRemoteInterchainTokenArgs, + config: &Config, +) -> eyre::Result { + let destination_minter = + utils::encode_its_destination(&config, &args.destination_chain, args.destination_minter)?; + + Ok( + axelar_solana_its::instruction::approve_deploy_remote_interchain_token( + *fee_payer, + args.deployer, + args.salt, + args.destination_chain, + destination_minter, + )?, + ) +} + +async fn revoke_deploy_remote_interchain_token( + fee_payer: &Pubkey, + args: RevokeDeployRemoteInterchainTokenArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::revoke_deploy_remote_interchain_token( + *fee_payer, + args.deployer, + args.salt, + args.destination_chain, + )?, + ) +} + +async fn register_canonical_interchain_token( + fee_payer: &Pubkey, + args: RegisterCanonicalInterchainTokenArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::register_canonical_interchain_token( + *fee_payer, + args.mint, + args.token_program, + )?, + ) +} + +async fn deploy_remote_canonical_interchain_token( + fee_payer: &Pubkey, + args: DeployRemoteCanonicalInterchainTokenArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + Ok( + axelar_solana_its::instruction::deploy_remote_canonical_interchain_token( + *fee_payer, + args.mint, + args.destination_chain, + args.gas_value, + gas_service, + gas_config_account, + )?, + ) +} + +async fn deploy_interchain_token( + fee_payer: &Pubkey, + args: DeployInterchainTokenArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::deploy_interchain_token( + *fee_payer, + args.salt, + args.name, + args.symbol, + args.decimals, + args.initial_supply, + args.minter, + )?) +} + +async fn deploy_remote_interchain_token( + fee_payer: &Pubkey, + args: DeployRemoteInterchainTokenArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + Ok( + axelar_solana_its::instruction::deploy_remote_interchain_token( + *fee_payer, + args.salt, + args.destination_chain, + args.gas_value, + gas_service, + gas_config_account, + )?, + ) +} + +async fn deploy_remote_interchain_token_with_minter( + fee_payer: &Pubkey, + args: DeployRemoteInterchainTokenWithMinterArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + let destination_minter = + utils::encode_its_destination(&config, &args.destination_chain, args.destination_minter)?; + Ok( + axelar_solana_its::instruction::deploy_remote_interchain_token_with_minter( + *fee_payer, + args.salt, + args.minter, + args.destination_chain, + destination_minter, + args.gas_value, + gas_service, + gas_config_account, + )?, + ) +} + +async fn register_token_metadata( + fee_payer: &Pubkey, + args: RegisterTokenMetadataArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + Ok(axelar_solana_its::instruction::register_token_metadata( + *fee_payer, + args.mint, + args.token_program, + args.gas_value, + gas_service, + gas_config_account, + )?) +} + +async fn register_custom_token( + fee_payer: &Pubkey, + args: RegisterCustomTokenArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::register_custom_token( + *fee_payer, + args.salt, + args.mint, + args.token_manager_type, + args.token_program, + args.operator, + )?) +} + +async fn link_token( + fee_payer: &Pubkey, + args: LinkTokenArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + Ok(axelar_solana_its::instruction::link_token( + *fee_payer, + args.salt, + args.destination_chain, + args.destination_token_address, + args.token_manager_type, + args.link_params, + args.gas_value, + gas_service, + gas_config_account, + )?) +} + +async fn interchain_transfer( + fee_payer: &Pubkey, + args: InterchainTransferArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + let timestamp: i64 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs() + .try_into()?; + + let destination_address = + utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + + Ok(axelar_solana_its::instruction::interchain_transfer( + *fee_payer, + args.source_account, + args.authority, + args.token_id, + args.destination_chain, + destination_address, + args.amount, + args.mint, + args.token_program, + args.gas_value, + gas_service, + gas_config_account, + timestamp, + )?) +} + +async fn call_contract_with_interchain_token( + fee_payer: &Pubkey, + args: CallContractWithInterchainTokenArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + let timestamp: i64 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs() + .try_into()?; + let destination_address = + utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + Ok( + axelar_solana_its::instruction::call_contract_with_interchain_token( + *fee_payer, + args.source_account, + args.authority, + args.token_id, + args.destination_chain, + destination_address, + args.amount, + args.mint, + args.data, + args.token_program, + args.gas_value, + gas_service, + gas_config_account, + timestamp, + )?, + ) +} + +async fn call_contract_with_interchain_token_offchain_data( + fee_payer: &Pubkey, + args: CallContractWithInterchainTokenOffchainDataArgs, + config: &Config, +) -> eyre::Result { + let gas_service = try_infer_gas_service_id(args.gas_service, config)?; + let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + let timestamp: i64 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs() + .try_into()?; + let destination_address = + utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + + let (instruction, payload) = + axelar_solana_its::instruction::call_contract_with_interchain_token_offchain_data( + *fee_payer, + args.source_account, + args.authority, + args.token_id, + args.destination_chain, + destination_address, + args.amount, + args.mint, + args.data, // This is the raw data, the function calculates the hash + args.token_program, + args.gas_value, + gas_service, + gas_config_account, + timestamp, + )?; + + let mut file = File::create(config.output_dir.join("offchain_data_payload.bin"))?; + file.write(&payload)?; + + Ok(instruction) +} + +async fn set_flow_limit(fee_payer: &Pubkey, args: SetFlowLimitArgs) -> eyre::Result { + Ok(axelar_solana_its::instruction::set_flow_limit( + *fee_payer, + args.token_id, + args.flow_limit, + )?) +} + +async fn transfer_operatorship( + fee_payer: &Pubkey, + args: TransferOperatorshipArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::transfer_operatorship( + *fee_payer, args.to, + )?) +} + +async fn propose_operatorship( + fee_payer: &Pubkey, + args: TransferOperatorshipArgs, // Reuses args from transfer +) -> eyre::Result { + Ok(axelar_solana_its::instruction::propose_operatorship( + *fee_payer, args.to, + )?) +} + +async fn accept_operatorship( + fee_payer: &Pubkey, + args: AcceptOperatorshipArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::accept_operatorship( + *fee_payer, args.from, + )?) +} diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 2606eb333..d8c5a900d 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -1,9 +1,12 @@ use serde::de::DeserializeOwned; -use serde::Serialize; +use serde::{Deserialize, Serialize}; +use solana_sdk::pubkey::Pubkey; use std::fs::File; use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::sync::LazyLock; +use crate::config::Config; use crate::error::{AppError, Result}; use crate::types::{ NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, @@ -150,3 +153,19 @@ pub(crate) fn create_offline_bundle( Ok(target_path) } + +pub(crate) fn encode_its_destination( + config: &Config, + destination_chain: &str, + destination_address: String, +) -> eyre::Result> { + let chain_type = String::deserialize( + &chains_info(config.network_type)[CHAINS_KEY][destination_chain][CHAIN_TYPE_KEY], + )?; + + match chain_type.to_lowercase().as_str() { + "stellar" => Ok(destination_address.into_bytes()), + "svm" => Ok(Pubkey::from_str(&destination_address)?.to_bytes().to_vec()), + _ => Ok(hex::decode(destination_address)?), + } +} From 7e0046bb0feddcb7d77e89eb393dba03ea4a12fe Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 12:17:45 +0200 Subject: [PATCH 10/59] feat: add solana-devnet to chains Not sure how this is supposed to be populated yet. I believe this is filled by Axelar since we need a chainId. Signed-off-by: Guilherme Felipe da Silva --- axelar-chains-config/info/devnet-amplifier.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 4f9576f1d..8556bb6ad 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -1,5 +1,19 @@ { "chains": { + "solana-devnet": { + "name": "Solana Devnet", + "axelarId": "solana-devnet", + "rpc": "https://api.devnet.solana.com", + "tokenSymbol": "SOL", + "decimals": 9, + "confirmations": 1, + "finality": "finalized", + "approxFinalityWaitTime": 13, + "chainType": "svm", + "explorer": { + "name": "solscan", + "url": "https://solscan.io/?cluster=devnet", + }, "core-avalanche": { "name": "Avalanche Fuji", "axelarId": "core-avalanche", From 271551d748947ad1d6f213ebabe8ef92862bb5ec Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 12:58:24 +0200 Subject: [PATCH 11/59] fix: add missing token manager types Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index a0b2d6e7d..c88b75519 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -103,6 +103,8 @@ fn parse_token_manager_type(s: &str) -> Result Ok(state::token_manager::Type::LockUnlock), "mintburn" | "mint_burn" => Ok(state::token_manager::Type::MintBurn), + "mintburnfrom" | "mint_burn_from" => Ok(state::token_manager::Type::MintBurnFrom), + "lockunlockfee" | "lock_unlock_fee" => Ok(state::token_manager::Type::LockUnlockFee), _ => Err(format!("Invalid token manager type: {}", s)), } } From 6fe4bb454b1e5387c1daaa1d14e903c35618296e Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 13:21:13 +0200 Subject: [PATCH 12/59] feat: add more its instructions Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 335 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 326 insertions(+), 9 deletions(-) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index c88b75519..07dee5921 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -80,9 +80,142 @@ pub(crate) enum Commands { #[clap(long_about = "Accept ITS operatorship transfer")] AcceptOperatorship(AcceptOperatorshipArgs), + + #[clap(subcommand, long_about = "Manage Token Managers")] + TokenManager(TokenManagerCommand), + + #[clap(subcommand, long_about = "Manage Interchain Tokens")] + InterchainToken(InterchainTokenCommand), +} + +#[derive(Subcommand, Debug)] +pub(crate) enum TokenManagerCommand { + #[clap(long_about = "Set the flow limit for a token manager")] + SetFlowLimit(TokenManagerSetFlowLimitArgs), + #[clap(long_about = "Add a flow limiter role to an account for a token manager")] + AddFlowLimiter(TokenManagerAddFlowLimiterArgs), + #[clap(long_about = "Remove a flow limiter role from an account for a token manager")] + RemoveFlowLimiter(TokenManagerRemoveFlowLimiterArgs), + #[clap(long_about = "Transfer operatorship of a token manager")] + TransferOperatorship(TokenManagerTransferOperatorshipArgs), + #[clap(long_about = "Propose operatorship transfer for a token manager")] + ProposeOperatorship(TokenManagerProposeOperatorshipArgs), + #[clap(long_about = "Accept operatorship transfer for a token manager")] + AcceptOperatorship(TokenManagerAcceptOperatorshipArgs), + #[clap(long_about = "Hand over mint authority from payer to token manager")] + HandoverMintAuthority(TokenManagerHandoverMintAuthorityArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerSetFlowLimitArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + flow_limit: u64, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerAddFlowLimiterArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + flow_limiter: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerRemoveFlowLimiterArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + flow_limiter: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerTransferOperatorshipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + to: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerProposeOperatorshipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + to: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerAcceptOperatorshipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + from: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct TokenManagerHandoverMintAuthorityArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + mint: Pubkey, + /// The token program used for the mint (spl_token or spl_token_2022). + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, +} + +#[derive(Subcommand, Debug)] +pub(crate) enum InterchainTokenCommand { + #[clap(long_about = "Mint interchain tokens (requires minter role)")] + Mint(InterchainTokenMintArgs), + #[clap(long_about = "Transfer mintership for an interchain token")] + TransferMintership(InterchainTokenTransferMintershipArgs), + #[clap(long_about = "Propose mintership transfer for an interchain token")] + ProposeMintership(InterchainTokenProposeMintershipArgs), + #[clap(long_about = "Accept mintership transfer for an interchain token")] + AcceptMintership(InterchainTokenAcceptMintershipArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct InterchainTokenMintArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + mint: Pubkey, + #[clap(long)] + to: Pubkey, + /// The token program used for the mint (spl_token or spl_token_2022). + #[clap(long, value_parser = parse_token_program)] + token_program: Pubkey, + #[clap(long)] + amount: u64, +} + +#[derive(Parser, Debug)] +pub(crate) struct InterchainTokenTransferMintershipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + to: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct InterchainTokenProposeMintershipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + to: Pubkey, +} + +#[derive(Parser, Debug)] +pub(crate) struct InterchainTokenAcceptMintershipArgs { + #[clap(long, value_parser = parse_hex_bytes32)] + token_id: [u8; 32], + #[clap(long)] + from: Pubkey, } -// Helper functions for parsing CLI arguments fn hash_salt(s: &str) -> eyre::Result<[u8; 32]> { Ok(solana_sdk::keccak::hash(s.as_bytes()).0) } @@ -91,6 +224,14 @@ fn parse_hex_vec(s: &str) -> Result, hex::FromHexError> { hex::decode(s.strip_prefix("0x").unwrap_or(s)) } +fn parse_hex_bytes32(s: &str) -> eyre::Result<[u8; 32]> { + let decoded: [u8; 32] = hex::decode(s.strip_prefix("0x").unwrap_or(s))? + .try_into() + .map_err(|_| eyre::eyre!("Invalid hex string length. Expected 32 bytes."))?; + + Ok(decoded) +} + fn parse_token_program(s: &str) -> Result { match s.to_lowercase().as_str() { "spl_token" => Ok(spl_token::id()), @@ -315,7 +456,7 @@ pub(crate) struct InterchainTransferArgs { source_account: Pubkey, #[clap(long)] authority: Option, // If None, uses TokenManager PDA - #[clap(long, value_parser = hash_salt)] + #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], #[clap(long)] destination_chain: String, @@ -344,7 +485,7 @@ pub(crate) struct CallContractWithInterchainTokenArgs { source_account: Pubkey, #[clap(long)] authority: Option, // If None, uses TokenManager PDA - #[clap(long, value_parser = hash_salt)] + #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], #[clap(long)] destination_chain: String, @@ -375,7 +516,7 @@ pub(crate) struct CallContractWithInterchainTokenOffchainDataArgs { source_account: Pubkey, #[clap(long)] authority: Option, // If None, uses TokenManager PDA - #[clap(long, value_parser = hash_salt)] + #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], #[clap(long)] destination_chain: String, @@ -405,7 +546,7 @@ pub(crate) struct CallContractWithInterchainTokenOffchainDataArgs { #[derive(Parser, Debug)] pub(crate) struct SetFlowLimitArgs { - #[clap(long, value_parser = hash_salt)] + #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], #[clap(long)] flow_limit: u64, @@ -472,13 +613,44 @@ pub(crate) async fn build_instruction( Commands::TransferOperatorship(args) => transfer_operatorship(fee_payer, args).await, Commands::ProposeOperatorship(args) => propose_operatorship(fee_payer, args).await, Commands::AcceptOperatorship(args) => accept_operatorship(fee_payer, args).await, + Commands::TokenManager(command) => match command { + TokenManagerCommand::SetFlowLimit(args) => { + token_manager_set_flow_limit(fee_payer, args).await + } + TokenManagerCommand::AddFlowLimiter(args) => { + token_manager_add_flow_limiter(fee_payer, args).await + } + TokenManagerCommand::RemoveFlowLimiter(args) => { + token_manager_remove_flow_limiter(fee_payer, args).await + } + TokenManagerCommand::TransferOperatorship(args) => { + token_manager_transfer_operatorship(fee_payer, args).await + } + TokenManagerCommand::ProposeOperatorship(args) => { + token_manager_propose_operatorship(fee_payer, args).await + } + TokenManagerCommand::AcceptOperatorship(args) => { + token_manager_accept_operatorship(fee_payer, args).await + } + TokenManagerCommand::HandoverMintAuthority(args) => { + token_manager_handover_mint_authority(fee_payer, args).await + } + }, + Commands::InterchainToken(command) => match command { + InterchainTokenCommand::Mint(args) => interchain_token_mint(fee_payer, args).await, + InterchainTokenCommand::TransferMintership(args) => { + interchain_token_transfer_mintership(fee_payer, args).await + } + InterchainTokenCommand::ProposeMintership(args) => { + interchain_token_propose_mintership(fee_payer, args).await + } + InterchainTokenCommand::AcceptMintership(args) => { + interchain_token_accept_mintership(fee_payer, args).await + } + }, } } -// Note: The `call_contract_with_interchain_token_offchain_data` instruction builder -// returns a tuple `(Instruction, Vec)`. This CLI currently only handles the -// `Instruction`. The offchain data needs separate handling (e.g., storing or logging). - async fn init( fee_payer: &Pubkey, init_args: InitArgs, @@ -837,3 +1009,148 @@ async fn accept_operatorship( *fee_payer, args.from, )?) } + +async fn token_manager_set_flow_limit( + fee_payer: &Pubkey, + args: TokenManagerSetFlowLimitArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::set_flow_limit( + *fee_payer, + args.token_id, + args.flow_limit, + )?, + ) +} + +async fn token_manager_add_flow_limiter( + fee_payer: &Pubkey, + args: TokenManagerAddFlowLimiterArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::add_flow_limiter( + *fee_payer, + args.token_id, + args.flow_limiter, + )?, + ) +} + +async fn token_manager_remove_flow_limiter( + fee_payer: &Pubkey, + args: TokenManagerRemoveFlowLimiterArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::remove_flow_limiter( + *fee_payer, + args.token_id, + args.flow_limiter, + )?, + ) +} + +async fn token_manager_transfer_operatorship( + fee_payer: &Pubkey, + args: TokenManagerTransferOperatorshipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::transfer_operatorship( + *fee_payer, + args.token_id, + args.to, + )?, + ) +} + +async fn token_manager_propose_operatorship( + fee_payer: &Pubkey, + args: TokenManagerProposeOperatorshipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::propose_operatorship( + *fee_payer, + args.token_id, + args.to, + )?, + ) +} + +async fn token_manager_accept_operatorship( + fee_payer: &Pubkey, + args: TokenManagerAcceptOperatorshipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::accept_operatorship( + *fee_payer, + args.token_id, + args.from, + )?, + ) +} + +async fn token_manager_handover_mint_authority( + fee_payer: &Pubkey, + args: TokenManagerHandoverMintAuthorityArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::token_manager::handover_mint_authority( + *fee_payer, + args.token_id, + args.mint, + args.token_program, + )?, + ) +} + +async fn interchain_token_mint( + fee_payer: &Pubkey, + args: InterchainTokenMintArgs, +) -> eyre::Result { + Ok(axelar_solana_its::instruction::interchain_token::mint( + args.token_id, // Note: payer is not the first argument here + args.mint, + args.to, + *fee_payer, // Payer is the minter in this context + args.token_program, + args.amount, + )?) +} + +async fn interchain_token_transfer_mintership( + fee_payer: &Pubkey, + args: InterchainTokenTransferMintershipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::interchain_token::transfer_mintership( + *fee_payer, + args.token_id, + args.to, + )?, + ) +} + +async fn interchain_token_propose_mintership( + fee_payer: &Pubkey, + args: InterchainTokenProposeMintershipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::interchain_token::propose_mintership( + *fee_payer, + args.token_id, + args.to, + )?, + ) +} + +async fn interchain_token_accept_mintership( + fee_payer: &Pubkey, + args: InterchainTokenAcceptMintershipArgs, +) -> eyre::Result { + Ok( + axelar_solana_its::instruction::interchain_token::accept_mintership( + *fee_payer, + args.token_id, + args.from, + )?, + ) +} From 19e0269015523094342a73ee56033ee1852f538e Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 15:53:57 +0200 Subject: [PATCH 13/59] fix(solana): fix its pause/unpause Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index 07dee5921..aa041afde 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -17,8 +17,11 @@ pub(crate) enum Commands { #[clap(long_about = "Initialize the ITS program")] Init(InitArgs), - #[clap(long_about = "Set the pause status of the ITS program")] - SetPauseStatus(SetPauseStatusArgs), + #[clap(long_about = "Pause ITS")] + Pause, + + #[clap(long_about = "Unpause ITS")] + Unpause, #[clap(long_about = "Add a new trusted chain to ITS")] SetTrustedChain(TrustedChainArgs), @@ -295,7 +298,7 @@ pub(crate) struct InitArgs { #[derive(Parser, Debug)] pub(crate) struct SetPauseStatusArgs { - #[clap(short, long)] + #[clap(short, long, required = true)] paused: bool, } @@ -571,8 +574,9 @@ pub(crate) async fn build_instruction( ) -> eyre::Result { match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await, - Commands::SetPauseStatus(set_pause_args) => { - set_pause_status(fee_payer, set_pause_args).await + Commands::Pause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: true }).await, + Commands::Unpause => { + set_pause_status(fee_payer, SetPauseStatusArgs { paused: false }).await } Commands::SetTrustedChain(set_trusted_chain_args) => { set_trusted_chain(fee_payer, set_trusted_chain_args).await From d8a54de2282f7aad19ff87bf5f0d0aa57fd9d265 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 15:54:35 +0200 Subject: [PATCH 14/59] refactor(solana): move transaction result printing Move to utils and reuse it within `send` subcommand flow. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/broadcast.rs | 34 ++++++---------------------------- solana/cli/src/send.rs | 17 ++++++++++++++--- solana/cli/src/utils.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/solana/cli/src/broadcast.rs b/solana/cli/src/broadcast.rs index 33d90b07d..68ccbc67f 100644 --- a/solana/cli/src/broadcast.rs +++ b/solana/cli/src/broadcast.rs @@ -1,7 +1,7 @@ use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::{BroadcastArgs, NetworkType, SignedSolanaTransaction}; -use crate::utils; +use crate::types::{BroadcastArgs, SignedSolanaTransaction}; +use crate::utils::{self, print_transaction_result}; use solana_client::rpc_client::RpcClient; use solana_sdk::{ commitment_config::CommitmentConfig, hash::Hash, instruction::Instruction as SolanaInstruction, @@ -135,32 +135,10 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Re args.signed_tx_path.display() ); - match submit_solana_transaction(&config.url, &signed_tx_data) { - Ok(tx_signature) => { - println!("------------------------------------------"); - println!("✅ Solana Transaction successfully broadcast and confirmed!"); - println!(" Transaction Signature (ID): {}", tx_signature); - println!(" RPC Endpoint: {}", config.url); - let explorer_base_url = "https://explorer.solana.com/tx/"; - let cluster_param = match config.network_type { - NetworkType::Mainnet => "", - NetworkType::Testnet => "?cluster=testnet", - NetworkType::Devnet => "?cluster=devnet", - NetworkType::Localnet => "?cluster=custom", - }; - println!( - " Explorer Link: {}{}{}", - explorer_base_url, tx_signature, cluster_param - ); - println!("------------------------------------------"); - } - Err(e) => { - eprintln!("------------------------------------------"); - eprintln!("❌ Solana Transaction broadcast failed."); - eprintln!("------------------------------------------"); - return Err(e); - } - } + print_transaction_result( + config, + submit_solana_transaction(&config.url, &signed_tx_data), + )?; Ok(()) } diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs index bb49b03fe..216193a2f 100644 --- a/solana/cli/src/send.rs +++ b/solana/cli/src/send.rs @@ -8,6 +8,7 @@ use solana_sdk::transaction::Transaction; use crate::config::Config; use crate::error::{AppError, Result}; use crate::types::SendArgs; +use crate::utils::print_transaction_result; pub(crate) fn build_and_send_solana_transaction( send_args: &SendArgs, @@ -16,8 +17,14 @@ pub(crate) fn build_and_send_solana_transaction( ) -> Result<()> { let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); let message = Message::new(&[instruction], Some(&send_args.fee_payer)); - let mut transaction = Transaction::new_unsigned(message); + + if send_args.signers.len() < transaction.signatures.len() { + return Err(AppError::SigningError( + "Not enough signers provided".to_string(), + )); + } + let mut signers = Vec::with_capacity(transaction.signatures.len()); let signer_context = clap::ArgMatches::default(); // Dummy context @@ -32,7 +39,11 @@ pub(crate) fn build_and_send_solana_transaction( let blockhash = rpc_client.get_latest_blockhash()?; transaction.sign(&signers, blockhash); - rpc_client.send_and_confirm_transaction(&transaction)?; - Ok(()) + Ok(print_transaction_result( + config, + rpc_client + .send_and_confirm_transaction(&transaction) + .map_err(|e| AppError::from(e)), + )?) } diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index d8c5a900d..f65c5f220 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -1,6 +1,7 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Signature; use std::fs::File; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -169,3 +170,35 @@ pub(crate) fn encode_its_destination( _ => Ok(hex::decode(destination_address)?), } } + +pub(crate) fn print_transaction_result(config: &Config, result: Result) -> Result<()> { + match result { + Ok(tx_signature) => { + println!("------------------------------------------"); + println!("✅ Solana Transaction successfully broadcast and confirmed!"); + println!(" Transaction Signature (ID): {}", tx_signature); + println!(" RPC Endpoint: {}", config.url); + let explorer_base_url = "https://explorer.solana.com/tx/"; + let cluster_param = match config.network_type { + NetworkType::Mainnet => "", + NetworkType::Testnet => "?cluster=testnet", + NetworkType::Devnet => "?cluster=devnet", + NetworkType::Localnet => "?cluster=custom", + }; + println!( + " Explorer Link: {}{}{}", + explorer_base_url, tx_signature, cluster_param + ); + println!("------------------------------------------"); + + Ok(()) + } + Err(e) => { + eprintln!("------------------------------------------"); + eprintln!("❌ Solana Transaction broadcast failed."); + eprintln!("------------------------------------------"); + + Err(e.into()) + } + } +} From f95177a6b316eeaa65df622cf2f608d5f4ca4ed8 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 30 Apr 2025 16:33:56 +0200 Subject: [PATCH 15/59] feat(solana): print token_id on deployments/registrations Just as convenience. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/its.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index aa041afde..2032b2c1e 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -740,6 +740,9 @@ async fn register_canonical_interchain_token( fee_payer: &Pubkey, args: RegisterCanonicalInterchainTokenArgs, ) -> eyre::Result { + let token_id = axelar_solana_its::canonical_interchain_token_id(&args.mint); + println!("Token ID: {}", hex::encode(token_id)); + Ok( axelar_solana_its::instruction::register_canonical_interchain_token( *fee_payer, @@ -772,6 +775,9 @@ async fn deploy_interchain_token( fee_payer: &Pubkey, args: DeployInterchainTokenArgs, ) -> eyre::Result { + let token_id = axelar_solana_its::interchain_token_id(fee_payer, &args.salt); + println!("Token ID: {}", hex::encode(token_id)); + Ok(axelar_solana_its::instruction::deploy_interchain_token( *fee_payer, args.salt, @@ -846,6 +852,9 @@ async fn register_custom_token( fee_payer: &Pubkey, args: RegisterCustomTokenArgs, ) -> eyre::Result { + let token_id = axelar_solana_its::linked_token_id(fee_payer, &args.salt); + println!("Token ID: {}", hex::encode(token_id)); + Ok(axelar_solana_its::instruction::register_custom_token( *fee_payer, args.salt, @@ -863,6 +872,7 @@ async fn link_token( ) -> eyre::Result { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; + Ok(axelar_solana_its::instruction::link_token( *fee_payer, args.salt, From f279ead0e337ec094733d1173859529f1da544ce Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 1 May 2025 13:17:47 +0200 Subject: [PATCH 16/59] fix(solana): update how we deal with chains info file We load it at run time instead of compile time. We accept a CLI argument with the path to the directory containing the chains info files, in case it's not provided, we use the current dir. We now also write to the file whenever a program is initialized. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 1 + solana/cli/Cargo.toml | 2 +- solana/cli/src/config.rs | 9 +++- solana/cli/src/gateway.rs | 27 ++++++------ solana/cli/src/its.rs | 87 +++++++++++++++++++++++++++++---------- solana/cli/src/main.rs | 7 +++- solana/cli/src/types.rs | 20 ++++++++- solana/cli/src/utils.rs | 71 +++++++++----------------------- 8 files changed, 132 insertions(+), 92 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index b7b6c2940..422ff6dc6 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -5988,6 +5988,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ + "indexmap 2.9.0", "itoa", "memchr", "ryu", diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index 5be2ad595..ef9f2f4b5 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -42,7 +42,7 @@ reqwest = { version = "0.12", features = ["json", "stream"] } rust_decimal = "1.37.1" rust_decimal_macros = "1.37.1" serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.140" +serde_json = { version = "1.0.140", features = ["preserve_order"] } solana-clap-v3-utils = "2.2.7" solana-cli-config = "2.2.7" solana-client = "2.2.7" diff --git a/solana/cli/src/config.rs b/solana/cli/src/config.rs index 7c11a11db..13cc6b2e9 100644 --- a/solana/cli/src/config.rs +++ b/solana/cli/src/config.rs @@ -1,20 +1,22 @@ use std::path::PathBuf; use std::{fs, str::FromStr}; +use crate::types::ChainsInfoFile; use crate::{ error::{AppError, Result}, types::NetworkType, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Config { pub url: String, pub output_dir: PathBuf, pub network_type: NetworkType, + pub chains_info_file: PathBuf, } impl Config { - pub fn new(url: String, output_dir: PathBuf) -> Result { + pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> Result { if !output_dir.exists() { fs::create_dir_all(&output_dir).map_err(|e| AppError::IoError(e))?; println!("Created output directory: {}", output_dir.display()); @@ -26,11 +28,14 @@ impl Config { } let network_type = NetworkType::from_str(&url)?; + let chains_info_filename: String = ChainsInfoFile::from(network_type).into(); + let chains_info_file = chains_info_dir.join(chains_info_filename); Ok(Self { url, output_dir, network_type, + chains_info_file, }) } } diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 6b42aa425..30458f25f 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -15,8 +15,8 @@ use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::ChainNameOnAxelar; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, - GRPC_KEY, MULTISIG_PROVER_KEY, + read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, + CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MULTISIG_PROVER_KEY, }; #[derive(Subcommand, Debug)] @@ -122,14 +122,15 @@ async fn init( init_args: InitArgs, config: &Config, ) -> eyre::Result { + let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); let multisig_prover_address = { let address = match init_args.multisig_prover_address { Some(address) => address, None => String::deserialize( - &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY] - [MULTISIG_PROVER_KEY][ChainNameOnAxelar::from(config.network_type).0] - [ADDRESS_KEY], + &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] + [ChainNameOnAxelar::from(config.network_type).0][ADDRESS_KEY], )?, }; @@ -139,9 +140,7 @@ async fn init( let axelar_grpc_endpoint = { match init_args.axelar_grpc_endpoint { Some(endpoint) => endpoint, - None => { - String::deserialize(&utils::chains_info(config.network_type)[AXELAR_KEY][GRPC_KEY])? - } + None => String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?, } }; @@ -168,9 +167,8 @@ async fn init( match init_args.domain_separator { Some(domain_separator) => domain_separator, None => String::deserialize( - &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY] - [MULTISIG_PROVER_KEY][ChainNameOnAxelar::from(config.network_type).0] - [DOMAIN_SEPARATOR_KEY], + &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] + [ChainNameOnAxelar::from(config.network_type).0][DOMAIN_SEPARATOR_KEY], )?, } }; @@ -187,9 +185,8 @@ async fn init( let payer = *fee_payer; let upgrade_authority = payer; - let mut updated_chains_info = utils::chains_info(config.network_type).clone(); - updated_chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0] - [CONTRACTS_KEY][GATEWAY_KEY] = json!({ + chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GATEWAY_KEY] = json!({ "address": bs58::encode(axelar_solana_gateway::id()).into_string(), "deployer": fee_payer, "operator": init_args.operator, @@ -198,7 +195,7 @@ async fn init( "domainSeparator": domain_separator, }); - utils::save_chains_info(config.network_type, updated_chains_info, &config.output_dir); + write_json_to_file_path(&chains_info, &config.chains_info_file)?; Ok(axelar_solana_gateway::instructions::initialize_config( payer, diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index 2032b2c1e..ec82cfad2 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -2,14 +2,15 @@ use std::{fs::File, io::Write, time::SystemTime}; use axelar_solana_its::state; use clap::{Parser, Subcommand}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::ChainNameOnAxelar; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CONTRACTS_KEY, GAS_CONFIG_ACCOUNT, GAS_SERVICE_KEY, ITS_KEY, + self, read_json_file_from_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, + CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, }; #[derive(Subcommand, Debug)] @@ -254,12 +255,12 @@ fn parse_token_manager_type(s: &str) -> Result, config: &Config) -> eyre::Result { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; match maybe_arg { Some(id) => Ok(id), None => { let id = Pubkey::deserialize( - &utils::chains_info(config.network_type) - [ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] [GAS_SERVICE_KEY][ADDRESS_KEY], ).map_err(|_| eyre::eyre!( "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ @@ -274,13 +275,13 @@ fn try_infer_gas_service_config_account( maybe_arg: Option, config: &Config, ) -> eyre::Result { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; match maybe_arg { Some(id) => Ok(id), None => { let id = Pubkey::deserialize( - &utils::chains_info(config.network_type) - [ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY][GAS_CONFIG_ACCOUNT], + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], ).map_err(|_| eyre::eyre!( "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ Please update the file or pass a value to --gas-config-account"))?; @@ -655,14 +656,38 @@ pub(crate) async fn build_instruction( } } +#[derive(Serialize, Deserialize, Debug)] +struct ItsInfo { + address: String, + #[serde(rename = "configAccount")] + config_account: String, + #[serde(rename = "upgradeAuthority")] + upgrade_authority: String, +} + async fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, ) -> eyre::Result { - let its_hub_address = String::deserialize( - &utils::chains_info(config.network_type)[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY], - )?; + let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let its_hub_address = + String::deserialize(&chains_info[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY])?; + + let its_info = ItsInfo { + address: axelar_solana_its::id().to_string(), + config_account: axelar_solana_its::find_its_root_pda( + &axelar_solana_gateway::get_gateway_root_config_pda().0, + ) + .0 + .to_string(), + upgrade_authority: fee_payer.to_string(), + }; + + chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [ITS_KEY] = serde_json::json!(its_info); + + utils::write_json_to_file_path(&chains_info, &config.chains_info_file)?; Ok(axelar_solana_its::instruction::initialize( *fee_payer, @@ -708,8 +733,12 @@ async fn approve_deploy_remote_interchain_token( args: ApproveDeployRemoteInterchainTokenArgs, config: &Config, ) -> eyre::Result { - let destination_minter = - utils::encode_its_destination(&config, &args.destination_chain, args.destination_minter)?; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let destination_minter = utils::encode_its_destination( + &chains_info, + &args.destination_chain, + args.destination_minter, + )?; Ok( axelar_solana_its::instruction::approve_deploy_remote_interchain_token( @@ -815,8 +844,12 @@ async fn deploy_remote_interchain_token_with_minter( ) -> eyre::Result { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; - let destination_minter = - utils::encode_its_destination(&config, &args.destination_chain, args.destination_minter)?; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let destination_minter = utils::encode_its_destination( + &chains_info, + &args.destination_chain, + args.destination_minter, + )?; Ok( axelar_solana_its::instruction::deploy_remote_interchain_token_with_minter( *fee_payer, @@ -898,8 +931,12 @@ async fn interchain_transfer( .as_secs() .try_into()?; - let destination_address = - utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let destination_address = utils::encode_its_destination( + &chains_info, + &args.destination_chain, + args.destination_address, + )?; Ok(axelar_solana_its::instruction::interchain_transfer( *fee_payer, @@ -929,8 +966,12 @@ async fn call_contract_with_interchain_token( .duration_since(SystemTime::UNIX_EPOCH)? .as_secs() .try_into()?; - let destination_address = - utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let destination_address = utils::encode_its_destination( + &chains_info, + &args.destination_chain, + args.destination_address, + )?; Ok( axelar_solana_its::instruction::call_contract_with_interchain_token( *fee_payer, @@ -962,8 +1003,12 @@ async fn call_contract_with_interchain_token_offchain_data( .duration_since(SystemTime::UNIX_EPOCH)? .as_secs() .try_into()?; - let destination_address = - utils::encode_its_destination(config, &args.destination_chain, args.destination_address)?; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let destination_address = utils::encode_its_destination( + &chains_info, + &args.destination_chain, + args.destination_address, + )?; let (instruction, payload) = axelar_solana_its::instruction::call_contract_with_interchain_token_offchain_data( @@ -975,7 +1020,7 @@ async fn call_contract_with_interchain_token_offchain_data( destination_address, args.amount, args.mint, - args.data, // This is the raw data, the function calculates the hash + args.data, args.token_program, args.gas_value, gas_service, diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index e2ab87265..1815cc0b2 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -57,6 +57,11 @@ struct Cli { help = "Directory for output files" )] output_dir: PathBuf, + + /// Directory containing the JSON files for Axelar chains configuration info + /// (devnet-amplifier.json, mainnet.json, testnet.json, etc) + #[clap(short, long, default_value = ".", parse(from_os_str))] + chains_info_dir: PathBuf, } #[derive(Subcommand, Debug)] @@ -201,7 +206,7 @@ async fn main() { async fn run() -> eyre::Result<()> { let cli = Cli::parse(); - let config = Config::new(cli.url, cli.output_dir)?; + let config = Config::new(cli.url, cli.output_dir, cli.chains_info_dir)?; match cli.command { Command::Send(args) => { diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index b82358e3b..daaaa19e7 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -21,11 +21,29 @@ impl FromStr for NetworkType { .then_some(NetworkType::Mainnet) .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) .or_else(|| s.contains("devnet").then_some(NetworkType::Devnet)) - .or_else(|| s.contains("localhost").then_some(NetworkType::Localnet)) + .or_else(|| s.contains("local").then_some(NetworkType::Localnet)) .ok_or_else(|| AppError::InvalidNetworkType(s.to_string())) } } +pub struct ChainsInfoFile(pub String); +impl From for String { + fn from(value: ChainsInfoFile) -> Self { + value.0 + } +} + +impl From for ChainsInfoFile { + fn from(value: NetworkType) -> Self { + match value { + NetworkType::Mainnet => Self("mainnet.json".to_owned()), + NetworkType::Testnet => Self("testnet.json".to_owned()), + NetworkType::Devnet => Self("devnet-amplifier.json".to_owned()), + NetworkType::Localnet => Self("local.json".to_owned()), + } + } +} + pub struct ChainNameOnAxelar(pub String); impl From for ChainNameOnAxelar { diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index f65c5f220..6b5b0863f 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -5,7 +5,6 @@ use solana_sdk::signature::Signature; use std::fs::File; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::LazyLock; use crate::config::Config; use crate::error::{AppError, Result}; @@ -13,96 +12,67 @@ use crate::types::{ NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, }; -const DEVNET_AMPLIFIER_CONFIG: &'static str = include_str!("../devnet-amplifier.json"); -const TESTNET_AMPLIFIER_CONFIG: &'static str = include_str!("../testnet.json"); -const MAINNET_AMPLIFIER_CONFIG: &'static str = include_str!("../mainnet.json"); - pub(crate) const ADDRESS_KEY: &str = "address"; pub(crate) const AXELAR_KEY: &str = "axelar"; pub(crate) const CHAINS_KEY: &str = "chains"; pub(crate) const CHAIN_TYPE_KEY: &str = "chainType"; pub(crate) const CONTRACTS_KEY: &str = "contracts"; pub(crate) const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; -pub(crate) const GAS_CONFIG_ACCOUNT: &str = "configAccount"; +pub(crate) const CONFIG_ACCOUNT_KEY: &str = "configAccount"; pub(crate) const GAS_SERVICE_KEY: &str = "AxelarGasService"; pub(crate) const GATEWAY_KEY: &str = "AxelarGateway"; pub(crate) const GRPC_KEY: &str = "grpc"; pub(crate) const ITS_KEY: &str = "InterchainTokenService"; pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; -static MAINNET_INFO: LazyLock = - LazyLock::new(|| serde_json::from_str(MAINNET_AMPLIFIER_CONFIG).unwrap()); - -static TESTNET_INFO: LazyLock = - LazyLock::new(|| serde_json::from_str(TESTNET_AMPLIFIER_CONFIG).unwrap()); - -static DEVNET_INFO: LazyLock = - LazyLock::new(|| serde_json::from_str(DEVNET_AMPLIFIER_CONFIG).unwrap()); - -pub(crate) fn chains_info(network: NetworkType) -> &'static serde_json::Value { - match network { - NetworkType::Mainnet => &*MAINNET_INFO, - NetworkType::Testnet => &*TESTNET_INFO, - NetworkType::Devnet => &*DEVNET_INFO, - NetworkType::Localnet => panic!( - "Cannot automatically load chains info for Localnet. \ - Please pass the required arguments to the CLI." - ), - } +pub(crate) fn read_json_file(file: &File) -> Result { + let reader = std::io::BufReader::new(file); + serde_json::from_reader(reader).map_err(|e| AppError::JsonError(e)) } -pub(crate) fn save_chains_info(network: NetworkType, info: serde_json::Value, output_dir: &Path) { - let path = match network { - NetworkType::Mainnet => "mainnet.json", - NetworkType::Testnet => "testnet.json", - NetworkType::Devnet => "devnet-amplifier.json", - NetworkType::Localnet => panic!("Cannot save chains info for Localnet."), - }; - - let file = std::fs::File::create(output_dir.join(path)).expect("Unable to create file"); - serde_json::to_writer_pretty(file, &info).expect("Unable to write data"); +pub(crate) fn write_json_file(data: &T, file: &File) -> Result<()> { + let writer = std::io::BufWriter::new(file); + serde_json::to_writer_pretty(writer, data).map_err(|e| AppError::JsonError(e)) } -pub(crate) fn read_json_file(path: &Path) -> Result { +pub(crate) fn read_json_file_from_path(path: &Path) -> Result { let file = File::open(path).map_err(|e| AppError::IoError(e))?; - let reader = std::io::BufReader::new(file); - serde_json::from_reader(reader).map_err(|e| AppError::JsonError(e)) + read_json_file(&file) } -pub(crate) fn write_json_file(data: &T, path: &Path) -> Result<()> { +pub(crate) fn write_json_to_file_path(data: &T, path: &Path) -> Result<()> { let file = File::create(path).map_err(|e| AppError::IoError(e))?; - let writer = std::io::BufWriter::new(file); - serde_json::to_writer_pretty(writer, data).map_err(|e| AppError::JsonError(e)) + write_json_file(data, &file) } pub(crate) fn load_unsigned_solana_transaction(path: &Path) -> Result { - read_json_file(path) + read_json_file_from_path(path) } pub(crate) fn save_unsigned_solana_transaction( tx: &UnsignedSolanaTransaction, path: &Path, ) -> Result<()> { - write_json_file(tx, path) + write_json_to_file_path(tx, path) } pub(crate) fn load_partial_signature(path: &Path) -> Result { - read_json_file(path) + read_json_file_from_path(path) } pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Result<()> { - write_json_file(sig, path) + write_json_to_file_path(sig, path) } pub(crate) fn load_signed_solana_transaction(path: &Path) -> Result { - read_json_file(path) + read_json_file_from_path(path) } pub(crate) fn save_signed_solana_transaction( tx: &SignedSolanaTransaction, path: &Path, ) -> Result<()> { - write_json_file(tx, path) + write_json_to_file_path(tx, path) } pub(crate) fn create_offline_bundle( @@ -156,13 +126,12 @@ pub(crate) fn create_offline_bundle( } pub(crate) fn encode_its_destination( - config: &Config, + chains_info: &serde_json::Value, destination_chain: &str, destination_address: String, ) -> eyre::Result> { - let chain_type = String::deserialize( - &chains_info(config.network_type)[CHAINS_KEY][destination_chain][CHAIN_TYPE_KEY], - )?; + let chain_type = + String::deserialize(&chains_info[CHAINS_KEY][destination_chain][CHAIN_TYPE_KEY])?; match chain_type.to_lowercase().as_str() { "stellar" => Ok(destination_address.into_bytes()), From a5f126a44364dbadac240ae957c1f506d89c401b Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 1 May 2025 14:17:05 +0200 Subject: [PATCH 17/59] fix(solana): be consistent with json manipulation Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gas_service.rs | 28 +++++++++++++++++--- solana/cli/src/gateway.rs | 15 ++++++----- solana/cli/src/its.rs | 49 ++++++++++++++--------------------- solana/cli/src/utils.rs | 4 +++ 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs index 4b2364320..e9fb9ca31 100644 --- a/solana/cli/src/gas_service.rs +++ b/solana/cli/src/gas_service.rs @@ -1,7 +1,14 @@ use clap::{Parser, Subcommand}; use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; -use crate::config::Config; +use crate::{ + config::Config, + types::ChainNameOnAxelar, + utils::{ + read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, + CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + }, +}; #[derive(Subcommand, Debug)] pub(crate) enum Commands { @@ -21,19 +28,32 @@ pub(crate) struct InitArgs { pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, - _config: &Config, + config: &Config, ) -> eyre::Result { match command { - Commands::Init(init_args) => init(fee_payer, init_args).await, + Commands::Init(init_args) => init(fee_payer, init_args, config).await, } } -async fn init(fee_payer: &Pubkey, init_args: InitArgs) -> eyre::Result { +async fn init( + fee_payer: &Pubkey, + init_args: InitArgs, + config: &Config, +) -> eyre::Result { let program_id = axelar_solana_gas_service::id(); let salt_hash = solana_sdk::keccak::hashv(&[init_args.salt.as_bytes()]).0; let (config_pda, _bump) = axelar_solana_gas_service::get_config_pda(&program_id, &salt_hash, &init_args.authority); + let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY] = serde_json::json!({ + ADDRESS_KEY: axelar_solana_gateway::id().to_string(), + CONFIG_ACCOUNT_KEY: config_pda.to_string(), + }); + + write_json_to_file_path(&chains_info, &config.chains_info_file)?; + Ok(axelar_solana_gas_service::instructions::init_config( &program_id, fee_payer, diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 30458f25f..e1bca4848 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -16,7 +16,8 @@ use crate::config::Config; use crate::types::ChainNameOnAxelar; use crate::utils::{ read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, - CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MULTISIG_PROVER_KEY, + CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, + MULTISIG_PROVER_KEY, OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -187,12 +188,12 @@ async fn init( chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] [GATEWAY_KEY] = json!({ - "address": bs58::encode(axelar_solana_gateway::id()).into_string(), - "deployer": fee_payer, - "operator": init_args.operator, - "minimumRotationDelay": init_args.minimum_rotation_delay, - "previousSignersRetention": init_args.previous_signers_retention, - "domainSeparator": domain_separator, + ADDRESS_KEY: axelar_solana_gateway::id().to_string(), + UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), + OPERATOR_KEY: init_args.operator.to_string(), + MINIMUM_ROTATION_DELAY_KEY: init_args.minimum_rotation_delay, + PREVIOUS_SIGNERS_RETENTION_KEY: init_args.previous_signers_retention, + DOMAIN_SEPARATOR_KEY: domain_separator, }); write_json_to_file_path(&chains_info, &config.chains_info_file)?; diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index ec82cfad2..0731d8f58 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -2,15 +2,16 @@ use std::{fs::File, io::Write, time::SystemTime}; use axelar_solana_its::state; use clap::{Parser, Subcommand}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::ChainNameOnAxelar; use crate::utils::{ - self, read_json_file_from_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, - CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, + encode_its_destination, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, + AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, + OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -656,15 +657,6 @@ pub(crate) async fn build_instruction( } } -#[derive(Serialize, Deserialize, Debug)] -struct ItsInfo { - address: String, - #[serde(rename = "configAccount")] - config_account: String, - #[serde(rename = "upgradeAuthority")] - upgrade_authority: String, -} - async fn init( fee_payer: &Pubkey, init_args: InitArgs, @@ -673,21 +665,20 @@ async fn init( let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; let its_hub_address = String::deserialize(&chains_info[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY])?; - - let its_info = ItsInfo { - address: axelar_solana_its::id().to_string(), - config_account: axelar_solana_its::find_its_root_pda( - &axelar_solana_gateway::get_gateway_root_config_pda().0, - ) - .0 - .to_string(), - upgrade_authority: fee_payer.to_string(), - }; + let its_root_config = axelar_solana_its::find_its_root_pda( + &axelar_solana_gateway::get_gateway_root_config_pda().0, + ) + .0; chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [ITS_KEY] = serde_json::json!(its_info); + [ITS_KEY] = serde_json::json!({ + ADDRESS_KEY: axelar_solana_gateway::id().to_string(), + CONFIG_ACCOUNT_KEY: its_root_config.to_string(), + UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), + OPERATOR_KEY: init_args.operator.to_string(), + }); - utils::write_json_to_file_path(&chains_info, &config.chains_info_file)?; + write_json_to_file_path(&chains_info, &config.chains_info_file)?; Ok(axelar_solana_its::instruction::initialize( *fee_payer, @@ -734,7 +725,7 @@ async fn approve_deploy_remote_interchain_token( config: &Config, ) -> eyre::Result { let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_minter = utils::encode_its_destination( + let destination_minter = encode_its_destination( &chains_info, &args.destination_chain, args.destination_minter, @@ -845,7 +836,7 @@ async fn deploy_remote_interchain_token_with_minter( let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_minter = utils::encode_its_destination( + let destination_minter = encode_its_destination( &chains_info, &args.destination_chain, args.destination_minter, @@ -932,7 +923,7 @@ async fn interchain_transfer( .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = utils::encode_its_destination( + let destination_address = encode_its_destination( &chains_info, &args.destination_chain, args.destination_address, @@ -967,7 +958,7 @@ async fn call_contract_with_interchain_token( .as_secs() .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = utils::encode_its_destination( + let destination_address = encode_its_destination( &chains_info, &args.destination_chain, args.destination_address, @@ -1004,7 +995,7 @@ async fn call_contract_with_interchain_token_offchain_data( .as_secs() .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = utils::encode_its_destination( + let destination_address = encode_its_destination( &chains_info, &args.destination_chain, args.destination_address, diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 6b5b0863f..21965333e 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -24,6 +24,10 @@ pub(crate) const GATEWAY_KEY: &str = "AxelarGateway"; pub(crate) const GRPC_KEY: &str = "grpc"; pub(crate) const ITS_KEY: &str = "InterchainTokenService"; pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; +pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; +pub(crate) const OPERATOR_KEY: &str = "operator"; +pub(crate) const MINIMUM_ROTATION_DELAY_KEY: &str = "minimumRotationDelay"; +pub(crate) const PREVIOUS_SIGNERS_RETENTION_KEY: &str = "previousSignersRetention"; pub(crate) fn read_json_file(file: &File) -> Result { let reader = std::io::BufReader::new(file); From f4f0d40f51a4e892f07baffd87746991cd6c388b Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 1 May 2025 17:44:34 +0200 Subject: [PATCH 18/59] feat(solana): add governance initialization Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/governance.rs | 78 ++++++++++++++++++++++++++++++++++++ solana/cli/src/main.rs | 7 ++++ solana/cli/src/utils.rs | 4 ++ 3 files changed, 89 insertions(+) create mode 100644 solana/cli/src/governance.rs diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs new file mode 100644 index 000000000..3342d69d8 --- /dev/null +++ b/solana/cli/src/governance.rs @@ -0,0 +1,78 @@ +use clap::{Parser, Subcommand}; +use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; + +use crate::{ + config::Config, + types::ChainNameOnAxelar, + utils::{ + read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, + CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, + GOVERNANCE_KEY, UPGRADE_AUTHORITY_KEY, + }, +}; + +#[derive(Subcommand, Debug)] +pub(crate) enum Commands { + #[clap(long_about = "Initialize the Gateway program")] + Init(InitArgs), +} + +#[derive(Parser, Debug)] +pub(crate) struct InitArgs { + #[clap(short, long)] + governance_chain: String, + + #[clap(short, long)] + governance_address: String, + + #[clap(short, long)] + minimum_proposal_eta_delay: u32, + + #[clap(short, long)] + operator: Pubkey, +} + +pub(crate) async fn build_instruction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result { + match command { + Commands::Init(init_args) => init(fee_payer, init_args, config).await, + } +} + +async fn init( + fee_payer: &Pubkey, + init_args: InitArgs, + config: &Config, +) -> eyre::Result { + let chain_hash = solana_sdk::keccak::hashv(&[init_args.governance_chain.as_bytes()]).0; + let address_hash = solana_sdk::keccak::hashv(&[init_args.governance_address.as_bytes()]).0; + let (config_pda, _bump) = axelar_solana_governance::state::GovernanceConfig::pda(); + + let governance_config = axelar_solana_governance::state::GovernanceConfig::new( + chain_hash, + address_hash, + init_args.minimum_proposal_eta_delay, + init_args.operator.to_bytes(), + ); + + let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GOVERNANCE_KEY] = serde_json::json!({ + ADDRESS_KEY: axelar_solana_gateway::id().to_string(), + CONFIG_ACCOUNT_KEY: config_pda.to_string(), + UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), + GOVERNANCE_ADDRESS_KEY: init_args.governance_address, + GOVERNANCE_CHAIN_KEY: init_args.governance_chain, + }); + + write_json_to_file_path(&chains_info, &config.chains_info_file)?; + + Ok( + axelar_solana_governance::instructions::builder::IxBuilder::new() + .initialize_config(fee_payer, &config_pda, governance_config) + .build(), + ) +} diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 1815cc0b2..09d1568cd 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -5,6 +5,7 @@ mod error; mod gas_service; mod gateway; mod generate; +mod governance; mod its; mod send; mod sign; @@ -148,6 +149,9 @@ enum InstructionSubcommand { #[clap(long_about = "Commands for InterchainTokenService program", subcommand)] Its(its::Commands), + + #[clap(long_about = "Commands for Governance program", subcommand)] + Governance(governance::Commands), } #[derive(Parser, Debug)] @@ -272,6 +276,9 @@ async fn build_instruction( InstructionSubcommand::Its(command) => { its::build_instruction(fee_payer, command, config).await? } + InstructionSubcommand::Governance(commands) => { + governance::build_instruction(fee_payer, commands, config).await? + } }; Ok(serializable_ix) diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 21965333e..b59b7cba1 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -28,6 +28,10 @@ pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; pub(crate) const OPERATOR_KEY: &str = "operator"; pub(crate) const MINIMUM_ROTATION_DELAY_KEY: &str = "minimumRotationDelay"; pub(crate) const PREVIOUS_SIGNERS_RETENTION_KEY: &str = "previousSignersRetention"; +pub(crate) const GOVERNANCE_KEY: &str = "InterchainGovernance"; +pub(crate) const MINIMUM_PROPOSAL_ETA_DELAY_KEY: &str = "minimumTimeDelay"; +pub(crate) const GOVERNANCE_CHAIN_KEY: &str = "governanceChain"; +pub(crate) const GOVERNANCE_ADDRESS_KEY: &str = "governanceAddress"; pub(crate) fn read_json_file(file: &File) -> Result { let reader = std::io::BufReader::new(file); From 7be155e1c5922e6dc84271b0f5536d96047a945a Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 2 May 2025 13:59:44 +0200 Subject: [PATCH 19/59] feat(solana): governance proposal execution Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 5 ++ solana/cli/Cargo.toml | 5 ++ solana/cli/src/governance.rs | 151 +++++++++++++++++++++++++++++++---- solana/cli/src/main.rs | 5 +- solana/cli/src/utils.rs | 33 ++++++++ 5 files changed, 183 insertions(+), 16 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index 422ff6dc6..f444bcaed 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -1391,6 +1391,7 @@ dependencies = [ name = "cli" version = "0.1.0" dependencies = [ + "alloy-sol-types", "anyhow", "axelar-executable", "axelar-solana-encoding", @@ -1399,7 +1400,9 @@ dependencies = [ "axelar-solana-governance", "axelar-solana-its", "axelar-wasm-std", + "base64 0.22.1", "bincode 2.0.1", + "borsh 1.5.7", "bs58", "clap 3.2.25", "cosmrs", @@ -1407,8 +1410,10 @@ dependencies = [ "cosmwasm-std 1.5.11", "eyre", "flate2", + "governance-gmp", "hex", "multisig-prover", + "program-utils", "rand 0.9.1", "reqwest 0.12.15", "rust_decimal", diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index ef9f2f4b5..a51e9778f 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -18,6 +18,8 @@ axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev ] } axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } +governance-gmp = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } +program-utils = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } axelar-wasm-std = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec" } voting-verifier = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ @@ -27,8 +29,10 @@ multisig-prover = { git = "https://github.com/eigerco/axelar-amplifier.git", rev "library", ] } +alloy-sol-types = "0.7.6" anyhow = "1.0.98" bincode = { version = "2.0.1", features = ["serde"] } +borsh = "1.5.1" bs58 = "0.5.1" clap = { version = "3.2", features = ["derive", "env"] } cosmrs = { version = "0.16", features = ["cosmwasm", "rpc", "grpc"] } @@ -54,3 +58,4 @@ walkdir = "2.5.0" spl-token = { version = "8.0.0", features = ["no-entrypoint"] } spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } +base64 = "0.22.1" diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs index 3342d69d8..0806e5be3 100644 --- a/solana/cli/src/governance.rs +++ b/solana/cli/src/governance.rs @@ -1,23 +1,32 @@ -use clap::{Parser, Subcommand}; -use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; +use axelar_solana_governance::instructions::builder::IxBuilder; +use base64::Engine; +use clap::{Args, Subcommand}; +use solana_sdk::{instruction::AccountMeta, instruction::Instruction, pubkey::Pubkey}; use crate::{ config::Config, types::ChainNameOnAxelar, utils::{ - read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, - CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, - GOVERNANCE_KEY, UPGRADE_AUTHORITY_KEY, + parse_account_meta_string, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, + CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, + GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, + UPGRADE_AUTHORITY_KEY, }, }; #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the Gateway program")] + #[clap(long_about = "Initialize the Governance program")] Init(InitArgs), + + #[clap(long_about = "Execute a scheduled proposal after its ETA")] + ExecuteProposal(ExecuteProposalArgs), + + #[clap(long_about = "Execute an operator-approved proposal (bypasses ETA)")] + ExecuteOperatorProposal(ExecuteOperatorProposalArgs), } -#[derive(Parser, Debug)] +#[derive(Args, Debug)] pub(crate) struct InitArgs { #[clap(short, long)] governance_chain: String, @@ -32,13 +41,75 @@ pub(crate) struct InitArgs { operator: Pubkey, } +// Common arguments for proposal execution +#[derive(Args, Debug, Clone)] +struct ProposalExecutionBaseArgs { + #[clap(long, help = "Target program ID for the proposal's instruction")] + target: Pubkey, + + #[clap( + long, + help = "Amount of native value (lamports) to transfer with the proposal" + )] + native_value: u64, + + #[clap( + long, + help = "Base64 encoded call data for the target program instruction" + )] + calldata: String, + + #[clap( + long, + help = "Account metas required by the target program instruction. Format: 'pubkey:is_signer:is_writable'", + value_parser = parse_account_meta_string, + )] + target_accounts: Vec, + + #[clap(long, help = "Optional account to receive the native value transfer")] + native_value_receiver: Option, +} + +#[derive(Args, Debug)] +pub(crate) struct ExecuteProposalArgs { + #[clap(flatten)] + base: ProposalExecutionBaseArgs, +} + +#[derive(Args, Debug)] +pub(crate) struct ExecuteOperatorProposalArgs { + #[clap(flatten)] + base: ProposalExecutionBaseArgs, + + #[clap(long, help = "Operator pubkey (must be a signer of the transaction)")] + operator: Pubkey, +} + +#[derive(Args, Debug)] +pub(crate) struct TransferOperatorshipArgs { + #[clap(long, help = "Pubkey of the new operator")] + new_operator: Pubkey, + + #[clap( + long, + help = "Pubkey of the current operator (must be a signer of the transaction)" + )] + operator: Pubkey, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, ) -> eyre::Result { + let (config_pda, _) = axelar_solana_governance::state::GovernanceConfig::pda(); + match command { - Commands::Init(init_args) => init(fee_payer, init_args, config).await, + Commands::Init(init_args) => init(fee_payer, init_args, config, &config_pda).await, + Commands::ExecuteProposal(args) => execute_proposal(fee_payer, args, &config_pda).await, + Commands::ExecuteOperatorProposal(args) => { + execute_operator_proposal(fee_payer, args, &config_pda).await + } } } @@ -46,10 +117,10 @@ async fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, + config_pda: &Pubkey, ) -> eyre::Result { let chain_hash = solana_sdk::keccak::hashv(&[init_args.governance_chain.as_bytes()]).0; let address_hash = solana_sdk::keccak::hashv(&[init_args.governance_address.as_bytes()]).0; - let (config_pda, _bump) = axelar_solana_governance::state::GovernanceConfig::pda(); let governance_config = axelar_solana_governance::state::GovernanceConfig::new( chain_hash, @@ -66,13 +137,65 @@ async fn init( UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), GOVERNANCE_ADDRESS_KEY: init_args.governance_address, GOVERNANCE_CHAIN_KEY: init_args.governance_chain, + MINIMUM_PROPOSAL_ETA_DELAY_KEY: init_args.minimum_proposal_eta_delay, }); write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok( - axelar_solana_governance::instructions::builder::IxBuilder::new() - .initialize_config(fee_payer, &config_pda, governance_config) - .build(), - ) + Ok(IxBuilder::new() + .initialize_config(fee_payer, config_pda, governance_config) + .build()) +} + +async fn execute_proposal( + fee_payer: &Pubkey, + args: ExecuteProposalArgs, + config_pda: &Pubkey, +) -> eyre::Result { + let calldata_bytes = base64::engine::general_purpose::STANDARD.decode(args.base.calldata)?; + let native_value_receiver_account = args + .base + .native_value_receiver + .map(|pk| AccountMeta::new(pk, false)); + + // Note: ETA is part of the proposal data stored on-chain, not provided here. + // The builder calculates the proposal hash based on target, calldata, native_value. + // The ETA value used in `with_proposal_data` is only relevant for *scheduling*, + // not execution, but the builder requires some value. We use 0 here. + let builder = IxBuilder::new().with_proposal_data( + args.base.target, + args.base.native_value, + 0, + native_value_receiver_account, + &args.base.target_accounts, + calldata_bytes, + ); + + Ok(builder.execute_proposal(fee_payer, config_pda).build()) +} + +async fn execute_operator_proposal( + fee_payer: &Pubkey, + args: ExecuteOperatorProposalArgs, + config_pda: &Pubkey, +) -> eyre::Result { + let calldata_bytes = base64::engine::general_purpose::STANDARD.decode(args.base.calldata)?; + let native_value_receiver_account = args + .base + .native_value_receiver + .map(|pk| AccountMeta::new(pk, false)); + + // ETA is irrelevant for operator execution. Use 0. + let builder = IxBuilder::new().with_proposal_data( + args.base.target, + args.base.native_value, + 0, + native_value_receiver_account, + &args.base.target_accounts, + calldata_bytes, + ); + + Ok(builder + .execute_operator_proposal(fee_payer, config_pda, &args.operator) + .build()) } diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 09d1568cd..3ad8b876b 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -212,6 +212,7 @@ async fn run() -> eyre::Result<()> { let config = Config::new(cli.url, cli.output_dir, cli.chains_info_dir)?; + // Proceed with building and potentially sending/signing/broadcasting a Solana transaction match cli.command { Command::Send(args) => { let send_args = SendArgs { @@ -276,8 +277,8 @@ async fn build_instruction( InstructionSubcommand::Its(command) => { its::build_instruction(fee_payer, command, config).await? } - InstructionSubcommand::Governance(commands) => { - governance::build_instruction(fee_payer, commands, config).await? + InstructionSubcommand::Governance(command) => { + governance::build_instruction(fee_payer, command, config).await? } }; diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index b59b7cba1..4bc6a182e 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -11,6 +11,7 @@ use crate::error::{AppError, Result}; use crate::types::{ NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, }; +pub(crate) use solana_sdk::instruction::AccountMeta; pub(crate) const ADDRESS_KEY: &str = "address"; pub(crate) const AXELAR_KEY: &str = "axelar"; @@ -148,6 +149,38 @@ pub(crate) fn encode_its_destination( } } +/// Parses a string representation of an AccountMeta. +/// Format: "pubkey:is_signer:is_writable" (e.g., "SomePubkey...:false:true") +pub fn parse_account_meta_string(s: &str) -> Result { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 3 { + return Err(AppError::InvalidInput(format!( + "Invalid AccountMeta format: '{}'. Expected 'pubkey:is_signer:is_writable'", + s + ))); + } + + let pubkey = Pubkey::from_str(parts[0])?; + let is_signer = bool::from_str(parts[1]).map_err(|_| { + AppError::InvalidInput(format!( + "Invalid is_signer value: '{}'. Expected 'true' or 'false'", + parts[1] + )) + })?; + let is_writable = bool::from_str(parts[2]).map_err(|_| { + AppError::InvalidInput(format!( + "Invalid is_writable value: '{}'. Expected 'true' or 'false'", + parts[2] + )) + })?; + + Ok(if is_writable { + AccountMeta::new(pubkey, is_signer) + } else { + AccountMeta::new_readonly(pubkey, is_signer) + }) +} + pub(crate) fn print_transaction_result(config: &Config, result: Result) -> Result<()> { match result { Ok(tx_signature) => { From c549ca630b9a453e93f3c5cc579ee3555ff5f0fa Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 7 May 2025 10:46:02 +0200 Subject: [PATCH 20/59] feat(solana): gateway `approve` (local only) Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 65 +++++- solana/cli/Cargo.toml | 1 + solana/cli/src/config.rs | 1 + solana/cli/src/gas_service.rs | 8 +- solana/cli/src/gateway.rs | 380 +++++++++++++++++++++++++++------- solana/cli/src/generate.rs | 6 +- solana/cli/src/governance.rs | 20 +- solana/cli/src/its.rs | 239 +++++++++++---------- solana/cli/src/main.rs | 34 ++- solana/cli/src/send.rs | 4 +- solana/cli/src/utils.rs | 67 ++++++ 11 files changed, 608 insertions(+), 217 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index f444bcaed..f52290fe1 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -684,7 +684,7 @@ dependencies = [ "event-utils", "hex", "itertools 0.12.1", - "libsecp256k1", + "libsecp256k1 0.6.0", "num-derive 0.4.2", "num-traits", "program-utils", @@ -1412,6 +1412,7 @@ dependencies = [ "flate2", "governance-gmp", "hex", + "libsecp256k1 0.7.2", "multisig-prover", "program-utils", "rand 0.9.1", @@ -3885,15 +3886,34 @@ dependencies = [ "base64 0.12.3", "digest 0.9.0", "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", + "libsecp256k1-core 0.2.2", + "libsecp256k1-gen-ecmult 0.2.1", + "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", "sha2 0.9.9", "typenum", ] +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core 0.3.0", + "libsecp256k1-gen-ecmult 0.3.0", + "libsecp256k1-gen-genmult 0.3.0", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + [[package]] name = "libsecp256k1-core" version = "0.2.2" @@ -3905,13 +3925,33 @@ dependencies = [ "subtle", ] +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + [[package]] name = "libsecp256k1-gen-ecmult" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" dependencies = [ - "libsecp256k1-core", + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core 0.3.0", ] [[package]] @@ -3920,7 +3960,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" dependencies = [ - "libsecp256k1-core", + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core 0.3.0", ] [[package]] @@ -7774,7 +7823,7 @@ checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" dependencies = [ "bincode 1.3.3", "digest 0.10.7", - "libsecp256k1", + "libsecp256k1 0.6.0", "serde", "serde_derive", "sha3", @@ -7791,7 +7840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ "borsh 1.5.7", - "libsecp256k1", + "libsecp256k1 0.6.0", "solana-define-syscall", "thiserror 2.0.12", ] diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index a51e9778f..b6963e1d4 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -59,3 +59,4 @@ spl-token = { version = "8.0.0", features = ["no-entrypoint"] } spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } base64 = "0.22.1" +libsecp256k1 = "0.7.2" diff --git a/solana/cli/src/config.rs b/solana/cli/src/config.rs index 13cc6b2e9..f53ac5213 100644 --- a/solana/cli/src/config.rs +++ b/solana/cli/src/config.rs @@ -17,6 +17,7 @@ pub struct Config { impl Config { pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> Result { + println!("URL: {}", url); if !output_dir.exists() { fs::create_dir_all(&output_dir).map_err(|e| AppError::IoError(e))?; println!("Created output directory: {}", output_dir.display()); diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs index e9fb9ca31..4b6f56cc6 100644 --- a/solana/cli/src/gas_service.rs +++ b/solana/cli/src/gas_service.rs @@ -29,7 +29,7 @@ pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await, } @@ -39,7 +39,7 @@ async fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let program_id = axelar_solana_gas_service::id(); let salt_hash = solana_sdk::keccak::hashv(&[init_args.salt.as_bytes()]).0; let (config_pda, _bump) = @@ -54,11 +54,11 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(axelar_solana_gas_service::instructions::init_config( + Ok(vec![axelar_solana_gas_service::instructions::init_config( &program_id, fee_payer, &init_args.authority, &config_pda, salt_hash, - )?) + )?]) } diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index e1bca4848..46b05f95c 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -1,23 +1,30 @@ use std::collections::BTreeMap; use std::str::FromStr; +use axelar_solana_encoding::hash_payload; use axelar_solana_encoding::hasher::NativeHasher; -use axelar_solana_encoding::types::pubkey::PublicKey; +use axelar_solana_encoding::types::execute_data::{ExecuteData, MerkleisedPayload}; +use axelar_solana_encoding::types::messages::{CrossChainId, Message, Messages}; +use axelar_solana_encoding::types::payload::Payload; +use axelar_solana_encoding::types::pubkey::{PublicKey, Signature}; use axelar_solana_encoding::types::verifier_set::VerifierSet; use axelar_solana_gateway::state::config::RotationDelaySecs; +use axelar_solana_gateway::state::incoming_message::command_id; use clap::{Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; use serde::Deserialize; use serde_json::json; +use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::ChainNameOnAxelar; use crate::utils::{ - read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, - CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, - MULTISIG_PROVER_KEY, OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, + read_json_file_from_path, write_json_to_file_path, SigningVerifierSet, TestSigner, ADDRESS_KEY, + AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, + MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, + UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -30,6 +37,9 @@ pub(crate) enum Commands { #[clap(long_about = "Transfer operatorship of the Gateway program")] TransferOperatorship(TransferOperatorshipArgs), + + #[clap(long_about = "Approve a message for test deployment")] + Approve(ApproveArgs), } #[derive(Parser, Debug)] @@ -40,15 +50,17 @@ pub(crate) struct InitArgs { #[clap(short, long)] minimum_rotation_delay: RotationDelaySecs, + /// Instead of querying the MultisigProver for the SignerSet, uses a local SignerSet created + /// with the default signer as set in the Solana CLI config. For testing purposes only. #[clap(short, long)] - axelar_grpc_endpoint: Option, - - #[clap(short = 'p', long)] - multisig_prover_address: Option, + local_signer: bool, #[clap(long)] operator: Pubkey, + /// Domain separator associated with the chain. + /// In case no value is passed, tries to load from MultisigProver entry for the chain. If that fails, defaults to 0x0 if not set (which is fine for + /// local tests). #[clap(short, long)] domain_separator: Option, } @@ -76,11 +88,29 @@ pub(crate) struct TransferOperatorshipArgs { new_operator: Pubkey, } +#[derive(Parser, Debug)] +pub(crate) struct ApproveArgs { + #[clap(long)] + source_chain: String, + + #[clap(short, long)] + message_id: String, + + #[clap(short, long)] + source_address: String, + + #[clap(short, long)] + destination_address: String, + + #[clap(short, long)] + payload: String, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await, Commands::CallContract(call_contract_args) => { @@ -89,6 +119,7 @@ pub(crate) async fn build_instruction( Commands::TransferOperatorship(transfer_operatorship_args) => { transfer_operatorship(fee_payer, transfer_operatorship_args).await } + Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await, } } @@ -118,68 +149,119 @@ async fn query( Ok(result) } -async fn init( - fee_payer: &Pubkey, - init_args: InitArgs, - config: &Config, -) -> eyre::Result { - let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; +fn secp256k1_keypair_from_seed(seed: &[u8]) -> (libsecp256k1::SecretKey, libsecp256k1::PublicKey) { + let mut digest = solana_sdk::keccak::hashv(&[seed]).0; + + loop { + match libsecp256k1::SecretKey::parse_slice(&digest) { + // 1 ≤ sk < n ? + Ok(sk) => { + let pk = libsecp256k1::PublicKey::from_secret_key(&sk); + return (sk, pk); + } + Err(_) => digest = solana_sdk::keccak::hashv(&[&digest]).0, + } + } +} - let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); - let multisig_prover_address = { - let address = match init_args.multisig_prover_address { - Some(address) => address, - None => String::deserialize( +async fn get_weighted_signers( + local_signer: bool, + config: &Config, + chains_info: &serde_json::Value, +) -> eyre::Result { + if local_signer { + let config_file = solana_cli_config::CONFIG_FILE + .as_ref() + .ok_or_else(|| eyre::eyre!("Missing config file"))?; + let cli_config = solana_cli_config::Config::load(config_file)?; + let signer_context = clap::ArgMatches::default(); // Dummy context + let signer = signer_from_path( + &signer_context, + &cli_config.keypair_path, + "signer", + &mut None, + ) + .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; + + // The gateway doesn't support Ed25519 signatures, thus, we generate a Secp256k1 keypair + // using the existing Ed25519 pubkey as seed. This is done only because this is for + // testing and we want to avoid requiring another external keypair. + let (_sk, pk) = secp256k1_keypair_from_seed(signer.pubkey().as_ref()); + + let pubkey = PublicKey::Secp256k1(pk.serialize_compressed()); + let signers = BTreeMap::from([(pubkey, 1_u128)]); + + Ok(VerifierSet { + nonce: 0, + signers, + quorum: 1_u128, + }) + } else { + let multisig_prover_address = { + let address = String::deserialize( &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] [ChainNameOnAxelar::from(config.network_type).0][ADDRESS_KEY], - )?, + )?; + + cosmrs::AccountId::from_str(&address).unwrap() }; - cosmrs::AccountId::from_str(&address).unwrap() - }; + let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; + let multisig_prover_response = query::( + axelar_grpc_endpoint, + multisig_prover_address, + serde_json::to_vec(&multisig_prover::msg::QueryMsg::CurrentVerifierSet)?, + ) + .await?; - let axelar_grpc_endpoint = { - match init_args.axelar_grpc_endpoint { - Some(endpoint) => endpoint, - None => String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?, + let mut signers = BTreeMap::new(); + for signer in multisig_prover_response.verifier_set.signers.values() { + let pubkey = PublicKey::Secp256k1(signer.pub_key.as_ref().try_into()?); + let weight = signer.weight.u128(); + signers.insert(pubkey, weight); } - }; - - let multisig_prover_response = query::( - axelar_grpc_endpoint, - multisig_prover_address, - serde_json::to_vec(&multisig_prover::msg::QueryMsg::CurrentVerifierSet {})?, - ) - .await?; - let mut signers = BTreeMap::new(); - for signer in multisig_prover_response.verifier_set.signers.values() { - let pubkey = PublicKey::Secp256k1(signer.pub_key.as_ref().try_into()?); - let weight = signer.weight.u128(); - signers.insert(pubkey, weight); + Ok(VerifierSet { + nonce: multisig_prover_response.verifier_set.created_at, + signers, + quorum: multisig_prover_response.verifier_set.threshold.u128(), + }) } - let verifier_set = VerifierSet { - nonce: multisig_prover_response.verifier_set.created_at, - signers, - quorum: multisig_prover_response.verifier_set.threshold.u128(), - }; +} +async fn init( + fee_payer: &Pubkey, + init_args: InitArgs, + config: &Config, +) -> eyre::Result> { + println!("gateway id: {:?}", axelar_solana_gateway::id()); + let mut chains_info: serde_json::Value = + read_json_file_from_path(&config.chains_info_file).unwrap_or_default(); + + let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); + let verifier_set = get_weighted_signers(init_args.local_signer, config, &chains_info).await?; let domain_separator = { - match init_args.domain_separator { - Some(domain_separator) => domain_separator, - None => String::deserialize( + let maybe_domain_separator = if init_args.domain_separator.is_none() { + String::deserialize( &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] [ChainNameOnAxelar::from(config.network_type).0][DOMAIN_SEPARATOR_KEY], - )?, + ) + .ok() + } else { + None + }; + + let mut domain_separator_bytes = [0_u8; 32]; + if let Some(domain_separator) = maybe_domain_separator { + hex::decode_to_slice(domain_separator, &mut domain_separator_bytes)?; } - }; - let mut domain_separator_bytes = [0_u8; 32]; - hex::decode_to_slice(&domain_separator, &mut domain_separator_bytes)?; + domain_separator_bytes + }; let verifier_set_hash = axelar_solana_encoding::types::verifier_set::verifier_set_hash::< NativeHasher, - >(&verifier_set, &domain_separator_bytes)?; + >(&verifier_set, &domain_separator)?; let (init_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda(verifier_set_hash); @@ -198,27 +280,29 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(axelar_solana_gateway::instructions::initialize_config( - payer, - upgrade_authority, - domain_separator_bytes, - vec![(verifier_set_hash, init_tracker_pda)], - init_args.minimum_rotation_delay, - init_args.operator, - init_args.previous_signers_retention.into(), - gateway_config_pda, - )?) + Ok(vec![ + axelar_solana_gateway::instructions::initialize_config( + payer, + upgrade_authority, + domain_separator, + vec![(verifier_set_hash, init_tracker_pda)], + init_args.minimum_rotation_delay, + init_args.operator, + init_args.previous_signers_retention.into(), + gateway_config_pda, + )?, + ]) } async fn call_contract( fee_payer: &Pubkey, call_contract_args: CallContractArgs, -) -> eyre::Result { +) -> eyre::Result> { let (signing_pda, signing_pda_bump) = axelar_solana_gateway::get_call_contract_signing_pda(*fee_payer); let payload = hex::decode(call_contract_args.payload)?; - Ok(axelar_solana_gateway::instructions::call_contract( + Ok(vec![axelar_solana_gateway::instructions::call_contract( axelar_solana_gateway::id(), axelar_solana_gateway::get_gateway_root_config_pda().0, *fee_payer, @@ -227,16 +311,170 @@ async fn call_contract( call_contract_args.destination_chain, call_contract_args.destination_contract_address, payload, - )?) + )?]) } async fn transfer_operatorship( fee_payer: &Pubkey, transfer_operatorship_args: TransferOperatorshipArgs, -) -> eyre::Result { - Ok(axelar_solana_gateway::instructions::transfer_operatorship( +) -> eyre::Result> { + Ok(vec![ + axelar_solana_gateway::instructions::transfer_operatorship( + *fee_payer, + transfer_operatorship_args.authority, + transfer_operatorship_args.new_operator, + )?, + ]) +} + +async fn approve( + fee_payer: &Pubkey, + approve_args: ApproveArgs, + config: &Config, +) -> eyre::Result> { + let mut instructions = vec![]; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let config_file = solana_cli_config::CONFIG_FILE + .as_ref() + .ok_or_else(|| eyre::eyre!("Missing config file"))?; + let cli_config = solana_cli_config::Config::load(config_file)?; + let signer_context = clap::ArgMatches::default(); // Dummy context + let signer = signer_from_path( + &signer_context, + &cli_config.keypair_path, + "signer", + &mut None, + ) + .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; + + // The gateway doesn't support Ed25519 signatures, thus, we generate a Secp256k1 keypair + // using the existing Ed25519 pubkey as seed. This is done only because this is for + // testing and we want to avoid requiring another external keypair. + let (sk, pk) = secp256k1_keypair_from_seed(signer.pubkey().as_ref()); + let signer = TestSigner { + inner: sk, + weight: 1_u128, + }; + + let domain_separator = { + let maybe_domain_separator = String::deserialize( + &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] + [ChainNameOnAxelar::from(config.network_type).0][DOMAIN_SEPARATOR_KEY], + ) + .ok(); + + let mut domain_separator_bytes = [0_u8; 32]; + if let Some(domain_separator) = maybe_domain_separator { + hex::decode_to_slice(domain_separator, &mut domain_separator_bytes)?; + } + + domain_separator_bytes + }; + + let payload_bytes = hex::decode( + approve_args + .payload + .strip_prefix("0x") + .unwrap_or(&approve_args.payload), + )?; + let payload_hash = solana_sdk::hash::hashv(&[&payload_bytes]).to_bytes(); + let signers_set = SigningVerifierSet::new(vec![signer], 0); + let message = Message { + cc_id: CrossChainId { + chain: approve_args.source_chain, + id: approve_args.message_id, + }, + source_address: approve_args.source_address, + destination_chain: ChainNameOnAxelar::from(config.network_type).0, + destination_address: approve_args.destination_address, + payload_hash, + }; + + let gmp_payload = Payload::Messages(Messages(vec![message])); + let message_hash = hash_payload( + &domain_separator, + &signers_set.verifier_set(), + gmp_payload.clone(), + )?; + + let message = libsecp256k1::Message::parse(&message_hash); + let (signature, recovery_id) = libsecp256k1::sign(&message, &sk); + let mut signature_bytes = signature.serialize().to_vec(); + signature_bytes.push(recovery_id.serialize()); + let signatures = { + BTreeMap::from([( + PublicKey::Secp256k1(pk.serialize_compressed()), + Signature::EcdsaRecoverable( + signature_bytes + .try_into() + .map_err(|e| eyre::eyre!("Invalid signature"))?, + ), + )]) + }; + let execute_data_bytes = axelar_solana_encoding::encode( + &signers_set.verifier_set(), + &signatures, + domain_separator, + gmp_payload, + )?; + + let execute_data: ExecuteData = borsh::from_slice(&execute_data_bytes)?; + let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; + + instructions.push( + axelar_solana_gateway::instructions::initialize_payload_verification_session( + *fee_payer, + gateway_config_pda, + execute_data.payload_merkle_root, + )?, + ); + + let (verifier_set_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda( + execute_data.signing_verifier_set_merkle_root, + ); + + for signature_leaf in &execute_data.signing_verifier_set_leaves { + instructions.push(axelar_solana_gateway::instructions::verify_signature( + gateway_config_pda, + verifier_set_tracker_pda, + execute_data.payload_merkle_root, + signature_leaf.clone(), + )?); + } + + let (verification_session_pda, _bump) = axelar_solana_gateway::get_signature_verification_pda( + &gateway_config_pda, + &execute_data.payload_merkle_root, + ); + + let MerkleisedPayload::NewMessages { mut messages } = execute_data.payload_items else { + eyre::bail!("Expected Messages payload"); + }; + + let Some(merkleised_message) = messages.pop() else { + eyre::bail!("No messages in the batch"); + }; + + let command_id = command_id( + &merkleised_message.leaf.message.cc_id.chain, + &merkleised_message.leaf.message.cc_id.id, + ); + + let (incoming_message_pda, _bump) = + axelar_solana_gateway::get_incoming_message_pda(&command_id); + + instructions.push(axelar_solana_gateway::instructions::approve_message( + merkleised_message, + execute_data.payload_merkle_root, + gateway_config_pda, *fee_payer, - transfer_operatorship_args.authority, - transfer_operatorship_args.new_operator, - )?) + verification_session_pda, + incoming_message_pda, + )?); + + Ok(instructions) } + +//async fn rotate(fee_payer: &Pubkey, rotate_args: RotateArgs) -> eyre::Result> { +// todo!() +//} diff --git a/solana/cli/src/generate.rs b/solana/cli/src/generate.rs index 02dca389d..ae0f622f5 100644 --- a/solana/cli/src/generate.rs +++ b/solana/cli/src/generate.rs @@ -74,7 +74,7 @@ fn fetch_nonce_data_and_verify( pub fn generate_unsigned_solana_transaction( args: &GenerateArgs, config: &Config, - instruction: SolanaInstruction, + mut instructions: Vec, ) -> Result<()> { println!("Starting unsigned Solana transaction generation..."); println!("Network Type: {:?}", config.network_type); @@ -113,7 +113,7 @@ pub fn generate_unsigned_solana_transaction( println!("Prepending AdvanceNonceAccount instruction."); sdk_instructions = vec![advance_nonce_ix]; - sdk_instructions.push(instruction); + sdk_instructions.append(&mut instructions); } (None, None) => { println!("Using latest blockhash flow."); @@ -123,7 +123,7 @@ pub fn generate_unsigned_solana_transaction( }; println!("Using Recent Blockhash: {}", blockhash_for_message); params.recent_blockhash = Some(blockhash_for_message.to_string()); - sdk_instructions = vec![instruction]; + sdk_instructions = instructions; } _ => { return Err(AppError::InconsistentState( diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs index 0806e5be3..7439b7469 100644 --- a/solana/cli/src/governance.rs +++ b/solana/cli/src/governance.rs @@ -101,7 +101,7 @@ pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let (config_pda, _) = axelar_solana_governance::state::GovernanceConfig::pda(); match command { @@ -118,7 +118,7 @@ async fn init( init_args: InitArgs, config: &Config, config_pda: &Pubkey, -) -> eyre::Result { +) -> eyre::Result> { let chain_hash = solana_sdk::keccak::hashv(&[init_args.governance_chain.as_bytes()]).0; let address_hash = solana_sdk::keccak::hashv(&[init_args.governance_address.as_bytes()]).0; @@ -142,16 +142,16 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(IxBuilder::new() + Ok(vec![IxBuilder::new() .initialize_config(fee_payer, config_pda, governance_config) - .build()) + .build()]) } async fn execute_proposal( fee_payer: &Pubkey, args: ExecuteProposalArgs, config_pda: &Pubkey, -) -> eyre::Result { +) -> eyre::Result> { let calldata_bytes = base64::engine::general_purpose::STANDARD.decode(args.base.calldata)?; let native_value_receiver_account = args .base @@ -171,14 +171,16 @@ async fn execute_proposal( calldata_bytes, ); - Ok(builder.execute_proposal(fee_payer, config_pda).build()) + Ok(vec![builder + .execute_proposal(fee_payer, config_pda) + .build()]) } async fn execute_operator_proposal( fee_payer: &Pubkey, args: ExecuteOperatorProposalArgs, config_pda: &Pubkey, -) -> eyre::Result { +) -> eyre::Result> { let calldata_bytes = base64::engine::general_purpose::STANDARD.decode(args.base.calldata)?; let native_value_receiver_account = args .base @@ -195,7 +197,7 @@ async fn execute_operator_proposal( calldata_bytes, ); - Ok(builder + Ok(vec![builder .execute_operator_proposal(fee_payer, config_pda, &args.operator) - .build()) + .build()]) } diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index 0731d8f58..f9f7096ce 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -573,7 +573,7 @@ pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await, Commands::Pause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: true }).await, @@ -661,7 +661,7 @@ async fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; let its_hub_address = String::deserialize(&chains_info[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY])?; @@ -680,50 +680,50 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(axelar_solana_its::instruction::initialize( + Ok(vec![axelar_solana_its::instruction::initialize( *fee_payer, axelar_solana_gateway::get_gateway_root_config_pda().0, init_args.operator, ChainNameOnAxelar::from(config.network_type).0, its_hub_address, - )?) + )?]) } async fn set_pause_status( fee_payer: &Pubkey, set_pause_args: SetPauseStatusArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::set_pause_status( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::set_pause_status( *fee_payer, set_pause_args.paused, - )?) + )?]) } async fn set_trusted_chain( fee_payer: &Pubkey, set_trusted_chain_args: TrustedChainArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::set_trusted_chain( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::set_trusted_chain( *fee_payer, set_trusted_chain_args.chain_name, - )?) + )?]) } async fn remove_trusted_chain( fee_payer: &Pubkey, remove_trusted_chain_args: TrustedChainArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::remove_trusted_chain( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::remove_trusted_chain( *fee_payer, remove_trusted_chain_args.chain_name, - )?) + )?]) } async fn approve_deploy_remote_interchain_token( fee_payer: &Pubkey, args: ApproveDeployRemoteInterchainTokenArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; let destination_minter = encode_its_destination( &chains_info, @@ -731,7 +731,7 @@ async fn approve_deploy_remote_interchain_token( args.destination_minter, )?; - Ok( + Ok(vec![ axelar_solana_its::instruction::approve_deploy_remote_interchain_token( *fee_payer, args.deployer, @@ -739,47 +739,47 @@ async fn approve_deploy_remote_interchain_token( args.destination_chain, destination_minter, )?, - ) + ]) } async fn revoke_deploy_remote_interchain_token( fee_payer: &Pubkey, args: RevokeDeployRemoteInterchainTokenArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::revoke_deploy_remote_interchain_token( *fee_payer, args.deployer, args.salt, args.destination_chain, )?, - ) + ]) } async fn register_canonical_interchain_token( fee_payer: &Pubkey, args: RegisterCanonicalInterchainTokenArgs, -) -> eyre::Result { +) -> eyre::Result> { let token_id = axelar_solana_its::canonical_interchain_token_id(&args.mint); println!("Token ID: {}", hex::encode(token_id)); - Ok( + Ok(vec![ axelar_solana_its::instruction::register_canonical_interchain_token( *fee_payer, args.mint, args.token_program, )?, - ) + ]) } async fn deploy_remote_canonical_interchain_token( fee_payer: &Pubkey, args: DeployRemoteCanonicalInterchainTokenArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; - Ok( + Ok(vec![ axelar_solana_its::instruction::deploy_remote_canonical_interchain_token( *fee_payer, args.mint, @@ -788,35 +788,37 @@ async fn deploy_remote_canonical_interchain_token( gas_service, gas_config_account, )?, - ) + ]) } async fn deploy_interchain_token( fee_payer: &Pubkey, args: DeployInterchainTokenArgs, -) -> eyre::Result { +) -> eyre::Result> { let token_id = axelar_solana_its::interchain_token_id(fee_payer, &args.salt); println!("Token ID: {}", hex::encode(token_id)); - Ok(axelar_solana_its::instruction::deploy_interchain_token( - *fee_payer, - args.salt, - args.name, - args.symbol, - args.decimals, - args.initial_supply, - args.minter, - )?) + Ok(vec![ + axelar_solana_its::instruction::deploy_interchain_token( + *fee_payer, + args.salt, + args.name, + args.symbol, + args.decimals, + args.initial_supply, + args.minter, + )?, + ]) } async fn deploy_remote_interchain_token( fee_payer: &Pubkey, args: DeployRemoteInterchainTokenArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; - Ok( + Ok(vec![ axelar_solana_its::instruction::deploy_remote_interchain_token( *fee_payer, args.salt, @@ -825,14 +827,14 @@ async fn deploy_remote_interchain_token( gas_service, gas_config_account, )?, - ) + ]) } async fn deploy_remote_interchain_token_with_minter( fee_payer: &Pubkey, args: DeployRemoteInterchainTokenWithMinterArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; @@ -841,7 +843,7 @@ async fn deploy_remote_interchain_token_with_minter( &args.destination_chain, args.destination_minter, )?; - Ok( + Ok(vec![ axelar_solana_its::instruction::deploy_remote_interchain_token_with_minter( *fee_payer, args.salt, @@ -852,52 +854,54 @@ async fn deploy_remote_interchain_token_with_minter( gas_service, gas_config_account, )?, - ) + ]) } async fn register_token_metadata( fee_payer: &Pubkey, args: RegisterTokenMetadataArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; - Ok(axelar_solana_its::instruction::register_token_metadata( - *fee_payer, - args.mint, - args.token_program, - args.gas_value, - gas_service, - gas_config_account, - )?) + Ok(vec![ + axelar_solana_its::instruction::register_token_metadata( + *fee_payer, + args.mint, + args.token_program, + args.gas_value, + gas_service, + gas_config_account, + )?, + ]) } async fn register_custom_token( fee_payer: &Pubkey, args: RegisterCustomTokenArgs, -) -> eyre::Result { +) -> eyre::Result> { let token_id = axelar_solana_its::linked_token_id(fee_payer, &args.salt); println!("Token ID: {}", hex::encode(token_id)); - Ok(axelar_solana_its::instruction::register_custom_token( + Ok(vec![axelar_solana_its::instruction::register_custom_token( *fee_payer, args.salt, args.mint, args.token_manager_type, args.token_program, args.operator, - )?) + )?]) } async fn link_token( fee_payer: &Pubkey, args: LinkTokenArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; - Ok(axelar_solana_its::instruction::link_token( + Ok(vec![axelar_solana_its::instruction::link_token( *fee_payer, args.salt, args.destination_chain, @@ -907,14 +911,14 @@ async fn link_token( args.gas_value, gas_service, gas_config_account, - )?) + )?]) } async fn interchain_transfer( fee_payer: &Pubkey, args: InterchainTransferArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let timestamp: i64 = SystemTime::now() @@ -929,7 +933,7 @@ async fn interchain_transfer( args.destination_address, )?; - Ok(axelar_solana_its::instruction::interchain_transfer( + Ok(vec![axelar_solana_its::instruction::interchain_transfer( *fee_payer, args.source_account, args.authority, @@ -943,14 +947,14 @@ async fn interchain_transfer( gas_service, gas_config_account, timestamp, - )?) + )?]) } async fn call_contract_with_interchain_token( fee_payer: &Pubkey, args: CallContractWithInterchainTokenArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let timestamp: i64 = SystemTime::now() @@ -963,7 +967,7 @@ async fn call_contract_with_interchain_token( &args.destination_chain, args.destination_address, )?; - Ok( + Ok(vec![ axelar_solana_its::instruction::call_contract_with_interchain_token( *fee_payer, args.source_account, @@ -980,14 +984,14 @@ async fn call_contract_with_interchain_token( gas_config_account, timestamp, )?, - ) + ]) } async fn call_contract_with_interchain_token_offchain_data( fee_payer: &Pubkey, args: CallContractWithInterchainTokenOffchainDataArgs, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let timestamp: i64 = SystemTime::now() @@ -1022,185 +1026,190 @@ async fn call_contract_with_interchain_token_offchain_data( let mut file = File::create(config.output_dir.join("offchain_data_payload.bin"))?; file.write(&payload)?; - Ok(instruction) + Ok(vec![instruction]) } -async fn set_flow_limit(fee_payer: &Pubkey, args: SetFlowLimitArgs) -> eyre::Result { - Ok(axelar_solana_its::instruction::set_flow_limit( +async fn set_flow_limit( + fee_payer: &Pubkey, + args: SetFlowLimitArgs, +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::set_flow_limit( *fee_payer, args.token_id, args.flow_limit, - )?) + )?]) } async fn transfer_operatorship( fee_payer: &Pubkey, args: TransferOperatorshipArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::transfer_operatorship( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::transfer_operatorship( *fee_payer, args.to, - )?) + )?]) } async fn propose_operatorship( fee_payer: &Pubkey, args: TransferOperatorshipArgs, // Reuses args from transfer -) -> eyre::Result { - Ok(axelar_solana_its::instruction::propose_operatorship( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::propose_operatorship( *fee_payer, args.to, - )?) + )?]) } async fn accept_operatorship( fee_payer: &Pubkey, args: AcceptOperatorshipArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::accept_operatorship( +) -> eyre::Result> { + Ok(vec![axelar_solana_its::instruction::accept_operatorship( *fee_payer, args.from, - )?) + )?]) } async fn token_manager_set_flow_limit( fee_payer: &Pubkey, args: TokenManagerSetFlowLimitArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::set_flow_limit( *fee_payer, args.token_id, args.flow_limit, )?, - ) + ]) } async fn token_manager_add_flow_limiter( fee_payer: &Pubkey, args: TokenManagerAddFlowLimiterArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::add_flow_limiter( *fee_payer, args.token_id, args.flow_limiter, )?, - ) + ]) } async fn token_manager_remove_flow_limiter( fee_payer: &Pubkey, args: TokenManagerRemoveFlowLimiterArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::remove_flow_limiter( *fee_payer, args.token_id, args.flow_limiter, )?, - ) + ]) } async fn token_manager_transfer_operatorship( fee_payer: &Pubkey, args: TokenManagerTransferOperatorshipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::transfer_operatorship( *fee_payer, args.token_id, args.to, )?, - ) + ]) } async fn token_manager_propose_operatorship( fee_payer: &Pubkey, args: TokenManagerProposeOperatorshipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::propose_operatorship( *fee_payer, args.token_id, args.to, )?, - ) + ]) } async fn token_manager_accept_operatorship( fee_payer: &Pubkey, args: TokenManagerAcceptOperatorshipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::accept_operatorship( *fee_payer, args.token_id, args.from, )?, - ) + ]) } async fn token_manager_handover_mint_authority( fee_payer: &Pubkey, args: TokenManagerHandoverMintAuthorityArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::token_manager::handover_mint_authority( *fee_payer, args.token_id, args.mint, args.token_program, )?, - ) + ]) } async fn interchain_token_mint( fee_payer: &Pubkey, args: InterchainTokenMintArgs, -) -> eyre::Result { - Ok(axelar_solana_its::instruction::interchain_token::mint( - args.token_id, // Note: payer is not the first argument here - args.mint, - args.to, - *fee_payer, // Payer is the minter in this context - args.token_program, - args.amount, - )?) +) -> eyre::Result> { + Ok(vec![ + axelar_solana_its::instruction::interchain_token::mint( + args.token_id, // Note: payer is not the first argument here + args.mint, + args.to, + *fee_payer, // Payer is the minter in this context + args.token_program, + args.amount, + )?, + ]) } async fn interchain_token_transfer_mintership( fee_payer: &Pubkey, args: InterchainTokenTransferMintershipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::interchain_token::transfer_mintership( *fee_payer, args.token_id, args.to, )?, - ) + ]) } async fn interchain_token_propose_mintership( fee_payer: &Pubkey, args: InterchainTokenProposeMintershipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::interchain_token::propose_mintership( *fee_payer, args.token_id, args.to, )?, - ) + ]) } async fn interchain_token_accept_mintership( fee_payer: &Pubkey, args: InterchainTokenAcceptMintershipArgs, -) -> eyre::Result { - Ok( +) -> eyre::Result> { + Ok(vec![ axelar_solana_its::instruction::interchain_token::accept_mintership( *fee_payer, args.token_id, args.from, )?, - ) + ]) } diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 3ad8b876b..a27f69981 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -15,6 +15,7 @@ mod utils; use clap::{ArgGroup, Parser, Subcommand}; use send::build_and_send_solana_transaction; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; +use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use std::path::PathBuf; @@ -101,10 +102,12 @@ enum Command { #[derive(Parser, Debug)] struct SendCommandArgs { - /// Fee Payer Pubkey (Base58 encoded string) + /// Fee Payer Pubkey (Base58 encoded string). Loads from Solana CLI config if not passed. #[clap(long)] - fee_payer: Pubkey, + fee_payer: Option, + /// List of signers (Base58 encoded strings). Fee payer should also be added here in case it's + /// not the default from Solana CLI config. #[clap(long, help = "List of signers (Base58 encoded strings)")] signer_keys: Vec, @@ -215,9 +218,30 @@ async fn run() -> eyre::Result<()> { // Proceed with building and potentially sending/signing/broadcasting a Solana transaction match cli.command { Command::Send(args) => { + let mut signer_keys = args.signer_keys; + let fee_payer = match args.fee_payer { + Some(fee_payer) => fee_payer, + None => { + let config_file = solana_cli_config::CONFIG_FILE + .as_ref() + .ok_or_else(|| eyre::eyre!("Missing config file"))?; + let cli_config = solana_cli_config::Config::load(config_file)?; + let signer_context = clap::ArgMatches::default(); // Dummy context + let signer = signer_from_path( + &signer_context, + &cli_config.keypair_path, + "signer", + &mut None, + ) + .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; + + signer_keys.push(cli_config.keypair_path); + signer.pubkey() + } + }; let send_args = SendArgs { - fee_payer: args.fee_payer, - signers: args.signer_keys, + fee_payer, + signers: signer_keys, }; let instruction = build_instruction(&send_args.fee_payer, args.instruction, &config).await?; @@ -266,7 +290,7 @@ async fn build_instruction( fee_payer: &Pubkey, instruction: InstructionSubcommand, config: &Config, -) -> eyre::Result { +) -> eyre::Result> { let serializable_ix = match instruction { InstructionSubcommand::Gateway(command) => { gateway::build_instruction(fee_payer, command, config).await? diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs index 216193a2f..42e133b18 100644 --- a/solana/cli/src/send.rs +++ b/solana/cli/src/send.rs @@ -13,10 +13,10 @@ use crate::utils::print_transaction_result; pub(crate) fn build_and_send_solana_transaction( send_args: &SendArgs, config: &Config, - instruction: Instruction, + instructions: Vec, ) -> Result<()> { let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); - let message = Message::new(&[instruction], Some(&send_args.fee_payer)); + let message = Message::new(&instructions, Some(&send_args.fee_payer)); let mut transaction = Transaction::new_unsigned(message); if send_args.signers.len() < transaction.signatures.len() { diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 4bc6a182e..86333f4ad 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -1,3 +1,5 @@ +use axelar_solana_encoding::types::pubkey::PublicKey; +use axelar_solana_encoding::types::verifier_set::VerifierSet; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; @@ -212,3 +214,68 @@ pub(crate) fn print_transaction_result(config: &Config, result: Result, + /// the nonce for the verifier set + pub nonce: u64, + /// quorum for the verifier set + pub quorum: u128, +} + +impl SigningVerifierSet { + /// Create a new `SigningVerifierSet` + /// + /// # Panics + /// if the calculated quorum is larger than u128 + pub fn new(signers: Vec, nonce: u64) -> Self { + let quorum = signers + .iter() + .map(|signer| signer.weight) + .try_fold(0, u128::checked_add) + .expect("no arithmetic overflow"); + Self::new_with_quorum(signers, nonce, quorum) + } + + /// Create a new `SigningVerifierSet` with a custom quorum + #[must_use] + pub const fn new_with_quorum(signers: Vec, nonce: u64, quorum: u128) -> Self { + Self { + signers, + nonce, + quorum, + } + } + + /// Transform into the verifier set that the gateway expects to operate on + #[must_use] + pub fn verifier_set(&self) -> VerifierSet { + let signers = self + .signers + .iter() + .map(|x| { + let pubkey = libsecp256k1::PublicKey::from_secret_key(&x.inner); + ( + PublicKey::Secp256k1(pubkey.serialize_compressed()), + x.weight, + ) + }) + .collect(); + VerifierSet { + nonce: self.nonce, + signers, + quorum: self.quorum, + } + } +} + +/// Single test signer +#[derive(Clone, Debug)] +pub struct TestSigner { + pub inner: libsecp256k1::SecretKey, + /// associated weight + pub weight: u128, +} From ac2cc1386a7ac576f32e6584bdf8c20563be467a Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 7 May 2025 12:13:48 +0200 Subject: [PATCH 21/59] refactor(solana): make implementation closer existing ones Since we can use the approve for devnet and testnet as well, let's not generate temporary keys and instead accept the signer(s) through the CLI. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gateway.rs | 112 ++++++++++++++++---------------------- solana/cli/src/types.rs | 32 +++++++++++ 2 files changed, 78 insertions(+), 66 deletions(-) diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 46b05f95c..166b40b88 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -10,16 +10,15 @@ use axelar_solana_encoding::types::pubkey::{PublicKey, Signature}; use axelar_solana_encoding::types::verifier_set::VerifierSet; use axelar_solana_gateway::state::config::RotationDelaySecs; use axelar_solana_gateway::state::incoming_message::command_id; -use clap::{Parser, Subcommand}; +use clap::{ArgGroup, Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; use serde::Deserialize; use serde_json::json; -use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; -use crate::types::ChainNameOnAxelar; +use crate::types::{ChainNameOnAxelar, SerializeableVerifierSet}; use crate::utils::{ read_json_file_from_path, write_json_to_file_path, SigningVerifierSet, TestSigner, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, @@ -43,6 +42,7 @@ pub(crate) enum Commands { } #[derive(Parser, Debug)] +#[clap(group(ArgGroup::new("signers_source").args(&["signer", "signer-set"]).multiple(false).requires("nonce").required(false)))] pub(crate) struct InitArgs { #[clap(short = 'r', long)] previous_signers_retention: u128, @@ -50,10 +50,17 @@ pub(crate) struct InitArgs { #[clap(short, long)] minimum_rotation_delay: RotationDelaySecs, - /// Instead of querying the MultisigProver for the SignerSet, uses a local SignerSet created - /// with the default signer as set in the Solana CLI config. For testing purposes only. + /// Hex string with secp256k1 compressed public key + #[clap(long)] + signer: Option, + + /// Nonce to be used for the SignerSet, required if `signer` or `signers` is set. #[clap(short, long)] - local_signer: bool, + nonce: u64, + + /// A JSON containing a SignerSet + #[clap(long)] + signer_set: Option, #[clap(long)] operator: Pubkey, @@ -90,6 +97,10 @@ pub(crate) struct TransferOperatorshipArgs { #[derive(Parser, Debug)] pub(crate) struct ApproveArgs { + /// Hex string with secp256k1 private key of the signer used to generate the proof + #[clap(long)] + signer: String, + #[clap(long)] source_chain: String, @@ -149,53 +160,29 @@ async fn query( Ok(result) } -fn secp256k1_keypair_from_seed(seed: &[u8]) -> (libsecp256k1::SecretKey, libsecp256k1::PublicKey) { - let mut digest = solana_sdk::keccak::hashv(&[seed]).0; - - loop { - match libsecp256k1::SecretKey::parse_slice(&digest) { - // 1 ≤ sk < n ? - Ok(sk) => { - let pk = libsecp256k1::PublicKey::from_secret_key(&sk); - return (sk, pk); - } - Err(_) => digest = solana_sdk::keccak::hashv(&[&digest]).0, - } - } -} - -async fn get_weighted_signers( - local_signer: bool, +async fn get_verifier_set( + init_args: &InitArgs, config: &Config, chains_info: &serde_json::Value, ) -> eyre::Result { - if local_signer { - let config_file = solana_cli_config::CONFIG_FILE - .as_ref() - .ok_or_else(|| eyre::eyre!("Missing config file"))?; - let cli_config = solana_cli_config::Config::load(config_file)?; - let signer_context = clap::ArgMatches::default(); // Dummy context - let signer = signer_from_path( - &signer_context, - &cli_config.keypair_path, - "signer", - &mut None, - ) - .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; - - // The gateway doesn't support Ed25519 signatures, thus, we generate a Secp256k1 keypair - // using the existing Ed25519 pubkey as seed. This is done only because this is for - // testing and we want to avoid requiring another external keypair. - let (_sk, pk) = secp256k1_keypair_from_seed(signer.pubkey().as_ref()); - + if let Some(signer_key) = &init_args.signer { + let key_bytes: [u8; 33] = hex::decode(signer_key.strip_prefix("0x").unwrap_or(signer_key)) + .map_err(|_| eyre::eyre!("Failed to decode hex"))? + .try_into() + .map_err(|_| eyre::eyre!("Invalid signer pubkey"))?; + let pk = libsecp256k1::PublicKey::parse_compressed(&key_bytes)?; let pubkey = PublicKey::Secp256k1(pk.serialize_compressed()); let signers = BTreeMap::from([(pubkey, 1_u128)]); Ok(VerifierSet { - nonce: 0, + nonce: init_args.nonce, signers, quorum: 1_u128, }) + } else if let Some(signer_set) = &init_args.signer_set { + let signer_set: SerializeableVerifierSet = serde_json::from_str(signer_set)?; + + Ok(signer_set.into()) } else { let multisig_prover_address = { let address = String::deserialize( @@ -234,12 +221,11 @@ async fn init( init_args: InitArgs, config: &Config, ) -> eyre::Result> { - println!("gateway id: {:?}", axelar_solana_gateway::id()); let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file).unwrap_or_default(); let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); - let verifier_set = get_weighted_signers(init_args.local_signer, config, &chains_info).await?; + let verifier_set = get_verifier_set(&init_args, config, &chains_info).await?; let domain_separator = { let maybe_domain_separator = if init_args.domain_separator.is_none() { String::deserialize( @@ -334,23 +320,17 @@ async fn approve( ) -> eyre::Result> { let mut instructions = vec![]; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let config_file = solana_cli_config::CONFIG_FILE - .as_ref() - .ok_or_else(|| eyre::eyre!("Missing config file"))?; - let cli_config = solana_cli_config::Config::load(config_file)?; - let signer_context = clap::ArgMatches::default(); // Dummy context - let signer = signer_from_path( - &signer_context, - &cli_config.keypair_path, - "signer", - &mut None, - ) - .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; - - // The gateway doesn't support Ed25519 signatures, thus, we generate a Secp256k1 keypair - // using the existing Ed25519 pubkey as seed. This is done only because this is for - // testing and we want to avoid requiring another external keypair. - let (sk, pk) = secp256k1_keypair_from_seed(signer.pubkey().as_ref()); + let secret_bytes: [u8; 32] = hex::decode( + approve_args + .signer + .strip_prefix("0x") + .unwrap_or(&approve_args.signer), + )? + .try_into() + .map_err(|_err| eyre::eyre!("Invalid signer key"))?; + let sk = libsecp256k1::SecretKey::parse(&secret_bytes)?; + let pk = libsecp256k1::PublicKey::from_secret_key(&sk); + let signer = TestSigner { inner: sk, weight: 1_u128, @@ -407,7 +387,7 @@ async fn approve( Signature::EcdsaRecoverable( signature_bytes .try_into() - .map_err(|e| eyre::eyre!("Invalid signature"))?, + .map_err(|_e| eyre::eyre!("Invalid signature"))?, ), )]) }; @@ -475,6 +455,6 @@ async fn approve( Ok(instructions) } -//async fn rotate(fee_payer: &Pubkey, rotate_args: RotateArgs) -> eyre::Result> { -// todo!() -//} +async fn rotate(fee_payer: &Pubkey, rotate_args: RotateArgs) -> eyre::Result> { + todo!() +} diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index daaaa19e7..53fa143ca 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -1,7 +1,10 @@ use crate::error::{AppError, Result}; +use axelar_solana_encoding::types::pubkey::PublicKey; +use axelar_solana_encoding::types::verifier_set::VerifierSet; use clap::ArgEnum; use serde::{Deserialize, Serialize}; use solana_sdk::{instruction::Instruction as SolanaInstruction, pubkey::Pubkey}; +use std::collections::BTreeMap; use std::path::PathBuf; use std::str::FromStr; @@ -179,3 +182,32 @@ pub struct CombineArgs { pub struct BroadcastArgs { pub signed_tx_path: PathBuf, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SerializeableVerifierSet { + pub signers: BTreeMap, + pub nonce: u64, + pub threshold: u128, +} + +impl From for VerifierSet { + fn from(value: SerializeableVerifierSet) -> Self { + let signers: BTreeMap = value + .signers + .iter() + .map(|(pk_str, weight)| { + let pk_bytes: [u8; 33] = hex::decode(pk_str) + .expect("Failed to decode public key") + .try_into() + .expect("Invalid public key length"); + (PublicKey::Secp256k1(pk_bytes), *weight) + }) + .collect(); + + Self { + signers, + nonce: value.nonce, + quorum: value.threshold, + } + } +} From 4c4243fba91c7c4b3758c8ce39442b9d9ee0ad8c Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 7 May 2025 17:28:03 +0200 Subject: [PATCH 22/59] feat(solana): rotate signers Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 77 +++----- solana/cli/Cargo.toml | 11 +- solana/cli/src/gateway.rs | 368 +++++++++++++++++++++++--------------- solana/cli/src/types.rs | 85 ++++++++- solana/cli/src/utils.rs | 134 +++++++------- 5 files changed, 396 insertions(+), 279 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index f52290fe1..dec7dbe4d 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -684,7 +684,7 @@ dependencies = [ "event-utils", "hex", "itertools 0.12.1", - "libsecp256k1 0.6.0", + "libsecp256k1", "num-derive 0.4.2", "num-traits", "program-utils", @@ -1412,7 +1412,7 @@ dependencies = [ "flate2", "governance-gmp", "hex", - "libsecp256k1 0.7.2", + "k256", "multisig-prover", "program-utils", "rand 0.9.1", @@ -2039,6 +2039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -2351,6 +2352,7 @@ dependencies = [ "ff", "generic-array", "group", + "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -3886,34 +3888,15 @@ dependencies = [ "base64 0.12.3", "digest 0.9.0", "hmac-drbg", - "libsecp256k1-core 0.2.2", - "libsecp256k1-gen-ecmult 0.2.1", - "libsecp256k1-gen-genmult 0.2.1", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", "rand 0.7.3", "serde", "sha2 0.9.9", "typenum", ] -[[package]] -name = "libsecp256k1" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" -dependencies = [ - "arrayref", - "base64 0.22.1", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core 0.3.0", - "libsecp256k1-gen-ecmult 0.3.0", - "libsecp256k1-gen-genmult 0.3.0", - "rand 0.8.5", - "serde", - "sha2 0.9.9", - "typenum", -] - [[package]] name = "libsecp256k1-core" version = "0.2.2" @@ -3925,33 +3908,13 @@ dependencies = [ "subtle", ] -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - [[package]] name = "libsecp256k1-gen-ecmult" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" dependencies = [ - "libsecp256k1-core 0.2.2", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core 0.3.0", + "libsecp256k1-core", ] [[package]] @@ -3960,16 +3923,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" dependencies = [ - "libsecp256k1-core 0.2.2", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core 0.3.0", + "libsecp256k1-core", ] [[package]] @@ -4630,6 +4584,15 @@ dependencies = [ "base64 0.13.1", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -7823,7 +7786,7 @@ checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" dependencies = [ "bincode 1.3.3", "digest 0.10.7", - "libsecp256k1 0.6.0", + "libsecp256k1", "serde", "serde_derive", "sha3", @@ -7840,7 +7803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ "borsh 1.5.7", - "libsecp256k1 0.6.0", + "libsecp256k1", "solana-define-syscall", "thiserror 2.0.12", ] diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index b6963e1d4..edc98055a 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -29,8 +29,10 @@ multisig-prover = { git = "https://github.com/eigerco/axelar-amplifier.git", rev "library", ] } +# libsecp256k1 = "0.7.2" alloy-sol-types = "0.7.6" anyhow = "1.0.98" +base64 = "0.22.1" bincode = { version = "2.0.1", features = ["serde"] } borsh = "1.5.1" bs58 = "0.5.1" @@ -41,6 +43,7 @@ cosmwasm-std = "1.5" eyre = "0.6.12" flate2 = { version = "1.1.1", default-features = false, features = ["zlib"] } hex = { version = "0.4.3", features = ["serde"] } +k256 = { version = "0.13", features = ["pkcs8", "pem", "ecdsa"] } rand = "0.9.1" reqwest = { version = "0.12", features = ["json", "stream"] } rust_decimal = "1.37.1" @@ -51,12 +54,10 @@ solana-clap-v3-utils = "2.2.7" solana-cli-config = "2.2.7" solana-client = "2.2.7" solana-sdk = "2.2.2" +spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } +spl-token = { version = "8.0.0", features = ["no-entrypoint"] } +spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } tar = "0.4.44" thiserror = "2.0.12" tokio = { version = "1", features = ["full"] } walkdir = "2.5.0" -spl-token = { version = "8.0.0", features = ["no-entrypoint"] } -spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } -spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } -base64 = "0.22.1" -libsecp256k1 = "0.7.2" diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 166b40b88..185d3f143 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -12,15 +12,17 @@ use axelar_solana_gateway::state::config::RotationDelaySecs; use axelar_solana_gateway::state::incoming_message::command_id; use clap::{ArgGroup, Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; +use k256::ecdsa::SigningKey; +use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::Deserialize; use serde_json::json; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; -use crate::types::{ChainNameOnAxelar, SerializeableVerifierSet}; +use crate::types::{ChainNameOnAxelar, LocalSigner, SerializeableVerifierSet, SigningVerifierSet}; use crate::utils::{ - read_json_file_from_path, write_json_to_file_path, SigningVerifierSet, TestSigner, ADDRESS_KEY, + self, domain_separator, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, @@ -39,6 +41,9 @@ pub(crate) enum Commands { #[clap(long_about = "Approve a message for test deployment")] Approve(ApproveArgs), + + #[clap(long_about = "Rotate the signers used by the Gateway program for message verification")] + Rotate(RotateArgs), } #[derive(Parser, Debug)] @@ -47,16 +52,16 @@ pub(crate) struct InitArgs { #[clap(short = 'r', long)] previous_signers_retention: u128, - #[clap(short, long)] + #[clap(long)] minimum_rotation_delay: RotationDelaySecs, - /// Hex string with secp256k1 compressed public key + /// Hex string with secp256k1 compressed public key used to create the initial SignerSet #[clap(long)] signer: Option, /// Nonce to be used for the SignerSet, required if `signer` or `signers` is set. - #[clap(short, long)] - nonce: u64, + #[clap(long)] + nonce: Option, /// A JSON containing a SignerSet #[clap(long)] @@ -64,12 +69,6 @@ pub(crate) struct InitArgs { #[clap(long)] operator: Pubkey, - - /// Domain separator associated with the chain. - /// In case no value is passed, tries to load from MultisigProver entry for the chain. If that fails, defaults to 0x0 if not set (which is fine for - /// local tests). - #[clap(short, long)] - domain_separator: Option, } #[derive(Parser, Debug)] @@ -80,43 +79,70 @@ pub(crate) struct CallContractArgs { #[clap(short = 'a', long)] destination_contract_address: String, - #[clap(short, long)] + #[clap(long)] payload: String, } #[derive(Parser, Debug)] pub(crate) struct TransferOperatorshipArgs { /// Current operator OR upgrade authority - #[clap(short, long)] + #[clap(long)] authority: Pubkey, /// Address of the new operator - #[clap(short, long)] + #[clap(long)] new_operator: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct ApproveArgs { /// Hex string with secp256k1 private key of the signer used to generate the proof + #[clap(long, value_parser=utils::parse_secret_key, value_hint=clap::ValueHint::AnyPath)] + signer: k256::SecretKey, + + /// Nonce associated with the SignerSet the signer is part of #[clap(long)] - signer: String, + nonce: u64, #[clap(long)] source_chain: String, - #[clap(short, long)] + #[clap(long)] message_id: String, - #[clap(short, long)] + #[clap(long)] source_address: String, - #[clap(short, long)] + #[clap(long)] destination_address: String, - #[clap(short, long)] + #[clap(long)] payload: String, } +#[derive(Parser, Debug)] +#[clap(group(ArgGroup::new("signers_source").args(&["new-signer", "new-signer-set"]).multiple(false).requires("nonce").required(false)))] +pub(crate) struct RotateArgs { + /// Hex string with secp256k1 private key of the signer used to generate the proof + #[clap(long, value_parser=utils::parse_secret_key, value_hint=clap::ValueHint::AnyPath)] + signer: k256::SecretKey, + + /// Nonce to be used for the SignerSet, required if `signer` or `signers` is set. + #[clap(long)] + nonce: u64, + + /// Hex string with secp256k1 compressed public key used to create the new SignerSet + #[clap(long)] + new_signer: Option, + + /// A JSON containing a SignerSet + #[clap(long)] + new_signer_set: Option, + + #[clap(long)] + new_nonce: Option, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, @@ -131,6 +157,7 @@ pub(crate) async fn build_instruction( transfer_operatorship(fee_payer, transfer_operatorship_args).await } Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await, + Commands::Rotate(rotate_args) => rotate(fee_payer, rotate_args, config).await, } } @@ -142,8 +169,8 @@ async fn query( if !endpoint.starts_with("https://") { endpoint = format!("https://{}", endpoint); } - let mut c = query_client::QueryClient::connect(endpoint).await?; + let mut c = query_client::QueryClient::connect(endpoint).await?; let res = c .smart_contract_state( cosmrs::proto::cosmwasm::wasm::v1::QuerySmartContractStateRequest { @@ -154,32 +181,35 @@ async fn query( .await? .into_inner() .data; - let result = serde_json::from_slice::(res.as_ref())?; Ok(result) } async fn get_verifier_set( - init_args: &InitArgs, + signer: &Option, + signer_set: &Option, + nonce: Option, config: &Config, chains_info: &serde_json::Value, ) -> eyre::Result { - if let Some(signer_key) = &init_args.signer { + if let Some(signer_key) = signer { let key_bytes: [u8; 33] = hex::decode(signer_key.strip_prefix("0x").unwrap_or(signer_key)) .map_err(|_| eyre::eyre!("Failed to decode hex"))? .try_into() .map_err(|_| eyre::eyre!("Invalid signer pubkey"))?; - let pk = libsecp256k1::PublicKey::parse_compressed(&key_bytes)?; - let pubkey = PublicKey::Secp256k1(pk.serialize_compressed()); + + let pk = k256::PublicKey::from_sec1_bytes(&key_bytes)?; + let pubkey = PublicKey::Secp256k1(pk.to_encoded_point(true).as_bytes().try_into()?); let signers = BTreeMap::from([(pubkey, 1_u128)]); + let nonce = nonce.ok_or(eyre::eyre!("Unexpected error: nonce is required"))?; Ok(VerifierSet { - nonce: init_args.nonce, + nonce, signers, quorum: 1_u128, }) - } else if let Some(signer_set) = &init_args.signer_set { + } else if let Some(signer_set) = signer_set { let signer_set: SerializeableVerifierSet = serde_json::from_str(signer_set)?; Ok(signer_set.into()) @@ -192,7 +222,6 @@ async fn get_verifier_set( cosmrs::AccountId::from_str(&address).unwrap() }; - let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; let multisig_prover_response = query::( axelar_grpc_endpoint, @@ -200,8 +229,8 @@ async fn get_verifier_set( serde_json::to_vec(&multisig_prover::msg::QueryMsg::CurrentVerifierSet)?, ) .await?; - let mut signers = BTreeMap::new(); + for signer in multisig_prover_response.verifier_set.signers.values() { let pubkey = PublicKey::Secp256k1(signer.pub_key.as_ref().try_into()?); let weight = signer.weight.u128(); @@ -216,6 +245,97 @@ async fn get_verifier_set( } } +async fn construct_execute_data( + signer_set: &SigningVerifierSet, + payload: Payload, + domain_separator: [u8; 32], +) -> eyre::Result { + let message_hash = hash_payload( + &domain_separator, + &signer_set.verifier_set(), + payload.clone(), + )?; + let signatures = signer_set + .signers + .iter() + .map(|signer| { + let signing_key = SigningKey::from(&signer.secret); + let (signature, recovery_id) = signing_key.sign_prehash_recoverable(&message_hash)?; + let mut signature_bytes = signature.normalize_s().unwrap_or(signature).to_vec(); + signature_bytes.push(recovery_id.to_byte()); + + Ok(( + PublicKey::Secp256k1( + signer + .secret + .public_key() + .to_encoded_point(true) + .as_bytes() + .try_into()?, + ), + Signature::EcdsaRecoverable( + signature_bytes + .try_into() + .map_err(|_e| eyre::eyre!("Invalid signature"))?, + ), + )) + }) + .collect::, eyre::Report>>()?; + let execute_data_bytes = axelar_solana_encoding::encode( + &signer_set.verifier_set(), + &signatures, + domain_separator, + payload, + )?; + let execute_data: ExecuteData = borsh::from_slice(&execute_data_bytes)?; + + Ok(execute_data) +} + +async fn build_signing_verifier_set(secret: k256::SecretKey, nonce: u64) -> SigningVerifierSet { + let signer = LocalSigner { + secret, + weight: 1_u128, + }; + + SigningVerifierSet::new(vec![signer], nonce) +} + +async fn append_verification_flow_instructions( + fee_payer: &Pubkey, + instructions: &mut Vec, + execute_data: &ExecuteData, + gateway_config_pda: &Pubkey, +) -> eyre::Result { + instructions.push( + axelar_solana_gateway::instructions::initialize_payload_verification_session( + *fee_payer, + *gateway_config_pda, + execute_data.payload_merkle_root, + )?, + ); + + let (verifier_set_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda( + execute_data.signing_verifier_set_merkle_root, + ); + + for signature_leaf in &execute_data.signing_verifier_set_leaves { + instructions.push(axelar_solana_gateway::instructions::verify_signature( + *gateway_config_pda, + verifier_set_tracker_pda, + execute_data.payload_merkle_root, + signature_leaf.clone(), + )?); + } + + let (verification_session_pda, _bump) = axelar_solana_gateway::get_signature_verification_pda( + &gateway_config_pda, + &execute_data.payload_merkle_root, + ); + + Ok(verification_session_pda) +} + async fn init( fee_payer: &Pubkey, init_args: InitArgs, @@ -223,33 +343,20 @@ async fn init( ) -> eyre::Result> { let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file).unwrap_or_default(); - let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); - let verifier_set = get_verifier_set(&init_args, config, &chains_info).await?; - let domain_separator = { - let maybe_domain_separator = if init_args.domain_separator.is_none() { - String::deserialize( - &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] - [ChainNameOnAxelar::from(config.network_type).0][DOMAIN_SEPARATOR_KEY], - ) - .ok() - } else { - None - }; - - let mut domain_separator_bytes = [0_u8; 32]; - if let Some(domain_separator) = maybe_domain_separator { - hex::decode_to_slice(domain_separator, &mut domain_separator_bytes)?; - } - - domain_separator_bytes - }; - + let verifier_set = get_verifier_set( + &init_args.signer, + &init_args.signer_set, + init_args.nonce, + config, + &chains_info, + ) + .await?; + let domain_separator = domain_separator(&chains_info, config.network_type)?; let verifier_set_hash = axelar_solana_encoding::types::verifier_set::verifier_set_hash::< NativeHasher, >(&verifier_set, &domain_separator)?; - - let (init_tracker_pda, _bump) = + let (verifier_set_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda(verifier_set_hash); let payer = *fee_payer; let upgrade_authority = payer; @@ -271,7 +378,7 @@ async fn init( payer, upgrade_authority, domain_separator, - vec![(verifier_set_hash, init_tracker_pda)], + vec![(verifier_set_hash, verifier_set_tracker_pda)], init_args.minimum_rotation_delay, init_args.operator, init_args.previous_signers_retention.into(), @@ -320,37 +427,9 @@ async fn approve( ) -> eyre::Result> { let mut instructions = vec![]; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let secret_bytes: [u8; 32] = hex::decode( - approve_args - .signer - .strip_prefix("0x") - .unwrap_or(&approve_args.signer), - )? - .try_into() - .map_err(|_err| eyre::eyre!("Invalid signer key"))?; - let sk = libsecp256k1::SecretKey::parse(&secret_bytes)?; - let pk = libsecp256k1::PublicKey::from_secret_key(&sk); - - let signer = TestSigner { - inner: sk, - weight: 1_u128, - }; - - let domain_separator = { - let maybe_domain_separator = String::deserialize( - &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] - [ChainNameOnAxelar::from(config.network_type).0][DOMAIN_SEPARATOR_KEY], - ) - .ok(); - - let mut domain_separator_bytes = [0_u8; 32]; - if let Some(domain_separator) = maybe_domain_separator { - hex::decode_to_slice(domain_separator, &mut domain_separator_bytes)?; - } - - domain_separator_bytes - }; - + let signer_set = + build_signing_verifier_set(approve_args.signer.clone(), approve_args.nonce).await; + let domain_separator = domain_separator(&chains_info, config.network_type)?; let payload_bytes = hex::decode( approve_args .payload @@ -358,7 +437,6 @@ async fn approve( .unwrap_or(&approve_args.payload), )?; let payload_hash = solana_sdk::hash::hashv(&[&payload_bytes]).to_bytes(); - let signers_set = SigningVerifierSet::new(vec![signer], 0); let message = Message { cc_id: CrossChainId { chain: approve_args.source_chain, @@ -369,77 +447,26 @@ async fn approve( destination_address: approve_args.destination_address, payload_hash, }; - - let gmp_payload = Payload::Messages(Messages(vec![message])); - let message_hash = hash_payload( - &domain_separator, - &signers_set.verifier_set(), - gmp_payload.clone(), - )?; - - let message = libsecp256k1::Message::parse(&message_hash); - let (signature, recovery_id) = libsecp256k1::sign(&message, &sk); - let mut signature_bytes = signature.serialize().to_vec(); - signature_bytes.push(recovery_id.serialize()); - let signatures = { - BTreeMap::from([( - PublicKey::Secp256k1(pk.serialize_compressed()), - Signature::EcdsaRecoverable( - signature_bytes - .try_into() - .map_err(|_e| eyre::eyre!("Invalid signature"))?, - ), - )]) - }; - let execute_data_bytes = axelar_solana_encoding::encode( - &signers_set.verifier_set(), - &signatures, - domain_separator, - gmp_payload, - )?; - - let execute_data: ExecuteData = borsh::from_slice(&execute_data_bytes)?; let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; - - instructions.push( - axelar_solana_gateway::instructions::initialize_payload_verification_session( - *fee_payer, - gateway_config_pda, - execute_data.payload_merkle_root, - )?, - ); - - let (verifier_set_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda( - execute_data.signing_verifier_set_merkle_root, - ); - - for signature_leaf in &execute_data.signing_verifier_set_leaves { - instructions.push(axelar_solana_gateway::instructions::verify_signature( - gateway_config_pda, - verifier_set_tracker_pda, - execute_data.payload_merkle_root, - signature_leaf.clone(), - )?); - } - - let (verification_session_pda, _bump) = axelar_solana_gateway::get_signature_verification_pda( + let gmp_payload = Payload::Messages(Messages(vec![message])); + let execute_data = construct_execute_data(&signer_set, gmp_payload, domain_separator).await?; + let verification_session_pda = append_verification_flow_instructions( + fee_payer, + &mut instructions, + &execute_data, &gateway_config_pda, - &execute_data.payload_merkle_root, - ); - + ) + .await?; let MerkleisedPayload::NewMessages { mut messages } = execute_data.payload_items else { eyre::bail!("Expected Messages payload"); }; - let Some(merkleised_message) = messages.pop() else { eyre::bail!("No messages in the batch"); }; - let command_id = command_id( &merkleised_message.leaf.message.cc_id.chain, &merkleised_message.leaf.message.cc_id.id, ); - let (incoming_message_pda, _bump) = axelar_solana_gateway::get_incoming_message_pda(&command_id); @@ -455,6 +482,53 @@ async fn approve( Ok(instructions) } -async fn rotate(fee_payer: &Pubkey, rotate_args: RotateArgs) -> eyre::Result> { - todo!() +async fn rotate( + fee_payer: &Pubkey, + rotate_args: RotateArgs, + config: &Config, +) -> eyre::Result> { + let mut instructions = vec![]; + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let signer_set = build_signing_verifier_set(rotate_args.signer, rotate_args.nonce).await; + let new_verifier_set = get_verifier_set( + &rotate_args.new_signer, + &rotate_args.new_signer_set, + rotate_args.new_nonce, + config, + &chains_info, + ) + .await?; + let domain_separator = domain_separator(&chains_info, config.network_type)?; + let verifier_set_hash = axelar_solana_encoding::types::verifier_set::verifier_set_hash::< + NativeHasher, + >(&signer_set.verifier_set(), &domain_separator)?; + let new_verifier_set_hash = axelar_solana_encoding::types::verifier_set::verifier_set_hash::< + NativeHasher, + >(&new_verifier_set, &domain_separator)?; + let (verifier_set_tracker_pda, _bump) = + axelar_solana_gateway::get_verifier_set_tracker_pda(verifier_set_hash); + let (new_verifier_set_tracker_pda, _bump) = + axelar_solana_gateway::get_verifier_set_tracker_pda(new_verifier_set_hash); + let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; + let payload = Payload::NewVerifierSet(new_verifier_set.clone()); + let execute_data = construct_execute_data(&signer_set, payload, domain_separator).await?; + let verification_session_pda = append_verification_flow_instructions( + fee_payer, + &mut instructions, + &execute_data, + &gateway_config_pda, + ) + .await?; + + instructions.push(axelar_solana_gateway::instructions::rotate_signers( + gateway_config_pda, + verification_session_pda, + verifier_set_tracker_pda, + new_verifier_set_tracker_pda, + *fee_payer, + None, + new_verifier_set_hash, + )?); + + Ok(instructions) } diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index 53fa143ca..f202258e9 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -1,12 +1,15 @@ -use crate::error::{AppError, Result}; +use std::collections::BTreeMap; +use std::path::PathBuf; +use std::str::FromStr; + use axelar_solana_encoding::types::pubkey::PublicKey; use axelar_solana_encoding::types::verifier_set::VerifierSet; use clap::ArgEnum; +use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::{Deserialize, Serialize}; use solana_sdk::{instruction::Instruction as SolanaInstruction, pubkey::Pubkey}; -use std::collections::BTreeMap; -use std::path::PathBuf; -use std::str::FromStr; + +use crate::error::{AppError, Result}; #[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] pub enum NetworkType { @@ -52,7 +55,7 @@ pub struct ChainNameOnAxelar(pub String); impl From for ChainNameOnAxelar { fn from(value: NetworkType) -> Self { match value { - NetworkType::Mainnet => Self("solana-mainnet".to_owned()), + NetworkType::Mainnet => Self("solana".to_owned()), NetworkType::Testnet => Self("solana-testnet".to_owned()), NetworkType::Devnet => Self("solana-devnet".to_owned()), NetworkType::Localnet => Self("solana-localnet".to_owned()), @@ -211,3 +214,75 @@ impl From for VerifierSet { } } } + +/// Uitility verifier set representation that has access to the signing keys +#[derive(Clone, Debug)] +pub struct SigningVerifierSet { + /// signers that have access to the given verifier set + pub signers: Vec, + /// the nonce for the verifier set + pub nonce: u64, + /// quorum for the verifier set + pub quorum: u128, +} + +impl SigningVerifierSet { + /// Create a new `SigningVerifierSet` + /// + /// # Panics + /// if the calculated quorum is larger than u128 + pub fn new(signers: Vec, nonce: u64) -> Self { + let quorum = signers + .iter() + .map(|signer| signer.weight) + .try_fold(0, u128::checked_add) + .expect("no arithmetic overflow"); + Self::new_with_quorum(signers, nonce, quorum) + } + + /// Create a new `SigningVerifierSet` with a custom quorum + #[must_use] + pub const fn new_with_quorum(signers: Vec, nonce: u64, quorum: u128) -> Self { + Self { + signers, + nonce, + quorum, + } + } + + /// Transform into the verifier set that the gateway expects to operate on + #[must_use] + pub fn verifier_set(&self) -> VerifierSet { + let signers = self + .signers + .iter() + .map(|x| { + let pubkey = x.secret.public_key(); + ( + PublicKey::Secp256k1( + pubkey + .to_encoded_point(true) + .as_bytes() + .to_owned() + .try_into() + .expect("Invalid pubkey derived from secret"), + ), + x.weight, + ) + }) + .collect(); + VerifierSet { + nonce: self.nonce, + signers, + quorum: self.quorum, + } + } +} + +/// Single test signer +#[derive(Clone, Debug)] +pub struct LocalSigner { + pub secret: k256::SecretKey, + /// associated weight + pub weight: u128, +} diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 86333f4ad..8319ba9f0 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -1,7 +1,9 @@ -use axelar_solana_encoding::types::pubkey::PublicKey; -use axelar_solana_encoding::types::verifier_set::VerifierSet; +use k256::elliptic_curve::FieldBytes; +use k256::pkcs8::DecodePrivateKey; +use k256::{Secp256k1, SecretKey}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use solana_sdk::keccak::hashv; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Signature; use std::fs::File; @@ -11,30 +13,34 @@ use std::str::FromStr; use crate::config::Config; use crate::error::{AppError, Result}; use crate::types::{ - NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, + ChainNameOnAxelar, NetworkType, PartialSignature, SignedSolanaTransaction, + UnsignedSolanaTransaction, }; pub(crate) use solana_sdk::instruction::AccountMeta; pub(crate) const ADDRESS_KEY: &str = "address"; +pub(crate) const AXELAR_ID_KEY: &str = "axelarId"; pub(crate) const AXELAR_KEY: &str = "axelar"; pub(crate) const CHAINS_KEY: &str = "chains"; +pub(crate) const CHAIN_ID_KEY: &str = "chainId"; pub(crate) const CHAIN_TYPE_KEY: &str = "chainType"; +pub(crate) const CONFIG_ACCOUNT_KEY: &str = "configAccount"; pub(crate) const CONTRACTS_KEY: &str = "contracts"; pub(crate) const DOMAIN_SEPARATOR_KEY: &str = "domainSeparator"; -pub(crate) const CONFIG_ACCOUNT_KEY: &str = "configAccount"; pub(crate) const GAS_SERVICE_KEY: &str = "AxelarGasService"; pub(crate) const GATEWAY_KEY: &str = "AxelarGateway"; +pub(crate) const GOVERNANCE_ADDRESS_KEY: &str = "governanceAddress"; +pub(crate) const GOVERNANCE_CHAIN_KEY: &str = "governanceChain"; +pub(crate) const GOVERNANCE_KEY: &str = "InterchainGovernance"; pub(crate) const GRPC_KEY: &str = "grpc"; pub(crate) const ITS_KEY: &str = "InterchainTokenService"; +pub(crate) const MINIMUM_PROPOSAL_ETA_DELAY_KEY: &str = "minimumTimeDelay"; +pub(crate) const MINIMUM_ROTATION_DELAY_KEY: &str = "minimumRotationDelay"; pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; -pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; pub(crate) const OPERATOR_KEY: &str = "operator"; -pub(crate) const MINIMUM_ROTATION_DELAY_KEY: &str = "minimumRotationDelay"; pub(crate) const PREVIOUS_SIGNERS_RETENTION_KEY: &str = "previousSignersRetention"; -pub(crate) const GOVERNANCE_KEY: &str = "InterchainGovernance"; -pub(crate) const MINIMUM_PROPOSAL_ETA_DELAY_KEY: &str = "minimumTimeDelay"; -pub(crate) const GOVERNANCE_CHAIN_KEY: &str = "governanceChain"; -pub(crate) const GOVERNANCE_ADDRESS_KEY: &str = "governanceAddress"; +pub(crate) const ROUTER_KEY: &str = "Router"; +pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; pub(crate) fn read_json_file(file: &File) -> Result { let reader = std::io::BufReader::new(file); @@ -215,67 +221,65 @@ pub(crate) fn print_transaction_result(config: &Config, result: Result, - /// the nonce for the verifier set - pub nonce: u64, - /// quorum for the verifier set - pub quorum: u128, +pub(crate) fn domain_separator( + chains_info: &serde_json::Value, + network_type: NetworkType, +) -> eyre::Result<[u8; 32]> { + if network_type == NetworkType::Localnet { + return Ok([0; 32]); + } + + let axelar_id = String::deserialize( + &chains_info[CHAINS_KEY][ChainNameOnAxelar::from(network_type).0][AXELAR_ID_KEY], + )?; + let router_address = String::deserialize( + &chains_info[CHAINS_KEY][AXELAR_KEY][CONTRACTS_KEY][ROUTER_KEY][ADDRESS_KEY], + )?; + let chain_id = + String::deserialize(&chains_info[CHAINS_KEY][AXELAR_KEY][ADDRESS_KEY][CHAIN_ID_KEY])?; + + Ok(hashv(&[ + axelar_id.as_bytes(), + router_address.as_bytes(), + chain_id.as_bytes(), + ]) + .to_bytes() + .try_into()?) } -impl SigningVerifierSet { - /// Create a new `SigningVerifierSet` - /// - /// # Panics - /// if the calculated quorum is larger than u128 - pub fn new(signers: Vec, nonce: u64) -> Self { - let quorum = signers - .iter() - .map(|signer| signer.weight) - .try_fold(0, u128::checked_add) - .expect("no arithmetic overflow"); - Self::new_with_quorum(signers, nonce, quorum) +pub(crate) fn parse_secret_key(raw: &str) -> eyre::Result { + if Path::new(raw).exists() { + let bytes = std::fs::read(raw)?; + return secret_from_bytes(&bytes) + .or_else(|| secret_from_str(std::str::from_utf8(&bytes).ok()?)) + .ok_or_else(|| eyre::eyre!("unrecognised key format in file".to_owned())); } - /// Create a new `SigningVerifierSet` with a custom quorum - #[must_use] - pub const fn new_with_quorum(signers: Vec, nonce: u64, quorum: u128) -> Self { - Self { - signers, - nonce, - quorum, - } + secret_from_str(raw).ok_or_else(|| eyre::eyre!("unrecognised key format".to_owned())) +} + +fn secret_from_bytes(b: &[u8]) -> Option { + SecretKey::from_pkcs8_der(b) + .ok() + .or_else(|| SecretKey::from_sec1_der(b).ok()) + .or_else(|| (b.len() == 32).then(|| SecretKey::from_bytes(b.try_into().ok()?).ok())?) +} + +fn secret_from_str(s: &str) -> Option { + let s = s.trim(); + + // PEM (SEC1 or PKCS8) + if s.starts_with("-----BEGIN") { + return SecretKey::from_pkcs8_pem(s) + .ok() + .or_else(|| SecretKey::from_sec1_pem(s).ok()); } - /// Transform into the verifier set that the gateway expects to operate on - #[must_use] - pub fn verifier_set(&self) -> VerifierSet { - let signers = self - .signers - .iter() - .map(|x| { - let pubkey = libsecp256k1::PublicKey::from_secret_key(&x.inner); - ( - PublicKey::Secp256k1(pubkey.serialize_compressed()), - x.weight, - ) - }) - .collect(); - VerifierSet { - nonce: self.nonce, - signers, - quorum: self.quorum, - } + // raw hex + if s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit()) { + let bytes = hex::decode(s).ok()?; + return SecretKey::from_bytes(FieldBytes::::from_slice(&bytes)).ok(); } -} -/// Single test signer -#[derive(Clone, Debug)] -pub struct TestSigner { - pub inner: libsecp256k1::SecretKey, - /// associated weight - pub weight: u128, + None } From ac5101a8f34f5ffe7cf1c68be35a4e8e616be1ef Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 9 May 2025 10:05:12 +0200 Subject: [PATCH 23/59] feat(solana): submit-proof Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gateway.rs | 106 ++++++++++++++++++++++++++++++++++++-- solana/cli/src/main.rs | 5 +- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 185d3f143..a540a8bed 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -14,6 +14,7 @@ use clap::{ArgGroup, Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; use k256::ecdsa::SigningKey; use k256::elliptic_curve::sec1::ToEncodedPoint; +use multisig_prover::msg::ProofStatus; use serde::Deserialize; use serde_json::json; use solana_sdk::instruction::Instruction; @@ -22,10 +23,10 @@ use solana_sdk::pubkey::Pubkey; use crate::config::Config; use crate::types::{ChainNameOnAxelar, LocalSigner, SerializeableVerifierSet, SigningVerifierSet}; use crate::utils::{ - self, domain_separator, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, - AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, - MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, - UPGRADE_AUTHORITY_KEY, + self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, + GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, + PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, + read_json_file_from_path, write_json_to_file_path, }; #[derive(Subcommand, Debug)] @@ -44,6 +45,11 @@ pub(crate) enum Commands { #[clap(long_about = "Rotate the signers used by the Gateway program for message verification")] Rotate(RotateArgs), + + #[clap( + long_about = "Submit a proof with either ApproveMessages or RotateSigners to the Gateway program" + )] + SubmitProof(SubmitProofArgs), } #[derive(Parser, Debug)] @@ -143,6 +149,12 @@ pub(crate) struct RotateArgs { new_nonce: Option, } +#[derive(Parser, Debug)] +pub(crate) struct SubmitProofArgs { + #[clap(long)] + multisig_session_id: u64, +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, @@ -158,6 +170,9 @@ pub(crate) async fn build_instruction( } Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await, Commands::Rotate(rotate_args) => rotate(fee_payer, rotate_args, config).await, + Commands::SubmitProof(submit_proof_args) => { + submit_proof(fee_payer, submit_proof_args, config).await + } } } @@ -532,3 +547,86 @@ async fn rotate( Ok(instructions) } + +async fn submit_proof( + fee_payer: &Pubkey, + submit_proof_args: SubmitProofArgs, + config: &Config, +) -> eyre::Result> { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + let multisig_prover_address = { + let address = String::deserialize( + &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] + [ChainNameOnAxelar::from(config.network_type).0][ADDRESS_KEY], + )?; + + cosmrs::AccountId::from_str(&address).unwrap() + }; + let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; + let multisig_prover_response = query::( + axelar_grpc_endpoint, + multisig_prover_address, + serde_json::to_vec(&multisig_prover::msg::QueryMsg::Proof { + multisig_session_id: submit_proof_args.multisig_session_id.into(), + })?, + ) + .await?; + + let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; + let execute_data: ExecuteData = match multisig_prover_response.status { + ProofStatus::Pending => eyre::bail!("Proof is not completed yet"), + ProofStatus::Completed { execute_data } => borsh::from_slice(&execute_data)?, + }; + + let mut instructions = Vec::new(); + let verification_session_pda = append_verification_flow_instructions( + fee_payer, + &mut instructions, + &execute_data, + &gateway_config_pda, + ) + .await?; + + match execute_data.payload_items { + MerkleisedPayload::VerifierSetRotation { + new_verifier_set_merkle_root, + } => { + let (verifier_set_tracker_pda, _bump) = + axelar_solana_gateway::get_verifier_set_tracker_pda( + execute_data.signing_verifier_set_merkle_root, + ); + let (new_verifier_set_tracker_pda, _bump) = + axelar_solana_gateway::get_verifier_set_tracker_pda(new_verifier_set_merkle_root); + instructions.push(axelar_solana_gateway::instructions::rotate_signers( + gateway_config_pda, + verification_session_pda, + verifier_set_tracker_pda, + new_verifier_set_tracker_pda, + *fee_payer, + None, + new_verifier_set_merkle_root, + )?); + } + MerkleisedPayload::NewMessages { messages } => { + for message in messages { + let command_id = command_id( + message.leaf.message.cc_id.chain.as_str(), + message.leaf.message.cc_id.id.as_str(), + ); + let (incoming_message_pda, _bump) = + axelar_solana_gateway::get_incoming_message_pda(&command_id); + instructions.push(axelar_solana_gateway::instructions::approve_message( + message, + execute_data.payload_merkle_root, + gateway_config_pda, + *fee_payer, + verification_session_pda, + incoming_message_pda, + )?); + } + } + } + + Ok(instructions) +} + diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index a27f69981..784933c2c 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -224,9 +224,9 @@ async fn run() -> eyre::Result<()> { None => { let config_file = solana_cli_config::CONFIG_FILE .as_ref() - .ok_or_else(|| eyre::eyre!("Missing config file"))?; + .ok_or_else(|| eyre::eyre!("Missing Solana config file"))?; let cli_config = solana_cli_config::Config::load(config_file)?; - let signer_context = clap::ArgMatches::default(); // Dummy context + let signer_context = clap::ArgMatches::default(); let signer = signer_from_path( &signer_context, &cli_config.keypair_path, @@ -308,3 +308,4 @@ async fn build_instruction( Ok(serializable_ix) } + From 6e153f3dc448c62ae4f821cd5d5e656739e4c6b5 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 9 May 2025 14:05:49 +0200 Subject: [PATCH 24/59] refactor(solana): major refactoring For `execute` calls, there are several transactions that need to be sent as to upload a message on-chain and not surpass the solana transaction size limit. For that to be suported, a big refactoring was needed so every instruction is now sent separately on its own transaction. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/broadcast.rs | 174 ++++++++++++++++++++++++++--- solana/cli/src/combine.rs | 40 ++++++- solana/cli/src/gas_service.rs | 52 ++++++++- solana/cli/src/gateway.rs | 74 +++++++++++- solana/cli/src/generate.rs | 177 ++++++++++++++++++----------- solana/cli/src/governance.rs | 53 ++++++++- solana/cli/src/its.rs | 45 +++++++- solana/cli/src/main.rs | 44 ++++---- solana/cli/src/send.rs | 204 ++++++++++++++++++++++++++++------ solana/cli/src/types.rs | 66 ++++++++++- solana/cli/src/utils.rs | 108 +++++++++++++++++- 11 files changed, 877 insertions(+), 160 deletions(-) diff --git a/solana/cli/src/broadcast.rs b/solana/cli/src/broadcast.rs index 68ccbc67f..a2ed96e1d 100644 --- a/solana/cli/src/broadcast.rs +++ b/solana/cli/src/broadcast.rs @@ -1,12 +1,19 @@ use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::{BroadcastArgs, SignedSolanaTransaction}; -use crate::utils::{self, print_transaction_result}; -use solana_client::rpc_client::RpcClient; +use crate::types::{BroadcastArgs, BroadcastMultipleArgs, SignedSolanaTransaction}; +use crate::utils::{self, print_transaction_result, create_compute_budget_instructions, DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE}; +use solana_client::{ + client_error::ClientErrorKind, + rpc_client::RpcClient, + rpc_request::RpcResponseErrorData, + rpc_response::RpcSimulateTransactionResult +}; use solana_sdk::{ - commitment_config::CommitmentConfig, hash::Hash, instruction::Instruction as SolanaInstruction, - message::Message, pubkey::Pubkey, signature::Signature, transaction::Transaction, + commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, hash::Hash, + instruction::Instruction as SolanaInstruction, instruction::InstructionError, + message::Message, pubkey::Pubkey, signature::Signature, transaction::{Transaction, TransactionError} }; +use axelar_solana_gateway::num_traits::FromPrimitive; use std::collections::HashMap; use std::str::FromStr; @@ -105,23 +112,81 @@ fn submit_solana_transaction( println!("Connecting to RPC client at {}", url); let rpc_client = RpcClient::new_with_commitment(url.to_string(), CommitmentConfig::confirmed()); + + // Don't automatically add compute budget instructions to avoid duplicates + // We'll use the original transaction directly + let tx_to_send = transaction; + + // Simulate the transaction before sending to check if we need to add compute units + match rpc_client.simulate_transaction(&tx_to_send) { + Ok(sim_result) => { + if let Some(units) = sim_result.value.units_consumed { + println!("Transaction simulation used {} compute units", units); + // If we're using significant compute units (>70% of default), we should log this + if units > 150_000 { + println!("WARNING: Transaction using significant compute units ({}). If this transaction fails with 'exceeded CUs meter', you'll need to add compute budget.", units); + } + } + }, + Err(err) => { + println!("Simulation warning: {:?}", err); + } + }; println!("Broadcasting transaction..."); - match rpc_client.send_and_confirm_transaction_with_spinner(&transaction) { + match rpc_client.send_and_confirm_transaction_with_spinner(&tx_to_send) { Ok(tx_signature) => { println!("Transaction broadcast and confirmed!"); Ok(tx_signature) } Err(client_err) => { eprintln!("Error during RPC broadcast/confirmation: {}", client_err); - if let solana_client::client_error::ClientErrorKind::RpcError( - solana_client::rpc_request::RpcError::RpcResponseError { data: solana_client::rpc_request::RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), .. } + + // Check if the error is a GatewayError and should proceed + let should_continue = if let ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { + data: RpcResponseErrorData::SendTransactionPreflightFailure( + RpcSimulateTransactionResult { + err: Some(TransactionError::InstructionError(_, + InstructionError::Custom(err_code))), + .. + } + ), + .. + } ) = client_err.kind() { - eprintln!(" -> Preflight Simulation Failure Result: {:?}", sim_result); - } else if let solana_client::client_error::ClientErrorKind::TransactionError(tx_err) = client_err.kind() { - eprintln!(" -> Transaction Error Detail: {:?}", tx_err); + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else if let ClientErrorKind::TransactionError( + TransactionError::InstructionError(_, + InstructionError::Custom(err_code)) + ) = client_err.kind() { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else { + false + }; + + if should_continue { + println!("Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction"); + // Return a dummy signature to indicate success for recoverable errors + Ok(Signature::default()) + } else { + // Print detailed error information + if let ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { + data: RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), + .. + } + ) = client_err.kind() { + eprintln!(" -> Preflight Simulation Failure Result: {:?}", sim_result); + } else if let ClientErrorKind::TransactionError(tx_err) = client_err.kind() { + eprintln!(" -> Transaction Error Detail: {:?}", tx_err); + } + + // Return the error as non-recoverable + Err(AppError::from(client_err)) } - Err(AppError::from(client_err)) } } } @@ -129,16 +194,89 @@ fn submit_solana_transaction( pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Result<()> { println!("Starting Solana transaction broadcast..."); - let signed_tx_data = utils::load_signed_solana_transaction(&args.signed_tx_path)?; + // Load the signed transaction data, handling potential format issues + let signed_tx_data = match utils::load_signed_solana_transaction(&args.signed_tx_path) { + Ok(tx_data) => tx_data, + Err(AppError::JsonError(e)) => { + // Provide more helpful error message for JSON parsing errors + return Err(AppError::BroadcastError(format!( + "Failed to parse transaction file. Make sure you're using a file generated by the 'combine' command, \ + not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", + e + ))); + }, + Err(e) => return Err(e), + }; println!( "Loaded combined signed transaction data from: {}", args.signed_tx_path.display() ); - print_transaction_result( - config, - submit_solana_transaction(&config.url, &signed_tx_data), - )?; + match submit_solana_transaction(&config.url, &signed_tx_data) { + Ok(signature) => { + // Handle the special case where we return a default signature for recoverable errors + if signature == Signature::default() { + println!("Transaction had a recoverable error - operation complete with recoverable error"); + Ok(()) + } else { + print_transaction_result(config, Ok(signature)) + } + }, + Err(err) => print_transaction_result(config, Err(err)), + } +} + +pub fn broadcast_multiple_transactions(args: &BroadcastMultipleArgs, config: &Config) -> Result<()> { + println!("Starting Solana batch transaction broadcast..."); + let mut success_count = 0; + let total_count = args.signed_tx_paths.len(); + + for (i, signed_tx_path) in args.signed_tx_paths.iter().enumerate() { + println!("\nBroadcasting transaction {} of {}...", i + 1, total_count); + + // Load the signed transaction data, handling potential format issues + let signed_tx_data = match utils::load_signed_solana_transaction(signed_tx_path) { + Ok(tx_data) => tx_data, + Err(AppError::JsonError(e)) => { + // Provide more helpful error message for JSON parsing errors + return Err(AppError::BroadcastError(format!( + "Failed to parse transaction file {}. Make sure you're using files generated by the 'combine' command, \ + not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", + signed_tx_path.display(), e + ))); + }, + Err(e) => return Err(e), + }; + println!( + "Loaded combined signed transaction data from: {}", + signed_tx_path.display() + ); + match submit_solana_transaction(&config.url, &signed_tx_data) { + Ok(signature) => { + // Handle the special case where we return a default signature for recoverable errors + if signature == Signature::default() { + println!("Transaction had a recoverable error - continuing with next transaction"); + } else { + print_transaction_result(config, Ok(signature))?; + success_count += 1; + } + }, + Err(err) => { + // We already checked for GatewayError in submit_solana_transaction, + // so this is a truly unrecoverable error + print_transaction_result(config, Err(err))?; + return Err(AppError::BroadcastError(format!( + "Failed at transaction {} of {}. {} succeeded.", + i + 1, + total_count, + success_count + ))); + } + } + } + + println!("\n{} of {} transactions broadcast successfully!", success_count, total_count); + Ok(()) -} +} \ No newline at end of file diff --git a/solana/cli/src/combine.rs b/solana/cli/src/combine.rs index 34784a227..b5c00f7b3 100644 --- a/solana/cli/src/combine.rs +++ b/solana/cli/src/combine.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::{CombineArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; +use crate::types::{CombineArgs, CombineMultipleArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; use crate::utils; use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; use std::collections::{HashMap, HashSet}; @@ -147,3 +147,41 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result< Ok(()) } + +pub fn combine_multiple_signatures(args: &CombineMultipleArgs, config: &Config) -> Result<()> { + println!("Starting batch Solana signature combination..."); + + // Validate inputs + if args.unsigned_tx_paths.len() != args.signature_paths_per_tx.len() || + args.unsigned_tx_paths.len() != args.output_signed_tx_paths.len() { + return Err(AppError::CombinationError( + "Mismatch in number of unsigned transactions, signature sets, and output paths".to_string(), + )); + } + + for i in 0..args.unsigned_tx_paths.len() { + let unsigned_tx_path = &args.unsigned_tx_paths[i]; + let signature_paths = &args.signature_paths_per_tx[i]; + let output_signed_tx_path = &args.output_signed_tx_paths[i]; + + println!("\nProcessing transaction {} of {}...", i + 1, args.unsigned_tx_paths.len()); + + // Create a CombineArgs for this single transaction + let single_combine_args = CombineArgs { + unsigned_tx_path: unsigned_tx_path.clone(), + signature_paths: signature_paths.clone(), + output_signed_tx_path: output_signed_tx_path.clone(), + }; + + // Use the existing function to combine signatures for this transaction + combine_solana_signatures(&single_combine_args, config)?; + } + + if config.network_type == NetworkType::Mainnet { + println!( + "-> All combined transaction files should be transferred to an online machine for broadcasting." + ); + } + + Ok(()) +} diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs index 4b6f56cc6..77a3caa83 100644 --- a/solana/cli/src/gas_service.rs +++ b/solana/cli/src/gas_service.rs @@ -1,12 +1,17 @@ use clap::{Parser, Subcommand}; -use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; +use solana_sdk::{ + instruction::Instruction, + message::Message, + pubkey::Pubkey, + transaction::Transaction as SolanaTransaction +}; use crate::{ config::Config, - types::ChainNameOnAxelar, + types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, - CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, + CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, }, }; @@ -35,6 +40,45 @@ pub(crate) async fn build_instruction( } } +pub(crate) async fn build_transaction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result> { + let instructions = match command { + Commands::Init(init_args) => init(fee_payer, init_args, config).await?, + }; + + // Get blockhash + let blockhash = fetch_latest_blockhash(&config.url)?; + + // Create a transaction for each individual instruction + let mut serializable_transactions = Vec::with_capacity(instructions.len()); + + for instruction in instructions { + // Build message and transaction with blockhash for a single instruction + let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let transaction = SolanaTransaction::new_unsigned(message); + + // Create the transaction parameters + // Note: Nonce account handling is done in generate_from_transactions + // rather than here, so each transaction gets the nonce instruction prepended + let params = SolanaTransactionParams { + fee_payer: fee_payer.to_string(), + recent_blockhash: Some(blockhash.to_string()), + nonce_account: None, + nonce_authority: None, + blockhash_for_message: blockhash.to_string(), + }; + + // Create a serializable transaction + let serializable_tx = SerializableSolanaTransaction::new(transaction, params); + serializable_transactions.push(serializable_tx); + } + + Ok(serializable_transactions) +} + async fn init( fee_payer: &Pubkey, init_args: InitArgs, diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index a540a8bed..85c4d07a7 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -21,13 +21,20 @@ use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use crate::config::Config; -use crate::types::{ChainNameOnAxelar, LocalSigner, SerializeableVerifierSet, SigningVerifierSet}; +use crate::error::AppError; +use crate::types::{ + ChainNameOnAxelar, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, + SigningVerifierSet, SolanaTransactionParams, +}; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, - GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, - PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, - read_json_file_from_path, write_json_to_file_path, + self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, + DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, + OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, }; +use solana_sdk::hash::Hash; +use solana_sdk::message::Message as SolanaMessage; +use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(Subcommand, Debug)] pub(crate) enum Commands { @@ -176,6 +183,62 @@ pub(crate) async fn build_instruction( } } +pub(crate) async fn build_transaction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result> { + let instructions = match command { + Commands::Init(init_args) => init(fee_payer, init_args, config).await?, + Commands::CallContract(call_contract_args) => { + call_contract(fee_payer, call_contract_args).await? + } + Commands::TransferOperatorship(transfer_operatorship_args) => { + transfer_operatorship(fee_payer, transfer_operatorship_args).await? + } + Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await?, + Commands::Rotate(rotate_args) => rotate(fee_payer, rotate_args, config).await?, + Commands::SubmitProof(submit_proof_args) => { + submit_proof(fee_payer, submit_proof_args, config).await? + } + }; + + // Get blockhash + let blockhash = fetch_latest_blockhash(&config.url)?; + + // Create a transaction for each individual instruction + let mut serializable_transactions = Vec::with_capacity(instructions.len()); + + for instruction in instructions { + // Create transaction with only the program instruction + // Note: We're no longer adding compute budget instructions at this stage + // to prevent duplicate instructions. The compute budget will be added + // during the sign_and_send_transactions phase based on simulation results + + // Build message and transaction with blockhash for a single instruction + let message = + SolanaMessage::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let transaction = SolanaTransaction::new_unsigned(message); + + // Create the transaction parameters + // Note: Nonce account handling is done in generate_from_transactions + // rather than here, so each transaction gets the nonce instruction prepended + let params = SolanaTransactionParams { + fee_payer: fee_payer.to_string(), + recent_blockhash: Some(blockhash.to_string()), + nonce_account: None, + nonce_authority: None, + blockhash_for_message: blockhash.to_string(), + }; + + // Create a serializable transaction + let serializable_tx = SerializableSolanaTransaction::new(transaction, params); + serializable_transactions.push(serializable_tx); + } + + Ok(serializable_transactions) +} + async fn query( mut endpoint: String, address: cosmrs::AccountId, @@ -629,4 +692,3 @@ async fn submit_proof( Ok(instructions) } - diff --git a/solana/cli/src/generate.rs b/solana/cli/src/generate.rs index ae0f622f5..7dfad2a6c 100644 --- a/solana/cli/src/generate.rs +++ b/solana/cli/src/generate.rs @@ -1,75 +1,18 @@ use crate::config::Config; use crate::error::{AppError, Result}; use crate::types::{ - GenerateArgs, NetworkType, SerializableInstruction, SolanaTransactionParams, + GenerateArgs, NetworkType, SerializableInstruction, SerializableSolanaTransaction, SolanaTransactionParams, UnsignedSolanaTransaction, }; -use crate::utils; -use solana_client::rpc_client::RpcClient; +use crate::utils::{self, fetch_latest_blockhash, fetch_nonce_data_and_verify}; use solana_sdk::{ - account::Account, hash::Hash, instruction::Instruction as SolanaInstruction, message::Message, - nonce::state::State as NonceState, pubkey::Pubkey, system_instruction, system_program, + hash::Hash, instruction::Instruction as SolanaInstruction, message::Message, + pubkey::Pubkey, system_instruction, transaction::Transaction as SolanaTransaction, }; use std::fs::File; use std::path::Path; use std::str::FromStr; -fn fetch_latest_blockhash(rpc_url: &str) -> Result { - let rpc_client = RpcClient::new(rpc_url.to_string()); - rpc_client.get_latest_blockhash().map_err(AppError::from) -} - -fn fetch_nonce_data_and_verify( - rpc_url: &str, - nonce_account_pubkey: &Pubkey, - expected_nonce_authority: &Pubkey, -) -> Result { - let rpc_client = RpcClient::new(rpc_url.to_string()); - let nonce_account: Account = rpc_client.get_account(nonce_account_pubkey)?; - - if !system_program::check_id(&nonce_account.owner) { - return Err(AppError::InvalidInput(format!( - "Nonce account {} is not owned by the system program ({}), owner is {}", - nonce_account_pubkey, - system_program::id(), - nonce_account.owner - ))); - } - - let (nonce_state, _size): (NonceState, usize) = - bincode::serde::decode_from_slice(&nonce_account.data, bincode::config::legacy()).map_err( - |e| { - AppError::ChainError(format!( - "Failed to borsh deserialize nonce account state ({}): {}", - nonce_account_pubkey, e - )) - }, - )?; - - match nonce_state { - NonceState::Initialized(data) => { - println!("Nonce account is initialized."); - println!(" -> Stored Nonce (Blockhash): {}", data.blockhash()); - println!(" -> Authority: {}", data.authority); - println!( - " -> Fee Lamports/Signature: {}", - data.fee_calculator.lamports_per_signature - ); - - if data.authority != *expected_nonce_authority { - return Err(AppError::InvalidInput(format!( - "Nonce account authority mismatch. Expected: {}, Found in account: {}", - expected_nonce_authority, data.authority - ))); - } - Ok(data.blockhash()) - } - NonceState::Uninitialized => Err(AppError::InvalidInput(format!( - "Nonce account {} is uninitialized", - nonce_account_pubkey - ))), - } -} pub fn generate_unsigned_solana_transaction( args: &GenerateArgs, @@ -134,7 +77,7 @@ pub fn generate_unsigned_solana_transaction( params.blockhash_for_message = blockhash_for_message.to_string(); - let message = Message::new_with_blockhash( + let message = solana_sdk::message::Message::new_with_blockhash( &sdk_instructions, Some(&args.fee_payer), &blockhash_for_message, @@ -142,8 +85,10 @@ pub fn generate_unsigned_solana_transaction( let message_bytes = message.serialize(); let signable_message_hex = hex::encode(&message_bytes); + + // Create unsigned transaction to write to file let unsigned_tx = UnsignedSolanaTransaction { - params, + params: params.clone(), instructions: sdk_instructions .iter() .map(SerializableInstruction::from) @@ -197,3 +142,109 @@ pub fn generate_unsigned_solana_transaction( Ok(()) } + +pub fn generate_from_transactions( + args: &GenerateArgs, + config: &Config, + mut transactions: Vec, +) -> Result<()> { + println!("Starting unsigned Solana transaction generation from transactions..."); + println!("Network Type: {:?}", config.network_type); + println!("Fee Payer: {}", args.fee_payer); + + // If nonce account is provided, we need to handle it specially + if let (Some(nonce_account), Some(nonce_authority)) = (&args.nonce_account, &args.nonce_authority) { + println!("Using Durable Nonce flow with account: {}", nonce_account); + + // Get nonce blockhash + let blockhash = fetch_nonce_data_and_verify(&config.url, nonce_account, nonce_authority)?; + println!("Using Nonce (Blockhash) from account: {}", blockhash); + + // For each transaction, we need to update with the nonce information + // and prepend the advance_nonce_account instruction + for tx in &mut transactions { + // Update transaction params + tx.params.nonce_account = Some(nonce_account.to_string()); + tx.params.nonce_authority = Some(nonce_authority.to_string()); + tx.params.blockhash_for_message = blockhash.to_string(); + tx.params.recent_blockhash = None; // Not needed with nonce + + // Create advance nonce account instruction + let advance_nonce_ix = solana_sdk::system_instruction::advance_nonce_account( + nonce_account, + nonce_authority + ); + + // Create a new transaction with advance_nonce_account as the first instruction + // followed by the original transaction's instructions + let mut instructions = vec![advance_nonce_ix]; + + // Add all the original instructions from the transaction + // We need to extract them from the message + let original_message = tx.transaction.message.clone(); + let account_keys = original_message.account_keys.clone(); + + for compiled_ix in &original_message.instructions { + let ix = solana_sdk::instruction::Instruction { + program_id: account_keys[compiled_ix.program_id_index as usize], + accounts: compiled_ix.accounts.iter() + .map(|idx| { + let pubkey = account_keys[*idx as usize]; + solana_sdk::instruction::AccountMeta { + pubkey, + is_signer: original_message.is_signer(*idx as usize), + is_writable: original_message.is_maybe_writable(*idx as usize, None), + } + }) + .collect(), + data: compiled_ix.data.clone(), + }; + + instructions.push(ix); + } + + // Create a new message with the combined instructions and nonce blockhash + let new_message = solana_sdk::message::Message::new_with_blockhash( + &instructions, + Some(&args.fee_payer), + &blockhash + ); + + // Update the transaction with the new message + *tx = SerializableSolanaTransaction::new( + solana_sdk::transaction::Transaction::new_unsigned(new_message), + tx.params.clone() + ); + } + } + + // Now save each transaction + for (i, tx) in transactions.iter().enumerate() { + // Convert the SerializableSolanaTransaction to an UnsignedSolanaTransaction + let unsigned_tx = tx.to_unsigned(); + + // Filename includes index if we have multiple transactions + let unsigned_tx_filename = if transactions.len() > 1 { + format!("{}.{}.unsigned.solana.json", args.output_file, i) + } else { + format!("{}.unsigned.solana.json", args.output_file) + }; + + let unsigned_tx_path = config.output_dir.join(&unsigned_tx_filename); + utils::save_unsigned_solana_transaction(&unsigned_tx, &unsigned_tx_path)?; + println!( + "Unsigned Solana transaction {} saved to: {}", + i + 1, + unsigned_tx_path.display() + ); + } + + if config.network_type == NetworkType::Mainnet { + println!("Mainnet detected. To create offline bundle, use the 'generate' command with instructions instead."); + println!("-> Transactions were saved as individual files that can be signed separately."); + } else { + println!("Testnet/Devnet detected. No offline dependency packaging needed."); + } + + Ok(()) +} \ No newline at end of file diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs index 7439b7469..8fd6046c6 100644 --- a/solana/cli/src/governance.rs +++ b/solana/cli/src/governance.rs @@ -1,15 +1,21 @@ use axelar_solana_governance::instructions::builder::IxBuilder; use base64::Engine; use clap::{Args, Subcommand}; -use solana_sdk::{instruction::AccountMeta, instruction::Instruction, pubkey::Pubkey}; +use solana_sdk::{ + instruction::AccountMeta, + instruction::Instruction, + message::Message, + pubkey::Pubkey, + transaction::Transaction as SolanaTransaction +}; use crate::{ config::Config, - types::ChainNameOnAxelar, + types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - parse_account_meta_string, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, - CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, - GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, + fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, + GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, UPGRADE_AUTHORITY_KEY, }, }; @@ -113,6 +119,43 @@ pub(crate) async fn build_instruction( } } +pub(crate) async fn build_transaction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result> { + let instructions = build_instruction(fee_payer, command, config).await?; + + // Get blockhash + let blockhash = fetch_latest_blockhash(&config.url)?; + + // Create a transaction for each individual instruction + let mut serializable_transactions = Vec::with_capacity(instructions.len()); + + for instruction in instructions { + // Build message and transaction with blockhash for a single instruction + let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let transaction = SolanaTransaction::new_unsigned(message); + + // Create the transaction parameters + // Note: Nonce account handling is done in generate_from_transactions + // rather than here, so each transaction gets the nonce instruction prepended + let params = SolanaTransactionParams { + fee_payer: fee_payer.to_string(), + recent_blockhash: Some(blockhash.to_string()), + nonce_account: None, + nonce_authority: None, + blockhash_for_message: blockhash.to_string(), + }; + + // Create a serializable transaction + let serializable_tx = SerializableSolanaTransaction::new(transaction, params); + serializable_transactions.push(serializable_tx); + } + + Ok(serializable_transactions) +} + async fn init( fee_payer: &Pubkey, init_args: InitArgs, diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index f9f7096ce..6e339f2c8 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -5,12 +5,14 @@ use clap::{Parser, Subcommand}; use serde::Deserialize; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; +use solana_sdk::message::Message; +use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; -use crate::types::ChainNameOnAxelar; +use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - encode_its_destination, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, - AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, + encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, }; @@ -657,6 +659,43 @@ pub(crate) async fn build_instruction( } } +pub(crate) async fn build_transaction( + fee_payer: &Pubkey, + command: Commands, + config: &Config, +) -> eyre::Result> { + let instructions = build_instruction(fee_payer, command, config).await?; + + // Get blockhash + let blockhash = fetch_latest_blockhash(&config.url)?; + + // Create a transaction for each individual instruction + let mut serializable_transactions = Vec::with_capacity(instructions.len()); + + for instruction in instructions { + // Build message and transaction with blockhash for a single instruction + let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let transaction = SolanaTransaction::new_unsigned(message); + + // Create the transaction parameters + // Note: Nonce account handling is done in generate_from_transactions + // rather than here, so each transaction gets the nonce instruction prepended + let params = SolanaTransactionParams { + fee_payer: fee_payer.to_string(), + recent_blockhash: Some(blockhash.to_string()), + nonce_account: None, + nonce_authority: None, + blockhash_for_message: blockhash.to_string(), + }; + + // Create a serializable transaction + let serializable_tx = SerializableSolanaTransaction::new(transaction, params); + serializable_transactions.push(serializable_tx); + } + + Ok(serializable_transactions) +} + async fn init( fee_payer: &Pubkey, init_args: InitArgs, diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 784933c2c..6a6bff557 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -13,19 +13,18 @@ mod types; mod utils; use clap::{ArgGroup, Parser, Subcommand}; -use send::build_and_send_solana_transaction; +use send::sign_and_send_transactions; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; -use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use std::path::PathBuf; use std::process::exit; -use types::SendArgs; +use types::{SendArgs, SerializableSolanaTransaction}; use crate::broadcast::broadcast_solana_transaction; use crate::combine::combine_solana_signatures; use crate::config::Config; -use crate::generate::generate_unsigned_solana_transaction; +use crate::generate::generate_from_transactions; use crate::sign::sign_solana_transaction; use crate::types::{BroadcastArgs, CombineArgs, GenerateArgs, SignArgs}; @@ -243,9 +242,11 @@ async fn run() -> eyre::Result<()> { fee_payer, signers: signer_keys, }; - let instruction = - build_instruction(&send_args.fee_payer, args.instruction, &config).await?; - build_and_send_solana_transaction(&send_args, &config, instruction)?; + + // Use the transaction-based approach + let transactions = + build_transaction(&send_args.fee_payer, args.instruction, &config).await?; + sign_and_send_transactions(&send_args, &config, transactions)?; } Command::Generate(args) => { let gen_args = GenerateArgs { @@ -255,10 +256,12 @@ async fn run() -> eyre::Result<()> { recent_blockhash: args.recent_blockhash, output_file: args.output_file, }; - let instruction = - build_instruction(&gen_args.fee_payer, args.instruction, &config).await?; - println!("Generating..."); - generate_unsigned_solana_transaction(&gen_args, &config, instruction)?; + + // Use the transaction-based approach + let transactions = + build_transaction(&gen_args.fee_payer, args.instruction, &config).await?; + println!("Generating transactions..."); + generate_from_transactions(&gen_args, &config, transactions)?; } Command::Sign(args) => { let sign_args = SignArgs { @@ -286,26 +289,23 @@ async fn run() -> eyre::Result<()> { Ok(()) } -async fn build_instruction( +async fn build_transaction( fee_payer: &Pubkey, instruction: InstructionSubcommand, config: &Config, -) -> eyre::Result> { - let serializable_ix = match instruction { +) -> eyre::Result> { + match instruction { InstructionSubcommand::Gateway(command) => { - gateway::build_instruction(fee_payer, command, config).await? + gateway::build_transaction(fee_payer, command, config).await } InstructionSubcommand::GasService(command) => { - gas_service::build_instruction(fee_payer, command, config).await? + gas_service::build_transaction(fee_payer, command, config).await } InstructionSubcommand::Its(command) => { - its::build_instruction(fee_payer, command, config).await? + its::build_transaction(fee_payer, command, config).await } InstructionSubcommand::Governance(command) => { - governance::build_instruction(fee_payer, command, config).await? + governance::build_transaction(fee_payer, command, config).await } - }; - - Ok(serializable_ix) + } } - diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs index 42e133b18..02fa1f217 100644 --- a/solana/cli/src/send.rs +++ b/solana/cli/src/send.rs @@ -1,49 +1,187 @@ +use axelar_solana_gateway::num_traits::FromPrimitive; use solana_clap_v3_utils::keypair::signer_from_path; -use solana_client::rpc_client::RpcClient; -use solana_sdk::commitment_config::CommitmentConfig; -use solana_sdk::instruction::Instruction; -use solana_sdk::message::Message; -use solana_sdk::transaction::Transaction; +use solana_client::{ + client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, + rpc_response::RpcSimulateTransactionResult, +}; +use solana_sdk::{ + commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, instruction::InstructionError, + transaction::{Transaction, TransactionError}, +}; use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::SendArgs; -use crate::utils::print_transaction_result; +use crate::types::{SendArgs, SerializableSolanaTransaction}; +use crate::utils::{print_transaction_result, create_compute_budget_instructions, DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE}; -pub(crate) fn build_and_send_solana_transaction( +pub(crate) fn sign_and_send_transactions( send_args: &SendArgs, config: &Config, - instructions: Vec, + serializable_txs: Vec, ) -> Result<()> { let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); - let message = Message::new(&instructions, Some(&send_args.fee_payer)); - let mut transaction = Transaction::new_unsigned(message); + let mut results = Vec::new(); - if send_args.signers.len() < transaction.signatures.len() { - return Err(AppError::SigningError( - "Not enough signers provided".to_string(), - )); - } + for serializable_tx in serializable_txs { + let mut transaction = serializable_tx.transaction; + + if send_args.signers.len() < transaction.signatures.len() { + return Err(AppError::SigningError( + "Not enough signers provided".to_string(), + )); + } + + let mut signers = Vec::with_capacity(transaction.signatures.len()); + let signer_context = clap::ArgMatches::default(); // Dummy context + + for signer in send_args.signers.iter() { + let signer = + signer_from_path(&signer_context, signer, "signer", &mut None).map_err(|e| { + AppError::SigningError(format!("Failed to load signer '{}': {}", signer, e)) + })?; - let mut signers = Vec::with_capacity(transaction.signatures.len()); - let signer_context = clap::ArgMatches::default(); // Dummy context + signers.push(signer); + } - for signer in send_args.signers.iter() { - let signer = - signer_from_path(&signer_context, signer, "signer", &mut None).map_err(|e| { - AppError::SigningError(format!("Failed to load signer '{}': {}", signer, e)) - })?; + // Get the latest blockhash + let blockhash = rpc_client.get_latest_blockhash()?; + + // Check if the transaction already has compute budget instructions + let has_compute_budget = transaction.message.instructions.iter().any(|ix| { + let program_id = transaction.message.account_keys[ix.program_id_index as usize]; + program_id == solana_sdk::compute_budget::id() + }); - signers.push(signer); + // First, we'll make a transaction with just the original instructions + transaction.sign(&signers, blockhash); + + // Only try to optimize if there are no compute budget instructions already + if !has_compute_budget { + // Try to simulate the transaction to see if it might exceed compute limits + println!("Simulating transaction before sending..."); + match rpc_client.simulate_transaction(&transaction) { + Ok(sim_result) => { + if let Some(units) = sim_result.value.units_consumed { + println!("Simulation used {} compute units", units); + + // If we're using a significant portion of the compute limit, add a compute budget + if units > 150_000 { + // Create a new transaction with compute budget instructions + println!("Transaction needs significant compute units, adding compute budget"); + + // Extract original instructions from the transaction message + // Use the transaction's message instructions directly + let message = &transaction.message; + + // Convert CompiledInstructions to regular Instructions + let original_instructions: Vec = message + .instructions + .iter() + .map(|compiled_ix| { + solana_sdk::instruction::Instruction { + program_id: message.account_keys[compiled_ix.program_id_index as usize], + accounts: compiled_ix.accounts.iter() + .map(|account_idx| { + let pubkey = message.account_keys[*account_idx as usize]; + solana_sdk::instruction::AccountMeta { + pubkey, + is_signer: message.is_signer(*account_idx as usize), + is_writable: message.is_maybe_writable(*account_idx as usize, None), + } + }) + .collect(), + data: compiled_ix.data.clone(), + } + }) + .collect(); + + // Create compute budget instructions + let compute_budget_instructions = create_compute_budget_instructions( + DEFAULT_COMPUTE_UNITS, + DEFAULT_PRIORITY_FEE + ); + + // Combine compute budget instructions with original instructions + let mut all_instructions = compute_budget_instructions; + all_instructions.extend(original_instructions); + + // Get the fee payer + let fee_payer = transaction.message.account_keys[0]; + + // Create a new message with all instructions + let message = solana_sdk::message::Message::new_with_blockhash( + &all_instructions, + Some(&fee_payer), + &blockhash + ); + + // Create and sign a new transaction + let mut optimized_tx = Transaction::new_unsigned(message); + optimized_tx.sign(&signers, blockhash); + + // Use the optimized transaction instead + transaction = optimized_tx; + println!("Added compute budget: {} units with {} micro-lamports priority fee", + DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE); + } + } + }, + Err(err) => { + println!("Simulation failed: {:?}, proceeding with regular transaction", err); + // If simulation fails, just use the original transaction + transaction.sign(&signers, blockhash); + } + }; + } else { + println!("Transaction already has compute budget instructions, skipping optimization"); + } + + // Now send the transaction (either original or optimized) + match rpc_client.send_and_confirm_transaction(&transaction) { + Ok(signature) => { + results.push(signature); + }, + Err(err) => { + let should_continue = if let ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { + data: RpcResponseErrorData::SendTransactionPreflightFailure( + RpcSimulateTransactionResult { + err: Some(TransactionError::InstructionError(_, + InstructionError::Custom(err_code))), + .. + } + ), + .. + } + ) = err.kind() { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else if let ClientErrorKind::TransactionError( + TransactionError::InstructionError(_, InstructionError::Custom(err_code)) + ) = err.kind() { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else { + false + }; + + if should_continue { + println!("Transaction error: GatewayError (code: {:?}), but continuing with next transaction as it's recoverable", + err.kind()); + continue; + } else { + println!("Transaction error: {:?}", err); + return Err(AppError::from(err)); + } + } + } } - let blockhash = rpc_client.get_latest_blockhash()?; - transaction.sign(&signers, blockhash); + // Print results + for (i, signature) in results.iter().enumerate() { + println!("Transaction {}: {}", i + 1, signature); + print_transaction_result(config, Ok(*signature))?; + } - Ok(print_transaction_result( - config, - rpc_client - .send_and_confirm_transaction(&transaction) - .map_err(|e| AppError::from(e)), - )?) -} + Ok(()) +} \ No newline at end of file diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index f202258e9..838e739c7 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -7,7 +7,13 @@ use axelar_solana_encoding::types::verifier_set::VerifierSet; use clap::ArgEnum; use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::{Deserialize, Serialize}; -use solana_sdk::{instruction::Instruction as SolanaInstruction, pubkey::Pubkey}; +use solana_sdk::{ + hash::Hash, + instruction::Instruction as SolanaInstruction, + message::Message, + pubkey::Pubkey, + transaction::Transaction as SolanaTransaction, +}; use crate::error::{AppError, Result}; @@ -152,6 +158,52 @@ pub struct SignedSolanaTransaction { pub signatures: Vec, } +/// A wrapper around SolanaTransaction that can be serialized and deserialized +#[derive(Debug, Clone)] +pub struct SerializableSolanaTransaction { + pub transaction: SolanaTransaction, + pub params: SolanaTransactionParams, +} + +impl SerializableSolanaTransaction { + pub fn new(transaction: SolanaTransaction, params: SolanaTransactionParams) -> Self { + Self { transaction, params } + } + + pub fn to_unsigned(&self) -> UnsignedSolanaTransaction { + let message = self.transaction.message.clone(); + let message_bytes = message.serialize(); + let signable_message_hex = hex::encode(&message_bytes); + + // Convert compiled instructions back to SerializableInstruction + let instructions = message.instructions.iter() + .map(|compiled_ix| { + let ix = SolanaInstruction { + program_id: message.account_keys[compiled_ix.program_id_index as usize], + accounts: compiled_ix.accounts.iter() + .map(|account_idx| { + let pubkey = message.account_keys[*account_idx as usize]; + solana_sdk::instruction::AccountMeta { + pubkey, + is_signer: message.is_signer(*account_idx as usize), + is_writable: message.is_maybe_writable(*account_idx as usize, None), + } + }) + .collect(), + data: compiled_ix.data.clone(), + }; + SerializableInstruction::from(&ix) + }) + .collect(); + + UnsignedSolanaTransaction { + params: self.params.clone(), + instructions, + signable_message_hex, + } + } +} + #[derive(Debug, Clone)] pub struct SendArgs { pub fee_payer: Pubkey, @@ -181,11 +233,23 @@ pub struct CombineArgs { pub output_signed_tx_path: PathBuf, } +#[derive(Debug, Clone)] +pub struct CombineMultipleArgs { + pub unsigned_tx_paths: Vec, + pub signature_paths_per_tx: Vec>, + pub output_signed_tx_paths: Vec, +} + #[derive(Debug, Clone)] pub struct BroadcastArgs { pub signed_tx_path: PathBuf, } +#[derive(Debug, Clone)] +pub struct BroadcastMultipleArgs { + pub signed_tx_paths: Vec, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SerializeableVerifierSet { pub signers: BTreeMap, diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 8319ba9f0..9f7985d28 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -3,9 +3,13 @@ use k256::pkcs8::DecodePrivateKey; use k256::{Secp256k1, SecretKey}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; -use solana_sdk::keccak::hashv; -use solana_sdk::pubkey::Pubkey; -use solana_sdk::signature::Signature; +use solana_client::rpc_client::RpcClient; +use solana_sdk::account_utils::StateMut; +use solana_sdk::nonce::state::Versions; +use solana_sdk::{ + compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction, keccak::hashv, + pubkey::Pubkey, signature::Signature, +}; use std::fs::File; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -18,6 +22,21 @@ use crate::types::{ }; pub(crate) use solana_sdk::instruction::AccountMeta; +// Default compute units to use for complex transactions +pub(crate) const DEFAULT_COMPUTE_UNITS: u32 = 1_400_000; // Maximum allowed is 1.4M compute units +pub(crate) const DEFAULT_PRIORITY_FEE: u64 = 10_000; // 10,000 micro-lamports per compute unit + +/// Creates compute budget instructions to increase the compute limit and set priority fee +pub(crate) fn create_compute_budget_instructions( + compute_units: u32, + priority_fee: u64, +) -> Vec { + vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units), + ComputeBudgetInstruction::set_compute_unit_price(priority_fee), + ] +} + pub(crate) const ADDRESS_KEY: &str = "address"; pub(crate) const AXELAR_ID_KEY: &str = "axelarId"; pub(crate) const AXELAR_KEY: &str = "axelar"; @@ -82,7 +101,31 @@ pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Res } pub(crate) fn load_signed_solana_transaction(path: &Path) -> Result { - read_json_file_from_path(path) + // Try to read the file as a SignedSolanaTransaction first + match read_json_file_from_path::(path) { + Ok(signed_tx) => Ok(signed_tx), + Err(err) => { + // If that fails, try to read it as an UnsignedSolanaTransaction + // This handles cases where the user might be using a file generated by the 'sign' command + // rather than the 'combine' command + match read_json_file_from_path::(path) { + Ok(unsigned_tx) => { + println!( + "Warning: Found unsigned transaction, converting to signed format without signatures" + ); + // Convert to a signed transaction with no signatures + Ok(SignedSolanaTransaction { + unsigned_tx_data: unsigned_tx, + signatures: Vec::new(), + }) + } + Err(_) => { + // If both reads fail, return the original error from reading as SignedSolanaTransaction + Err(err) + } + } + } + } } pub(crate) fn save_signed_solana_transaction( @@ -258,6 +301,63 @@ pub(crate) fn parse_secret_key(raw: &str) -> eyre::Result { secret_from_str(raw).ok_or_else(|| eyre::eyre!("unrecognised key format".to_owned())) } +pub(crate) fn fetch_latest_blockhash(rpc_url: &str) -> Result { + let rpc_client = RpcClient::new(rpc_url.to_string()); + rpc_client.get_latest_blockhash().map_err(AppError::from) +} + +pub(crate) fn fetch_nonce_data_and_verify( + rpc_url: &str, + nonce_account_pubkey: &Pubkey, + expected_nonce_authority: &Pubkey, +) -> Result { + let rpc_client = RpcClient::new(rpc_url.to_string()); + let nonce_account = rpc_client.get_account(nonce_account_pubkey)?; + + if !solana_sdk::system_program::check_id(&nonce_account.owner) { + return Err(AppError::InvalidInput(format!( + "Nonce account {} is not owned by the system program ({}), owner is {}", + nonce_account_pubkey, + solana_sdk::system_program::id(), + nonce_account.owner + ))); + } + + // Try with regular bincode deserialization + let nonce_state: solana_sdk::nonce::state::State = StateMut::::state(&nonce_account) + .map_err(|_| { + AppError::InvalidInput(format!( + "Failed to deserialize nonce account {}", + nonce_account_pubkey + )) + })? + .into(); + + match nonce_state { + solana_sdk::nonce::state::State::Initialized(data) => { + println!("Nonce account is initialized."); + println!(" -> Stored Nonce (Blockhash): {}", data.blockhash()); + println!(" -> Authority: {}", data.authority); + + // If there's a mismatch, we'll print a warning but still proceed + if data.authority != *expected_nonce_authority { + return Err(AppError::InvalidInput(format!( + "Nonce account authority mismatch: expected {}, found {}", + expected_nonce_authority, data.authority + ))); + } + + // Always return the blockhash, regardless of authority mismatch + // This works around potential deserialization issues + Ok(data.blockhash()) + } + solana_sdk::nonce::state::State::Uninitialized => Err(AppError::InvalidInput(format!( + "Nonce account {} is uninitialized", + nonce_account_pubkey + ))), + } +} + fn secret_from_bytes(b: &[u8]) -> Option { SecretKey::from_pkcs8_der(b) .ok() From ffa1f6966a7c5ce44a7b4110c1865f3bef160fcf Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 9 May 2025 15:33:44 +0200 Subject: [PATCH 25/59] feat(solana): execute Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 44 +++++- solana/cli/Cargo.toml | 1 + solana/cli/src/broadcast.rs | 136 ++++++----------- solana/cli/src/combine.rs | 40 +---- solana/cli/src/config.rs | 2 +- solana/cli/src/gas_service.rs | 25 +-- solana/cli/src/gateway.rs | 235 +++++++++++++++++++++++----- solana/cli/src/generate.rs | 277 ++++++++-------------------------- solana/cli/src/governance.rs | 43 +++--- solana/cli/src/its.rs | 15 +- solana/cli/src/main.rs | 18 +-- solana/cli/src/send.rs | 120 +++++++++------ solana/cli/src/types.rs | 36 ++--- solana/cli/src/utils.rs | 67 +------- 14 files changed, 491 insertions(+), 568 deletions(-) diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index dec7dbe4d..d596686eb 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -531,6 +531,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -1412,6 +1423,7 @@ dependencies = [ "flate2", "governance-gmp", "hex", + "its-instruction-builder", "k256", "multisig-prover", "program-utils", @@ -2412,7 +2424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3731,6 +3743,24 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "its-instruction-builder" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +dependencies = [ + "async-recursion", + "axelar-executable", + "axelar-solana-encoding", + "axelar-solana-gateway", + "axelar-solana-its", + "bincode 1.3.3", + "borsh 1.5.7", + "interchain-token-transfer-gmp", + "solana-client", + "solana-sdk", + "spl-token-2022 8.0.1", +] + [[package]] name = "jni" version = "0.21.1" @@ -4832,7 +4862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.101", @@ -4949,7 +4979,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5597,7 +5627,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5695,7 +5725,7 @@ dependencies = [ "security-framework 3.2.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -9409,7 +9439,7 @@ dependencies = [ "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -10398,7 +10428,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index edc98055a..774a0df94 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -20,6 +20,7 @@ axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } governance-gmp = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } program-utils = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } +its-instruction-builder = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } axelar-wasm-std = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec" } voting-verifier = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ diff --git a/solana/cli/src/broadcast.rs b/solana/cli/src/broadcast.rs index a2ed96e1d..8c2828737 100644 --- a/solana/cli/src/broadcast.rs +++ b/solana/cli/src/broadcast.rs @@ -1,19 +1,22 @@ use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::{BroadcastArgs, BroadcastMultipleArgs, SignedSolanaTransaction}; -use crate::utils::{self, print_transaction_result, create_compute_budget_instructions, DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE}; +use crate::types::{BroadcastArgs, SignedSolanaTransaction}; +use crate::utils::{self, print_transaction_result}; +use axelar_solana_gateway::num_traits::FromPrimitive; use solana_client::{ - client_error::ClientErrorKind, - rpc_client::RpcClient, - rpc_request::RpcResponseErrorData, - rpc_response::RpcSimulateTransactionResult + client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, + rpc_response::RpcSimulateTransactionResult, }; use solana_sdk::{ - commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, hash::Hash, - instruction::Instruction as SolanaInstruction, instruction::InstructionError, - message::Message, pubkey::Pubkey, signature::Signature, transaction::{Transaction, TransactionError} + commitment_config::CommitmentConfig, + hash::Hash, + instruction::Instruction as SolanaInstruction, + instruction::InstructionError, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::{Transaction, TransactionError}, }; -use axelar_solana_gateway::num_traits::FromPrimitive; use std::collections::HashMap; use std::str::FromStr; @@ -112,7 +115,7 @@ fn submit_solana_transaction( println!("Connecting to RPC client at {}", url); let rpc_client = RpcClient::new_with_commitment(url.to_string(), CommitmentConfig::confirmed()); - + // Don't automatically add compute budget instructions to avoid duplicates // We'll use the original transaction directly let tx_to_send = transaction; @@ -124,10 +127,13 @@ fn submit_solana_transaction( println!("Transaction simulation used {} compute units", units); // If we're using significant compute units (>70% of default), we should log this if units > 150_000 { - println!("WARNING: Transaction using significant compute units ({}). If this transaction fails with 'exceeded CUs meter', you'll need to add compute budget.", units); + println!( + "WARNING: Transaction using significant compute units ({}). If this transaction fails with 'exceeded CUs meter', you'll need to add compute budget.", + units + ); } } - }, + } Err(err) => { println!("Simulation warning: {:?}", err); } @@ -145,22 +151,28 @@ fn submit_solana_transaction( // Check if the error is a GatewayError and should proceed let should_continue = if let ClientErrorKind::RpcError( solana_client::rpc_request::RpcError::RpcResponseError { - data: RpcResponseErrorData::SendTransactionPreflightFailure( - RpcSimulateTransactionResult { - err: Some(TransactionError::InstructionError(_, - InstructionError::Custom(err_code))), - .. - } - ), + data: + RpcResponseErrorData::SendTransactionPreflightFailure( + RpcSimulateTransactionResult { + err: + Some(TransactionError::InstructionError( + _, + InstructionError::Custom(err_code), + )), + .. + }, + ), .. - } - ) = client_err.kind() { + }, + ) = client_err.kind() + { axelar_solana_gateway::error::GatewayError::from_u32(*err_code) .is_some_and(|gw_err| gw_err.should_relayer_proceed()) - } else if let ClientErrorKind::TransactionError( - TransactionError::InstructionError(_, - InstructionError::Custom(err_code)) - ) = client_err.kind() { + } else if let ClientErrorKind::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(err_code), + )) = client_err.kind() + { axelar_solana_gateway::error::GatewayError::from_u32(*err_code) .is_some_and(|gw_err| gw_err.should_relayer_proceed()) } else { @@ -168,7 +180,9 @@ fn submit_solana_transaction( }; if should_continue { - println!("Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction"); + println!( + "Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction" + ); // Return a dummy signature to indicate success for recoverable errors Ok(Signature::default()) } else { @@ -177,8 +191,9 @@ fn submit_solana_transaction( solana_client::rpc_request::RpcError::RpcResponseError { data: RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), .. - } - ) = client_err.kind() { + }, + ) = client_err.kind() + { eprintln!(" -> Preflight Simulation Failure Result: {:?}", sim_result); } else if let ClientErrorKind::TransactionError(tx_err) = client_err.kind() { eprintln!(" -> Transaction Error Detail: {:?}", tx_err); @@ -204,7 +219,7 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Re not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", e ))); - }, + } Err(e) => return Err(e), }; println!( @@ -216,67 +231,14 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Re Ok(signature) => { // Handle the special case where we return a default signature for recoverable errors if signature == Signature::default() { - println!("Transaction had a recoverable error - operation complete with recoverable error"); + println!( + "Transaction had a recoverable error - operation complete with recoverable error" + ); Ok(()) } else { print_transaction_result(config, Ok(signature)) } - }, + } Err(err) => print_transaction_result(config, Err(err)), } } - -pub fn broadcast_multiple_transactions(args: &BroadcastMultipleArgs, config: &Config) -> Result<()> { - println!("Starting Solana batch transaction broadcast..."); - let mut success_count = 0; - let total_count = args.signed_tx_paths.len(); - - for (i, signed_tx_path) in args.signed_tx_paths.iter().enumerate() { - println!("\nBroadcasting transaction {} of {}...", i + 1, total_count); - - // Load the signed transaction data, handling potential format issues - let signed_tx_data = match utils::load_signed_solana_transaction(signed_tx_path) { - Ok(tx_data) => tx_data, - Err(AppError::JsonError(e)) => { - // Provide more helpful error message for JSON parsing errors - return Err(AppError::BroadcastError(format!( - "Failed to parse transaction file {}. Make sure you're using files generated by the 'combine' command, \ - not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", - signed_tx_path.display(), e - ))); - }, - Err(e) => return Err(e), - }; - println!( - "Loaded combined signed transaction data from: {}", - signed_tx_path.display() - ); - - match submit_solana_transaction(&config.url, &signed_tx_data) { - Ok(signature) => { - // Handle the special case where we return a default signature for recoverable errors - if signature == Signature::default() { - println!("Transaction had a recoverable error - continuing with next transaction"); - } else { - print_transaction_result(config, Ok(signature))?; - success_count += 1; - } - }, - Err(err) => { - // We already checked for GatewayError in submit_solana_transaction, - // so this is a truly unrecoverable error - print_transaction_result(config, Err(err))?; - return Err(AppError::BroadcastError(format!( - "Failed at transaction {} of {}. {} succeeded.", - i + 1, - total_count, - success_count - ))); - } - } - } - - println!("\n{} of {} transactions broadcast successfully!", success_count, total_count); - - Ok(()) -} \ No newline at end of file diff --git a/solana/cli/src/combine.rs b/solana/cli/src/combine.rs index b5c00f7b3..34784a227 100644 --- a/solana/cli/src/combine.rs +++ b/solana/cli/src/combine.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::error::{AppError, Result}; -use crate::types::{CombineArgs, CombineMultipleArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; +use crate::types::{CombineArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; use crate::utils; use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; use std::collections::{HashMap, HashSet}; @@ -147,41 +147,3 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result< Ok(()) } - -pub fn combine_multiple_signatures(args: &CombineMultipleArgs, config: &Config) -> Result<()> { - println!("Starting batch Solana signature combination..."); - - // Validate inputs - if args.unsigned_tx_paths.len() != args.signature_paths_per_tx.len() || - args.unsigned_tx_paths.len() != args.output_signed_tx_paths.len() { - return Err(AppError::CombinationError( - "Mismatch in number of unsigned transactions, signature sets, and output paths".to_string(), - )); - } - - for i in 0..args.unsigned_tx_paths.len() { - let unsigned_tx_path = &args.unsigned_tx_paths[i]; - let signature_paths = &args.signature_paths_per_tx[i]; - let output_signed_tx_path = &args.output_signed_tx_paths[i]; - - println!("\nProcessing transaction {} of {}...", i + 1, args.unsigned_tx_paths.len()); - - // Create a CombineArgs for this single transaction - let single_combine_args = CombineArgs { - unsigned_tx_path: unsigned_tx_path.clone(), - signature_paths: signature_paths.clone(), - output_signed_tx_path: output_signed_tx_path.clone(), - }; - - // Use the existing function to combine signatures for this transaction - combine_solana_signatures(&single_combine_args, config)?; - } - - if config.network_type == NetworkType::Mainnet { - println!( - "-> All combined transaction files should be transferred to an online machine for broadcasting." - ); - } - - Ok(()) -} diff --git a/solana/cli/src/config.rs b/solana/cli/src/config.rs index f53ac5213..22e0fbe91 100644 --- a/solana/cli/src/config.rs +++ b/solana/cli/src/config.rs @@ -19,7 +19,7 @@ impl Config { pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> Result { println!("URL: {}", url); if !output_dir.exists() { - fs::create_dir_all(&output_dir).map_err(|e| AppError::IoError(e))?; + fs::create_dir_all(&output_dir).map_err(AppError::IoError)?; println!("Created output directory: {}", output_dir.display()); } else if !output_dir.is_dir() { return Err(AppError::ConfigError(format!( diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs index 77a3caa83..35048249a 100644 --- a/solana/cli/src/gas_service.rs +++ b/solana/cli/src/gas_service.rs @@ -1,17 +1,14 @@ use clap::{Parser, Subcommand}; use solana_sdk::{ - instruction::Instruction, - message::Message, - pubkey::Pubkey, - transaction::Transaction as SolanaTransaction + instruction::Instruction, pubkey::Pubkey, transaction::Transaction as SolanaTransaction, }; use crate::{ config::Config, types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, - CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, }, }; @@ -30,16 +27,6 @@ pub(crate) struct InitArgs { salt: String, } -pub(crate) async fn build_instruction( - fee_payer: &Pubkey, - command: Commands, - config: &Config, -) -> eyre::Result> { - match command { - Commands::Init(init_args) => init(fee_payer, init_args, config).await, - } -} - pub(crate) async fn build_transaction( fee_payer: &Pubkey, command: Commands, @@ -57,7 +44,11 @@ pub(crate) async fn build_transaction( for instruction in instructions { // Build message and transaction with blockhash for a single instruction - let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let message = solana_sdk::message::Message::new_with_blockhash( + &[instruction], + Some(fee_payer), + &blockhash, + ); let transaction = SolanaTransaction::new_unsigned(message); // Create the transaction parameters diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 85c4d07a7..6e638bd13 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::str::FromStr; +use std::sync::LazyLock; use axelar_solana_encoding::hash_payload; use axelar_solana_encoding::hasher::NativeHasher; @@ -17,22 +18,23 @@ use k256::elliptic_curve::sec1::ToEncodedPoint; use multisig_prover::msg::ProofStatus; use serde::Deserialize; use serde_json::json; +use solana_sdk::hash::Hash; use solana_sdk::instruction::Instruction; +use solana_sdk::packet::PACKET_DATA_SIZE; use solana_sdk::pubkey::Pubkey; +use solana_sdk::transaction::Transaction; use crate::config::Config; -use crate::error::AppError; use crate::types::{ ChainNameOnAxelar, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, - DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, - OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, + self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, + GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, + PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, }; -use solana_sdk::hash::Hash; use solana_sdk::message::Message as SolanaMessage; use solana_sdk::transaction::Transaction as SolanaTransaction; @@ -57,6 +59,9 @@ pub(crate) enum Commands { long_about = "Submit a proof with either ApproveMessages or RotateSigners to the Gateway program" )] SubmitProof(SubmitProofArgs), + + #[clap(long_about = "Execute a cross-chain message with provided payload")] + Execute(ExecuteArgs), } #[derive(Parser, Debug)] @@ -162,25 +167,22 @@ pub(crate) struct SubmitProofArgs { multisig_session_id: u64, } -pub(crate) async fn build_instruction( - fee_payer: &Pubkey, - command: Commands, - config: &Config, -) -> eyre::Result> { - match command { - Commands::Init(init_args) => init(fee_payer, init_args, config).await, - Commands::CallContract(call_contract_args) => { - call_contract(fee_payer, call_contract_args).await - } - Commands::TransferOperatorship(transfer_operatorship_args) => { - transfer_operatorship(fee_payer, transfer_operatorship_args).await - } - Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await, - Commands::Rotate(rotate_args) => rotate(fee_payer, rotate_args, config).await, - Commands::SubmitProof(submit_proof_args) => { - submit_proof(fee_payer, submit_proof_args, config).await - } - } +#[derive(Parser, Debug)] +pub(crate) struct ExecuteArgs { + #[clap(long)] + source_chain: String, + + #[clap(long)] + message_id: String, + + #[clap(long)] + source_address: String, + + #[clap(long)] + destination_address: String, + + #[clap(long)] + payload: String, } pub(crate) async fn build_transaction( @@ -201,28 +203,16 @@ pub(crate) async fn build_transaction( Commands::SubmitProof(submit_proof_args) => { submit_proof(fee_payer, submit_proof_args, config).await? } + Commands::Execute(execute_args) => execute(fee_payer, execute_args, config).await?, }; - // Get blockhash let blockhash = fetch_latest_blockhash(&config.url)?; - - // Create a transaction for each individual instruction let mut serializable_transactions = Vec::with_capacity(instructions.len()); for instruction in instructions { - // Create transaction with only the program instruction - // Note: We're no longer adding compute budget instructions at this stage - // to prevent duplicate instructions. The compute budget will be added - // during the sign_and_send_transactions phase based on simulation results - - // Build message and transaction with blockhash for a single instruction let message = SolanaMessage::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); let transaction = SolanaTransaction::new_unsigned(message); - - // Create the transaction parameters - // Note: Nonce account handling is done in generate_from_transactions - // rather than here, so each transaction gets the nonce instruction prepended let params = SolanaTransactionParams { fee_payer: fee_payer.to_string(), recent_blockhash: Some(blockhash.to_string()), @@ -231,7 +221,6 @@ pub(crate) async fn build_transaction( blockhash_for_message: blockhash.to_string(), }; - // Create a serializable transaction let serializable_tx = SerializableSolanaTransaction::new(transaction, params); serializable_transactions.push(serializable_tx); } @@ -407,7 +396,7 @@ async fn append_verification_flow_instructions( } let (verification_session_pda, _bump) = axelar_solana_gateway::get_signature_verification_pda( - &gateway_config_pda, + gateway_config_pda, &execute_data.payload_merkle_root, ); @@ -692,3 +681,169 @@ async fn submit_proof( Ok(instructions) } + +/// Maximum number of bytes we can pack into each `GatewayInstruction::WriteMessagePayload` +/// instruction. +/// +/// Calculates the maximum payload size that can fit in a Solana transaction for the +/// `WriteMessagePayload` instruction. This is done by creating a baseline transaction with empty +/// payload, measuring its size, and subtracting it from the maximum Solana packet size. +/// +/// The calculation is performed once on first access and cached, using random data since we only +/// care about the structure size, not the actual values. +/// +/// # Panics +/// +/// Will panic during initialization if: +/// - Fails to create the `WriteMessagePayload` instruction. +/// - Fails to serialize the transaction with `bincode`. +/// - Fails to convert the size from a u64 value to a usize. +/// +/// Based on: `https://github.com/solana-labs/solana/pull/19654` +static MAX_CHUNK_SIZE: LazyLock = LazyLock::new(|| { + // Generate a random pubkey for all fields since we only care about size + let random_pubkey = Pubkey::new_unique(); + + // Create baseline instruction with empty payload data + let instruction = axelar_solana_gateway::instructions::write_message_payload( + random_pubkey, + random_pubkey, + random_pubkey.to_bytes(), + &[], // empty data + 0, + ) + .expect("Failed to create baseline WriteMessagePayload instruction"); + + let baseline_msg = + SolanaMessage::new_with_blockhash(&[instruction], Some(&random_pubkey), &Hash::default()); + + let mut writer = bincode::enc::write::SizeWriter::default(); + bincode::serde::encode_into_writer( + &Transaction { + signatures: vec![ + solana_sdk::signature::Signature::default(); + baseline_msg.header.num_required_signatures.into() + ], + message: baseline_msg, + }, + &mut writer, + bincode::config::legacy(), + ) + .expect("Failed to calculate transaction size"); + + // Subtract baseline size and 1 byte for shortvec encoding + PACKET_DATA_SIZE + .saturating_sub(writer.bytes_written) + .saturating_sub(1) +}); + +async fn execute( + fee_payer: &Pubkey, + execute_args: ExecuteArgs, + config: &Config, +) -> eyre::Result> { + let message = Message { + cc_id: CrossChainId { + chain: execute_args.source_chain, + id: execute_args.message_id, + }, + source_address: execute_args.source_address, + destination_chain: ChainNameOnAxelar::from(config.network_type).0, + destination_address: execute_args.destination_address, + payload_hash: solana_sdk::hash::hashv(&[&hex::decode( + execute_args + .payload + .strip_prefix("0x") + .unwrap_or(&execute_args.payload), + )?]) + .to_bytes(), + }; + + let command_id = command_id(&message.cc_id.chain, &message.cc_id.id); + let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; + let (incoming_message_pda, _) = axelar_solana_gateway::get_incoming_message_pda(&command_id); + let mut instructions = Vec::new(); + let payload = hex::decode( + execute_args + .payload + .strip_prefix("0x") + .unwrap_or(&execute_args.payload), + )?; + + instructions.push( + axelar_solana_gateway::instructions::initialize_message_payload( + gateway_config_pda, + *fee_payer, + command_id, + payload.len().try_into()?, + )?, + ); + + let chunks = payload + .chunks(*MAX_CHUNK_SIZE) + .enumerate() + .map(|(index, chunk)| (chunk, index * *MAX_CHUNK_SIZE)); + + for (chunk, offset) in chunks { + instructions.push(axelar_solana_gateway::instructions::write_message_payload( + gateway_config_pda, + *fee_payer, + command_id, + chunk, + offset.try_into()?, + )?); + } + + instructions.push(axelar_solana_gateway::instructions::commit_message_payload( + gateway_config_pda, + *fee_payer, + command_id, + )?); + + if let Ok(destination_address) = Pubkey::from_str(&message.destination_address) { + let (message_payload_pda, _) = axelar_solana_gateway::find_message_payload_pda( + gateway_config_pda, + command_id, + *fee_payer, + ); + + // Handle special destination addresses + if destination_address == axelar_solana_its::id() { + let ix = its_instruction_builder::build_its_gmp_instruction( + *fee_payer, + incoming_message_pda, + message_payload_pda, + message.clone(), + payload.clone(), + &solana_client::nonblocking::rpc_client::RpcClient::new(config.url.clone()), + ) + .await?; + instructions.push(ix); + } else if destination_address == axelar_solana_governance::id() { + let ix = axelar_solana_governance::instructions::builder::calculate_gmp_ix( + *fee_payer, + incoming_message_pda, + message_payload_pda, + &message, + &payload, + )?; + instructions.push(ix); + } else { + let ix = axelar_executable::construct_axelar_executable_ix( + &message, + &payload, + incoming_message_pda, + message_payload_pda, + )?; + instructions.push(ix); + } + } + + instructions.push(axelar_solana_gateway::instructions::close_message_payload( + gateway_config_pda, + *fee_payer, + command_id, + )?); + + Ok(instructions) +} diff --git a/solana/cli/src/generate.rs b/solana/cli/src/generate.rs index 7dfad2a6c..23d5caf40 100644 --- a/solana/cli/src/generate.rs +++ b/solana/cli/src/generate.rs @@ -1,147 +1,7 @@ use crate::config::Config; -use crate::error::{AppError, Result}; -use crate::types::{ - GenerateArgs, NetworkType, SerializableInstruction, SerializableSolanaTransaction, SolanaTransactionParams, - UnsignedSolanaTransaction, -}; -use crate::utils::{self, fetch_latest_blockhash, fetch_nonce_data_and_verify}; -use solana_sdk::{ - hash::Hash, instruction::Instruction as SolanaInstruction, message::Message, - pubkey::Pubkey, system_instruction, transaction::Transaction as SolanaTransaction, -}; -use std::fs::File; -use std::path::Path; -use std::str::FromStr; - - -pub fn generate_unsigned_solana_transaction( - args: &GenerateArgs, - config: &Config, - mut instructions: Vec, -) -> Result<()> { - println!("Starting unsigned Solana transaction generation..."); - println!("Network Type: {:?}", config.network_type); - - println!("Fee Payer: {}", args.fee_payer); - - let mut sdk_instructions: Vec; - let blockhash_for_message: Hash; - let mut params = SolanaTransactionParams { - fee_payer: args.fee_payer.to_string(), - recent_blockhash: None, - nonce_account: None, - nonce_authority: None, - blockhash_for_message: Hash::default().to_string(), - }; - - match (&args.nonce_account, &args.nonce_authority) { - (Some(nonce_account), Some(nonce_authority)) => { - println!("Using Durable Nonce flow."); - if args.recent_blockhash.is_some() { - println!("Warning: --recent-blockhash is ignored when using --nonce-account."); - } - - blockhash_for_message = - fetch_nonce_data_and_verify(&config.url, &nonce_account, &nonce_authority)?; - println!( - "Using Nonce (Blockhash) from account {}: {}", - nonce_account, blockhash_for_message - ); - - params.nonce_account = Some(nonce_account.to_string()); - params.nonce_authority = Some(nonce_authority.to_string()); - - let advance_nonce_ix = - system_instruction::advance_nonce_account(&nonce_account, &nonce_authority); - println!("Prepending AdvanceNonceAccount instruction."); - - sdk_instructions = vec![advance_nonce_ix]; - sdk_instructions.append(&mut instructions); - } - (None, None) => { - println!("Using latest blockhash flow."); - blockhash_for_message = match &args.recent_blockhash { - Some(bh_str) => Hash::from_str(bh_str)?, - None => fetch_latest_blockhash(&config.url)?, - }; - println!("Using Recent Blockhash: {}", blockhash_for_message); - params.recent_blockhash = Some(blockhash_for_message.to_string()); - sdk_instructions = instructions; - } - _ => { - return Err(AppError::InconsistentState( - "Internal Error: CLI parser should have prevented providing only one nonce argument.".to_string(), - )); - } - } - - params.blockhash_for_message = blockhash_for_message.to_string(); - - let message = solana_sdk::message::Message::new_with_blockhash( - &sdk_instructions, - Some(&args.fee_payer), - &blockhash_for_message, - ); - - let message_bytes = message.serialize(); - let signable_message_hex = hex::encode(&message_bytes); - - // Create unsigned transaction to write to file - let unsigned_tx = UnsignedSolanaTransaction { - params: params.clone(), - instructions: sdk_instructions - .iter() - .map(SerializableInstruction::from) - .collect(), - signable_message_hex, - }; - - let unsigned_tx_filename = format!("{}.unsigned.solana.json", args.output_file); - let unsigned_tx_path = config.output_dir.join(&unsigned_tx_filename); - utils::save_unsigned_solana_transaction(&unsigned_tx, &unsigned_tx_path)?; - println!( - "Unsigned Solana transaction saved to: {}", - unsigned_tx_path.display() - ); - - if config.network_type == NetworkType::Mainnet { - println!("Mainnet detected. Packaging dependencies for offline signing..."); - let mut files_to_include = Vec::new(); - files_to_include.push(("unsigned_tx.solana.json", unsigned_tx_path.as_path())); - files_to_include.push(("Cargo.toml", Path::new("./Cargo.toml"))); - files_to_include.push(("Cargo.lock", Path::new("./Cargo.lock"))); - files_to_include.push(("README.md", Path::new("./README.md"))); - files_to_include.push(("src", Path::new("./src"))); - - std::fs::create_dir_all(".cargo").unwrap(); - let config_toml = File::create(".cargo/config.toml").unwrap(); - - let mut cmd = std::process::Command::new("cargo") - .arg("vendor") - .stdout(config_toml) - .spawn() - .unwrap(); - cmd.wait().unwrap(); - - files_to_include.push(("vendor", Path::new("./vendor"))); - files_to_include.push((".cargo/config.toml", Path::new("./.cargo/config.toml"))); - - println!("OK {}", line!()); - let bundle_name = format!("{}.solana.bundle", args.output_file); - let bundle_path = - utils::create_offline_bundle(&bundle_name, &config.output_dir, &files_to_include) - .unwrap(); - println!( - "Offline bundle created for Mainnet: {}", - bundle_path.display() - ); - println!("-> This bundle should be securely transferred to each signer's offline machine."); - } else { - println!("Testnet/Devnet detected. No offline dependency packaging needed."); - } - - Ok(()) -} +use crate::error::Result; +use crate::types::{GenerateArgs, SerializableSolanaTransaction}; +use crate::utils::{self, fetch_nonce_data_and_verify}; pub fn generate_from_transactions( args: &GenerateArgs, @@ -151,71 +11,73 @@ pub fn generate_from_transactions( println!("Starting unsigned Solana transaction generation from transactions..."); println!("Network Type: {:?}", config.network_type); println!("Fee Payer: {}", args.fee_payer); + println!( + "Using Durable Nonce flow with account: {}", + args.nonce_account + ); - // If nonce account is provided, we need to handle it specially - if let (Some(nonce_account), Some(nonce_authority)) = (&args.nonce_account, &args.nonce_authority) { - println!("Using Durable Nonce flow with account: {}", nonce_account); - - // Get nonce blockhash - let blockhash = fetch_nonce_data_and_verify(&config.url, nonce_account, nonce_authority)?; - println!("Using Nonce (Blockhash) from account: {}", blockhash); - - // For each transaction, we need to update with the nonce information - // and prepend the advance_nonce_account instruction - for tx in &mut transactions { - // Update transaction params - tx.params.nonce_account = Some(nonce_account.to_string()); - tx.params.nonce_authority = Some(nonce_authority.to_string()); - tx.params.blockhash_for_message = blockhash.to_string(); - tx.params.recent_blockhash = None; // Not needed with nonce - - // Create advance nonce account instruction - let advance_nonce_ix = solana_sdk::system_instruction::advance_nonce_account( - nonce_account, - nonce_authority - ); - - // Create a new transaction with advance_nonce_account as the first instruction - // followed by the original transaction's instructions - let mut instructions = vec![advance_nonce_ix]; - - // Add all the original instructions from the transaction - // We need to extract them from the message - let original_message = tx.transaction.message.clone(); - let account_keys = original_message.account_keys.clone(); + // Get nonce blockhash + let blockhash = + fetch_nonce_data_and_verify(&config.url, &args.nonce_account, &args.nonce_authority)?; + println!("Using Nonce (Blockhash) from account: {}", blockhash); + + // For each transaction, we need to update with the nonce information + // and prepend the advance_nonce_account instruction + for tx in &mut transactions { + // Update transaction params + tx.params.nonce_account = Some(args.nonce_account.to_string()); + tx.params.nonce_authority = Some(args.nonce_authority.to_string()); + tx.params.blockhash_for_message = blockhash.to_string(); + tx.params.recent_blockhash = None; // Not needed with nonce + + // Create advance nonce account instruction + let advance_nonce_ix = solana_sdk::system_instruction::advance_nonce_account( + &args.nonce_account, + &args.nonce_authority, + ); - for compiled_ix in &original_message.instructions { - let ix = solana_sdk::instruction::Instruction { - program_id: account_keys[compiled_ix.program_id_index as usize], - accounts: compiled_ix.accounts.iter() - .map(|idx| { - let pubkey = account_keys[*idx as usize]; - solana_sdk::instruction::AccountMeta { - pubkey, - is_signer: original_message.is_signer(*idx as usize), - is_writable: original_message.is_maybe_writable(*idx as usize, None), - } - }) - .collect(), - data: compiled_ix.data.clone(), - }; + // Create a new transaction with advance_nonce_account as the first instruction + // followed by the original transaction's instructions + let mut instructions = vec![advance_nonce_ix]; + + // Add all the original instructions from the transaction + // We need to extract them from the message + let original_message = tx.transaction.message.clone(); + let account_keys = original_message.account_keys.clone(); + + for compiled_ix in &original_message.instructions { + let ix = solana_sdk::instruction::Instruction { + program_id: account_keys[compiled_ix.program_id_index as usize], + accounts: compiled_ix + .accounts + .iter() + .map(|idx| { + let pubkey = account_keys[*idx as usize]; + solana_sdk::instruction::AccountMeta { + pubkey, + is_signer: original_message.is_signer(*idx as usize), + is_writable: original_message.is_maybe_writable(*idx as usize, None), + } + }) + .collect(), + data: compiled_ix.data.clone(), + }; - instructions.push(ix); - } + instructions.push(ix); + } - // Create a new message with the combined instructions and nonce blockhash - let new_message = solana_sdk::message::Message::new_with_blockhash( - &instructions, - Some(&args.fee_payer), - &blockhash - ); + // Create a new message with the combined instructions and nonce blockhash + let new_message = solana_sdk::message::Message::new_with_blockhash( + &instructions, + Some(&args.fee_payer), + &blockhash, + ); - // Update the transaction with the new message - *tx = SerializableSolanaTransaction::new( - solana_sdk::transaction::Transaction::new_unsigned(new_message), - tx.params.clone() - ); - } + // Update the transaction with the new message + *tx = SerializableSolanaTransaction::new( + solana_sdk::transaction::Transaction::new_unsigned(new_message), + tx.params.clone(), + ); } // Now save each transaction @@ -239,12 +101,5 @@ pub fn generate_from_transactions( ); } - if config.network_type == NetworkType::Mainnet { - println!("Mainnet detected. To create offline bundle, use the 'generate' command with instructions instead."); - println!("-> Transactions were saved as individual files that can be signed separately."); - } else { - println!("Testnet/Devnet detected. No offline dependency packaging needed."); - } - Ok(()) -} \ No newline at end of file +} diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs index 8fd6046c6..4dd16e53c 100644 --- a/solana/cli/src/governance.rs +++ b/solana/cli/src/governance.rs @@ -2,21 +2,18 @@ use axelar_solana_governance::instructions::builder::IxBuilder; use base64::Engine; use clap::{Args, Subcommand}; use solana_sdk::{ - instruction::AccountMeta, - instruction::Instruction, - message::Message, - pubkey::Pubkey, - transaction::Transaction as SolanaTransaction + instruction::AccountMeta, instruction::Instruction, pubkey::Pubkey, + transaction::Transaction as SolanaTransaction, }; use crate::{ config::Config, types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, - GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, - UPGRADE_AUTHORITY_KEY, + ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, + GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, + UPGRADE_AUTHORITY_KEY, fetch_latest_blockhash, parse_account_meta_string, + read_json_file_from_path, write_json_to_file_path, }, }; @@ -134,7 +131,11 @@ pub(crate) async fn build_transaction( for instruction in instructions { // Build message and transaction with blockhash for a single instruction - let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let message = solana_sdk::message::Message::new_with_blockhash( + &[instruction], + Some(fee_payer), + &blockhash, + ); let transaction = SolanaTransaction::new_unsigned(message); // Create the transaction parameters @@ -185,9 +186,11 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(vec![IxBuilder::new() - .initialize_config(fee_payer, config_pda, governance_config) - .build()]) + Ok(vec![ + IxBuilder::new() + .initialize_config(fee_payer, config_pda, governance_config) + .build(), + ]) } async fn execute_proposal( @@ -214,9 +217,9 @@ async fn execute_proposal( calldata_bytes, ); - Ok(vec![builder - .execute_proposal(fee_payer, config_pda) - .build()]) + Ok(vec![ + builder.execute_proposal(fee_payer, config_pda).build(), + ]) } async fn execute_operator_proposal( @@ -240,7 +243,9 @@ async fn execute_operator_proposal( calldata_bytes, ); - Ok(vec![builder - .execute_operator_proposal(fee_payer, config_pda, &args.operator) - .build()]) + Ok(vec![ + builder + .execute_operator_proposal(fee_payer, config_pda, &args.operator) + .build(), + ]) } diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index 6e339f2c8..c6023d00a 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -5,15 +5,14 @@ use clap::{Parser, Subcommand}; use serde::Deserialize; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; -use solana_sdk::message::Message; use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, - ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, - OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, + ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, + read_json_file_from_path, write_json_to_file_path, }; #[derive(Subcommand, Debug)] @@ -674,7 +673,11 @@ pub(crate) async fn build_transaction( for instruction in instructions { // Build message and transaction with blockhash for a single instruction - let message = solana_sdk::message::Message::new_with_blockhash(&[instruction], Some(fee_payer), &blockhash); + let message = solana_sdk::message::Message::new_with_blockhash( + &[instruction], + Some(fee_payer), + &blockhash, + ); let transaction = SolanaTransaction::new_unsigned(message); // Create the transaction parameters @@ -1063,7 +1066,7 @@ async fn call_contract_with_interchain_token_offchain_data( )?; let mut file = File::create(config.output_dir.join("offchain_data_payload.bin"))?; - file.write(&payload)?; + file.write_all(&payload)?; Ok(vec![instruction]) } diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index 6a6bff557..baa78d412 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -12,7 +12,7 @@ mod sign; mod types; mod utils; -use clap::{ArgGroup, Parser, Subcommand}; +use clap::{Parser, Subcommand}; use send::sign_and_send_transactions; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; @@ -115,23 +115,18 @@ struct SendCommandArgs { } #[derive(Parser, Debug)] -#[clap(group(ArgGroup::new("blockhash_source").required(false).args(&["nonce-account", "recent-blockhash"])))] struct GenerateCommandArgs { /// Fee Payer Pubkey (Base58 encoded string) #[clap(long)] fee_payer: Pubkey, - /// Nonce account Pubkey (Base58). Requires --nonce-authority. - #[clap(long, requires = "nonce-authority")] - nonce_account: Option, + /// Nonce account Pubkey (Base58). + #[clap(long)] + nonce_account: Pubkey, /// Nonce authority Pubkey (Base58). Must sign the transaction. - #[clap(long, requires = "nonce-account")] - nonce_authority: Option, - - /// Specify a recent blockhash (Base58) instead of fetching or using a nonce. - #[clap(long, global = true)] - recent_blockhash: Option, + #[clap(long)] + nonce_authority: Pubkey, /// Base name for output files (e.g., 'my_tx' -> my_tx.unsigned.solana.json) #[clap(long = "output-name")] @@ -253,7 +248,6 @@ async fn run() -> eyre::Result<()> { fee_payer: args.fee_payer, nonce_account: args.nonce_account, nonce_authority: args.nonce_authority, - recent_blockhash: args.recent_blockhash, output_file: args.output_file, }; diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs index 02fa1f217..93eb7443c 100644 --- a/solana/cli/src/send.rs +++ b/solana/cli/src/send.rs @@ -5,14 +5,18 @@ use solana_client::{ rpc_response::RpcSimulateTransactionResult, }; use solana_sdk::{ - commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, instruction::InstructionError, + commitment_config::CommitmentConfig, + instruction::InstructionError, transaction::{Transaction, TransactionError}, }; use crate::config::Config; use crate::error::{AppError, Result}; use crate::types::{SendArgs, SerializableSolanaTransaction}; -use crate::utils::{print_transaction_result, create_compute_budget_instructions, DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE}; +use crate::utils::{ + DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, create_compute_budget_instructions, + print_transaction_result, +}; pub(crate) fn sign_and_send_transactions( send_args: &SendArgs, @@ -45,7 +49,7 @@ pub(crate) fn sign_and_send_transactions( // Get the latest blockhash let blockhash = rpc_client.get_latest_blockhash()?; - + // Check if the transaction already has compute budget instructions let has_compute_budget = transaction.message.instructions.iter().any(|ix| { let program_id = transaction.message.account_keys[ix.program_id_index as usize]; @@ -63,71 +67,85 @@ pub(crate) fn sign_and_send_transactions( Ok(sim_result) => { if let Some(units) = sim_result.value.units_consumed { println!("Simulation used {} compute units", units); - + // If we're using a significant portion of the compute limit, add a compute budget if units > 150_000 { // Create a new transaction with compute budget instructions - println!("Transaction needs significant compute units, adding compute budget"); - + println!( + "Transaction needs significant compute units, adding compute budget" + ); + // Extract original instructions from the transaction message // Use the transaction's message instructions directly let message = &transaction.message; - + // Convert CompiledInstructions to regular Instructions - let original_instructions: Vec = message - .instructions - .iter() - .map(|compiled_ix| { - solana_sdk::instruction::Instruction { - program_id: message.account_keys[compiled_ix.program_id_index as usize], - accounts: compiled_ix.accounts.iter() + let original_instructions: Vec = + message + .instructions + .iter() + .map(|compiled_ix| solana_sdk::instruction::Instruction { + program_id: message.account_keys + [compiled_ix.program_id_index as usize], + accounts: compiled_ix + .accounts + .iter() .map(|account_idx| { - let pubkey = message.account_keys[*account_idx as usize]; + let pubkey = + message.account_keys[*account_idx as usize]; solana_sdk::instruction::AccountMeta { pubkey, - is_signer: message.is_signer(*account_idx as usize), - is_writable: message.is_maybe_writable(*account_idx as usize, None), + is_signer: message + .is_signer(*account_idx as usize), + is_writable: message.is_maybe_writable( + *account_idx as usize, + None, + ), } }) .collect(), data: compiled_ix.data.clone(), - } - }) - .collect(); - + }) + .collect(); + // Create compute budget instructions let compute_budget_instructions = create_compute_budget_instructions( DEFAULT_COMPUTE_UNITS, - DEFAULT_PRIORITY_FEE + DEFAULT_PRIORITY_FEE, ); - + // Combine compute budget instructions with original instructions let mut all_instructions = compute_budget_instructions; all_instructions.extend(original_instructions); - + // Get the fee payer let fee_payer = transaction.message.account_keys[0]; - + // Create a new message with all instructions let message = solana_sdk::message::Message::new_with_blockhash( &all_instructions, Some(&fee_payer), - &blockhash + &blockhash, ); - + // Create and sign a new transaction let mut optimized_tx = Transaction::new_unsigned(message); optimized_tx.sign(&signers, blockhash); - + // Use the optimized transaction instead transaction = optimized_tx; - println!("Added compute budget: {} units with {} micro-lamports priority fee", - DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE); + println!( + "Added compute budget: {} units with {} micro-lamports priority fee", + DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE + ); } } - }, + } Err(err) => { - println!("Simulation failed: {:?}, proceeding with regular transaction", err); + println!( + "Simulation failed: {:?}, proceeding with regular transaction", + err + ); // If simulation fails, just use the original transaction transaction.sign(&signers, blockhash); } @@ -140,25 +158,31 @@ pub(crate) fn sign_and_send_transactions( match rpc_client.send_and_confirm_transaction(&transaction) { Ok(signature) => { results.push(signature); - }, + } Err(err) => { let should_continue = if let ClientErrorKind::RpcError( solana_client::rpc_request::RpcError::RpcResponseError { - data: RpcResponseErrorData::SendTransactionPreflightFailure( - RpcSimulateTransactionResult { - err: Some(TransactionError::InstructionError(_, - InstructionError::Custom(err_code))), - .. - } - ), + data: + RpcResponseErrorData::SendTransactionPreflightFailure( + RpcSimulateTransactionResult { + err: + Some(TransactionError::InstructionError( + _, + InstructionError::Custom(err_code), + )), + .. + }, + ), .. - } - ) = err.kind() { + }, + ) = err.kind() + { axelar_solana_gateway::error::GatewayError::from_u32(*err_code) .is_some_and(|gw_err| gw_err.should_relayer_proceed()) } else if let ClientErrorKind::TransactionError( - TransactionError::InstructionError(_, InstructionError::Custom(err_code)) - ) = err.kind() { + TransactionError::InstructionError(_, InstructionError::Custom(err_code)), + ) = err.kind() + { axelar_solana_gateway::error::GatewayError::from_u32(*err_code) .is_some_and(|gw_err| gw_err.should_relayer_proceed()) } else { @@ -166,8 +190,10 @@ pub(crate) fn sign_and_send_transactions( }; if should_continue { - println!("Transaction error: GatewayError (code: {:?}), but continuing with next transaction as it's recoverable", - err.kind()); + println!( + "Transaction error: GatewayError (code: {:?}), but continuing with next transaction as it's recoverable", + err.kind() + ); continue; } else { println!("Transaction error: {:?}", err); @@ -184,4 +210,4 @@ pub(crate) fn sign_and_send_transactions( } Ok(()) -} \ No newline at end of file +} diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index 838e739c7..af6899f9e 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -8,10 +8,7 @@ use clap::ArgEnum; use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::{Deserialize, Serialize}; use solana_sdk::{ - hash::Hash, - instruction::Instruction as SolanaInstruction, - message::Message, - pubkey::Pubkey, + instruction::Instruction as SolanaInstruction, pubkey::Pubkey, transaction::Transaction as SolanaTransaction, }; @@ -167,7 +164,10 @@ pub struct SerializableSolanaTransaction { impl SerializableSolanaTransaction { pub fn new(transaction: SolanaTransaction, params: SolanaTransactionParams) -> Self { - Self { transaction, params } + Self { + transaction, + params, + } } pub fn to_unsigned(&self) -> UnsignedSolanaTransaction { @@ -176,11 +176,15 @@ impl SerializableSolanaTransaction { let signable_message_hex = hex::encode(&message_bytes); // Convert compiled instructions back to SerializableInstruction - let instructions = message.instructions.iter() + let instructions = message + .instructions + .iter() .map(|compiled_ix| { let ix = SolanaInstruction { program_id: message.account_keys[compiled_ix.program_id_index as usize], - accounts: compiled_ix.accounts.iter() + accounts: compiled_ix + .accounts + .iter() .map(|account_idx| { let pubkey = message.account_keys[*account_idx as usize]; solana_sdk::instruction::AccountMeta { @@ -213,9 +217,8 @@ pub struct SendArgs { #[derive(Debug, Clone)] pub struct GenerateArgs { pub fee_payer: Pubkey, - pub nonce_account: Option, - pub nonce_authority: Option, - pub recent_blockhash: Option, + pub nonce_account: Pubkey, + pub nonce_authority: Pubkey, pub output_file: String, } @@ -233,23 +236,10 @@ pub struct CombineArgs { pub output_signed_tx_path: PathBuf, } -#[derive(Debug, Clone)] -pub struct CombineMultipleArgs { - pub unsigned_tx_paths: Vec, - pub signature_paths_per_tx: Vec>, - pub output_signed_tx_paths: Vec, -} - #[derive(Debug, Clone)] pub struct BroadcastArgs { pub signed_tx_path: PathBuf, } - -#[derive(Debug, Clone)] -pub struct BroadcastMultipleArgs { - pub signed_tx_paths: Vec, -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SerializeableVerifierSet { pub signers: BTreeMap, diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index 9f7985d28..be717ec77 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -11,7 +11,7 @@ use solana_sdk::{ pubkey::Pubkey, signature::Signature, }; use std::fs::File; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str::FromStr; use crate::config::Config; @@ -63,21 +63,21 @@ pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; pub(crate) fn read_json_file(file: &File) -> Result { let reader = std::io::BufReader::new(file); - serde_json::from_reader(reader).map_err(|e| AppError::JsonError(e)) + serde_json::from_reader(reader).map_err(AppError::JsonError) } pub(crate) fn write_json_file(data: &T, file: &File) -> Result<()> { let writer = std::io::BufWriter::new(file); - serde_json::to_writer_pretty(writer, data).map_err(|e| AppError::JsonError(e)) + serde_json::to_writer_pretty(writer, data).map_err(AppError::JsonError) } pub(crate) fn read_json_file_from_path(path: &Path) -> Result { - let file = File::open(path).map_err(|e| AppError::IoError(e))?; + let file = File::open(path).map_err(AppError::IoError)?; read_json_file(&file) } pub(crate) fn write_json_to_file_path(data: &T, path: &Path) -> Result<()> { - let file = File::create(path).map_err(|e| AppError::IoError(e))?; + let file = File::create(path).map_err(AppError::IoError)?; write_json_file(data, &file) } @@ -135,56 +135,6 @@ pub(crate) fn save_signed_solana_transaction( write_json_to_file_path(tx, path) } -pub(crate) fn create_offline_bundle( - bundle_name: &str, - output_dir: &Path, - files_to_include: &[(&str, &Path)], -) -> Result { - let target_path = output_dir.join(format!("{}.tar.gz", bundle_name)); - let tar_gz_file = File::create(&target_path).unwrap(); - let gz_encoder = flate2::write::GzEncoder::new(tar_gz_file, flate2::Compression::default()); - let mut tar_builder = tar::Builder::new(gz_encoder); - tar_builder.follow_symlinks(true); - - for (name_in_archive, path_on_disk) in files_to_include { - if !path_on_disk.exists() { - return Err(AppError::PackagingError(format!( - "File specified for packaging not found: {}", - path_on_disk.display() - ))); - } - if path_on_disk.is_file() { - println!( - "Adding file to bundle: {} (from {})", - name_in_archive, - path_on_disk.display() - ); - tar_builder - .append_path_with_name(path_on_disk, name_in_archive) - .unwrap(); - } else if path_on_disk.is_dir() { - println!( - "Adding directory to bundle: {} (from {})", - name_in_archive, - path_on_disk.display() - ); - tar_builder - .append_dir_all(name_in_archive, path_on_disk) - .unwrap(); - } else { - return Err(AppError::PackagingError(format!( - "Path specified for packaging is not a file or directory: {}", - path_on_disk.display() - ))); - } - } - - let gz_encoder = tar_builder.into_inner().unwrap(); - gz_encoder.finish().unwrap(); - - Ok(target_path) -} - pub(crate) fn encode_its_destination( chains_info: &serde_json::Value, destination_chain: &str, @@ -259,7 +209,7 @@ pub(crate) fn print_transaction_result(config: &Config, result: Result eyre::Result { @@ -362,7 +311,7 @@ fn secret_from_bytes(b: &[u8]) -> Option { SecretKey::from_pkcs8_der(b) .ok() .or_else(|| SecretKey::from_sec1_der(b).ok()) - .or_else(|| (b.len() == 32).then(|| SecretKey::from_bytes(b.try_into().ok()?).ok())?) + .or_else(|| (b.len() == 32).then(|| SecretKey::from_bytes(b.into()).ok())?) } fn secret_from_str(s: &str) -> Option { From d0f268a700d7f0f12257ed535fddaa185aaeb213 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 9 May 2025 16:23:20 +0200 Subject: [PATCH 26/59] refactor(solana): be consistent with error handling Since we 1) don't need to handle errors, just return them and 2) want to be consistent, let's just use eyre for all the error handling and not create custom errors. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/Cargo.lock | 1 - solana/cli/Cargo.toml | 3 +- solana/cli/src/broadcast.rs | 35 ++++++------- solana/cli/src/combine.rs | 22 +++------ solana/cli/src/config.rs | 15 +++--- solana/cli/src/error.rs | 93 ----------------------------------- solana/cli/src/gas_service.rs | 4 +- solana/cli/src/gateway.rs | 27 +++++----- solana/cli/src/generate.rs | 3 +- solana/cli/src/governance.rs | 30 +++++------ solana/cli/src/its.rs | 13 ++--- solana/cli/src/main.rs | 6 +-- solana/cli/src/send.rs | 20 +++----- solana/cli/src/sign.rs | 30 ++++------- solana/cli/src/types.rs | 15 +++--- solana/cli/src/utils.rs | 80 ++++++++++++++++-------------- 16 files changed, 142 insertions(+), 255 deletions(-) delete mode 100644 solana/cli/src/error.rs diff --git a/solana/cli/Cargo.lock b/solana/cli/Cargo.lock index d596686eb..163290b96 100644 --- a/solana/cli/Cargo.lock +++ b/solana/cli/Cargo.lock @@ -1441,7 +1441,6 @@ dependencies = [ "spl-token 8.0.0", "spl-token-2022 8.0.1", "tar", - "thiserror 2.0.12", "tokio", "voting-verifier", "walkdir", diff --git a/solana/cli/Cargo.toml b/solana/cli/Cargo.toml index 774a0df94..a04fea4dc 100644 --- a/solana/cli/Cargo.toml +++ b/solana/cli/Cargo.toml @@ -41,7 +41,7 @@ clap = { version = "3.2", features = ["derive", "env"] } cosmrs = { version = "0.16", features = ["cosmwasm", "rpc", "grpc"] } cosmwasm-schema = "2" cosmwasm-std = "1.5" -eyre = "0.6.12" +eyre = "0.6.11" flate2 = { version = "1.1.1", default-features = false, features = ["zlib"] } hex = { version = "0.4.3", features = ["serde"] } k256 = { version = "0.13", features = ["pkcs8", "pem", "ecdsa"] } @@ -59,6 +59,5 @@ spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] spl-token = { version = "8.0.0", features = ["no-entrypoint"] } spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } tar = "0.4.44" -thiserror = "2.0.12" tokio = { version = "1", features = ["full"] } walkdir = "2.5.0" diff --git a/solana/cli/src/broadcast.rs b/solana/cli/src/broadcast.rs index 8c2828737..5b8572f97 100644 --- a/solana/cli/src/broadcast.rs +++ b/solana/cli/src/broadcast.rs @@ -1,8 +1,8 @@ use crate::config::Config; -use crate::error::{AppError, Result}; use crate::types::{BroadcastArgs, SignedSolanaTransaction}; use crate::utils::{self, print_transaction_result}; use axelar_solana_gateway::num_traits::FromPrimitive; +use eyre::eyre; use solana_client::{ client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, rpc_response::RpcSimulateTransactionResult, @@ -23,7 +23,7 @@ use std::str::FromStr; fn submit_solana_transaction( url: &str, signed_tx_data: &SignedSolanaTransaction, -) -> Result { +) -> eyre::Result { println!( "Reconstructing Solana transaction for broadcasting via RPC: {}", url @@ -37,7 +37,7 @@ fn submit_solana_transaction( .instructions .iter() .map(SolanaInstruction::try_from) - .collect::>>()?; + .collect::>>()?; let message = Message::new(&sdk_instructions, Some(&fee_payer)); @@ -50,7 +50,7 @@ fn submit_solana_transaction( Signature::from_str(&ps.signature)?, )) }) - .collect::>>()?; + .collect::>>()?; let mut ordered_signatures: Vec = Vec::with_capacity(message.header.num_required_signatures as usize); @@ -74,9 +74,9 @@ fn submit_solana_transaction( } if missing_sig_for_required_signer { - return Err(AppError::BroadcastError( - "Cannot broadcast: Missing signature for one or more required signers during final reconstruction.".to_string() - )); + eyre::bail!( + "Cannot broadcast: Missing signature for one or more required signers during final reconstruction." + ); } if !signatures_map.is_empty() { @@ -92,11 +92,11 @@ fn submit_solana_transaction( let mut transaction = Transaction::new_unsigned(message); if ordered_signatures.len() != transaction.signatures.len() { - return Err(AppError::InconsistentState(format!( + eyre::bail!( "Signature count mismatch during reconstruction: Expected {} based on message header, but gathered {}.", transaction.signatures.len(), ordered_signatures.len() - ))); + ); } transaction.signatures = ordered_signatures; transaction.message.recent_blockhash = recent_blockhash; @@ -107,10 +107,10 @@ fn submit_solana_transaction( ); if let Err(e) = transaction.verify() { - return Err(AppError::BroadcastError(format!( + eyre::bail!( "Constructed transaction failed structural verification: {}", e - ))); + ); } println!("Connecting to RPC client at {}", url); @@ -200,25 +200,23 @@ fn submit_solana_transaction( } // Return the error as non-recoverable - Err(AppError::from(client_err)) + Err(eyre!("RPC client error: {}", client_err)) } } } } -pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Result<()> { +pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> eyre::Result<()> { println!("Starting Solana transaction broadcast..."); - // Load the signed transaction data, handling potential format issues let signed_tx_data = match utils::load_signed_solana_transaction(&args.signed_tx_path) { Ok(tx_data) => tx_data, - Err(AppError::JsonError(e)) => { - // Provide more helpful error message for JSON parsing errors - return Err(AppError::BroadcastError(format!( + Err(e) if e.to_string().contains("json") => { + eyre::bail!( "Failed to parse transaction file. Make sure you're using a file generated by the 'combine' command, \ not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", e - ))); + ); } Err(e) => return Err(e), }; @@ -229,7 +227,6 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> Re match submit_solana_transaction(&config.url, &signed_tx_data) { Ok(signature) => { - // Handle the special case where we return a default signature for recoverable errors if signature == Signature::default() { println!( "Transaction had a recoverable error - operation complete with recoverable error" diff --git a/solana/cli/src/combine.rs b/solana/cli/src/combine.rs index 34784a227..8906193c3 100644 --- a/solana/cli/src/combine.rs +++ b/solana/cli/src/combine.rs @@ -1,5 +1,4 @@ use crate::config::Config; -use crate::error::{AppError, Result}; use crate::types::{CombineArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; use crate::utils; use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; @@ -10,7 +9,7 @@ fn get_required_signers_from_instructions( instructions: &[crate::types::SerializableInstruction], fee_payer: &Pubkey, nonce_authority: Option<&Pubkey>, -) -> Result> { +) -> eyre::Result> { let mut signers = HashSet::new(); signers.insert(*fee_payer); if let Some(na) = nonce_authority { @@ -26,7 +25,7 @@ fn get_required_signers_from_instructions( Ok(signers) } -pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result<()> { +pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::Result<()> { println!("Starting Solana signature combination..."); let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; @@ -80,18 +79,16 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result< } if let Some(existing_sig) = signatures_map.insert(signer_pubkey, signature) { if existing_sig != signature { - return Err(AppError::CombinationError(format!( + eyre::bail!( "Conflicting signatures provided for the same signer: {}.", signer_pubkey - ))); + ); } } } if signatures_map.is_empty() { - return Err(AppError::CombinationError( - "No valid signatures were loaded from the provided paths.".to_string(), - )); + eyre::bail!("No valid signatures were loaded from the provided paths."); } println!("Loaded {} unique signatures.", signatures_map.len()); @@ -103,20 +100,17 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> Result< } if !missing_signers.is_empty() { - return Err(AppError::CombinationError(format!( - "Missing required signatures for: {:?}", - missing_signers - ))); + eyre::bail!("Missing required signatures for: {:?}", missing_signers); } println!("Validation OK: All required signers have provided signatures."); let message_bytes = hex::decode(&unsigned_tx.signable_message_hex)?; for (signer_pubkey, signature) in &signatures_map { if !signature.verify(signer_pubkey.as_ref(), &message_bytes) { - return Err(AppError::CombinationError(format!( + eyre::bail!( "Signature verification failed for signer: {}", signer_pubkey - ))); + ); } } diff --git a/solana/cli/src/config.rs b/solana/cli/src/config.rs index 22e0fbe91..2b5f8228b 100644 --- a/solana/cli/src/config.rs +++ b/solana/cli/src/config.rs @@ -1,11 +1,9 @@ +use eyre::eyre; use std::path::PathBuf; use std::{fs, str::FromStr}; use crate::types::ChainsInfoFile; -use crate::{ - error::{AppError, Result}, - types::NetworkType, -}; +use crate::types::NetworkType; #[derive(Debug)] pub struct Config { @@ -16,16 +14,17 @@ pub struct Config { } impl Config { - pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> Result { + pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> eyre::Result { println!("URL: {}", url); if !output_dir.exists() { - fs::create_dir_all(&output_dir).map_err(AppError::IoError)?; + fs::create_dir_all(&output_dir) + .map_err(|e| eyre!("Failed to create output directory: {}", e))?; println!("Created output directory: {}", output_dir.display()); } else if !output_dir.is_dir() { - return Err(AppError::ConfigError(format!( + eyre::bail!( "Specified output path exists but is not a directory: {}", output_dir.display() - ))); + ); } let network_type = NetworkType::from_str(&url)?; diff --git a/solana/cli/src/error.rs b/solana/cli/src/error.rs deleted file mode 100644 index 914271f25..000000000 --- a/solana/cli/src/error.rs +++ /dev/null @@ -1,93 +0,0 @@ -use solana_sdk::{hash::ParseHashError, transaction::TransactionError}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum AppError { - #[error("Configuration Error: {0}")] - ConfigError(String), - - #[error("I/O Error: {0}")] - IoError(#[from] std::io::Error), - - #[error("Serialization Error (JSON): {0}")] - JsonError(#[from] serde_json::Error), - - #[error("Serialization Error (Hex): {0}")] - HexError(#[from] hex::FromHexError), - - #[error("Serialization Error (Base58): {0}")] - Base58Error(#[from] bs58::decode::Error), - - #[error("Serialization Error (Bincode): {0}")] - BincodeError(#[from] bincode::error::EncodeError), - - #[error("Packaging Error: {0}")] - PackagingError(String), - - #[error("Signing Error: {0}")] - SigningError(String), - - #[error("Hardware Wallet Error: {0}")] - HardwareWalletError(String), - - #[error("Key Not Found: {0}")] - KeyNotFoundError(String), - - #[error("Signature Combination Error: {0}")] - CombinationError(String), - - #[error("Broadcasting Error: {0}")] - BroadcastError(String), - - #[error("Sending error: {0}")] - SendError(String), - - #[error("Invalid Input: {0}")] - InvalidInput(String), - - #[error("Blockchain Interaction Error: {0}")] - ChainError(String), - - #[error("Invalid Network Type: {0}")] - InvalidNetworkType(String), - - #[error("Solana RPC Client Error: {0}")] - SolanaClientError(#[from] solana_client::client_error::ClientError), - - #[error("Solana Program/SDK Error: {0}")] - SolanaProgSdkError(String), - - #[error("Inconsistent State: {0}")] - InconsistentState(String), - - #[error("Feature Not Implemented: {0}")] - NotImplemented(String), - - #[error("Failed to parse hash: {0}")] - ParseHashError(#[from] ParseHashError), - - #[error("Transaction error: {0}")] - TransactionError(#[from] TransactionError), - - #[error("Unknown Error: {0}")] - Unknown(String), -} - -impl From for AppError { - fn from(err: solana_sdk::pubkey::ParsePubkeyError) -> Self { - AppError::InvalidInput(format!("Invalid Solana Pubkey: {}", err)) - } -} -impl From for AppError { - fn from(err: solana_sdk::signature::ParseSignatureError) -> Self { - AppError::InvalidInput(format!("Invalid Solana Signature: {}", err)) - } -} - -impl From for AppError { - fn from(err: solana_sdk::program_error::ProgramError) -> Self { - AppError::SolanaProgSdkError(format!("Solana Program Error: {}", err)) - } -} - -pub type Result = std::result::Result; diff --git a/solana/cli/src/gas_service.rs b/solana/cli/src/gas_service.rs index 35048249a..55b0bb917 100644 --- a/solana/cli/src/gas_service.rs +++ b/solana/cli/src/gas_service.rs @@ -7,8 +7,8 @@ use crate::{ config::Config, types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, + CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, }, }; diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 6e638bd13..9f16a6abb 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -13,6 +13,7 @@ use axelar_solana_gateway::state::config::RotationDelaySecs; use axelar_solana_gateway::state::incoming_message::command_id; use clap::{ArgGroup, Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; +use eyre::eyre; use k256::ecdsa::SigningKey; use k256::elliptic_curve::sec1::ToEncodedPoint; use multisig_prover::msg::ProofStatus; @@ -30,10 +31,10 @@ use crate::types::{ SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, - GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, - PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, + DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, + OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, }; use solana_sdk::message::Message as SolanaMessage; use solana_sdk::transaction::Transaction as SolanaTransaction; @@ -261,15 +262,19 @@ async fn get_verifier_set( chains_info: &serde_json::Value, ) -> eyre::Result { if let Some(signer_key) = signer { - let key_bytes: [u8; 33] = hex::decode(signer_key.strip_prefix("0x").unwrap_or(signer_key)) - .map_err(|_| eyre::eyre!("Failed to decode hex"))? + let key_bytes: [u8; 33] = hex::decode(signer_key.strip_prefix("0x").unwrap_or(signer_key))? .try_into() - .map_err(|_| eyre::eyre!("Invalid signer pubkey"))?; + .map_err(|_| eyre!("Invalid key length"))?; let pk = k256::PublicKey::from_sec1_bytes(&key_bytes)?; - let pubkey = PublicKey::Secp256k1(pk.to_encoded_point(true).as_bytes().try_into()?); + let pubkey = PublicKey::Secp256k1( + pk.to_encoded_point(true) + .as_bytes() + .try_into() + .map_err(|_| eyre!("Invalid encoded point conversion"))?, + ); let signers = BTreeMap::from([(pubkey, 1_u128)]); - let nonce = nonce.ok_or(eyre::eyre!("Unexpected error: nonce is required"))?; + let nonce = nonce.ok_or_else(|| eyre!("Nonce is required"))?; Ok(VerifierSet { nonce, @@ -343,11 +348,11 @@ async fn construct_execute_data( Signature::EcdsaRecoverable( signature_bytes .try_into() - .map_err(|_e| eyre::eyre!("Invalid signature"))?, + .map_err(|_e| eyre!("Invalid signature"))?, ), )) }) - .collect::, eyre::Report>>()?; + .collect::>>()?; let execute_data_bytes = axelar_solana_encoding::encode( &signer_set.verifier_set(), &signatures, diff --git a/solana/cli/src/generate.rs b/solana/cli/src/generate.rs index 23d5caf40..c91c56ba1 100644 --- a/solana/cli/src/generate.rs +++ b/solana/cli/src/generate.rs @@ -1,5 +1,4 @@ use crate::config::Config; -use crate::error::Result; use crate::types::{GenerateArgs, SerializableSolanaTransaction}; use crate::utils::{self, fetch_nonce_data_and_verify}; @@ -7,7 +6,7 @@ pub fn generate_from_transactions( args: &GenerateArgs, config: &Config, mut transactions: Vec, -) -> Result<()> { +) -> eyre::Result<()> { println!("Starting unsigned Solana transaction generation from transactions..."); println!("Network Type: {:?}", config.network_type); println!("Fee Payer: {}", args.fee_payer); diff --git a/solana/cli/src/governance.rs b/solana/cli/src/governance.rs index 4dd16e53c..15684e2dd 100644 --- a/solana/cli/src/governance.rs +++ b/solana/cli/src/governance.rs @@ -10,10 +10,10 @@ use crate::{ config::Config, types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, - GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, - UPGRADE_AUTHORITY_KEY, fetch_latest_blockhash, parse_account_meta_string, - read_json_file_from_path, write_json_to_file_path, + fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, + GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, + MINIMUM_PROPOSAL_ETA_DELAY_KEY, UPGRADE_AUTHORITY_KEY, }, }; @@ -186,11 +186,9 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(vec![ - IxBuilder::new() - .initialize_config(fee_payer, config_pda, governance_config) - .build(), - ]) + Ok(vec![IxBuilder::new() + .initialize_config(fee_payer, config_pda, governance_config) + .build()]) } async fn execute_proposal( @@ -217,9 +215,9 @@ async fn execute_proposal( calldata_bytes, ); - Ok(vec![ - builder.execute_proposal(fee_payer, config_pda).build(), - ]) + Ok(vec![builder + .execute_proposal(fee_payer, config_pda) + .build()]) } async fn execute_operator_proposal( @@ -243,9 +241,7 @@ async fn execute_operator_proposal( calldata_bytes, ); - Ok(vec![ - builder - .execute_operator_proposal(fee_payer, config_pda, &args.operator) - .build(), - ]) + Ok(vec![builder + .execute_operator_proposal(fee_payer, config_pda, &args.operator) + .build()]) } diff --git a/solana/cli/src/its.rs b/solana/cli/src/its.rs index c6023d00a..7f6a27dd4 100644 --- a/solana/cli/src/its.rs +++ b/solana/cli/src/its.rs @@ -2,6 +2,7 @@ use std::{fs::File, io::Write, time::SystemTime}; use axelar_solana_its::state; use clap::{Parser, Subcommand}; +use eyre::eyre; use serde::Deserialize; use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; @@ -10,9 +11,9 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, - read_json_file_from_path, write_json_to_file_path, + encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, + CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -233,7 +234,7 @@ fn parse_hex_vec(s: &str) -> Result, hex::FromHexError> { fn parse_hex_bytes32(s: &str) -> eyre::Result<[u8; 32]> { let decoded: [u8; 32] = hex::decode(s.strip_prefix("0x").unwrap_or(s))? .try_into() - .map_err(|_| eyre::eyre!("Invalid hex string length. Expected 32 bytes."))?; + .map_err(|_| eyre!("Invalid hex string length. Expected 32 bytes."))?; Ok(decoded) } @@ -264,7 +265,7 @@ fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre: let id = Pubkey::deserialize( &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] [GAS_SERVICE_KEY][ADDRESS_KEY], - ).map_err(|_| eyre::eyre!( + ).map_err(|_| eyre!( "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ Please update the file or pass a value to --gas-service"))?; @@ -284,7 +285,7 @@ fn try_infer_gas_service_config_account( let id = Pubkey::deserialize( &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], - ).map_err(|_| eyre::eyre!( + ).map_err(|_| eyre!( "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ Please update the file or pass a value to --gas-config-account"))?; diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index baa78d412..f45b2ca9e 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -1,7 +1,6 @@ mod broadcast; mod combine; mod config; -mod error; mod gas_service; mod gateway; mod generate; @@ -13,6 +12,7 @@ mod types; mod utils; use clap::{Parser, Subcommand}; +use eyre::eyre; use send::sign_and_send_transactions; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; @@ -218,7 +218,7 @@ async fn run() -> eyre::Result<()> { None => { let config_file = solana_cli_config::CONFIG_FILE .as_ref() - .ok_or_else(|| eyre::eyre!("Missing Solana config file"))?; + .ok_or_else(|| eyre!("Missing Solana config file"))?; let cli_config = solana_cli_config::Config::load(config_file)?; let signer_context = clap::ArgMatches::default(); let signer = signer_from_path( @@ -227,7 +227,7 @@ async fn run() -> eyre::Result<()> { "signer", &mut None, ) - .map_err(|e| eyre::eyre!("Failed to load fee payer: {}", e))?; + .map_err(|e| eyre!("Failed to load fee payer: {}", e))?; signer_keys.push(cli_config.keypair_path); signer.pubkey() diff --git a/solana/cli/src/send.rs b/solana/cli/src/send.rs index 93eb7443c..274cd1e4c 100644 --- a/solana/cli/src/send.rs +++ b/solana/cli/src/send.rs @@ -1,4 +1,5 @@ use axelar_solana_gateway::num_traits::FromPrimitive; +use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; use solana_client::{ client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, @@ -11,18 +12,17 @@ use solana_sdk::{ }; use crate::config::Config; -use crate::error::{AppError, Result}; use crate::types::{SendArgs, SerializableSolanaTransaction}; use crate::utils::{ - DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, create_compute_budget_instructions, - print_transaction_result, + create_compute_budget_instructions, print_transaction_result, DEFAULT_COMPUTE_UNITS, + DEFAULT_PRIORITY_FEE, }; pub(crate) fn sign_and_send_transactions( send_args: &SendArgs, config: &Config, serializable_txs: Vec, -) -> Result<()> { +) -> eyre::Result<()> { let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); let mut results = Vec::new(); @@ -30,19 +30,15 @@ pub(crate) fn sign_and_send_transactions( let mut transaction = serializable_tx.transaction; if send_args.signers.len() < transaction.signatures.len() { - return Err(AppError::SigningError( - "Not enough signers provided".to_string(), - )); + eyre::bail!("Not enough signers provided"); } let mut signers = Vec::with_capacity(transaction.signatures.len()); let signer_context = clap::ArgMatches::default(); // Dummy context for signer in send_args.signers.iter() { - let signer = - signer_from_path(&signer_context, signer, "signer", &mut None).map_err(|e| { - AppError::SigningError(format!("Failed to load signer '{}': {}", signer, e)) - })?; + let signer = signer_from_path(&signer_context, signer, "signer", &mut None) + .map_err(|e| eyre!("Failed to load signer '{}': {}", signer, e))?; signers.push(signer); } @@ -197,7 +193,7 @@ pub(crate) fn sign_and_send_transactions( continue; } else { println!("Transaction error: {:?}", err); - return Err(AppError::from(err)); + eyre::bail!("Transaction simulation error: {:?}", err); } } } diff --git a/solana/cli/src/sign.rs b/solana/cli/src/sign.rs index 2b73fe9ff..3f3dfa61d 100644 --- a/solana/cli/src/sign.rs +++ b/solana/cli/src/sign.rs @@ -1,6 +1,6 @@ -use crate::error::{AppError, Result}; use crate::types::{PartialSignature, SignArgs}; // Removed NetworkType import use crate::utils; +use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::{pubkey::Pubkey, signer::Signer}; use std::collections::HashSet; @@ -10,7 +10,7 @@ fn get_required_signers_from_instructions( instructions: &[crate::types::SerializableInstruction], fee_payer: &Pubkey, nonce_authority: Option<&Pubkey>, -) -> Result> { +) -> eyre::Result> { let mut signers = HashSet::new(); signers.insert(*fee_payer); @@ -28,7 +28,7 @@ fn get_required_signers_from_instructions( Ok(signers) } -pub fn sign_solana_transaction(args: &SignArgs) -> Result<()> { +pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { println!("Starting Solana transaction signing..."); let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; @@ -38,10 +38,10 @@ pub fn sign_solana_transaction(args: &SignArgs) -> Result<()> { ); let message_bytes = hex::decode(&unsigned_tx.signable_message_hex).map_err(|e| { - AppError::SigningError(format!( + eyre!( "Failed to decode signable_message_hex from unsigned tx file: {}", e - )) + ) })?; println!( "Decoded message bytes ({} bytes) to sign.", @@ -50,24 +50,16 @@ pub fn sign_solana_transaction(args: &SignArgs) -> Result<()> { println!("Loading signer from: {}", args.signer_key); let signer_context = clap::ArgMatches::default(); // Dummy context - let signer = - signer_from_path(&signer_context, &args.signer_key, "signer", &mut None).map_err(|e| { - AppError::SigningError(format!( - "Failed to load signer '{}': {}", - args.signer_key, e - )) - })?; + let signer = signer_from_path(&signer_context, &args.signer_key, "signer", &mut None) + .map_err(|e| eyre!("Failed to load signer '{}': {}", args.signer_key, e))?; let signer_pubkey = signer.pubkey(); println!("Signer loaded successfully. Pubkey: {}", signer_pubkey); println!("Signing message with loaded signer..."); - let signature = signer.try_sign_message(&message_bytes).map_err(|e| { - AppError::SigningError(format!( - "Failed to sign message using '{}': {}", - args.signer_key, e - )) - })?; + let signature = signer + .try_sign_message(&message_bytes) + .map_err(|e| eyre!("Failed to sign message using '{}': {}", args.signer_key, e))?; println!("Generated signature: {}", signature); let partial_signature = PartialSignature { @@ -94,8 +86,6 @@ pub fn sign_solana_transaction(args: &SignArgs) -> Result<()> { "Warning: Signer {} provided a signature, but is not found in the list of required signers (Fee Payer, Nonce Authority, or Instruction Signers).", signer_pubkey ); - // Consider making this an error: - // return Err(AppError::SigningError(format!("Signer {} is not required by the transaction", signer_pubkey))); } else { println!( "Validation OK: Signer {} is required by the transaction.", diff --git a/solana/cli/src/types.rs b/solana/cli/src/types.rs index af6899f9e..17f6d950c 100644 --- a/solana/cli/src/types.rs +++ b/solana/cli/src/types.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use axelar_solana_encoding::types::pubkey::PublicKey; use axelar_solana_encoding::types::verifier_set::VerifierSet; use clap::ArgEnum; +use eyre::eyre; use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::{Deserialize, Serialize}; use solana_sdk::{ @@ -12,8 +13,6 @@ use solana_sdk::{ transaction::Transaction as SolanaTransaction, }; -use crate::error::{AppError, Result}; - #[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] pub enum NetworkType { Mainnet, @@ -23,15 +22,15 @@ pub enum NetworkType { } impl FromStr for NetworkType { - type Err = AppError; + type Err = eyre::Error; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> eyre::Result { s.contains("mainnet") .then_some(NetworkType::Mainnet) .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) .or_else(|| s.contains("devnet").then_some(NetworkType::Devnet)) .or_else(|| s.contains("local").then_some(NetworkType::Localnet)) - .ok_or_else(|| AppError::InvalidNetworkType(s.to_string())) + .ok_or_else(|| eyre!("Invalid network type: {}", s)) } } @@ -94,9 +93,9 @@ pub struct SerializableAccountMeta { } impl TryFrom<&SerializableInstruction> for SolanaInstruction { - type Error = AppError; + type Error = eyre::Error; - fn try_from(si: &SerializableInstruction) -> Result { + fn try_from(si: &SerializableInstruction) -> eyre::Result { let program_id = Pubkey::from_str(&si.program_id)?; let accounts = si .accounts @@ -108,7 +107,7 @@ impl TryFrom<&SerializableInstruction> for SolanaInstruction { is_writable: sa.is_writable, }) }) - .collect::>>()?; + .collect::>>()?; Ok(SolanaInstruction { program_id, diff --git a/solana/cli/src/utils.rs b/solana/cli/src/utils.rs index be717ec77..a6ae7cbc9 100644 --- a/solana/cli/src/utils.rs +++ b/solana/cli/src/utils.rs @@ -1,3 +1,4 @@ +use eyre::eyre; use k256::elliptic_curve::FieldBytes; use k256::pkcs8::DecodePrivateKey; use k256::{Secp256k1, SecretKey}; @@ -15,7 +16,6 @@ use std::path::Path; use std::str::FromStr; use crate::config::Config; -use crate::error::{AppError, Result}; use crate::types::{ ChainNameOnAxelar, NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, @@ -61,46 +61,48 @@ pub(crate) const PREVIOUS_SIGNERS_RETENTION_KEY: &str = "previousSignersRetentio pub(crate) const ROUTER_KEY: &str = "Router"; pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; -pub(crate) fn read_json_file(file: &File) -> Result { +pub(crate) fn read_json_file(file: &File) -> eyre::Result { let reader = std::io::BufReader::new(file); - serde_json::from_reader(reader).map_err(AppError::JsonError) + Ok(serde_json::from_reader(reader)?) } -pub(crate) fn write_json_file(data: &T, file: &File) -> Result<()> { +pub(crate) fn write_json_file(data: &T, file: &File) -> eyre::Result<()> { let writer = std::io::BufWriter::new(file); - serde_json::to_writer_pretty(writer, data).map_err(AppError::JsonError) + Ok(serde_json::to_writer_pretty(writer, data)?) } -pub(crate) fn read_json_file_from_path(path: &Path) -> Result { - let file = File::open(path).map_err(AppError::IoError)?; +pub(crate) fn read_json_file_from_path(path: &Path) -> eyre::Result { + let file = File::open(path)?; read_json_file(&file) } -pub(crate) fn write_json_to_file_path(data: &T, path: &Path) -> Result<()> { - let file = File::create(path).map_err(AppError::IoError)?; +pub(crate) fn write_json_to_file_path(data: &T, path: &Path) -> eyre::Result<()> { + let file = File::create(path)?; write_json_file(data, &file) } -pub(crate) fn load_unsigned_solana_transaction(path: &Path) -> Result { +pub(crate) fn load_unsigned_solana_transaction( + path: &Path, +) -> eyre::Result { read_json_file_from_path(path) } pub(crate) fn save_unsigned_solana_transaction( tx: &UnsignedSolanaTransaction, path: &Path, -) -> Result<()> { +) -> eyre::Result<()> { write_json_to_file_path(tx, path) } -pub(crate) fn load_partial_signature(path: &Path) -> Result { +pub(crate) fn load_partial_signature(path: &Path) -> eyre::Result { read_json_file_from_path(path) } -pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> Result<()> { +pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> eyre::Result<()> { write_json_to_file_path(sig, path) } -pub(crate) fn load_signed_solana_transaction(path: &Path) -> Result { +pub(crate) fn load_signed_solana_transaction(path: &Path) -> eyre::Result { // Try to read the file as a SignedSolanaTransaction first match read_json_file_from_path::(path) { Ok(signed_tx) => Ok(signed_tx), @@ -131,7 +133,7 @@ pub(crate) fn load_signed_solana_transaction(path: &Path) -> Result Result<()> { +) -> eyre::Result<()> { write_json_to_file_path(tx, path) } @@ -152,27 +154,27 @@ pub(crate) fn encode_its_destination( /// Parses a string representation of an AccountMeta. /// Format: "pubkey:is_signer:is_writable" (e.g., "SomePubkey...:false:true") -pub fn parse_account_meta_string(s: &str) -> Result { +pub fn parse_account_meta_string(s: &str) -> eyre::Result { let parts: Vec<&str> = s.split(':').collect(); if parts.len() != 3 { - return Err(AppError::InvalidInput(format!( + eyre::bail!( "Invalid AccountMeta format: '{}'. Expected 'pubkey:is_signer:is_writable'", s - ))); + ); } let pubkey = Pubkey::from_str(parts[0])?; let is_signer = bool::from_str(parts[1]).map_err(|_| { - AppError::InvalidInput(format!( + eyre!( "Invalid is_signer value: '{}'. Expected 'true' or 'false'", parts[1] - )) + ) })?; let is_writable = bool::from_str(parts[2]).map_err(|_| { - AppError::InvalidInput(format!( + eyre!( "Invalid is_writable value: '{}'. Expected 'true' or 'false'", parts[2] - )) + ) })?; Ok(if is_writable { @@ -182,7 +184,10 @@ pub fn parse_account_meta_string(s: &str) -> Result { }) } -pub(crate) fn print_transaction_result(config: &Config, result: Result) -> Result<()> { +pub(crate) fn print_transaction_result( + config: &Config, + result: eyre::Result, +) -> eyre::Result<()> { match result { Ok(tx_signature) => { println!("------------------------------------------"); @@ -244,41 +249,41 @@ pub(crate) fn parse_secret_key(raw: &str) -> eyre::Result { let bytes = std::fs::read(raw)?; return secret_from_bytes(&bytes) .or_else(|| secret_from_str(std::str::from_utf8(&bytes).ok()?)) - .ok_or_else(|| eyre::eyre!("unrecognised key format in file".to_owned())); + .ok_or_else(|| eyre!("unrecognised key format in file")); } - secret_from_str(raw).ok_or_else(|| eyre::eyre!("unrecognised key format".to_owned())) + secret_from_str(raw).ok_or_else(|| eyre!("unrecognised key format")) } -pub(crate) fn fetch_latest_blockhash(rpc_url: &str) -> Result { +pub(crate) fn fetch_latest_blockhash(rpc_url: &str) -> eyre::Result { let rpc_client = RpcClient::new(rpc_url.to_string()); - rpc_client.get_latest_blockhash().map_err(AppError::from) + Ok(rpc_client.get_latest_blockhash()?) } pub(crate) fn fetch_nonce_data_and_verify( rpc_url: &str, nonce_account_pubkey: &Pubkey, expected_nonce_authority: &Pubkey, -) -> Result { +) -> eyre::Result { let rpc_client = RpcClient::new(rpc_url.to_string()); let nonce_account = rpc_client.get_account(nonce_account_pubkey)?; if !solana_sdk::system_program::check_id(&nonce_account.owner) { - return Err(AppError::InvalidInput(format!( + eyre::bail!( "Nonce account {} is not owned by the system program ({}), owner is {}", nonce_account_pubkey, solana_sdk::system_program::id(), nonce_account.owner - ))); + ); } // Try with regular bincode deserialization let nonce_state: solana_sdk::nonce::state::State = StateMut::::state(&nonce_account) .map_err(|_| { - AppError::InvalidInput(format!( + eyre!( "Failed to deserialize nonce account {}", nonce_account_pubkey - )) + ) })? .into(); @@ -290,20 +295,21 @@ pub(crate) fn fetch_nonce_data_and_verify( // If there's a mismatch, we'll print a warning but still proceed if data.authority != *expected_nonce_authority { - return Err(AppError::InvalidInput(format!( + return Err(eyre!( "Nonce account authority mismatch: expected {}, found {}", - expected_nonce_authority, data.authority - ))); + expected_nonce_authority, + data.authority + )); } // Always return the blockhash, regardless of authority mismatch // This works around potential deserialization issues Ok(data.blockhash()) } - solana_sdk::nonce::state::State::Uninitialized => Err(AppError::InvalidInput(format!( + solana_sdk::nonce::state::State::Uninitialized => Err(eyre!( "Nonce account {} is uninitialized", nonce_account_pubkey - ))), + )), } } From 012411d151ca00b59933bd62ff5993b9e9dd6b7c Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Mon, 12 May 2025 11:12:37 +0200 Subject: [PATCH 27/59] fix(solana): use correct hash function Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/gateway.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/solana/cli/src/gateway.rs b/solana/cli/src/gateway.rs index 9f16a6abb..3acd5b0cc 100644 --- a/solana/cli/src/gateway.rs +++ b/solana/cli/src/gateway.rs @@ -31,10 +31,10 @@ use crate::types::{ SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, - DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, - OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, + self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, + GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, + PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, }; use solana_sdk::message::Message as SolanaMessage; use solana_sdk::transaction::Transaction as SolanaTransaction; @@ -170,18 +170,24 @@ pub(crate) struct SubmitProofArgs { #[derive(Parser, Debug)] pub(crate) struct ExecuteArgs { + /// Chain where the message originated from #[clap(long)] source_chain: String, + /// Message ID of the message #[clap(long)] message_id: String, + /// Source address of the message in the source chain #[clap(long)] source_address: String, + /// The address on the Solana chain where the message should be sent to #[clap(long)] destination_address: String, + /// The hex encoded string of the AxelarExecutable payload (which contains the raw payload plus + /// accounts required by the destination program). #[clap(long)] payload: String, } @@ -508,7 +514,7 @@ async fn approve( .strip_prefix("0x") .unwrap_or(&approve_args.payload), )?; - let payload_hash = solana_sdk::hash::hashv(&[&payload_bytes]).to_bytes(); + let payload_hash = solana_sdk::keccak::hashv(&[&payload_bytes]).to_bytes(); let message = Message { cc_id: CrossChainId { chain: approve_args.source_chain, @@ -755,7 +761,7 @@ async fn execute( source_address: execute_args.source_address, destination_chain: ChainNameOnAxelar::from(config.network_type).0, destination_address: execute_args.destination_address, - payload_hash: solana_sdk::hash::hashv(&[&hex::decode( + payload_hash: solana_sdk::keccak::hashv(&[&hex::decode( execute_args .payload .strip_prefix("0x") From 73110630d63b5dff0a204b2e4908948f4921c4ce Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Mon, 12 May 2025 11:13:06 +0200 Subject: [PATCH 28/59] feat(solana): add misc helper commands The first being build-axelar-message. If anyone has raw payload data and want to send it to solana, an axelar executable payload has to be created from the payload plus the required accounts. Signed-off-by: Guilherme Felipe da Silva --- solana/cli/src/main.rs | 18 +++++++++- solana/cli/src/misc.rs | 80 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 solana/cli/src/misc.rs diff --git a/solana/cli/src/main.rs b/solana/cli/src/main.rs index f45b2ca9e..603cf7d35 100644 --- a/solana/cli/src/main.rs +++ b/solana/cli/src/main.rs @@ -6,6 +6,7 @@ mod gateway; mod generate; mod governance; mod its; +mod misc; mod send; mod sign; mod types; @@ -25,6 +26,7 @@ use crate::broadcast::broadcast_solana_transaction; use crate::combine::combine_solana_signatures; use crate::config::Config; use crate::generate::generate_from_transactions; +use crate::misc::build_message; use crate::sign::sign_solana_transaction; use crate::types::{BroadcastArgs, CombineArgs, GenerateArgs, SignArgs}; @@ -97,6 +99,10 @@ enum Command { and broadcasts it to the specified network via RPC. Waits for confirmation." )] Broadcast(BroadcastCommandArgs), + + /// Miscellaneous utilities. + #[clap(long_about = "Miscellaneous utilities for working with Axelar payloads and messages.")] + Misc(MiscCommandArgs), } #[derive(Parser, Debug)] @@ -196,10 +202,16 @@ struct BroadcastCommandArgs { signed_tx_path: PathBuf, } +#[derive(Parser, Debug)] +struct MiscCommandArgs { + #[clap(subcommand)] + instruction: misc::Commands, +} + #[tokio::main] async fn main() { if let Err(e) = run().await { - eprintln!("\nError: {}", e); + eprintln!("\nError: {:?}", e); exit(1); } } @@ -279,6 +291,10 @@ async fn run() -> eyre::Result<()> { }; broadcast_solana_transaction(&broadcast_args, &config)?; } + Command::Misc(args) => { + let result = build_message(args.instruction)?; + println!("{}", result); + } } Ok(()) } diff --git a/solana/cli/src/misc.rs b/solana/cli/src/misc.rs new file mode 100644 index 000000000..c1628c253 --- /dev/null +++ b/solana/cli/src/misc.rs @@ -0,0 +1,80 @@ +use axelar_executable::AxelarMessagePayload; +use axelar_executable::EncodingScheme; +use clap::{Args, Subcommand}; +use eyre::Result; +use solana_sdk::instruction::AccountMeta; +use solana_sdk::pubkey::Pubkey; +use std::str::FromStr; + +/// Commands for miscellaneous utilities +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Build an axelar-executable message + BuildAxelarMessage(BuildAxelarMessageArgs), +} + +#[derive(Args, Debug)] +pub struct BuildAxelarMessageArgs { + /// Accounts in the format of "pubkey:is_signer:is_writable" (e.g., "HQ57JcVZEMkpfEYJRJqnoH6wQdrNqNP6TDvzqnpPYBXQ:true:false"). The order should be the same as expected by the destination program. + #[clap(long, multiple_values = true)] + accounts: Vec, + + /// Raw payload as a hex string + #[clap(long)] + payload: String, + + /// Use ABI encoding instead of Borsh + #[clap(long)] + abi: bool, +} + +/// Build a message for miscellaneous utilities +pub fn build_message(args: Commands) -> Result { + match args { + Commands::BuildAxelarMessage(args) => build_axelar_message(args), + } +} + +fn build_axelar_message(args: BuildAxelarMessageArgs) -> Result { + // Parse accounts + let mut account_metas = Vec::with_capacity(args.accounts.len()); + for account_str in args.accounts { + let parts: Vec<&str> = account_str.split(':').collect(); + if parts.len() != 3 { + return Err(eyre::eyre!( + "Invalid account format. Expected 'pubkey:is_signer:is_writable'" + )); + } + + let pubkey = Pubkey::from_str(parts[0])?; + let is_signer = parts[1].parse::()?; + let is_writable = parts[2].parse::()?; + + account_metas.push(AccountMeta { + pubkey, + is_signer, + is_writable, + }); + } + + // Decode payload from hex + let payload_bytes = hex::decode(&args.payload)?; + + // Set encoding scheme + let encoding_scheme = if args.abi { + EncodingScheme::AbiEncoding + } else { + EncodingScheme::Borsh + }; + + // Build AxelarMessagePayload + let axelar_message = AxelarMessagePayload::new(&payload_bytes, &account_metas, encoding_scheme); + + // Encode the payload + let encoded = axelar_message + .encode() + .map_err(|e| eyre::eyre!("Failed to encode message: {}", e))?; + + // Return the encoded payload as a hex string + Ok(hex::encode(encoded)) +} From 6a72411f532c9615d9d92178dacf00b81c9216c1 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Mon, 12 May 2025 12:31:09 +0200 Subject: [PATCH 29/59] fix(solana): remove changes to devnet-amplifier.json We haven't deployed the contracts yet using the scripts. The JSON should be updated when we first deploy to a chain. Although we have already deployed to devnet, we need a new deployment using the scripts available in this repo. Signed-off-by: Guilherme Felipe da Silva --- axelar-chains-config/info/devnet-amplifier.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 8556bb6ad..4f9576f1d 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -1,19 +1,5 @@ { "chains": { - "solana-devnet": { - "name": "Solana Devnet", - "axelarId": "solana-devnet", - "rpc": "https://api.devnet.solana.com", - "tokenSymbol": "SOL", - "decimals": 9, - "confirmations": 1, - "finality": "finalized", - "approxFinalityWaitTime": 13, - "chainType": "svm", - "explorer": { - "name": "solscan", - "url": "https://solscan.io/?cluster=devnet", - }, "core-avalanche": { "name": "Avalanche Fuji", "axelarId": "core-avalanche", From bec308404ae0f1239839528737be3eef3db8d8fb Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Mon, 12 May 2025 14:25:48 +0200 Subject: [PATCH 30/59] refactor(solana): move cli to solana root dir Signed-off-by: Guilherme Felipe da Silva --- solana/{cli => }/.gitignore | 0 solana/{cli => }/Cargo.lock | 529 ++++++++++++++-------------- solana/{cli => }/Cargo.toml | 2 +- solana/cli/devnet-amplifier.json | 1 - solana/cli/mainnet.json | 1 - solana/cli/testnet.json | 1 - solana/devnet-amplifier.json | 1 + solana/mainnet.json | 1 + solana/{cli => }/src/broadcast.rs | 0 solana/{cli => }/src/combine.rs | 0 solana/{cli => }/src/config.rs | 0 solana/{cli => }/src/gas_service.rs | 0 solana/{cli => }/src/gateway.rs | 0 solana/{cli => }/src/generate.rs | 0 solana/{cli => }/src/governance.rs | 0 solana/{cli => }/src/its.rs | 0 solana/{cli => }/src/main.rs | 0 solana/{cli => }/src/misc.rs | 0 solana/{cli => }/src/send.rs | 0 solana/{cli => }/src/sign.rs | 0 solana/{cli => }/src/types.rs | 0 solana/{cli => }/src/utils.rs | 0 solana/testnet.json | 1 + 23 files changed, 274 insertions(+), 263 deletions(-) rename solana/{cli => }/.gitignore (100%) rename solana/{cli => }/Cargo.lock (97%) rename solana/{cli => }/Cargo.toml (98%) delete mode 120000 solana/cli/devnet-amplifier.json delete mode 120000 solana/cli/mainnet.json delete mode 120000 solana/cli/testnet.json create mode 120000 solana/devnet-amplifier.json create mode 120000 solana/mainnet.json rename solana/{cli => }/src/broadcast.rs (100%) rename solana/{cli => }/src/combine.rs (100%) rename solana/{cli => }/src/config.rs (100%) rename solana/{cli => }/src/gas_service.rs (100%) rename solana/{cli => }/src/gateway.rs (100%) rename solana/{cli => }/src/generate.rs (100%) rename solana/{cli => }/src/governance.rs (100%) rename solana/{cli => }/src/its.rs (100%) rename solana/{cli => }/src/main.rs (100%) rename solana/{cli => }/src/misc.rs (100%) rename solana/{cli => }/src/send.rs (100%) rename solana/{cli => }/src/sign.rs (100%) rename solana/{cli => }/src/types.rs (100%) rename solana/{cli => }/src/utils.rs (100%) create mode 120000 solana/testnet.json diff --git a/solana/cli/.gitignore b/solana/.gitignore similarity index 100% rename from solana/cli/.gitignore rename to solana/.gitignore diff --git a/solana/cli/Cargo.lock b/solana/Cargo.lock similarity index 97% rename from solana/cli/Cargo.lock rename to solana/Cargo.lock index 163290b96..8b7899def 100644 --- a/solana/cli/Cargo.lock +++ b/solana/Cargo.lock @@ -69,7 +69,7 @@ version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "973a83d0d66d1f04647d1146a07736864f0742300b56bf2a5aadf5ce7b22fe47" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "solana-epoch-schedule", "solana-feature-set-interface", "solana-hash", @@ -90,15 +90,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.16", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -846,9 +846,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -964,7 +964,7 @@ dependencies = [ "rand_core 0.6.4", "ripemd", "secp256k1", - "sha2 0.10.8", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -1129,9 +1129,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf19e729cdbd51af9a397fb9ef8ac8378007b797f8273cfbfdf45dcaa316167b" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1154,7 +1154,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2 0.10.8", + "sha2 0.10.9", "tinyvec", ] @@ -1281,9 +1281,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.20" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -1398,54 +1398,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "cli" -version = "0.1.0" -dependencies = [ - "alloy-sol-types", - "anyhow", - "axelar-executable", - "axelar-solana-encoding", - "axelar-solana-gas-service", - "axelar-solana-gateway", - "axelar-solana-governance", - "axelar-solana-its", - "axelar-wasm-std", - "base64 0.22.1", - "bincode 2.0.1", - "borsh 1.5.7", - "bs58", - "clap 3.2.25", - "cosmrs", - "cosmwasm-schema", - "cosmwasm-std 1.5.11", - "eyre", - "flate2", - "governance-gmp", - "hex", - "its-instruction-builder", - "k256", - "multisig-prover", - "program-utils", - "rand 0.9.1", - "reqwest 0.12.15", - "rust_decimal", - "rust_decimal_macros", - "serde", - "serde_json", - "solana-clap-v3-utils", - "solana-cli-config", - "solana-client", - "solana-sdk", - "spl-associated-token-account", - "spl-token 8.0.0", - "spl-token-2022 8.0.1", - "tar", - "tokio", - "voting-verifier", - "walkdir", -] - [[package]] name = "client" version = "1.0.0" @@ -1680,7 +1632,7 @@ dependencies = [ "p256", "rand_core 0.6.4", "rayon", - "sha2 0.10.8", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -1745,7 +1697,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm 0.5.2", - "sha2 0.10.8", + "sha2 0.10.9", "static_assertions", "thiserror 1.0.69", ] @@ -1769,7 +1721,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm 1.0.1", - "sha2 0.10.8", + "sha2 0.10.9", "static_assertions", "thiserror 1.0.69", ] @@ -2298,7 +2250,7 @@ dependencies = [ "curve25519-dalek 4.1.3", "ed25519 2.2.3", "serde", - "sha2 0.10.8", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -2312,7 +2264,7 @@ dependencies = [ "derivation-path", "ed25519-dalek 1.0.1", "hmac 0.12.1", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -2341,7 +2293,7 @@ dependencies = [ "hashbrown 0.14.5", "hex", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.9", "zeroize", ] @@ -2423,7 +2375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2653,6 +2605,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastbloom" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" +dependencies = [ + "getrandom 0.3.3", + "rand 0.9.1", + "siphasher 1.0.1", + "wide", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -2996,9 +2960,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -3076,9 +3040,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -3108,7 +3072,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", ] [[package]] @@ -3117,15 +3081,15 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "allocator-api2", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -3325,7 +3289,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.9", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -3360,7 +3324,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.26", + "rustls 0.23.27", "rustls-pki-types", "tokio", "tokio-rustls 0.26.2", @@ -3441,21 +3405,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -3464,31 +3429,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -3496,67 +3441,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -3576,9 +3508,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -3646,7 +3578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] @@ -3788,7 +3720,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -3827,7 +3759,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2 0.10.8", + "sha2 0.10.9", "signature 2.2.0", ] @@ -3864,7 +3796,7 @@ checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" dependencies = [ "lambdaworks-math", "serde", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", ] @@ -3892,9 +3824,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -3974,9 +3906,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -3994,6 +3926,12 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchit" version = "0.7.3" @@ -4468,9 +4406,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", @@ -4493,7 +4431,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -4714,6 +4652,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -4726,7 +4673,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy", ] [[package]] @@ -4861,7 +4808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.101", @@ -4928,9 +4875,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -4938,7 +4885,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.26", + "rustls 0.23.27", "socket2", "thiserror 2.0.12", "tokio", @@ -4948,16 +4895,18 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.2", + "fastbloom", + "getrandom 0.3.3", + "lru-slab", "rand 0.9.1", "ring", "rustc-hash 2.1.1", - "rustls 0.23.26", + "rustls 0.23.27", "rustls-pki-types", "rustls-platform-verifier", "slab", @@ -4969,16 +4918,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5090,7 +5039,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -5142,9 +5091,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.0", ] @@ -5266,7 +5215,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.9", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "http-body-util", @@ -5493,7 +5442,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" dependencies = [ - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -5618,15 +5567,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5643,14 +5592,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.1", + "rustls-webpki 0.103.3", "subtle", "zeroize", ] @@ -5699,32 +5648,33 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", ] [[package]] name = "rustls-platform-verifier" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4937d110d34408e9e5ad30ba0b0ca3b6a8a390f8db3636db60144ac4fa792750" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ "core-foundation 0.10.0", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.26", + "rustls 0.23.27", "rustls-native-certs 0.8.1", "rustls-platform-verifier-android", - "rustls-webpki 0.103.1", + "rustls-webpki 0.103.3", "security-framework 3.2.0", "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.52.0", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", ] [[package]] @@ -5745,9 +5695,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -5778,6 +5728,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6185,9 +6144,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -6228,9 +6187,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -6284,6 +6243,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "size-of" version = "0.1.5" @@ -6388,6 +6353,54 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "solana-axelar-cli" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "anyhow", + "axelar-executable", + "axelar-solana-encoding", + "axelar-solana-gas-service", + "axelar-solana-gateway", + "axelar-solana-governance", + "axelar-solana-its", + "axelar-wasm-std", + "base64 0.22.1", + "bincode 2.0.1", + "borsh 1.5.7", + "bs58", + "clap 3.2.25", + "cosmrs", + "cosmwasm-schema", + "cosmwasm-std 1.5.11", + "eyre", + "flate2", + "governance-gmp", + "hex", + "its-instruction-builder", + "k256", + "multisig-prover", + "program-utils", + "rand 0.9.1", + "reqwest 0.12.15", + "rust_decimal", + "rust_decimal_macros", + "serde", + "serde_json", + "solana-clap-v3-utils", + "solana-cli-config", + "solana-client", + "solana-sdk", + "spl-associated-token-account", + "spl-token 8.0.0", + "spl-token-2022 8.0.1", + "tar", + "tokio", + "voting-verifier", + "walkdir", +] + [[package]] name = "solana-big-mod-exp" version = "2.2.1" @@ -6626,9 +6639,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-interface" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a5df17b195d312b66dccdde9beec6709766d8230cb4718c4c08854f780d0309" +checksum = "8432d2c4c22d0499aa06d62e4f7e333f81777b3d7c96050ae9e5cb71a8c3aee4" dependencies = [ "borsh 1.5.7", "serde", @@ -6760,7 +6773,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" dependencies = [ - "siphasher", + "siphasher 0.3.11", "solana-hash", "solana-pubkey", ] @@ -6824,7 +6837,7 @@ version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92f6c09cc41059c0e03ccbee7f5d4cc0a315d68ef0d59b67eb90246adfd8cc35" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "lazy_static", "solana-epoch-schedule", "solana-hash", @@ -6838,7 +6851,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02007757246e40f10aa936dae4fa27efbf8dbd6a59575a12ccc802c1aea6e708" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "solana-pubkey", ] @@ -7226,7 +7239,7 @@ version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97222a3fda48570754ce114e43ca56af34741098c357cb8d3cb6695751e60330" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "bincode 1.3.3", "bv", "caps", @@ -7501,7 +7514,7 @@ dependencies = [ "log", "quinn", "quinn-proto", - "rustls 0.23.26", + "rustls 0.23.27", "solana-connection-cache", "solana-keypair", "solana-measure", @@ -7874,7 +7887,7 @@ checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -7912,7 +7925,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" dependencies = [ - "sha2 0.10.8", + "sha2 0.10.9", "solana-define-syscall", "solana-hash", ] @@ -8044,7 +8057,7 @@ dependencies = [ "quinn", "quinn-proto", "rand 0.8.5", - "rustls 0.23.26", + "rustls 0.23.27", "smallvec", "socket2", "solana-keypair", @@ -8186,7 +8199,7 @@ version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f227b3813b6c26c8ed38910b90a0b641baedb2ad075ea51ccfbff1992ee394" dependencies = [ - "rustls 0.23.26", + "rustls 0.23.27", "solana-keypair", "solana-pubkey", "solana-signer", @@ -8384,9 +8397,9 @@ dependencies = [ [[package]] name = "solana-zk-sdk" -version = "2.2.12" +version = "2.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c757a8d8b66af3e150c29e961310bafa9d8c91ad826f96fb88b2bface31ba2" +checksum = "dd14204c32f51f4ddf52ac24904417db13e54bd3b518e839e2e6ad9cca8ffef8" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -8531,7 +8544,7 @@ checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", + "sha2 0.10.9", "syn 2.0.101", "thiserror 1.0.69", ] @@ -8643,7 +8656,7 @@ checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", + "sha2 0.10.9", "syn 2.0.101", ] @@ -8655,7 +8668,7 @@ checksum = "2a2539e259c66910d78593475540e8072f0b10f0f61d7607bbf7593899ed52d0" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", + "sha2 0.10.9", "syn 2.0.101", ] @@ -9351,9 +9364,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -9430,15 +9443,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -9463,7 +9476,7 @@ dependencies = [ "serde_bytes", "serde_json", "serde_repr", - "sha2 0.10.8", + "sha2 0.10.9", "signature 2.2.0", "subtle", "subtle-encoding", @@ -9662,9 +9675,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -9687,9 +9700,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -9750,7 +9763,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.26", + "rustls 0.23.27", "tokio", ] @@ -10141,12 +10154,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -10383,9 +10390,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "0.26.9" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.0", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180d2741b6115c3d906577e6533ad89472d48d96df00270fccb78233073d77f7" +checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4" dependencies = [ "rustls-pki-types", ] @@ -10405,6 +10421,16 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "wide" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" @@ -10427,7 +10453,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -10795,9 +10821,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -10821,17 +10847,11 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -10872,9 +10892,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -10884,23 +10904,14 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", "syn 2.0.101", - "synstructure 0.13.1", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", + "synstructure 0.13.2", ] [[package]] @@ -10909,18 +10920,7 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.25", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "zerocopy-derive", ] [[package]] @@ -10952,7 +10952,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.101", - "synstructure 0.13.1", + "synstructure 0.13.2", ] [[package]] @@ -10975,11 +10975,22 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -10988,9 +10999,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/solana/cli/Cargo.toml b/solana/Cargo.toml similarity index 98% rename from solana/cli/Cargo.toml rename to solana/Cargo.toml index a04fea4dc..e6b732d3b 100644 --- a/solana/cli/Cargo.toml +++ b/solana/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cli" +name = "solana-axelar-cli" version = "0.1.0" edition = "2024" diff --git a/solana/cli/devnet-amplifier.json b/solana/cli/devnet-amplifier.json deleted file mode 120000 index b01c8bbfa..000000000 --- a/solana/cli/devnet-amplifier.json +++ /dev/null @@ -1 +0,0 @@ -../../axelar-chains-config/info/devnet-amplifier.json \ No newline at end of file diff --git a/solana/cli/mainnet.json b/solana/cli/mainnet.json deleted file mode 120000 index 9be267eff..000000000 --- a/solana/cli/mainnet.json +++ /dev/null @@ -1 +0,0 @@ -../../axelar-chains-config/info/mainnet.json \ No newline at end of file diff --git a/solana/cli/testnet.json b/solana/cli/testnet.json deleted file mode 120000 index 2f2d28d24..000000000 --- a/solana/cli/testnet.json +++ /dev/null @@ -1 +0,0 @@ -../../axelar-chains-config/info/testnet.json \ No newline at end of file diff --git a/solana/devnet-amplifier.json b/solana/devnet-amplifier.json new file mode 120000 index 000000000..695a20331 --- /dev/null +++ b/solana/devnet-amplifier.json @@ -0,0 +1 @@ +../axelar-chains-config/info/devnet-amplifier.json \ No newline at end of file diff --git a/solana/mainnet.json b/solana/mainnet.json new file mode 120000 index 000000000..97cc00764 --- /dev/null +++ b/solana/mainnet.json @@ -0,0 +1 @@ +../axelar-chains-config/info/mainnet.json \ No newline at end of file diff --git a/solana/cli/src/broadcast.rs b/solana/src/broadcast.rs similarity index 100% rename from solana/cli/src/broadcast.rs rename to solana/src/broadcast.rs diff --git a/solana/cli/src/combine.rs b/solana/src/combine.rs similarity index 100% rename from solana/cli/src/combine.rs rename to solana/src/combine.rs diff --git a/solana/cli/src/config.rs b/solana/src/config.rs similarity index 100% rename from solana/cli/src/config.rs rename to solana/src/config.rs diff --git a/solana/cli/src/gas_service.rs b/solana/src/gas_service.rs similarity index 100% rename from solana/cli/src/gas_service.rs rename to solana/src/gas_service.rs diff --git a/solana/cli/src/gateway.rs b/solana/src/gateway.rs similarity index 100% rename from solana/cli/src/gateway.rs rename to solana/src/gateway.rs diff --git a/solana/cli/src/generate.rs b/solana/src/generate.rs similarity index 100% rename from solana/cli/src/generate.rs rename to solana/src/generate.rs diff --git a/solana/cli/src/governance.rs b/solana/src/governance.rs similarity index 100% rename from solana/cli/src/governance.rs rename to solana/src/governance.rs diff --git a/solana/cli/src/its.rs b/solana/src/its.rs similarity index 100% rename from solana/cli/src/its.rs rename to solana/src/its.rs diff --git a/solana/cli/src/main.rs b/solana/src/main.rs similarity index 100% rename from solana/cli/src/main.rs rename to solana/src/main.rs diff --git a/solana/cli/src/misc.rs b/solana/src/misc.rs similarity index 100% rename from solana/cli/src/misc.rs rename to solana/src/misc.rs diff --git a/solana/cli/src/send.rs b/solana/src/send.rs similarity index 100% rename from solana/cli/src/send.rs rename to solana/src/send.rs diff --git a/solana/cli/src/sign.rs b/solana/src/sign.rs similarity index 100% rename from solana/cli/src/sign.rs rename to solana/src/sign.rs diff --git a/solana/cli/src/types.rs b/solana/src/types.rs similarity index 100% rename from solana/cli/src/types.rs rename to solana/src/types.rs diff --git a/solana/cli/src/utils.rs b/solana/src/utils.rs similarity index 100% rename from solana/cli/src/utils.rs rename to solana/src/utils.rs diff --git a/solana/testnet.json b/solana/testnet.json new file mode 120000 index 000000000..6619f9b38 --- /dev/null +++ b/solana/testnet.json @@ -0,0 +1 @@ +../axelar-chains-config/info/testnet.json \ No newline at end of file From 32fcbe323e0797c7296a9c1d84ce3cdf18092e58 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Mon, 12 May 2025 21:23:44 +0200 Subject: [PATCH 31/59] fix(solana): be consistent with help comments Signed-off-by: Guilherme Felipe da Silva --- solana/solana-axelar-cli | 6 + solana/src/broadcast.rs | 18 +- solana/src/combine.rs | 18 +- solana/src/config.rs | 2 + solana/src/gas_service.rs | 5 +- solana/src/gateway.rs | 88 ++++--- solana/src/generate.rs | 12 +- solana/src/governance.rs | 44 ++-- solana/src/its.rs | 471 ++++++++++++++++++++++++++++---------- solana/src/main.rs | 67 +++--- solana/src/misc.rs | 3 +- solana/src/send.rs | 9 +- solana/src/sign.rs | 18 +- solana/src/types.rs | 33 --- solana/src/utils.rs | 7 +- 15 files changed, 532 insertions(+), 269 deletions(-) create mode 100755 solana/solana-axelar-cli diff --git a/solana/solana-axelar-cli b/solana/solana-axelar-cli new file mode 100755 index 000000000..c5b44ab04 --- /dev/null +++ b/solana/solana-axelar-cli @@ -0,0 +1,6 @@ +#! /bin/env bash + +project_dir="$(dirname ${0})" +chains_info_dir="${project_dir}/../axelar-chains-config/info/" + +cargo run --manifest-path="${project_dir}/Cargo.toml" -- --chains-info-dir="${chains_info_dir}" ${@} diff --git a/solana/src/broadcast.rs b/solana/src/broadcast.rs index 5b8572f97..9660cbd5f 100644 --- a/solana/src/broadcast.rs +++ b/solana/src/broadcast.rs @@ -1,6 +1,7 @@ -use crate::config::Config; -use crate::types::{BroadcastArgs, SignedSolanaTransaction}; -use crate::utils::{self, print_transaction_result}; +use std::collections::HashMap; +use std::path::PathBuf; +use std::str::FromStr; + use axelar_solana_gateway::num_traits::FromPrimitive; use eyre::eyre; use solana_client::{ @@ -17,8 +18,15 @@ use solana_sdk::{ signature::Signature, transaction::{Transaction, TransactionError}, }; -use std::collections::HashMap; -use std::str::FromStr; + +use crate::config::Config; +use crate::types::SignedSolanaTransaction; +use crate::utils::{self, print_transaction_result}; + +#[derive(Debug, Clone)] +pub struct BroadcastArgs { + pub signed_tx_path: PathBuf, +} fn submit_solana_transaction( url: &str, diff --git a/solana/src/combine.rs b/solana/src/combine.rs index 8906193c3..4f86ea8e6 100644 --- a/solana/src/combine.rs +++ b/solana/src/combine.rs @@ -1,10 +1,20 @@ -use crate::config::Config; -use crate::types::{CombineArgs, NetworkType, PartialSignature, SignedSolanaTransaction}; -use crate::utils; -use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; use std::collections::{HashMap, HashSet}; +use std::path::PathBuf; use std::str::FromStr; +use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; + +use crate::config::Config; +use crate::types::{NetworkType, PartialSignature, SignedSolanaTransaction}; +use crate::utils; + +#[derive(Debug, Clone)] +pub struct CombineArgs { + pub unsigned_tx_path: PathBuf, + pub signature_paths: Vec, + pub output_signed_tx_path: PathBuf, +} + fn get_required_signers_from_instructions( instructions: &[crate::types::SerializableInstruction], fee_payer: &Pubkey, diff --git a/solana/src/config.rs b/solana/src/config.rs index 2b5f8228b..e3678de47 100644 --- a/solana/src/config.rs +++ b/solana/src/config.rs @@ -31,6 +31,8 @@ impl Config { let chains_info_filename: String = ChainsInfoFile::from(network_type).into(); let chains_info_file = chains_info_dir.join(chains_info_filename); + dbg!(&chains_info_file); + Ok(Self { url, output_dir, diff --git a/solana/src/gas_service.rs b/solana/src/gas_service.rs index 55b0bb917..0229c51f6 100644 --- a/solana/src/gas_service.rs +++ b/solana/src/gas_service.rs @@ -14,15 +14,18 @@ use crate::{ #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the Gateway program")] + /// Initialize the AxelarGasService program on Solana Init(InitArgs), } #[derive(Parser, Debug)] pub(crate) struct InitArgs { + /// The account to set as authority of the AxelarGasService program. This account will be able + /// to withdraw funds from the AxelarGasService program and update the configuration. #[clap(short, long)] authority: Pubkey, + /// The salt used to derive the config PDA. This should be a unique value for each deployment. #[clap(short, long)] salt: String, } diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 3acd5b0cc..26894f9bf 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -31,73 +31,89 @@ use crate::types::{ SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, - GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, - PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, + DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, + OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, }; use solana_sdk::message::Message as SolanaMessage; use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the Gateway program")] + /// Initialize the AxelarGateway program on Solana Init(InitArgs), - #[clap(long_about = "Call contract on an Axelar enabled destination chain")] + /// Call a contract on another chain CallContract(CallContractArgs), - #[clap(long_about = "Transfer operatorship of the Gateway program")] + /// Transfer the AxelarGateway program's operatorship to another address TransferOperatorship(TransferOperatorshipArgs), - #[clap(long_about = "Approve a message for test deployment")] + /// Approve a message using a local SignerSet (required to be the current VerifierSet registered + /// with the AxelarGateway) Approve(ApproveArgs), - #[clap(long_about = "Rotate the signers used by the Gateway program for message verification")] + /// Rotate the VerifierSet on the AxelarGateway program. Omit `new_signer` and `new_signer_set` + /// to query the MultisigProver for the current VerifierSet Rotate(RotateArgs), - #[clap( - long_about = "Submit a proof with either ApproveMessages or RotateSigners to the Gateway program" - )] + /// Submit a proof to the AxelarGateway program, triggering VerifierSet rotation or message + /// approvals SubmitProof(SubmitProofArgs), - #[clap(long_about = "Execute a cross-chain message with provided payload")] + /// Execute a cross-chain message on Solana Execute(ExecuteArgs), } #[derive(Parser, Debug)] -#[clap(group(ArgGroup::new("signers_source").args(&["signer", "signer-set"]).multiple(false).requires("nonce").required(false)))] +#[clap( + group( + ArgGroup::new("signers_source") + .args(&["signer", "signer-set"]) + .multiple(false) + .requires("nonce") + .required(false) + ) + ) +] pub(crate) struct InitArgs { - #[clap(short = 'r', long)] + /// Previous SignerSet retention + #[clap(long)] previous_signers_retention: u128, + /// Minimum delay between SignerSet rotations #[clap(long)] minimum_rotation_delay: RotationDelaySecs, - /// Hex string with secp256k1 compressed public key used to create the initial SignerSet + /// Optional hex string with secp256k1 compressed public key used to create the initial SignerSet #[clap(long)] signer: Option, - /// Nonce to be used for the SignerSet, required if `signer` or `signers` is set. + /// Nonce to be used for the SignerSet, required if `signer` or `signers` is set #[clap(long)] nonce: Option, - /// A JSON containing a SignerSet + /// An optional JSON containing a SignerSet #[clap(long)] signer_set: Option, + /// Address of the AxelarGateway program operator #[clap(long)] operator: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct CallContractArgs { - #[clap(short = 'd', long)] + /// The chain where the message has to be sent to + #[clap(long)] destination_chain: String, - #[clap(short = 'a', long)] - destination_contract_address: String, + /// The destination contract address on the destination chain that should receive the message + #[clap(long)] + destination_address: String, + /// The payload as expected by the destination contract as a hex encoded string #[clap(long)] payload: String, } @@ -123,24 +139,37 @@ pub(crate) struct ApproveArgs { #[clap(long)] nonce: u64, + /// The chain where the message originated from #[clap(long)] source_chain: String, + /// The Axelar message identifier #[clap(long)] message_id: String, + /// The address of the contract where the message originated from #[clap(long)] source_address: String, + /// The destination contract address on Solana that should receive the message #[clap(long)] destination_address: String, + /// The payload as expected by the destination contract as a hex encoded string #[clap(long)] payload: String, } #[derive(Parser, Debug)] -#[clap(group(ArgGroup::new("signers_source").args(&["new-signer", "new-signer-set"]).multiple(false).requires("nonce").required(false)))] +#[clap( + group( + ArgGroup::new("signers_source") + .args(&["new-signer", "new-signer-set"]) + .multiple(false) + .requires("nonce") + .required(false)) + ) +] pub(crate) struct RotateArgs { /// Hex string with secp256k1 private key of the signer used to generate the proof #[clap(long, value_parser=utils::parse_secret_key, value_hint=clap::ValueHint::AnyPath)] @@ -150,7 +179,7 @@ pub(crate) struct RotateArgs { #[clap(long)] nonce: u64, - /// Hex string with secp256k1 compressed public key used to create the new SignerSet + /// Hex string with secp256k1 compressed public key used to create the new SignerSet. #[clap(long)] new_signer: Option, @@ -158,12 +187,14 @@ pub(crate) struct RotateArgs { #[clap(long)] new_signer_set: Option, + /// The new nonce to be used for the new SignerSet, required if `new_signer` or `new_signers` is set #[clap(long)] new_nonce: Option, } #[derive(Parser, Debug)] pub(crate) struct SubmitProofArgs { + /// The session id associated with the proof, used o query the MultisigProver #[clap(long)] multisig_session_id: u64, } @@ -174,7 +205,7 @@ pub(crate) struct ExecuteArgs { #[clap(long)] source_chain: String, - /// Message ID of the message + /// The Axelar message identifier #[clap(long)] message_id: String, @@ -182,12 +213,11 @@ pub(crate) struct ExecuteArgs { #[clap(long)] source_address: String, - /// The address on the Solana chain where the message should be sent to + /// The destination contract address on Solana that should receive the message #[clap(long)] destination_address: String, - /// The hex encoded string of the AxelarExecutable payload (which contains the raw payload plus - /// accounts required by the destination program). + /// The payload as expected by the destination contract as a hex encoded string #[clap(long)] payload: String, } @@ -446,7 +476,7 @@ async fn init( OPERATOR_KEY: init_args.operator.to_string(), MINIMUM_ROTATION_DELAY_KEY: init_args.minimum_rotation_delay, PREVIOUS_SIGNERS_RETENTION_KEY: init_args.previous_signers_retention, - DOMAIN_SEPARATOR_KEY: domain_separator, + DOMAIN_SEPARATOR_KEY: hex::encode(domain_separator), }); write_json_to_file_path(&chains_info, &config.chains_info_file)?; @@ -480,7 +510,7 @@ async fn call_contract( signing_pda, signing_pda_bump, call_contract_args.destination_chain, - call_contract_args.destination_contract_address, + call_contract_args.destination_address, payload, )?]) } diff --git a/solana/src/generate.rs b/solana/src/generate.rs index c91c56ba1..d876ec612 100644 --- a/solana/src/generate.rs +++ b/solana/src/generate.rs @@ -1,7 +1,17 @@ +use solana_sdk::pubkey::Pubkey; + use crate::config::Config; -use crate::types::{GenerateArgs, SerializableSolanaTransaction}; +use crate::types::SerializableSolanaTransaction; use crate::utils::{self, fetch_nonce_data_and_verify}; +#[derive(Debug, Clone)] +pub struct GenerateArgs { + pub fee_payer: Pubkey, + pub nonce_account: Pubkey, + pub nonce_authority: Pubkey, + pub output_file: String, +} + pub fn generate_from_transactions( args: &GenerateArgs, config: &Config, diff --git a/solana/src/governance.rs b/solana/src/governance.rs index 15684e2dd..806924696 100644 --- a/solana/src/governance.rs +++ b/solana/src/governance.rs @@ -19,27 +19,31 @@ use crate::{ #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the Governance program")] + /// Initialize the InterchainGovernance program on Solana Init(InitArgs), - #[clap(long_about = "Execute a scheduled proposal after its ETA")] + /// Execute a scheduled proposal after its ETA has elapsed ExecuteProposal(ExecuteProposalArgs), - #[clap(long_about = "Execute an operator-approved proposal (bypasses ETA)")] + /// Execute an operator-approved proposal (bypasses ETA) ExecuteOperatorProposal(ExecuteOperatorProposalArgs), } #[derive(Args, Debug)] pub(crate) struct InitArgs { + /// The name of the chain in charge of the governance #[clap(short, long)] governance_chain: String, + /// The address of the governance contract on the governance chain #[clap(short, long)] governance_address: String, + /// Minimum value (in seconds) for a proposal ETA #[clap(short, long)] minimum_proposal_eta_delay: u32, + /// The account to receive the operator role on the Interchain Governance program on Solana #[clap(short, long)] operator: Pubkey, } @@ -47,29 +51,21 @@ pub(crate) struct InitArgs { // Common arguments for proposal execution #[derive(Args, Debug, Clone)] struct ProposalExecutionBaseArgs { - #[clap(long, help = "Target program ID for the proposal's instruction")] + /// Target program ID for the proposal's instruction target: Pubkey, - #[clap( - long, - help = "Amount of native value (lamports) to transfer with the proposal" - )] + /// The amount of native value (lamports) to transfer with the proposal native_value: u64, - #[clap( - long, - help = "Base64 encoded call data for the target program instruction" - )] + /// Call data for the target program instruction calldata: String, - #[clap( - long, - help = "Account metas required by the target program instruction. Format: 'pubkey:is_signer:is_writable'", - value_parser = parse_account_meta_string, - )] + /// Account metas required by the target program instruction. Format: 'pubkey:is_signer:is_writable' + #[clap(long, value_parser = parse_account_meta_string)] target_accounts: Vec, - #[clap(long, help = "Optional account to receive the native value transfer")] + /// Optional receiver of native value (lamports) for the proposal + #[clap(long)] native_value_receiver: Option, } @@ -84,19 +80,19 @@ pub(crate) struct ExecuteOperatorProposalArgs { #[clap(flatten)] base: ProposalExecutionBaseArgs, - #[clap(long, help = "Operator pubkey (must be a signer of the transaction)")] + /// Operator account, must be a signer of the transaction + #[clap(long)] operator: Pubkey, } #[derive(Args, Debug)] pub(crate) struct TransferOperatorshipArgs { - #[clap(long, help = "Pubkey of the new operator")] + /// The account to receive the operator role on the Interchain Governance program on Solana + #[clap(long)] new_operator: Pubkey, - #[clap( - long, - help = "Pubkey of the current operator (must be a signer of the transaction)" - )] + /// The account from which the operator role is being transferred + #[clap(long)] operator: Pubkey, } diff --git a/solana/src/its.rs b/solana/src/its.rs index 7f6a27dd4..7f30d5e4b 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -18,559 +18,784 @@ use crate::utils::{ #[derive(Subcommand, Debug)] pub(crate) enum Commands { - #[clap(long_about = "Initialize the ITS program")] + /// Initialize the Interchain Token Service (ITS) on Solana Init(InitArgs), - #[clap(long_about = "Pause ITS")] + /// Pause the Interchain Token Service on Solana, blocking incoming GMP calls and + /// custom/canonical token registration Pause, - #[clap(long_about = "Unpause ITS")] + /// Unpause the Interchain Token Service on Solana, allowing incoming GMP calls and + /// custom/canonical token registration + /// registration Unpause, - #[clap(long_about = "Add a new trusted chain to ITS")] + /// Whitelists a chain on the Interchain Token Service SetTrustedChain(TrustedChainArgs), - #[clap(long_about = "Remove an existing trusted chain from ITS")] + /// Removes a chain from the Interchain Token Service whitelist RemoveTrustedChain(TrustedChainArgs), - #[clap(long_about = "Approve deploying a remote interchain token with a specific minter")] + /// Approve deploying a remote interchain token with a specific minter ApproveDeployRemoteInterchainToken(ApproveDeployRemoteInterchainTokenArgs), - #[clap(long_about = "Revoke approval for deploying a remote interchain token")] + /// Revoke approval for deploying a remote interchain token RevokeDeployRemoteInterchainToken(RevokeDeployRemoteInterchainTokenArgs), - #[clap(long_about = "Register a canonical token as an interchain token")] + /// Register a canonical token as an interchain token RegisterCanonicalInterchainToken(RegisterCanonicalInterchainTokenArgs), - #[clap(long_about = "Deploy a canonical interchain token on a remote chain")] + /// Deploy a canonical interchain token on a remote chain DeployRemoteCanonicalInterchainToken(DeployRemoteCanonicalInterchainTokenArgs), - #[clap(long_about = "Deploy a new interchain token")] + /// Deploy a new interchain token on Solana DeployInterchainToken(DeployInterchainTokenArgs), - #[clap(long_about = "Deploy an existing interchain token to a remote chain")] + /// Deploy an existing interchain token to a remote chain DeployRemoteInterchainToken(DeployRemoteInterchainTokenArgs), - #[clap( - long_about = "Deploy an existing interchain token to a remote chain with a specific minter" - )] + /// Deploy an existing interchain token to a remote chain with a specific minter DeployRemoteInterchainTokenWithMinter(DeployRemoteInterchainTokenWithMinterArgs), - #[clap(long_about = "Register token metadata with the ITS hub")] + /// Register token metadata with the Interchain Token Service Hub RegisterTokenMetadata(RegisterTokenMetadataArgs), - #[clap(long_about = "Register a custom token with ITS")] + /// Register a custom token with the Interchain Token Service RegisterCustomToken(RegisterCustomTokenArgs), - #[clap(long_about = "Link a local token to a remote token")] + /// Link a local token to a remote token LinkToken(LinkTokenArgs), - #[clap(long_about = "Transfer interchain tokens to a remote chain")] + /// Transfer interchain tokens InterchainTransfer(InterchainTransferArgs), - #[clap(long_about = "Transfer interchain tokens and call a contract on the remote chain")] + /// Transfer interchain tokens to a contract and call it CallContractWithInterchainToken(CallContractWithInterchainTokenArgs), - #[clap( - long_about = "Transfer interchain tokens and call a contract on the remote chain using offchain data" - )] + /// Transfer interchain tokens to a contract and call it using offchain data (recommended for + /// payloads that exceed the Solana transaction size limit) CallContractWithInterchainTokenOffchainData(CallContractWithInterchainTokenOffchainDataArgs), - #[clap(long_about = "Set the flow limit for a token manager")] + /// Set the flow limit for an interchain token SetFlowLimit(SetFlowLimitArgs), - #[clap(long_about = "Transfer ITS operatorship")] + /// Transfer the Interchain Token Service operatorship to another account TransferOperatorship(TransferOperatorshipArgs), - #[clap(long_about = "Propose ITS operatorship transfer")] + /// Pose transfer of operatorship of the Interchain Token Service to another account ProposeOperatorship(TransferOperatorshipArgs), // Uses same args as transfer - #[clap(long_about = "Accept ITS operatorship transfer")] + /// Accept an existing proposal for the transfer of operatorship of the Interchain Token + /// Service from another account AcceptOperatorship(AcceptOperatorshipArgs), - #[clap(subcommand, long_about = "Manage Token Managers")] + /// TokenManager specific commands + #[clap(subcommand)] TokenManager(TokenManagerCommand), - #[clap(subcommand, long_about = "Manage Interchain Tokens")] + /// Interchain Token specific commands + #[clap(subcommand)] InterchainToken(InterchainTokenCommand), } #[derive(Subcommand, Debug)] pub(crate) enum TokenManagerCommand { - #[clap(long_about = "Set the flow limit for a token manager")] + /// Set the flow limit for an Interchain Token on a TokenManager SetFlowLimit(TokenManagerSetFlowLimitArgs), - #[clap(long_about = "Add a flow limiter role to an account for a token manager")] + + /// Add the flow limiter role on a TokenManager to an account AddFlowLimiter(TokenManagerAddFlowLimiterArgs), - #[clap(long_about = "Remove a flow limiter role from an account for a token manager")] + + /// Remove the flow limiter role on a TokenManager from an account RemoveFlowLimiter(TokenManagerRemoveFlowLimiterArgs), - #[clap(long_about = "Transfer operatorship of a token manager")] + + /// Transfer operatorship of a TokenManager to another account TransferOperatorship(TokenManagerTransferOperatorshipArgs), - #[clap(long_about = "Propose operatorship transfer for a token manager")] + + /// Porpose transfer of operatorship of a TokenManager to another account ProposeOperatorship(TokenManagerProposeOperatorshipArgs), - #[clap(long_about = "Accept operatorship transfer for a token manager")] + + /// Accept an existing proposal for the transfer of operatorship of a TokenManager from another account AcceptOperatorship(TokenManagerAcceptOperatorshipArgs), - #[clap(long_about = "Hand over mint authority from payer to token manager")] + + /// Handover mint authority of an SPL token to the TokenManager HandoverMintAuthority(TokenManagerHandoverMintAuthorityArgs), } #[derive(Parser, Debug)] pub(crate) struct TokenManagerSetFlowLimitArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The flow limit to set for the Interchain Token #[clap(long)] flow_limit: u64, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerAddFlowLimiterArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to add as a flow limiter #[clap(long)] flow_limiter: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerRemoveFlowLimiterArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to remove as a flow limiter #[clap(long)] flow_limiter: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerTransferOperatorshipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to transfer operatorship to #[clap(long)] to: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerProposeOperatorshipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to propose operatorship transfer to #[clap(long)] to: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerAcceptOperatorshipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to accept operatorship transfer from #[clap(long)] from: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct TokenManagerHandoverMintAuthorityArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The mint whose authority will be handed over to the TokenManager #[clap(long)] mint: Pubkey, - /// The token program used for the mint (spl_token or spl_token_2022). + + /// The token program which owns the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, } #[derive(Subcommand, Debug)] pub(crate) enum InterchainTokenCommand { - #[clap(long_about = "Mint interchain tokens (requires minter role)")] + /// Mint interchain tokens (requires minter role) Mint(InterchainTokenMintArgs), - #[clap(long_about = "Transfer mintership for an interchain token")] + + /// Transfer mintership of an interchain token (requires minter role) TransferMintership(InterchainTokenTransferMintershipArgs), - #[clap(long_about = "Propose mintership transfer for an interchain token")] + + /// Propose mintership transfer for an interchain token (requires minter role) ProposeMintership(InterchainTokenProposeMintershipArgs), - #[clap(long_about = "Accept mintership transfer for an interchain token")] + + /// Accept mintership transfer for an interchain token (requires minter role) AcceptMintership(InterchainTokenAcceptMintershipArgs), } #[derive(Parser, Debug)] pub(crate) struct InterchainTokenMintArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The mint account associated with the Interchain Token #[clap(long)] mint: Pubkey, + + /// The token account to which the tokens will be minted #[clap(long)] to: Pubkey, - /// The token program used for the mint (spl_token or spl_token_2022). + + /// The token program which owns the the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// The amount of tokens to mint #[clap(long)] amount: u64, } #[derive(Parser, Debug)] pub(crate) struct InterchainTokenTransferMintershipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to which the minter role will be transferred #[clap(long)] to: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct InterchainTokenProposeMintershipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account to which the minter role transfer will be proposed #[clap(long)] to: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct InterchainTokenAcceptMintershipArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The account from which the minter role transfer proposal will be accepted #[clap(long)] from: Pubkey, } -fn hash_salt(s: &str) -> eyre::Result<[u8; 32]> { - Ok(solana_sdk::keccak::hash(s.as_bytes()).0) -} - -fn parse_hex_vec(s: &str) -> Result, hex::FromHexError> { - hex::decode(s.strip_prefix("0x").unwrap_or(s)) -} - -fn parse_hex_bytes32(s: &str) -> eyre::Result<[u8; 32]> { - let decoded: [u8; 32] = hex::decode(s.strip_prefix("0x").unwrap_or(s))? - .try_into() - .map_err(|_| eyre!("Invalid hex string length. Expected 32 bytes."))?; - - Ok(decoded) -} - -fn parse_token_program(s: &str) -> Result { - match s.to_lowercase().as_str() { - "spl_token" => Ok(spl_token::id()), - "spl_token_2022" => Ok(spl_token_2022::id()), - _ => Err(format!("Invalid token program: {}", s)), - } -} - -fn parse_token_manager_type(s: &str) -> Result { - match s.to_lowercase().as_str() { - "lockunlock" | "lock_unlock" => Ok(state::token_manager::Type::LockUnlock), - "mintburn" | "mint_burn" => Ok(state::token_manager::Type::MintBurn), - "mintburnfrom" | "mint_burn_from" => Ok(state::token_manager::Type::MintBurnFrom), - "lockunlockfee" | "lock_unlock_fee" => Ok(state::token_manager::Type::LockUnlockFee), - _ => Err(format!("Invalid token manager type: {}", s)), - } -} - -fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre::Result { - let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - match maybe_arg { - Some(id) => Ok(id), - None => { - let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY][ADDRESS_KEY], - ).map_err(|_| eyre!( - "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ - Please update the file or pass a value to --gas-service"))?; - - Ok(id) - } - } -} - -fn try_infer_gas_service_config_account( - maybe_arg: Option, - config: &Config, -) -> eyre::Result { - let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - match maybe_arg { - Some(id) => Ok(id), - None => { - let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], - ).map_err(|_| eyre!( - "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ - Please update the file or pass a value to --gas-config-account"))?; - - Ok(id) - } - } -} - #[derive(Parser, Debug)] pub(crate) struct InitArgs { + /// The operator account for the Interchain Token Service #[clap(short, long)] operator: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct SetPauseStatusArgs { + /// The pause status to set for the Interchain Token Service #[clap(short, long, required = true)] paused: bool, } #[derive(Parser, Debug)] pub(crate) struct TrustedChainArgs { + /// The name of the chain to set as trusted #[clap(short, long)] chain_name: String, } #[derive(Parser, Debug)] pub(crate) struct ApproveDeployRemoteInterchainTokenArgs { + /// The account authorized to deploy the remote interchain token #[clap(long)] deployer: Pubkey, + + /// The salt for the approval #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The chain which the remote interchain token will be deployed on #[clap(long)] destination_chain: String, + + /// The address to receive the minter role on the token deployed on destination chain #[clap(long)] destination_minter: String, } #[derive(Parser, Debug)] pub(crate) struct RevokeDeployRemoteInterchainTokenArgs { + /// The account that was initially authorized to deploy the remote interchain token #[clap(long)] deployer: Pubkey, + + /// The salt for the approval #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The chain which the remote interchain token would be deployed on #[clap(long)] destination_chain: String, } #[derive(Parser, Debug)] pub(crate) struct RegisterCanonicalInterchainTokenArgs { + /// The mint account of the canonical token #[clap(long)] mint: Pubkey, - /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + /// The token program which owns the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct DeployRemoteCanonicalInterchainTokenArgs { + /// The mint account of the canonical token #[clap(long)] mint: Pubkey, + + /// The chain which the remote interchain token will be deployed on #[clap(long)] destination_chain: String, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, } #[derive(Parser, Debug)] pub(crate) struct DeployInterchainTokenArgs { + /// The salt used to derive the interchain token id #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The name of the interchain token #[clap(long)] name: String, + + /// The symbol of the interchain token #[clap(long)] symbol: String, + + /// The number of decimals for the interchain token #[clap(long)] decimals: u8, + + /// Initial supply of the interchain token #[clap(long)] initial_supply: u64, + + /// Optional mint account for the interchain token. Required if initial_supply is zero #[clap(long)] minter: Option, } #[derive(Parser, Debug)] pub(crate) struct DeployRemoteInterchainTokenArgs { + /// The salt used to derive the interchain token id #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The chain which the remote interchain token will be deployed on #[clap(long)] destination_chain: String, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, } #[derive(Parser, Debug)] pub(crate) struct DeployRemoteInterchainTokenWithMinterArgs { + /// The salt used to derive the interchain token id #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The account that has the minter role on the interchain token on Solana #[clap(long)] minter: Pubkey, + + /// The chain which the remote interchain token will be deployed on #[clap(long)] destination_chain: String, + + /// The address to receive the minter role on the token deployed on destination chain #[clap(long)] destination_minter: String, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, } #[derive(Parser, Debug)] pub(crate) struct RegisterTokenMetadataArgs { + /// The mint account being registered whose metadata should be registered #[clap(long)] mint: Pubkey, - /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + /// The token program which owns the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, } #[derive(Parser, Debug)] pub(crate) struct RegisterCustomTokenArgs { + /// The salt used to derive the interchain token id #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The mint to register #[clap(long)] mint: Pubkey, + + /// The TokenManager type to use for this token #[clap(long, value_parser = parse_token_manager_type)] token_manager_type: state::token_manager::Type, - /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + + /// The token program which owns the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// An optional account to receive the operator role on the TokenManager associated with the token #[clap(long)] operator: Option, } #[derive(Parser, Debug)] pub(crate) struct LinkTokenArgs { + /// The salt used to derive the interchain token id #[clap(long, value_parser = hash_salt)] salt: [u8; 32], + + /// The chain on which the token should be linked #[clap(long)] destination_chain: String, + + /// The address of the token on the destination chain to link #[clap(long, value_parser = parse_hex_vec)] destination_token_address: Vec, + + /// The TokenManager type to use for this token #[clap(long, value_parser = parse_token_manager_type)] token_manager_type: state::token_manager::Type, + + /// Additional arguments for the link, depending on the chain specific implementation #[clap(long, value_parser = parse_hex_vec)] link_params: Vec, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, } #[derive(Parser, Debug)] pub(crate) struct InterchainTransferArgs { + /// The token account from which tokens should transferred #[clap(long)] source_account: Pubkey, + + /// The authority with rights to transfer the tokens (i.e.: owner, delegate authority). If not + /// set, tries to use the TokenManager PDA. #[clap(long)] - authority: Option, // If None, uses TokenManager PDA + authority: Option, + + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The chain to which the tokens should be transferred #[clap(long)] destination_chain: String, + + /// The address on the destination chain to which the tokens should be transferred #[clap(long)] destination_address: String, + + /// The amount of tokens to transfer #[clap(long)] amount: u64, + + /// The mint account associated with the Interchain Token #[clap(long)] mint: Pubkey, - /// The token program to use for the mint. This can be either spl_token or spl_token_2022. + + /// The token program which owns the mint (spl_token or spl_token_2022). #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, + + /// Optional timestamp for the transaction. If not provided, the current time will be used. + /// This is used to track the token flow. Attention must be paid when generating the + /// transaction for offline signing, when this value should be set to the expected time the + /// transaction will be broadcasted. #[clap(long)] - timestamp: Option, // Defaults to current time if not provided + timestamp: Option, } #[derive(Parser, Debug)] pub(crate) struct CallContractWithInterchainTokenArgs { + /// The token account from which tokens should transferred #[clap(long)] source_account: Pubkey, + + /// The authority with rights to transfer the tokens (i.e.: owner, delegate authority). If not + /// set, tries to use the TokenManager PDA. #[clap(long)] - authority: Option, // If None, uses TokenManager PDA + authority: Option, + + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The chain to which the tokens should be transferred #[clap(long)] destination_chain: String, + + /// The address on the destination chain to which the tokens should be transferred and data + /// sent #[clap(long)] destination_address: String, + + /// The amount of tokens to transfer #[clap(long)] amount: u64, + + /// The mint account associated with the Interchain Token #[clap(long)] mint: Pubkey, + + /// The call data to be sent to the contract on the destination chain #[clap(long, value_parser = parse_hex_vec)] data: Vec, + /// The token program to use for the mint. This can be either spl_token or spl_token_2022. #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, + + /// Optional timestamp for the transaction. If not provided, the current time will be used. + /// This is used to track the token flow. Attention must be paid when generating the + /// transaction for offline signing, when this value should be set to the expected time the + /// transaction will be broadcasted. #[clap(long)] - timestamp: Option, // Defaults to current time if not provided + timestamp: Option, } #[derive(Parser, Debug)] pub(crate) struct CallContractWithInterchainTokenOffchainDataArgs { + /// The token account from which tokens should transferred #[clap(long)] source_account: Pubkey, + + /// The authority with rights to transfer the tokens (i.e.: owner, delegate authority). If not + /// set, tries to use the TokenManager PDA. #[clap(long)] - authority: Option, // If None, uses TokenManager PDA + authority: Option, + + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The chain to which the tokens should be transferred #[clap(long)] destination_chain: String, + + /// The address on the destination chain to which the tokens should be transferred and data + /// sent #[clap(long)] destination_address: String, + + /// The amount of tokens to transfer #[clap(long)] amount: u64, + + /// The mint account associated with the Interchain Token #[clap(long)] mint: Pubkey, - /// Hex string with the calldata to be sent to the contract. + /// The call data to be sent to the contract on the destination chain #[clap(long, value_parser = parse_hex_vec)] data: Vec, /// The token program to use for the mint. This can be either spl_token or spl_token_2022. #[clap(long, value_parser = parse_token_program)] token_program: Pubkey, + + /// The amount of gas to pay for the cross-chain transaction #[clap(long)] gas_value: u64, + + /// Optional AxelarGasService program id on Solana #[clap(long)] gas_service: Option, + + /// Optional AxelarGasService config account on Solana #[clap(long)] gas_config_account: Option, + + /// Optional timestamp for the transaction. If not provided, the current time will be used. + /// This is used to track the token flow. Attention must be paid when generating the + /// transaction for offline signing, when this value should be set to the expected time the + /// transaction will be broadcasted. #[clap(long)] - timestamp: Option, // Defaults to current time if not provided + timestamp: Option, } #[derive(Parser, Debug)] pub(crate) struct SetFlowLimitArgs { + /// The token id of the Interchain Token #[clap(long, value_parser = parse_hex_bytes32)] token_id: [u8; 32], + + /// The flow limit to set for the Interchain Token #[clap(long)] flow_limit: u64, } #[derive(Parser, Debug)] pub(crate) struct TransferOperatorshipArgs { + /// The account to which the operatorship will be transferred #[clap(long)] to: Pubkey, } #[derive(Parser, Debug)] pub(crate) struct AcceptOperatorshipArgs { + /// The account from which the operatorship will be accepted #[clap(long)] from: Pubkey, } +fn hash_salt(s: &str) -> eyre::Result<[u8; 32]> { + Ok(solana_sdk::keccak::hash(s.as_bytes()).0) +} + +fn parse_hex_vec(s: &str) -> Result, hex::FromHexError> { + hex::decode(s.strip_prefix("0x").unwrap_or(s)) +} + +fn parse_hex_bytes32(s: &str) -> eyre::Result<[u8; 32]> { + let decoded: [u8; 32] = hex::decode(s.strip_prefix("0x").unwrap_or(s))? + .try_into() + .map_err(|_| eyre!("Invalid hex string length. Expected 32 bytes."))?; + + Ok(decoded) +} + +fn parse_token_program(s: &str) -> Result { + match s.to_lowercase().as_str() { + "spl_token" => Ok(spl_token::id()), + "spl_token_2022" => Ok(spl_token_2022::id()), + _ => Err(format!("Invalid token program: {}", s)), + } +} + +fn parse_token_manager_type(s: &str) -> Result { + match s.to_lowercase().as_str() { + "lockunlock" | "lock_unlock" => Ok(state::token_manager::Type::LockUnlock), + "mintburn" | "mint_burn" => Ok(state::token_manager::Type::MintBurn), + "mintburnfrom" | "mint_burn_from" => Ok(state::token_manager::Type::MintBurnFrom), + "lockunlockfee" | "lock_unlock_fee" => Ok(state::token_manager::Type::LockUnlockFee), + _ => Err(format!("Invalid token manager type: {}", s)), + } +} + +fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre::Result { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + match maybe_arg { + Some(id) => Ok(id), + None => { + let id = Pubkey::deserialize( + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][ADDRESS_KEY], + ).map_err(|_| eyre!( + "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-service"))?; + + Ok(id) + } + } +} + +fn try_infer_gas_service_config_account( + maybe_arg: Option, + config: &Config, +) -> eyre::Result { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + match maybe_arg { + Some(id) => Ok(id), + None => { + let id = Pubkey::deserialize( + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], + ).map_err(|_| eyre!( + "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-config-account"))?; + + Ok(id) + } + } +} + pub(crate) async fn build_instruction( fee_payer: &Pubkey, command: Commands, diff --git a/solana/src/main.rs b/solana/src/main.rs index 603cf7d35..1e96c324f 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -12,15 +12,20 @@ mod sign; mod types; mod utils; +use std::path::PathBuf; +use std::process::exit; + +use broadcast::BroadcastArgs; use clap::{Parser, Subcommand}; +use combine::CombineArgs; use eyre::eyre; -use send::sign_and_send_transactions; +use generate::GenerateArgs; +use send::{sign_and_send_transactions, SendArgs}; +use sign::SignArgs; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::pubkey::Pubkey; -use std::path::PathBuf; -use std::process::exit; -use types::{SendArgs, SerializableSolanaTransaction}; +use types::SerializableSolanaTransaction; use crate::broadcast::broadcast_solana_transaction; use crate::combine::combine_solana_signatures; @@ -28,26 +33,22 @@ use crate::config::Config; use crate::generate::generate_from_transactions; use crate::misc::build_message; use crate::sign::sign_solana_transaction; -use crate::types::{BroadcastArgs, CombineArgs, GenerateArgs, SignArgs}; +/// A CLI tool to generate, sign (offline/Ledger), combine, and broadcast Solana transactions +/// related to the Axelar protocol, supporting durable nonces for delayed signing scenarios. #[derive(Parser, Debug)] -#[clap( - author, - version, - about = "Solana Key Management Tool for Offline/Multisig Workflows", - long_about = "A CLI tool to generate, sign (offline/Ledger), combine, and broadcast Solana transactions, supporting durable nonces for delayed signing scenarios." -)] +#[clap(author, version, about = "Solana Axelar CLI")] struct Cli { #[clap(subcommand)] command: Command, + /// URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, + /// devnet, localhost]", #[clap( short, long, env = "URL_OR_MONIKER", value_parser = parse_url_or_moniker, - help = "URL for Solana's JSON RPC or moniker (or their first letter): \ - [mainnet-beta, testnet, devnet, localhost]", )] url: String, @@ -56,52 +57,35 @@ struct Cli { short = 'o', long = "output-dir", default_value = "./output", - parse(from_os_str), - help = "Directory for output files" + parse(from_os_str) )] output_dir: PathBuf, /// Directory containing the JSON files for Axelar chains configuration info /// (devnet-amplifier.json, mainnet.json, testnet.json, etc) - #[clap(short, long, default_value = ".", parse(from_os_str))] + #[clap(short, long, default_value = ".", parse(from_os_str), hide(true))] chains_info_dir: PathBuf, } #[derive(Subcommand, Debug)] enum Command { - #[clap(long_about = "")] + /// Build and send a transaction to the Solana network. Send(SendCommandArgs), - #[clap(long_about = "Generates an unsigned Solana transaction JSON file. \ - Use --nonce-account and --nonce-authority for durable nonces, otherwise fetches the latest blockhash. \ - On mainnet, also creates a *.tar.gz bundle for offline signing.")] + /// Generates an unsigned Solana transaction JSON file. Uses --nonce-account and + /// --nonce-authority for durable nonces Generate(GenerateCommandArgs), /// Sign an unsigned transaction using a local keypair file or Ledger. - #[clap( - long_about = "Signs the message bytes from an unsigned transaction JSON file. \ - Requires a keypair file path (for testnet/devnet) or the signer's public key (for mainnet/Ledger). \ - Outputs a partial signature JSON file." - )] Sign(SignCommandArgs), /// Combine multiple partial signatures into a single file. - #[clap( - long_about = "Combines multiple partial signature JSON files corresponding to an unsigned transaction. \ - Validates that all required signers (including fee payer and nonce authority if applicable) have provided signatures. \ - Outputs a combined signed transaction JSON file." - )] Combine(CombineCommandArgs), /// Broadcast a combined signed transaction to the Solana network. - #[clap( - long_about = "Reconstructs a Solana transaction from a combined signed transaction JSON file \ - and broadcasts it to the specified network via RPC. Waits for confirmation." - )] Broadcast(BroadcastCommandArgs), /// Miscellaneous utilities. - #[clap(long_about = "Miscellaneous utilities for working with Axelar payloads and messages.")] Misc(MiscCommandArgs), } @@ -113,7 +97,6 @@ struct SendCommandArgs { /// List of signers (Base58 encoded strings). Fee payer should also be added here in case it's /// not the default from Solana CLI config. - #[clap(long, help = "List of signers (Base58 encoded strings)")] signer_keys: Vec, #[clap(subcommand)] @@ -144,16 +127,20 @@ struct GenerateCommandArgs { #[derive(Subcommand, Debug)] enum InstructionSubcommand { - #[clap(long_about = "Commands for Gateway program", subcommand)] + /// Commands to interface with the AxelarGateway program on Solana + #[clap(subcommand)] Gateway(gateway::Commands), - #[clap(long_about = "Commands for GasService program", subcommand)] + /// Commands to interface with the AxelarGasService program on Solana + #[clap(subcommand)] GasService(gas_service::Commands), - #[clap(long_about = "Commands for InterchainTokenService program", subcommand)] + /// Commands to interface with the InterchainTokenService program on Solana + #[clap(subcommand)] Its(its::Commands), - #[clap(long_about = "Commands for Governance program", subcommand)] + /// Commands to interface with the InterchainGovernance program on Solana + #[clap(subcommand)] Governance(governance::Commands), } diff --git a/solana/src/misc.rs b/solana/src/misc.rs index c1628c253..700cbcd82 100644 --- a/solana/src/misc.rs +++ b/solana/src/misc.rs @@ -1,10 +1,11 @@ +use std::str::FromStr; + use axelar_executable::AxelarMessagePayload; use axelar_executable::EncodingScheme; use clap::{Args, Subcommand}; use eyre::Result; use solana_sdk::instruction::AccountMeta; use solana_sdk::pubkey::Pubkey; -use std::str::FromStr; /// Commands for miscellaneous utilities #[derive(Subcommand, Debug)] diff --git a/solana/src/send.rs b/solana/src/send.rs index 274cd1e4c..3e8dd4689 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -8,16 +8,23 @@ use solana_client::{ use solana_sdk::{ commitment_config::CommitmentConfig, instruction::InstructionError, + pubkey::Pubkey, transaction::{Transaction, TransactionError}, }; use crate::config::Config; -use crate::types::{SendArgs, SerializableSolanaTransaction}; +use crate::types::SerializableSolanaTransaction; use crate::utils::{ create_compute_budget_instructions, print_transaction_result, DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, }; +#[derive(Debug, Clone)] +pub struct SendArgs { + pub fee_payer: Pubkey, + pub signers: Vec, +} + pub(crate) fn sign_and_send_transactions( send_args: &SendArgs, config: &Config, diff --git a/solana/src/sign.rs b/solana/src/sign.rs index 3f3dfa61d..c375bad7e 100644 --- a/solana/src/sign.rs +++ b/solana/src/sign.rs @@ -1,10 +1,20 @@ -use crate::types::{PartialSignature, SignArgs}; // Removed NetworkType import -use crate::utils; +use std::collections::HashSet; +use std::path::PathBuf; +use std::str::FromStr; + use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::{pubkey::Pubkey, signer::Signer}; -use std::collections::HashSet; -use std::str::FromStr; + +use crate::types::PartialSignature; +use crate::utils; + +#[derive(Debug, Clone)] +pub struct SignArgs { + pub unsigned_tx_path: PathBuf, + pub signer_key: String, + pub output_signature_path: PathBuf, +} fn get_required_signers_from_instructions( instructions: &[crate::types::SerializableInstruction], diff --git a/solana/src/types.rs b/solana/src/types.rs index 17f6d950c..e37eaebb7 100644 --- a/solana/src/types.rs +++ b/solana/src/types.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::path::PathBuf; use std::str::FromStr; use axelar_solana_encoding::types::pubkey::PublicKey; @@ -207,38 +206,6 @@ impl SerializableSolanaTransaction { } } -#[derive(Debug, Clone)] -pub struct SendArgs { - pub fee_payer: Pubkey, - pub signers: Vec, -} - -#[derive(Debug, Clone)] -pub struct GenerateArgs { - pub fee_payer: Pubkey, - pub nonce_account: Pubkey, - pub nonce_authority: Pubkey, - pub output_file: String, -} - -#[derive(Debug, Clone)] -pub struct SignArgs { - pub unsigned_tx_path: PathBuf, - pub signer_key: String, - pub output_signature_path: PathBuf, -} - -#[derive(Debug, Clone)] -pub struct CombineArgs { - pub unsigned_tx_path: PathBuf, - pub signature_paths: Vec, - pub output_signed_tx_path: PathBuf, -} - -#[derive(Debug, Clone)] -pub struct BroadcastArgs { - pub signed_tx_path: PathBuf, -} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SerializeableVerifierSet { pub signers: BTreeMap, diff --git a/solana/src/utils.rs b/solana/src/utils.rs index a6ae7cbc9..0bdae7525 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -1,3 +1,7 @@ +use std::fs::File; +use std::path::Path; +use std::str::FromStr; + use eyre::eyre; use k256::elliptic_curve::FieldBytes; use k256::pkcs8::DecodePrivateKey; @@ -11,9 +15,6 @@ use solana_sdk::{ compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction, keccak::hashv, pubkey::Pubkey, signature::Signature, }; -use std::fs::File; -use std::path::Path; -use std::str::FromStr; use crate::config::Config; use crate::types::{ From 0a8872c0398d1d5c794c684516c0df14b9fc5c59 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 13 May 2025 11:19:29 +0200 Subject: [PATCH 32/59] feat(solana): readme Signed-off-by: Guilherme Felipe da Silva --- solana/README.md | 448 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 solana/README.md diff --git a/solana/README.md b/solana/README.md new file mode 100644 index 000000000..8e6e65e31 --- /dev/null +++ b/solana/README.md @@ -0,0 +1,448 @@ +# Solana deployments + +## Instalation + +Install Solana CLI + +```sh +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +``` + +For more info on how to install the Solana tooling, check the official documentation [here](https://solana.com/docs/intro/installation). + +Create a new Solana keypair + +```sh +# Set default cluster +solana config set --url testnet + +# Generate a new keypair +solana-keygen new + +# Address +solana address + +# Generate a new keypair and overwrite the previously generated one +solana-keygen new --force + +``` + +Testnet funds can be obtained via [this link](https://faucet.solana.com/) or using the Solana CLI: + +```sh +solana airdrop 2 +``` + +## Deployments + +Setup + +1. Clone the solana-axelar repo. +2. Compile the Solana programs. + +> [!IMPORTANT] +> For the initial deployment of Solana programs to any of the clusters (devnet, testnet, and mainnet-beta), the program keypairs are required. The pubkey is the program ID and is hardcoded in the program using the `declare_id` macro. In case a new set of keypairs is required, a new release of the crates needs to happen afterwards (due to the id being hardcoded). Updating the ids can be done within the `solana-axelar/solana` directory by invoking: +> ```sh +> cargo xtask update-ids +> ``` +> The keypair files should be stored securely as they're needed for the initial deployment on other clusters as well. + +> [!NOTE] +> Initial deployment of Solana programs doesn't support offline signing, the process needs to be done online. When deploying, an `upgrade-authority` can be set, which will later be able to perform program upgrades — upgrades support offline signing. + +```sh +# Go to the solana directory within the cloned repo +pushd solana-axelar/solana/ + +# Compile the Solana programs +cargo xtask build + +# Go back +popd +``` + +### Gateway + +Deploy the gateway program. If `--authority` is omitted, the current Solana CLI keypair is set as upgrade-authority. + +```sh +solana program-v4 deploy --program-keypair path/to/gateway-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so +``` + +### Gas Service + +Deploy the gas service program + +```sh +solana program-v4 deploy --program-keypair path/to/gas-service-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so +``` + +### Interchain Token Service + +Deploy the ITS program + +```sh +solana program-v4 deploy --program-keypair path/to/its-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so +``` + +### Governance + +Deploy the governance program + +```sh +solana program-v4 deploy --program-keypair path/to/governance-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so +``` + +### Multicall + +Deploy the multicall program + +```sh +solana program-v4 deploy --program-keypair path/to/multicall-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so +``` + +## Upgrades + +To upgrade a program, a similar command is used as for the initial deployment, but with the `--program-id` option instead of `--program-keypair`. The upgrade should be performed by the authority assigned during the initial deployment. + + +```sh +solana program-v4 deploy --program-id +``` + +For upgrades with offline signing, recovery of failed deployments, and other information about Solana program deployment, please check the [official docs](https://solana.com/docs/programs/deploying). + +--- + +## Contract Interaction + +Solana contracts can be interacted with using the provided CLI. The CLI supports both direct execution and offline signing workflows. + +### CLI Usage + +The Solana Axelar CLI (`solana-axelar-cli`) provides several commands for interacting with the deployed contracts. The basic usage is: + +```sh +solana/solana-axelar-cli [OPTIONS] [SUBCOMMAND] +``` + +Main commands: + +- `send`: Build and send a transaction to the Solana network +- `generate`: Generate an unsigned transaction for offline signing +- `sign`: Sign an unsigned transaction using a local keypair or Ledger +- `combine`: Combine multiple partial signatures into a single file +- `broadcast`: Broadcast a combined signed transaction to the Solana network +- `misc`: Miscellaneous utilities + +`send` and `generate` have associated subcommands for specific contract interactions. + +### Network Configuration + +Specify the Solana network to connect to: + +```sh +export URL_OR_MONIKER= +``` + +or, on every command: + +```sh +solana/solana-axelar-cli --url [OPTIONS] +``` + +The URL can be a full RPC URL or a moniker: +- `mainnet-beta`: Solana mainnet +- `testnet`: Solana testnet +- `devnet`: Solana devnet +- `localhost`: Local Solana validator + +### Gateway + +To get help on gateway commands, run: + +```sh +solana/solana-axelar-cli send --help +solana/solana-axelar-cli send gateway --help +``` + +#### Initialize Gateway + +```sh +solana/solana-axelar-cli send gateway init \ + --previous-signers-retention 3 \ + --minimum-rotation-delay 86400 \ + --operator +``` + +#### Call Contract + +Send a message to another chain: + +```sh +solana/solana-axelar-cli send gateway call-contract \ + --destination-chain avalanche \ + --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ + --payload 0x1234 +``` + +#### Submit Proof + +Submit a proof constructed on Amplifier to the Solana gateway contract: + +```sh +solana/solana-axelar-cli send gateway submit-proof \ + --multisig-session-id 123456 +``` + +#### Execute Message + +Execute a cross-chain message that was approved on the Solana gateway: + +```sh +solana/solana-axelar-cli send gateway execute \ + --source-chain avalanche \ + --message-id '0x0bcbbfc9b006db6958f3fce75f11fdc306b45e8e43396211f414f40d2d6db7c5-0' \ + --source-address 0xba76c6980428A0b10CFC5d8ccb61949677A61233 \ + --destination-address \ + --payload 0x1234 +``` + +#### Rotate Signers + +```sh +solana/solana-axelar-cli send gateway rotate \ + --signer \ + --nonce 123 \ + --new-nonce 456 +``` + +#### Transfer Operatorship + +```sh +# Transfer Gateway operatorship +solana/solana-axelar-cli send gateway transfer-operatorship \ + --authority \ + --new-operator +``` + +### Interchain Token Service (ITS) + +To get help on ITS commands, run: + +```sh +solana/solana-axelar-cli send its --help +``` + +#### Initialize ITS + +```sh +solana/solana-axelar-cli send its init --operator +``` + +#### Set/Remove Trusted Chain + +```sh +# Add a trusted chain +solana/solana-axelar-cli send its set-trusted-chain --chain-name avalanche + +# Remove a trusted chain +solana/solana-axelar-cli send its remove-trusted-chain --chain-name avalanche +``` + +#### Deploy Interchain Token + +```sh +solana/solana-axelar-cli send its deploy-interchain-token \ + --salt \ + --name "My Token" \ + --symbol "MTK" \ + --decimals 8 \ + --initial-supply 1000000000 +``` + +#### Deploy Remote Interchain Token + +```sh +solana/solana-axelar-cli send its deploy-remote-interchain-token \ + --salt \ + --destination-chain avalanche \ + --gas-value 500000 +``` + +#### Register Canonical Token + +```sh +solana/solana-axelar-cli send its register-canonical-interchain-token \ + --mint \ + --token-program spl_token +``` + +#### Deploy Remote Canonical Token + +```sh +solana/solana-axelar-cli send its deploy-remote-canonical-interchain-token \ + --mint \ + --destination-chain avalanche \ + --gas-value 500000 +``` + +#### Interchain Transfer + +```sh +solana/solana-axelar-cli send its interchain-transfer \ + --source-account \ + --token-id \ + --destination-chain avalanche \ + --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ + --amount 1000000 \ + --mint \ + --token-program spl_token \ + --gas-value 500000 +``` + +#### Call Contract With Interchain Token + +```sh +solana/solana-axelar-cli send its call-contract-with-interchain-token \ + --source-account \ + --token-id \ + --destination-chain avalanche \ + --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ + --amount 1000000 \ + --mint \ + --data 0x1234 \ + --token-program spl_token \ + --gas-value 500000 +``` + +#### Set Flow Limit + +```sh +solana/solana-axelar-cli send its set-flow-limit \ + --token-id \ + --flow-limit 1000000 +``` + +#### Pausable Functionality + +```sh +# Check if ITS is paused +solana/solana-axelar-cli send its paused + +# Pause ITS +solana/solana-axelar-cli send its pause + +# Unpause ITS +solana/solana-axelar-cli send its unpause +``` + +#### TokenManager Operations + +```sh +# Set flow limit on a token manager +solana/solana-axelar-cli send its token-manager set-flow-limit \ + --token-id \ + --flow-limit 1000000 + +# Add flow limiter to a token manager +solana/solana-axelar-cli send its token-manager add-flow-limiter \ + --token-id \ + --flow-limiter +``` + +#### InterchainToken Operations + +```sh +# Mint interchain tokens +solana/solana-axelar-cli send its interchain-token mint \ + --token-id \ + --mint \ + --to \ + --token-program spl_token \ + --amount 1000000 +``` + +#### Transfer Operatorship + +```sh +# Transfer ITS operatorship +solana/solana-axelar-cli send its transfer-operatorship --to +``` +## Governance + +For governance-related commands: + +```sh +solana/solana-axelar-cli send governance --help +``` + +## Gas Service + +For gas service commands: + +```sh +solana/solana-axelar-cli send gas-service --help +``` + +### Offline Signing Workflow + +For security-critical operations or when using hardware wallets, you can use the offline signing workflow: + +#### Creating a Durable Nonce Account + +Durable nonces are necessary for offline signing to ensure transactions remain valid across block hashes. To create and manage a durable nonce account: + +```sh +# Create a nonce account (requires SOL for rent exemption) +solana create-nonce-account --nonce-authority +``` + +#### 1. Generate the unsigned transaction + +```sh +solana/solana-axelar-cli generate \ + --fee-payer \ + --nonce-account \ + --nonce-authority \ + --output-name my_transaction \ + gateway call-contract \ + --destination-chain avalanche \ + --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ + --payload 0x1234 +``` + +#### 2. Sign the transaction (on each signing device) + +```sh +solana/solana-axelar-cli sign \ + --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ + --signer /path/to/keypair.json \ + --output-sig ./output/signature1.sig.json +``` + +For Ledger: + +```sh +solana/solana-axelar-cli sign \ + --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ + --signer usb://ledger \ + --output-sig ./output/signature2.sig.json +``` + +#### 3. Combine all signatures + +```sh +solana/solana-axelar-cli combine \ + --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ + --signatures ./output/signature1.sig.json ./output/signature2.sig.json \ + --output-signed ./output/my_transaction.signed.solana.json +``` + +#### 4. Broadcast the transaction + +```sh +solana/solana-axelar-cli broadcast \ + --url mainnet-beta \ + ./output/my_transaction.signed.solana.json +``` From 986051c9c50b9959bab8763e9a8850d3c375ae66 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 13 May 2025 16:10:52 +0200 Subject: [PATCH 33/59] fix(solana): make output fila names consistent Signed-off-by: Guilherme Felipe da Silva --- solana/README.md | 25 ++++++++--------- solana/solana-axelar-cli | 2 +- solana/src/broadcast.rs | 13 +++------ solana/src/combine.rs | 26 +++++++++++++++--- solana/src/generate.rs | 28 ++++++------------- solana/src/main.rs | 58 +++++++++++++++++++++------------------- solana/src/send.rs | 19 ------------- solana/src/sign.rs | 32 +++++++++++++++++----- solana/src/utils.rs | 50 ++++++++++++++++------------------ 9 files changed, 126 insertions(+), 127 deletions(-) diff --git a/solana/README.md b/solana/README.md index 8e6e65e31..b38b496e0 100644 --- a/solana/README.md +++ b/solana/README.md @@ -405,44 +405,45 @@ solana/solana-axelar-cli generate \ --fee-payer \ --nonce-account \ --nonce-authority \ - --output-name my_transaction \ gateway call-contract \ --destination-chain avalanche \ --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ --payload 0x1234 ``` +This will generate a file like `./output/gateway_init.unsigned.json` in the default output directory. You can specify a custom output directory with `--output-dir /path/to/directory`. + #### 2. Sign the transaction (on each signing device) ```sh solana/solana-axelar-cli sign \ - --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ - --signer /path/to/keypair.json \ - --output-sig ./output/signature1.sig.json + ./output/gateway_init.unsigned.json \ + --signer /path/to/keypair.json ``` For Ledger: ```sh solana/solana-axelar-cli sign \ - --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ - --signer usb://ledger \ - --output-sig ./output/signature2.sig.json + ./output/gateway_init.unsigned.json \ + --signer usb://ledger ``` +This will generate signature files like `./output/gateway_init.5hW1cNgX6N8RhvHHiX6nAnKbZftG1K3ckNBuJdRSPFPK.partial.sig` where the signer's full public key is included in the filename for uniqueness. + #### 3. Combine all signatures ```sh solana/solana-axelar-cli combine \ - --unsigned-tx-path ./output/my_transaction.unsigned.solana.json \ - --signatures ./output/signature1.sig.json ./output/signature2.sig.json \ - --output-signed ./output/my_transaction.signed.solana.json + --unsigned-tx-path ./output/gateway_init.unsigned.json \ + --signatures ./output/gateway_init.5hW1cNgX6N8RhvHHiX6nAnKbZftG1K3ckNBuJdRSPFPK.partial.sig ./output/gateway_init.DL6NBsMvnEMbUJ5XHeLMyfGpmEukV2i7ZVukGCfxWvP5.partial.sig ``` +This will generate a file like `./output/gateway_init.signed.json`. + #### 4. Broadcast the transaction ```sh solana/solana-axelar-cli broadcast \ - --url mainnet-beta \ - ./output/my_transaction.signed.solana.json + ./output/gateway_init.signed.json ``` diff --git a/solana/solana-axelar-cli b/solana/solana-axelar-cli index c5b44ab04..fbc7230a3 100755 --- a/solana/solana-axelar-cli +++ b/solana/solana-axelar-cli @@ -1,4 +1,4 @@ -#! /bin/env bash +#!/bin/env bash project_dir="$(dirname ${0})" chains_info_dir="${project_dir}/../axelar-chains-config/info/" diff --git a/solana/src/broadcast.rs b/solana/src/broadcast.rs index 9660cbd5f..a9cad1885 100644 --- a/solana/src/broadcast.rs +++ b/solana/src/broadcast.rs @@ -123,12 +123,8 @@ fn submit_solana_transaction( println!("Connecting to RPC client at {}", url); let rpc_client = RpcClient::new_with_commitment(url.to_string(), CommitmentConfig::confirmed()); - - // Don't automatically add compute budget instructions to avoid duplicates - // We'll use the original transaction directly let tx_to_send = transaction; - // Simulate the transaction before sending to check if we need to add compute units match rpc_client.simulate_transaction(&tx_to_send) { Ok(sim_result) => { if let Some(units) = sim_result.value.units_consumed { @@ -156,7 +152,6 @@ fn submit_solana_transaction( Err(client_err) => { eprintln!("Error during RPC broadcast/confirmation: {}", client_err); - // Check if the error is a GatewayError and should proceed let should_continue = if let ClientErrorKind::RpcError( solana_client::rpc_request::RpcError::RpcResponseError { data: @@ -191,10 +186,8 @@ fn submit_solana_transaction( println!( "Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction" ); - // Return a dummy signature to indicate success for recoverable errors Ok(Signature::default()) } else { - // Print detailed error information if let ClientErrorKind::RpcError( solana_client::rpc_request::RpcError::RpcResponseError { data: RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), @@ -207,7 +200,6 @@ fn submit_solana_transaction( eprintln!(" -> Transaction Error Detail: {:?}", tx_err); } - // Return the error as non-recoverable Err(eyre!("RPC client error: {}", client_err)) } } @@ -221,8 +213,9 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> ey Ok(tx_data) => tx_data, Err(e) if e.to_string().contains("json") => { eyre::bail!( - "Failed to parse transaction file. Make sure you're using a file generated by the 'combine' command, \ - not directly from 'sign' or 'generate'. If you've only signed with one key, run 'combine' first: {}", + "Failed to parse transaction file. Make sure you're using a signed transaction file (*.signed.json) \ + generated by the 'combine' command, not directly from 'sign' or 'generate'. \ + If you've only signed with one key, run 'combine' first: {}", e ); } diff --git a/solana/src/combine.rs b/solana/src/combine.rs index 4f86ea8e6..5581545e1 100644 --- a/solana/src/combine.rs +++ b/solana/src/combine.rs @@ -12,7 +12,7 @@ use crate::utils; pub struct CombineArgs { pub unsigned_tx_path: PathBuf, pub signature_paths: Vec, - pub output_signed_tx_path: PathBuf, + pub output_dir: Option, } fn get_required_signers_from_instructions( @@ -137,10 +137,30 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::R signatures: partial_signatures_vec, }; - utils::save_signed_solana_transaction(&signed_tx, &args.output_signed_tx_path)?; + let output_dir = args.output_dir.clone().unwrap_or_else(|| { + args.unsigned_tx_path + .parent() + .map(|p| p.to_path_buf()) + .unwrap_or_else(|| std::path::PathBuf::from(".")) + }); + + std::fs::create_dir_all(&output_dir)?; + + let unsigned_file_stem = args + .unsigned_tx_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("unknown"); + + let tx_name = unsigned_file_stem.replace(".unsigned", ""); + + let signed_filename = format!("{}.signed.json", tx_name); + let signed_tx_path = output_dir.join(signed_filename); + + utils::save_signed_solana_transaction(&signed_tx, &signed_tx_path)?; println!( "Combined signed Solana transaction data saved to: {}", - args.output_signed_tx_path.display() + signed_tx_path.display() ); if config.network_type == NetworkType::Mainnet { diff --git a/solana/src/generate.rs b/solana/src/generate.rs index d876ec612..7dd2bab69 100644 --- a/solana/src/generate.rs +++ b/solana/src/generate.rs @@ -9,13 +9,14 @@ pub struct GenerateArgs { pub fee_payer: Pubkey, pub nonce_account: Pubkey, pub nonce_authority: Pubkey, - pub output_file: String, + pub output_dir: std::path::PathBuf, } pub fn generate_from_transactions( args: &GenerateArgs, config: &Config, mut transactions: Vec, + filename: &str, ) -> eyre::Result<()> { println!("Starting unsigned Solana transaction generation from transactions..."); println!("Network Type: {:?}", config.network_type); @@ -25,32 +26,22 @@ pub fn generate_from_transactions( args.nonce_account ); - // Get nonce blockhash let blockhash = fetch_nonce_data_and_verify(&config.url, &args.nonce_account, &args.nonce_authority)?; println!("Using Nonce (Blockhash) from account: {}", blockhash); - // For each transaction, we need to update with the nonce information - // and prepend the advance_nonce_account instruction for tx in &mut transactions { - // Update transaction params tx.params.nonce_account = Some(args.nonce_account.to_string()); tx.params.nonce_authority = Some(args.nonce_authority.to_string()); tx.params.blockhash_for_message = blockhash.to_string(); - tx.params.recent_blockhash = None; // Not needed with nonce + tx.params.recent_blockhash = None; - // Create advance nonce account instruction let advance_nonce_ix = solana_sdk::system_instruction::advance_nonce_account( &args.nonce_account, &args.nonce_authority, ); - - // Create a new transaction with advance_nonce_account as the first instruction - // followed by the original transaction's instructions let mut instructions = vec![advance_nonce_ix]; - // Add all the original instructions from the transaction - // We need to extract them from the message let original_message = tx.transaction.message.clone(); let account_keys = original_message.account_keys.clone(); @@ -75,33 +66,30 @@ pub fn generate_from_transactions( instructions.push(ix); } - // Create a new message with the combined instructions and nonce blockhash let new_message = solana_sdk::message::Message::new_with_blockhash( &instructions, Some(&args.fee_payer), &blockhash, ); - // Update the transaction with the new message *tx = SerializableSolanaTransaction::new( solana_sdk::transaction::Transaction::new_unsigned(new_message), tx.params.clone(), ); } - // Now save each transaction + std::fs::create_dir_all(&args.output_dir)?; + for (i, tx) in transactions.iter().enumerate() { - // Convert the SerializableSolanaTransaction to an UnsignedSolanaTransaction let unsigned_tx = tx.to_unsigned(); - // Filename includes index if we have multiple transactions let unsigned_tx_filename = if transactions.len() > 1 { - format!("{}.{}.unsigned.solana.json", args.output_file, i) + format!("{}.{}.unsigned.json", filename, i) } else { - format!("{}.unsigned.solana.json", args.output_file) + format!("{}.unsigned.json", filename) }; - let unsigned_tx_path = config.output_dir.join(&unsigned_tx_filename); + let unsigned_tx_path = args.output_dir.join(&unsigned_tx_filename); utils::save_unsigned_solana_transaction(&unsigned_tx, &unsigned_tx_path)?; println!( "Unsigned Solana transaction {} saved to: {}", diff --git a/solana/src/main.rs b/solana/src/main.rs index 1e96c324f..fe1022499 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -16,7 +16,7 @@ use std::path::PathBuf; use std::process::exit; use broadcast::BroadcastArgs; -use clap::{Parser, Subcommand}; +use clap::{FromArgMatches, IntoApp, Parser, Subcommand}; use combine::CombineArgs; use eyre::eyre; use generate::GenerateArgs; @@ -117,9 +117,9 @@ struct GenerateCommandArgs { #[clap(long)] nonce_authority: Pubkey, - /// Base name for output files (e.g., 'my_tx' -> my_tx.unsigned.solana.json) - #[clap(long = "output-name")] - output_file: String, + /// Directory to store unsigned transaction files + #[clap(long = "output-dir", parse(from_os_str))] + output_dir: Option, #[clap(subcommand)] instruction: InstructionSubcommand, @@ -146,7 +146,7 @@ enum InstructionSubcommand { #[derive(Parser, Debug)] struct SignCommandArgs { - /// Path to the unsigned Solana transaction JSON file (*.unsigned.solana.json) + /// Path to the unsigned Solana transaction JSON file (*.unsigned.json) #[clap(parse(from_os_str))] unsigned_tx_path: PathBuf, @@ -154,19 +154,19 @@ struct SignCommandArgs { #[clap(long = "signer", short = 'k')] signer_key: String, - /// Output file path for the generated partial signature JSON (*.sig.json) - #[clap(long = "output-sig", short = 's', parse(from_os_str))] - // Changed from arg(value_parser = ...) - output_signature_path: PathBuf, + /// Output directory for signature files + /// If not specified, signatures will be placed in the same directory as the unsigned transaction + #[clap(long = "output-dir", parse(from_os_str))] + output_dir: Option, } #[derive(Parser, Debug)] struct CombineCommandArgs { - /// Path to the original unsigned Solana transaction JSON file (*.unsigned.solana.json) + /// Path to the original unsigned Solana transaction JSON file (*.unsigned.json) #[clap(long, parse(from_os_str))] unsigned_tx_path: PathBuf, - /// Paths to the partial signature JSON files (*.sig.json) to combine (provide at least one) + /// Paths to the partial signature JSON files (*.partial.sig) to combine (provide at least one) #[clap( long = "signatures", short = 's', @@ -177,14 +177,15 @@ struct CombineCommandArgs { )] signature_paths: Vec, - /// Output file path for the combined signed transaction JSON (*.signed.solana.json) - #[clap(long = "output-signed", short = 'f', parse(from_os_str))] - output_signed_tx_path: PathBuf, + /// Output directory for the combined signed transaction JSON + /// If not specified, will use the same directory as the unsigned transaction + #[clap(long = "output-dir", parse(from_os_str))] + output_dir: Option, } #[derive(Parser, Debug)] struct BroadcastCommandArgs { - /// Path to the combined signed Solana transaction JSON file (*.signed.solana.json) + /// Path to the combined signed Solana transaction JSON file (*.signed.json) #[clap(parse(from_os_str))] signed_tx_path: PathBuf, } @@ -204,7 +205,8 @@ async fn main() { } async fn run() -> eyre::Result<()> { - let cli = Cli::parse(); + let matches = Cli::command().get_matches(); + let cli = Cli::from_arg_matches(&matches)?; let config = Config::new(cli.url, cli.output_dir, cli.chains_info_dir)?; @@ -219,14 +221,9 @@ async fn run() -> eyre::Result<()> { .as_ref() .ok_or_else(|| eyre!("Missing Solana config file"))?; let cli_config = solana_cli_config::Config::load(config_file)?; - let signer_context = clap::ArgMatches::default(); - let signer = signer_from_path( - &signer_context, - &cli_config.keypair_path, - "signer", - &mut None, - ) - .map_err(|e| eyre!("Failed to load fee payer: {}", e))?; + let signer = + signer_from_path(&matches, &cli_config.keypair_path, "signer", &mut None) + .map_err(|e| eyre!("Failed to load fee payer: {}", e))?; signer_keys.push(cli_config.keypair_path); signer.pubkey() @@ -243,24 +240,29 @@ async fn run() -> eyre::Result<()> { sign_and_send_transactions(&send_args, &config, transactions)?; } Command::Generate(args) => { + // Determine output directory - use provided dir or default to config.output_dir + let output_dir = args.output_dir.unwrap_or_else(|| config.output_dir.clone()); + let gen_args = GenerateArgs { fee_payer: args.fee_payer, nonce_account: args.nonce_account, nonce_authority: args.nonce_authority, - output_file: args.output_file, + output_dir, }; // Use the transaction-based approach let transactions = build_transaction(&gen_args.fee_payer, args.instruction, &config).await?; println!("Generating transactions..."); - generate_from_transactions(&gen_args, &config, transactions)?; + + let filename = utils::serialized_transactions_filename_from_arg_matches(&matches); + generate_from_transactions(&gen_args, &config, transactions, &filename)?; } Command::Sign(args) => { let sign_args = SignArgs { unsigned_tx_path: args.unsigned_tx_path, signer_key: args.signer_key, - output_signature_path: args.output_signature_path, + output_dir: args.output_dir, }; sign_solana_transaction(&sign_args)?; } @@ -268,7 +270,7 @@ async fn run() -> eyre::Result<()> { let combine_args = CombineArgs { unsigned_tx_path: args.unsigned_tx_path, signature_paths: args.signature_paths, - output_signed_tx_path: args.output_signed_tx_path, + output_dir: args.output_dir, }; combine_solana_signatures(&combine_args, &config)?; } diff --git a/solana/src/send.rs b/solana/src/send.rs index 3e8dd4689..3e1d8efc9 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -50,39 +50,29 @@ pub(crate) fn sign_and_send_transactions( signers.push(signer); } - // Get the latest blockhash let blockhash = rpc_client.get_latest_blockhash()?; - // Check if the transaction already has compute budget instructions let has_compute_budget = transaction.message.instructions.iter().any(|ix| { let program_id = transaction.message.account_keys[ix.program_id_index as usize]; program_id == solana_sdk::compute_budget::id() }); - // First, we'll make a transaction with just the original instructions transaction.sign(&signers, blockhash); - // Only try to optimize if there are no compute budget instructions already if !has_compute_budget { - // Try to simulate the transaction to see if it might exceed compute limits println!("Simulating transaction before sending..."); match rpc_client.simulate_transaction(&transaction) { Ok(sim_result) => { if let Some(units) = sim_result.value.units_consumed { println!("Simulation used {} compute units", units); - // If we're using a significant portion of the compute limit, add a compute budget if units > 150_000 { - // Create a new transaction with compute budget instructions println!( "Transaction needs significant compute units, adding compute budget" ); - // Extract original instructions from the transaction message - // Use the transaction's message instructions directly let message = &transaction.message; - // Convert CompiledInstructions to regular Instructions let original_instructions: Vec = message .instructions @@ -111,31 +101,25 @@ pub(crate) fn sign_and_send_transactions( }) .collect(); - // Create compute budget instructions let compute_budget_instructions = create_compute_budget_instructions( DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, ); - // Combine compute budget instructions with original instructions let mut all_instructions = compute_budget_instructions; all_instructions.extend(original_instructions); - // Get the fee payer let fee_payer = transaction.message.account_keys[0]; - // Create a new message with all instructions let message = solana_sdk::message::Message::new_with_blockhash( &all_instructions, Some(&fee_payer), &blockhash, ); - // Create and sign a new transaction let mut optimized_tx = Transaction::new_unsigned(message); optimized_tx.sign(&signers, blockhash); - // Use the optimized transaction instead transaction = optimized_tx; println!( "Added compute budget: {} units with {} micro-lamports priority fee", @@ -149,7 +133,6 @@ pub(crate) fn sign_and_send_transactions( "Simulation failed: {:?}, proceeding with regular transaction", err ); - // If simulation fails, just use the original transaction transaction.sign(&signers, blockhash); } }; @@ -157,7 +140,6 @@ pub(crate) fn sign_and_send_transactions( println!("Transaction already has compute budget instructions, skipping optimization"); } - // Now send the transaction (either original or optimized) match rpc_client.send_and_confirm_transaction(&transaction) { Ok(signature) => { results.push(signature); @@ -206,7 +188,6 @@ pub(crate) fn sign_and_send_transactions( } } - // Print results for (i, signature) in results.iter().enumerate() { println!("Transaction {}: {}", i + 1, signature); print_transaction_result(config, Ok(*signature))?; diff --git a/solana/src/sign.rs b/solana/src/sign.rs index c375bad7e..65dc6919f 100644 --- a/solana/src/sign.rs +++ b/solana/src/sign.rs @@ -13,7 +13,7 @@ use crate::utils; pub struct SignArgs { pub unsigned_tx_path: PathBuf, pub signer_key: String, - pub output_signature_path: PathBuf, + pub output_dir: Option, } fn get_required_signers_from_instructions( @@ -59,7 +59,7 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { ); println!("Loading signer from: {}", args.signer_key); - let signer_context = clap::ArgMatches::default(); // Dummy context + let signer_context = clap::ArgMatches::default(); let signer = signer_from_path(&signer_context, &args.signer_key, "signer", &mut None) .map_err(|e| eyre!("Failed to load signer '{}': {}", args.signer_key, e))?; @@ -107,12 +107,30 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { println!(" Signer Pubkey: {}", partial_signature.signer_pubkey); println!(" Signature: {}", partial_signature.signature); - utils::save_partial_signature(&partial_signature, &args.output_signature_path)?; + let output_dir = args.output_dir.clone().unwrap_or_else(|| { + args.unsigned_tx_path + .parent() + .map(|p| p.to_path_buf()) + .unwrap_or_else(|| std::path::PathBuf::from(".")) + }); - println!( - "Partial signature saved to: {}", - args.output_signature_path.display() - ); + std::fs::create_dir_all(&output_dir)?; + + let unsigned_file_stem = args + .unsigned_tx_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("unknown"); + + let tx_name = unsigned_file_stem.replace(".unsigned", ""); + + let pubkey_str = signer_pubkey.to_string(); + let sig_filename = format!("{}.{}.partial.sig", tx_name, pubkey_str); + let sig_path = output_dir.join(sig_filename); + + utils::save_partial_signature(&partial_signature, &sig_path)?; + + println!("Partial signature saved to: {}", sig_path.display()); Ok(()) } diff --git a/solana/src/utils.rs b/solana/src/utils.rs index 0bdae7525..6df12e54d 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::path::Path; use std::str::FromStr; +use clap::ArgMatches; use eyre::eyre; use k256::elliptic_curve::FieldBytes; use k256::pkcs8::DecodePrivateKey; @@ -23,11 +24,9 @@ use crate::types::{ }; pub(crate) use solana_sdk::instruction::AccountMeta; -// Default compute units to use for complex transactions pub(crate) const DEFAULT_COMPUTE_UNITS: u32 = 1_400_000; // Maximum allowed is 1.4M compute units pub(crate) const DEFAULT_PRIORITY_FEE: u64 = 10_000; // 10,000 micro-lamports per compute unit -/// Creates compute budget instructions to increase the compute limit and set priority fee pub(crate) fn create_compute_budget_instructions( compute_units: u32, priority_fee: u64, @@ -104,30 +103,20 @@ pub(crate) fn save_partial_signature(sig: &PartialSignature, path: &Path) -> eyr } pub(crate) fn load_signed_solana_transaction(path: &Path) -> eyre::Result { - // Try to read the file as a SignedSolanaTransaction first match read_json_file_from_path::(path) { Ok(signed_tx) => Ok(signed_tx), - Err(err) => { - // If that fails, try to read it as an UnsignedSolanaTransaction - // This handles cases where the user might be using a file generated by the 'sign' command - // rather than the 'combine' command - match read_json_file_from_path::(path) { - Ok(unsigned_tx) => { - println!( - "Warning: Found unsigned transaction, converting to signed format without signatures" - ); - // Convert to a signed transaction with no signatures - Ok(SignedSolanaTransaction { - unsigned_tx_data: unsigned_tx, - signatures: Vec::new(), - }) - } - Err(_) => { - // If both reads fail, return the original error from reading as SignedSolanaTransaction - Err(err) - } + Err(err) => match read_json_file_from_path::(path) { + Ok(unsigned_tx) => { + println!( + "Warning: Found unsigned transaction, converting to signed format without signatures" + ); + Ok(SignedSolanaTransaction { + unsigned_tx_data: unsigned_tx, + signatures: Vec::new(), + }) } - } + Err(_) => Err(err), + }, } } @@ -278,7 +267,6 @@ pub(crate) fn fetch_nonce_data_and_verify( ); } - // Try with regular bincode deserialization let nonce_state: solana_sdk::nonce::state::State = StateMut::::state(&nonce_account) .map_err(|_| { eyre!( @@ -294,7 +282,6 @@ pub(crate) fn fetch_nonce_data_and_verify( println!(" -> Stored Nonce (Blockhash): {}", data.blockhash()); println!(" -> Authority: {}", data.authority); - // If there's a mismatch, we'll print a warning but still proceed if data.authority != *expected_nonce_authority { return Err(eyre!( "Nonce account authority mismatch: expected {}, found {}", @@ -303,8 +290,6 @@ pub(crate) fn fetch_nonce_data_and_verify( )); } - // Always return the blockhash, regardless of authority mismatch - // This works around potential deserialization issues Ok(data.blockhash()) } solana_sdk::nonce::state::State::Uninitialized => Err(eyre!( @@ -339,3 +324,14 @@ fn secret_from_str(s: &str) -> Option { None } + +pub(crate) fn serialized_transactions_filename_from_arg_matches(matches: &ArgMatches) -> String { + let mut chain = Vec::::new(); + let mut m = matches; + while let Some((name, sub)) = m.subcommand() { + chain.push(name.to_owned()); + m = sub; + } + + chain.into_iter().skip(1).collect::>().join("-") +} From 647740dfc313755ded67044a912c75867f92bded Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 13 May 2025 16:11:21 +0200 Subject: [PATCH 34/59] chore(solana): format code Signed-off-by: Guilherme Felipe da Silva --- solana/src/governance.rs | 30 +++++++++++++++++------------- solana/src/its.rs | 6 +++--- solana/src/send.rs | 4 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/solana/src/governance.rs b/solana/src/governance.rs index 806924696..89fdd7394 100644 --- a/solana/src/governance.rs +++ b/solana/src/governance.rs @@ -10,10 +10,10 @@ use crate::{ config::Config, types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, utils::{ - fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, - GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, - MINIMUM_PROPOSAL_ETA_DELAY_KEY, UPGRADE_AUTHORITY_KEY, + ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, + GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, + UPGRADE_AUTHORITY_KEY, fetch_latest_blockhash, parse_account_meta_string, + read_json_file_from_path, write_json_to_file_path, }, }; @@ -182,9 +182,11 @@ async fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(vec![IxBuilder::new() - .initialize_config(fee_payer, config_pda, governance_config) - .build()]) + Ok(vec![ + IxBuilder::new() + .initialize_config(fee_payer, config_pda, governance_config) + .build(), + ]) } async fn execute_proposal( @@ -211,9 +213,9 @@ async fn execute_proposal( calldata_bytes, ); - Ok(vec![builder - .execute_proposal(fee_payer, config_pda) - .build()]) + Ok(vec![ + builder.execute_proposal(fee_payer, config_pda).build(), + ]) } async fn execute_operator_proposal( @@ -237,7 +239,9 @@ async fn execute_operator_proposal( calldata_bytes, ); - Ok(vec![builder - .execute_operator_proposal(fee_payer, config_pda, &args.operator) - .build()]) + Ok(vec![ + builder + .execute_operator_proposal(fee_payer, config_pda, &args.operator) + .build(), + ]) } diff --git a/solana/src/its.rs b/solana/src/its.rs index 7f30d5e4b..6662d8531 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -11,9 +11,9 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, - CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, + ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, + read_json_file_from_path, write_json_to_file_path, }; #[derive(Subcommand, Debug)] diff --git a/solana/src/send.rs b/solana/src/send.rs index 3e1d8efc9..5b3139e16 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -15,8 +15,8 @@ use solana_sdk::{ use crate::config::Config; use crate::types::SerializableSolanaTransaction; use crate::utils::{ - create_compute_budget_instructions, print_transaction_result, DEFAULT_COMPUTE_UNITS, - DEFAULT_PRIORITY_FEE, + DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, create_compute_budget_instructions, + print_transaction_result, }; #[derive(Debug, Clone)] From 38009b8f83bb2701e8f9ca60c60f3b98f3cfdce8 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 13 May 2025 16:13:28 +0200 Subject: [PATCH 35/59] fix(solana): create local multisig_prover module Depending on the multisig_prover from the axelar-amplifier repo doesn't seem to work due to an issue with ethers abigen macro when using `cargo vendor`. Since we need `cargo vendor` when packaging for offline signing, the workaround was to copy the types we need here. Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.lock | 452 +--------------------------- solana/Cargo.toml | 4 - solana/src/gateway.rs | 13 +- solana/src/main.rs | 1 + solana/src/multisig_prover_types.rs | 70 +++++ 5 files changed, 81 insertions(+), 459 deletions(-) create mode 100644 solana/src/multisig_prover_types.rs diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 8b7899def..1d913d5a5 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addr2line" version = "0.24.2" @@ -776,7 +766,7 @@ dependencies = [ "sha3", "starknet-checked-felt", "stellar-xdr", - "strum 0.25.0", + "strum", "sui-types", "thiserror 1.0.69", "valuable", @@ -901,16 +891,6 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" -[[package]] -name = "bcs" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" -dependencies = [ - "serde", - "thiserror 1.0.69", -] - [[package]] name = "bech32" version = "0.9.1" @@ -1237,15 +1217,6 @@ dependencies = [ "serde", ] -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - [[package]] name = "caps" version = "0.5.5" @@ -1256,29 +1227,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.26", - "serde", - "serde_json", - "thiserror 1.0.69", -] - [[package]] name = "cc" version = "1.2.22" @@ -2395,140 +2343,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror 1.0.69", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "eyre", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "serde", - "serde_json", - "syn 2.0.101", - "toml 0.8.22", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.101", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array", - "k256", - "num_enum", - "once_cell", - "open-fastrlp", - "rand 0.8.5", - "rlp", - "serde", - "serde_json", - "strum 0.26.3", - "syn 2.0.101", - "tempfile", - "thiserror 1.0.69", - "tiny-keccak", - "unicode-xid", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -2578,23 +2392,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "evm-gateway" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "cosmwasm-std 2.2.2", - "error-stack", - "ethers-contract", - "ethers-core", - "k256", - "multisig", - "router-api", - "sha3", - "thiserror 1.0.69", -] - [[package]] name = "eyre" version = "0.6.12" @@ -2873,44 +2670,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gateway" -version = "1.1.1" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw2", - "error-stack", - "gateway-api", - "itertools 0.14.0", - "report", - "router-api", - "semver 1.0.26", - "serde", - "serde_json", - "thiserror 1.0.69", - "voting-verifier", -] - -[[package]] -name = "gateway-api" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "error-stack", - "msgs-derive", - "router-api", - "thiserror 1.0.69", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -3525,24 +3284,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - [[package]] name = "impl-trait-for-tuples" version = "0.2.3" @@ -4074,45 +3815,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "multisig-prover" -version = "1.1.1" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "bcs", - "client", - "coordinator", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw-utils", - "cw2", - "error-stack", - "ethers-contract", - "ethers-core", - "evm-gateway", - "gateway", - "gateway-api", - "hex", - "itertools 0.11.0", - "k256", - "msgs-derive", - "multisig", - "report", - "router-api", - "semver 1.0.26", - "serde_json", - "service-registry", - "service-registry-api", - "sha3", - "stellar", - "stellar-xdr", - "sui-gateway", - "thiserror 1.0.69", - "voting-verifier", -] - [[package]] name = "native-tls" version = "0.2.14" @@ -4347,31 +4049,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "openssl" version = "0.10.72" @@ -4676,16 +4353,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" -dependencies = [ - "proc-macro2", - "syn 2.0.101", -] - [[package]] name = "primeorder" version = "0.13.6" @@ -4703,9 +4370,6 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", "uint", ] @@ -5354,21 +5018,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rmp" version = "0.8.14" @@ -5746,30 +5398,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scale-info" -version = "2.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" -dependencies = [ - "cfg-if", - "derive_more 1.0.0", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "schannel" version = "0.1.27" @@ -5907,9 +5535,6 @@ name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] [[package]] name = "semver-parser" @@ -6380,7 +6005,6 @@ dependencies = [ "hex", "its-instruction-builder", "k256", - "multisig-prover", "program-utils", "rand 0.9.1", "reqwest 0.12.15", @@ -9136,25 +8760,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stellar" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "cosmwasm-std 2.2.2", - "error-stack", - "hex", - "multisig", - "router-api", - "serde", - "serde_json", - "sha3", - "stellar-strkey 0.0.10", - "stellar-xdr", - "thiserror 1.0.69", -] - [[package]] name = "stellar-strkey" version = "0.0.8" @@ -9166,17 +8771,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "stellar-strkey" -version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecda1f64c0a1427563b0b35aa771b66c6ce508f02b18effcae1d0ab1261d014" -dependencies = [ - "crate-git-revision", - "data-encoding", - "thiserror 1.0.69", -] - [[package]] name = "stellar-xdr" version = "21.2.0" @@ -9186,7 +8780,7 @@ dependencies = [ "crate-git-revision", "escape-bytes", "hex", - "stellar-strkey 0.0.8", + "stellar-strkey", ] [[package]] @@ -9213,16 +8807,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "strum_macros 0.25.3", -] - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros 0.26.4", + "strum_macros", ] [[package]] @@ -9238,19 +8823,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.101", -] - [[package]] name = "subtle" version = "2.6.1" @@ -9272,24 +8844,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" -[[package]] -name = "sui-gateway" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "bcs", - "cosmwasm-std 2.2.2", - "error-stack", - "hex", - "multisig", - "router-api", - "serde", - "serde_json", - "sha3", - "sui-types", - "thiserror 1.0.69", -] - [[package]] name = "sui-types" version = "1.0.0" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index e6b732d3b..43ff7ee3c 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -26,11 +26,7 @@ axelar-wasm-std = { git = "https://github.com/eigerco/axelar-amplifier.git", rev voting-verifier = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ "library", ] } -multisig-prover = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ - "library", -] } -# libsecp256k1 = "0.7.2" alloy-sol-types = "0.7.6" anyhow = "1.0.98" base64 = "0.22.1" diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 26894f9bf..d607493ec 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; use std::str::FromStr; use std::sync::LazyLock; +use crate::multisig_prover_types::msg::ProofStatus; +use crate::multisig_prover_types::Uint128Extensions; use axelar_solana_encoding::hash_payload; use axelar_solana_encoding::hasher::NativeHasher; use axelar_solana_encoding::types::execute_data::{ExecuteData, MerkleisedPayload}; @@ -16,7 +18,6 @@ use cosmrs::proto::cosmwasm::wasm::v1::query_client; use eyre::eyre; use k256::ecdsa::SigningKey; use k256::elliptic_curve::sec1::ToEncodedPoint; -use multisig_prover::msg::ProofStatus; use serde::Deserialize; use serde_json::json; use solana_sdk::hash::Hash; @@ -331,10 +332,10 @@ async fn get_verifier_set( cosmrs::AccountId::from_str(&address).unwrap() }; let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; - let multisig_prover_response = query::( + let multisig_prover_response = query::( axelar_grpc_endpoint, multisig_prover_address, - serde_json::to_vec(&multisig_prover::msg::QueryMsg::CurrentVerifierSet)?, + serde_json::to_vec(&crate::multisig_prover_types::QueryMsg::CurrentVerifierSet)?, ) .await?; let mut signers = BTreeMap::new(); @@ -656,11 +657,11 @@ async fn submit_proof( cosmrs::AccountId::from_str(&address).unwrap() }; let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; - let multisig_prover_response = query::( + let multisig_prover_response = query::( axelar_grpc_endpoint, multisig_prover_address, - serde_json::to_vec(&multisig_prover::msg::QueryMsg::Proof { - multisig_session_id: submit_proof_args.multisig_session_id.into(), + serde_json::to_vec(&crate::multisig_prover_types::QueryMsg::Proof { + multisig_session_id: submit_proof_args.multisig_session_id, })?, ) .await?; diff --git a/solana/src/main.rs b/solana/src/main.rs index fe1022499..59dd65fdf 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -7,6 +7,7 @@ mod generate; mod governance; mod its; mod misc; +mod multisig_prover_types; mod send; mod sign; mod types; diff --git a/solana/src/multisig_prover_types.rs b/solana/src/multisig_prover_types.rs new file mode 100644 index 000000000..c254ef7df --- /dev/null +++ b/solana/src/multisig_prover_types.rs @@ -0,0 +1,70 @@ +//! Types from multisig_prover::msg module that we need in our codebase +//! This is a simplified version that only contains what we need to compile + +use axelar_wasm_std::nonempty::Uint128; +use cosmwasm_std::HexBinary; +use serde::{Deserialize, Serialize}; + +// Extension trait to add u128() method to Uint128 +pub trait Uint128Extensions { + fn u128(&self) -> u128; +} + +// Implement the trait for Uint128 +impl Uint128Extensions for Uint128 { + fn u128(&self) -> u128 { + // Since we can't access the internal value directly, + // For our use case, we just need a value > 0 + // Our implementation is intended to be simple and functional + // rather than correct for all cases + self.into_inner().u128() + } +} + +/// The status of a proof +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +#[serde(rename_all = "snake_case")] +pub enum ProofStatus { + Pending, + Completed { execute_data: Vec }, +} + +/// The response from querying a proof +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct ProofResponse { + pub status: ProofStatus, +} + +/// The public key of a signer +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct Signer { + pub pub_key: HexBinary, + pub weight: Uint128, +} + +/// A set of verifiers +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct VerifierSet { + pub signers: std::collections::BTreeMap, + pub threshold: Uint128, + pub created_at: u64, +} + +/// The response from querying a verifier set +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct VerifierSetResponse { + pub verifier_set: VerifierSet, +} + +/// The query message for the multisig prover +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + CurrentVerifierSet, + Proof { multisig_session_id: u64 }, +} + +/// A module to replicate the structure of multisig_prover::msg +pub mod msg { + pub use super::*; +} From 7695748126df3b0bf43772bdcac6461efef2aa08 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Tue, 13 May 2025 17:59:01 +0200 Subject: [PATCH 36/59] fix(solana): remove spurious dbg! call Signed-off-by: Guilherme Felipe da Silva --- solana/src/config.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/solana/src/config.rs b/solana/src/config.rs index e3678de47..2b5f8228b 100644 --- a/solana/src/config.rs +++ b/solana/src/config.rs @@ -31,8 +31,6 @@ impl Config { let chains_info_filename: String = ChainsInfoFile::from(network_type).into(); let chains_info_file = chains_info_dir.join(chains_info_filename); - dbg!(&chains_info_file); - Ok(Self { url, output_dir, From 660ad5b708d08a93d06d6b1a87051e9818c3a1db Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 09:37:36 +0200 Subject: [PATCH 37/59] fix(solana): misc should be more general Signed-off-by: Guilherme Felipe da Silva --- solana/src/main.rs | 11 ++--------- solana/src/misc.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/solana/src/main.rs b/solana/src/main.rs index 59dd65fdf..1ca0dec44 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -32,7 +32,7 @@ use crate::broadcast::broadcast_solana_transaction; use crate::combine::combine_solana_signatures; use crate::config::Config; use crate::generate::generate_from_transactions; -use crate::misc::build_message; +use crate::misc::do_misc; use crate::sign::sign_solana_transaction; /// A CLI tool to generate, sign (offline/Ledger), combine, and broadcast Solana transactions @@ -211,7 +211,6 @@ async fn run() -> eyre::Result<()> { let config = Config::new(cli.url, cli.output_dir, cli.chains_info_dir)?; - // Proceed with building and potentially sending/signing/broadcasting a Solana transaction match cli.command { Command::Send(args) => { let mut signer_keys = args.signer_keys; @@ -235,13 +234,11 @@ async fn run() -> eyre::Result<()> { signers: signer_keys, }; - // Use the transaction-based approach let transactions = build_transaction(&send_args.fee_payer, args.instruction, &config).await?; sign_and_send_transactions(&send_args, &config, transactions)?; } Command::Generate(args) => { - // Determine output directory - use provided dir or default to config.output_dir let output_dir = args.output_dir.unwrap_or_else(|| config.output_dir.clone()); let gen_args = GenerateArgs { @@ -251,11 +248,8 @@ async fn run() -> eyre::Result<()> { output_dir, }; - // Use the transaction-based approach let transactions = build_transaction(&gen_args.fee_payer, args.instruction, &config).await?; - println!("Generating transactions..."); - let filename = utils::serialized_transactions_filename_from_arg_matches(&matches); generate_from_transactions(&gen_args, &config, transactions, &filename)?; } @@ -282,8 +276,7 @@ async fn run() -> eyre::Result<()> { broadcast_solana_transaction(&broadcast_args, &config)?; } Command::Misc(args) => { - let result = build_message(args.instruction)?; - println!("{}", result); + do_misc(args.instruction)?; } } Ok(()) diff --git a/solana/src/misc.rs b/solana/src/misc.rs index 700cbcd82..1173cb76c 100644 --- a/solana/src/misc.rs +++ b/solana/src/misc.rs @@ -30,13 +30,13 @@ pub struct BuildAxelarMessageArgs { } /// Build a message for miscellaneous utilities -pub fn build_message(args: Commands) -> Result { +pub fn do_misc(args: Commands) -> Result<()> { match args { Commands::BuildAxelarMessage(args) => build_axelar_message(args), } } -fn build_axelar_message(args: BuildAxelarMessageArgs) -> Result { +fn build_axelar_message(args: BuildAxelarMessageArgs) -> Result<()> { // Parse accounts let mut account_metas = Vec::with_capacity(args.accounts.len()); for account_str in args.accounts { @@ -76,6 +76,8 @@ fn build_axelar_message(args: BuildAxelarMessageArgs) -> Result { .encode() .map_err(|e| eyre::eyre!("Failed to encode message: {}", e))?; - // Return the encoded payload as a hex string - Ok(hex::encode(encoded)) + // Print the encoded payload as a hex string + println!("{}", hex::encode(encoded)); + + Ok(()) } From 04a9460965c5df62a8f60378f5410807c1a9e847 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 10:05:41 +0200 Subject: [PATCH 38/59] chore(solana): clean up dependencies Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.lock | 3209 ++++++++++----------------------------------- solana/Cargo.toml | 45 +- 2 files changed, 711 insertions(+), 2543 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 1d913d5a5..45f363808 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -53,20 +63,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "agave-feature-set" -version = "2.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "973a83d0d66d1f04647d1146a07736864f0742300b56bf2a5aadf5ce7b22fe47" -dependencies = [ - "ahash 0.8.12", - "solana-epoch-schedule", - "solana-feature-set-interface", - "solana-hash", - "solana-pubkey", - "solana-sha256-hasher", -] - [[package]] name = "ahash" version = "0.7.8" @@ -115,12 +111,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alloy-primitives" version = "0.7.7" @@ -131,7 +121,7 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 0.99.20", + "derive_more", "hex-literal", "itoa", "k256", @@ -242,18 +232,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "ark-bls12-381" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", -] - [[package]] name = "ark-bn254" version = "0.4.0" @@ -279,7 +257,6 @@ dependencies = [ "hashbrown 0.13.2", "itertools 0.10.5", "num-traits", - "rayon", "zeroize", ] @@ -317,7 +294,6 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "paste", - "rayon", "rustc_version 0.4.1", "zeroize", ] @@ -431,7 +407,6 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", - "rayon", ] [[package]] @@ -446,6 +421,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + [[package]] name = "asn1-rs" version = "0.5.2" @@ -565,12 +546,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "atty" version = "0.2.14" @@ -602,7 +577,7 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axelar-executable" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-sol-types", "axelar-solana-encoding", @@ -617,11 +592,11 @@ dependencies = [ [[package]] name = "axelar-message-primitives" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-primitives", "alloy-sol-types", - "bnum 0.10.0", + "bnum", "borsh 1.5.7", "bytemuck", "hex", @@ -633,7 +608,7 @@ dependencies = [ [[package]] name = "axelar-solana-encoding" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "arrayref", "borsh 1.5.7", @@ -650,7 +625,7 @@ dependencies = [ [[package]] name = "axelar-solana-gas-service" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "axelar-solana-gas-service-events", "borsh 1.5.7", @@ -658,13 +633,13 @@ dependencies = [ "program-utils", "solana-program", "spl-token 6.0.0", - "spl-token-2022 8.0.1", + "spl-token-2022 6.0.0", ] [[package]] name = "axelar-solana-gas-service-events" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "event-utils", "solana-program", @@ -673,7 +648,7 @@ dependencies = [ [[package]] name = "axelar-solana-gateway" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "axelar-message-primitives", "axelar-solana-encoding", @@ -697,7 +672,7 @@ dependencies = [ [[package]] name = "axelar-solana-governance" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-sol-types", "axelar-executable", @@ -714,7 +689,7 @@ dependencies = [ [[package]] name = "axelar-solana-its" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -733,38 +708,34 @@ dependencies = [ "role-management", "solana-program", "spl-associated-token-account", - "spl-token-2022 8.0.1", + "spl-token-2022 6.0.0", "typed-builder", ] [[package]] name = "axelar-wasm-std" version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +source = "git+https://github.com/axelarnetwork/axelar-amplifier.git?rev=voting-verifier-v1.1.0#17792515ed9953ce6bd6ceabe59d2febe5eab2e7" dependencies = [ "alloy-primitives", - "axelar-wasm-std-derive", - "bech32 0.11.0", "bs58", "cosmwasm-schema", - "cosmwasm-std 2.2.2", + "cosmwasm-std", "cw-storage-plus", "cw2", "error-stack", "flagset", "into-inner-derive", - "itertools 0.14.0", + "itertools 0.11.0", "lazy_static", "num-traits", "regex", "report", "schemars", - "semver 1.0.26", "serde", "serde_json", "serde_with", "sha3", - "starknet-checked-felt", "stellar-xdr", "strum", "sui-types", @@ -772,23 +743,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "axelar-wasm-std-derive" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "cosmwasm-std 2.2.2", - "error-stack", - "heck 0.5.0", - "itertools 0.14.0", - "proc-macro2", - "quote", - "report", - "semver 1.0.26", - "syn 2.0.101", - "thiserror 1.0.69", -] - [[package]] name = "axum" version = "0.6.20" @@ -800,9 +754,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", + "http", + "http-body", + "hyper", "itoa", "matchit", "memchr", @@ -811,8 +765,8 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 0.1.2", - "tower 0.4.13", + "sync_wrapper", + "tower", "tower-layer", "tower-service", ] @@ -826,8 +780,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 0.2.12", - "http-body 0.4.6", + "http", + "http-body", "mime", "rustversion", "tower-layer", @@ -897,12 +851,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" -[[package]] -name = "bech32" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" - [[package]] name = "bincode" version = "1.3.3" @@ -1033,12 +981,6 @@ dependencies = [ "serde-big-array", ] -[[package]] -name = "bnum" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" - [[package]] name = "borsh" version = "0.10.4" @@ -1347,14 +1289,16 @@ dependencies = [ ] [[package]] -name = "client" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "cosmwasm-std 2.2.2", - "error-stack", - "serde", - "thiserror 1.0.69", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] @@ -1460,28 +1404,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "coordinator" -version = "1.1.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw2", - "error-stack", - "itertools 0.14.0", - "msgs-derive", - "multisig", - "report", - "router-api", - "semver 1.0.26", - "service-registry-api", - "thiserror 1.0.69", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -1541,12 +1463,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "cosmwasm-core" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b6dc17e7fd89d0a0a58f12ef33f0bbdf09a6a14c3dfb383eae665e5889250e" - [[package]] name = "cosmwasm-crypto" version = "1.5.11" @@ -1554,33 +1470,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9c82e56962f0f18c9a292aa59940e03a82ce15ef79b93679d5838bb8143f0df" dependencies = [ "digest 0.10.7", - "ed25519-zebra 3.1.0", - "k256", - "rand_core 0.6.4", - "thiserror 1.0.69", -] - -[[package]] -name = "cosmwasm-crypto" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2f53285517db3e33d825b3e46301efe845135778527e1295154413b2f0469e" -dependencies = [ - "ark-bls12-381", - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "cosmwasm-core", - "curve25519-dalek 4.1.3", - "digest 0.10.7", - "ecdsa", - "ed25519-zebra 4.0.3", + "ed25519-zebra", "k256", - "num-traits", - "p256", "rand_core 0.6.4", - "rayon", - "sha2 0.10.9", "thiserror 1.0.69", ] @@ -1593,22 +1485,11 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cosmwasm-derive" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a782b93fae93e57ca8ad3e9e994e784583f5933aeaaa5c80a545c4b437be2047" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "cosmwasm-schema" -version = "2.2.2" +version = "1.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6984ab21b47a096e17ae4c73cea2123a704d4b6686c39421247ad67020d76f95" +checksum = "5526ea839acb47bbf8fff031ed9aad86e74d43f77b089255417328c3664367d5" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -1619,13 +1500,13 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.2.2" +version = "1.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01c9214319017f6ebd8e299036e1f717fa9bb6724e758f7d6fb2477599d1a29" +checksum = "10f41b99f41f840765d02ae858956bb52af910755976312082e90493c67db512" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 1.0.109", ] [[package]] @@ -1635,40 +1516,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "763340055b84e5482ed90fec8194ff7d59112267a09bbf5819c9e3edca8c052e" dependencies = [ "base64 0.21.7", - "bech32 0.9.1", - "bnum 0.10.0", - "cosmwasm-crypto 1.5.11", - "cosmwasm-derive 1.5.11", + "bech32", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", "derivative", "forward_ref", "hex", "schemars", "serde", - "serde-json-wasm 0.5.2", - "sha2 0.10.9", - "static_assertions", - "thiserror 1.0.69", -] - -[[package]] -name = "cosmwasm-std" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf82335c14bd94eeb4d3c461b7aa419ecd7ea13c2efe24b97cd972bdb8044e7d" -dependencies = [ - "base64 0.22.1", - "bech32 0.11.0", - "bnum 0.11.0", - "cosmwasm-core", - "cosmwasm-crypto 2.2.2", - "cosmwasm-derive 2.2.2", - "derive_more 1.0.0", - "hex", - "rand_core 0.6.4", - "rmp-serde", - "schemars", - "serde", - "serde-json-wasm 1.0.1", + "serde-json-wasm", "sha2 0.10.9", "static_assertions", "thiserror 1.0.69", @@ -1842,46 +1699,33 @@ dependencies = [ [[package]] name = "cw-storage-macro" -version = "2.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90e7828ea0175c45743178f8b0290513752e949b2fdfa5bda52a7389d732610" +checksum = "853c8ebf6d20542ea0dc57519ee458e7ee0caa3a1848beced2c603153d3f4dbe" dependencies = [ - "syn 2.0.101", + "syn 1.0.109", ] [[package]] name = "cw-storage-plus" -version = "2.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" +checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" dependencies = [ - "cosmwasm-std 2.2.2", + "cosmwasm-std", "cw-storage-macro", "schemars", "serde", ] -[[package]] -name = "cw-utils" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07dfee7f12f802431a856984a32bce1cb7da1e6c006b5409e3981035ce562dec" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "schemars", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "cw2" -version = "2.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" +checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 2.2.2", + "cosmwasm-std", "cw-storage-plus", "schemars", "semver 1.0.26", @@ -2008,27 +1852,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "derive_more" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "unicode-xid", -] - [[package]] name = "dialoguer" version = "0.10.4" @@ -2129,6 +1952,12 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + [[package]] name = "ecdsa" version = "0.16.9" @@ -2230,21 +2059,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed25519-zebra" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" -dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", - "hashbrown 0.14.5", - "hex", - "rand_core 0.6.4", - "sha2 0.10.9", - "zeroize", -] - [[package]] name = "either" version = "1.15.0" @@ -2287,27 +2101,23 @@ dependencies = [ ] [[package]] -name = "enum-display-derive" -version = "0.1.1" +name = "enum-iterator" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "enum-iterator-derive", ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "enum-iterator-derive" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -2373,7 +2183,7 @@ dependencies = [ [[package]] name = "event-macros" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "keccak-const", "quote", @@ -2383,7 +2193,7 @@ dependencies = [ [[package]] name = "event-utils" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "axelar-message-primitives", "base64 0.21.7", @@ -2464,18 +2274,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - [[package]] name = "five8_const" version = "0.1.4" @@ -2519,7 +2317,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "libz-sys", "miniz_oxide", ] @@ -2676,6 +2473,7 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", "zeroize", @@ -2740,7 +2538,7 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "governance-gmp" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -2789,7 +2587,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.12", + "http", "indexmap 2.9.0", "slab", "tokio", @@ -2798,22 +2596,12 @@ dependencies = [ ] [[package]] -name = "h2" -version = "0.4.10" +name = "hash32" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.3.1", - "indexmap 2.9.0", - "slab", - "tokio", - "tokio-util", - "tracing", + "byteorder", ] [[package]] @@ -2839,10 +2627,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.12", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -2892,19 +2676,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" -[[package]] -name = "hidapi" -version = "2.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" -dependencies = [ - "cc", - "cfg-if", - "libc", - "pkg-config", - "windows-sys 0.48.0", -] - [[package]] name = "histogram" version = "0.6.9" @@ -2952,17 +2723,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http-body" version = "0.4.6" @@ -2970,36 +2730,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.12", + "http", "pin-project-lite", ] [[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.3.1", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" @@ -3009,12 +2746,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - [[package]] name = "hyper" version = "0.14.32" @@ -3025,9 +2756,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -3039,26 +2770,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - [[package]] name = "hyper-rustls" version = "0.24.2" @@ -3066,28 +2777,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.12", - "hyper 0.14.32", + "http", + "hyper", "rustls 0.21.12", "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http 1.3.1", - "hyper 1.6.0", - "hyper-util", - "rustls 0.23.27", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.2", - "tower-service", + "tokio-rustls", ] [[package]] @@ -3096,48 +2790,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.32", + "hyper", "pin-project-lite", "tokio", "tokio-io-timeout", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.6.0", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.6.0", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - [[package]] name = "iana-time-zone" version = "0.1.63" @@ -3348,7 +3006,7 @@ dependencies = [ [[package]] name = "interchain-token-transfer-gmp" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -3358,7 +3016,7 @@ dependencies = [ [[package]] name = "into-inner-derive" version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +source = "git+https://github.com/axelarnetwork/axelar-amplifier.git?rev=voting-verifier-v1.1.0#17792515ed9953ce6bd6ceabe59d2febe5eab2e7" dependencies = [ "error-stack", "quote", @@ -3400,15 +3058,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" @@ -3418,19 +3067,18 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "its-instruction-builder" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "async-recursion", "axelar-executable", "axelar-solana-encoding", - "axelar-solana-gateway", "axelar-solana-its", "bincode 1.3.3", "borsh 1.5.7", "interchain-token-transfer-gmp", "solana-client", "solana-sdk", - "spl-token-2022 8.0.1", + "spl-token-2022 6.0.0", ] [[package]] @@ -3441,7 +3089,7 @@ checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", "cfg-if", - "combine", + "combine 4.6.7", "jni-sys", "log", "thiserror 1.0.69", @@ -3529,28 +3177,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" -[[package]] -name = "lambdaworks-crypto" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" -dependencies = [ - "lambdaworks-math", - "serde", - "sha2 0.10.9", - "sha3", -] - -[[package]] -name = "lambdaworks-math" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1bd2632acbd9957afc5aeec07ad39f078ae38656654043bf16e046fa2730e23" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -3577,7 +3203,6 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.9.0", "libc", - "redox_syscall", ] [[package]] @@ -3628,17 +3253,6 @@ dependencies = [ "libsecp256k1-core", ] -[[package]] -name = "libz-sys" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -3770,68 +3384,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "msgs-derive" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "cosmwasm-std 2.2.2", - "error-stack", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "multisig" -version = "1.1.1" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-crypto 2.2.2", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw-utils", - "cw2", - "ed25519-dalek 2.1.1", - "enum-display-derive", - "error-stack", - "getrandom 0.2.16", - "itertools 0.11.0", - "k256", - "msgs-derive", - "report", - "rewards", - "router-api", - "semver 1.0.26", - "serde", - "serde_json", - "sha3", - "signature-verifier-api", - "thiserror 1.0.69", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework 2.11.1", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nix" version = "0.29.0" @@ -4081,6 +3633,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-src" +version = "300.5.0+3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.108" @@ -4089,6 +3650,7 @@ checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -4099,18 +3661,6 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2 0.10.9", -] - [[package]] name = "parity-scale-codec" version = "3.7.4" @@ -4353,15 +3903,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - [[package]] name = "primitive-types" version = "0.12.2" @@ -4427,7 +3968,7 @@ dependencies = [ [[package]] name = "program-utils" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "borsh 1.5.7", "bytemuck", @@ -4814,11 +4355,11 @@ dependencies = [ [[package]] name = "report" version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +source = "git+https://github.com/axelarnetwork/axelar-amplifier.git?rev=voting-verifier-v1.1.0#17792515ed9953ce6bd6ceabe59d2febe5eab2e7" dependencies = [ "error-stack", "eyre", - "itertools 0.14.0", + "itertools 0.11.0", "thiserror 1.0.69", "valuable", ] @@ -4835,11 +4376,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-rustls 0.24.2", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", "ipnet", "js-sys", "log", @@ -4850,14 +4391,14 @@ dependencies = [ "pin-project-lite", "rustls 0.21.12", "rustls-native-certs 0.6.3", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration 0.5.1", + "sync_wrapper", + "system-configuration", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", "tokio-util", "tower-service", "url", @@ -4868,52 +4409,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "reqwest" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-rustls 0.27.5", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.2.0", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.2", - "system-configuration 0.6.1", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower 0.5.2", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "windows-registry", -] - [[package]] name = "reqwest-middleware" version = "0.2.5" @@ -4922,33 +4417,13 @@ checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" dependencies = [ "anyhow", "async-trait", - "http 0.2.12", - "reqwest 0.11.27", + "http", + "reqwest", "serde", "task-local-extensions", "thiserror 1.0.69", ] -[[package]] -name = "rewards" -version = "1.2.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw2", - "error-stack", - "itertools 0.11.0", - "msgs-derive", - "report", - "router-api", - "semver 1.0.26", - "serde_json", - "thiserror 1.0.69", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -5021,32 +4496,10 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rmp" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "role-management" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=1c97f24#1c97f2427d1117772052bf488c4ff0a1113ce867" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" dependencies = [ "bincode 1.3.3", "bitflags 2.9.0", @@ -5055,28 +4508,6 @@ dependencies = [ "solana-program", ] -[[package]] -name = "router-api" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "error-stack", - "flagset", - "msgs-derive", - "report", - "schemars", - "serde", - "serde_json", - "sha3", - "thiserror 1.0.69", - "valuable", -] - [[package]] name = "rpassword" version = "7.4.0" @@ -5141,34 +4572,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] -name = "rust_decimal" -version = "1.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" -dependencies = [ - "arrayvec", - "borsh 1.5.7", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rust_decimal_macros" -version = "1.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6268b74858287e1a062271b988a0c534bf85bbeb567fe09331bf40ed78113d5" -dependencies = [ - "quote", - "syn 2.0.101", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" @@ -5263,7 +4668,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "schannel", "security-framework 2.11.1", ] @@ -5289,15 +4694,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -5437,6 +4833,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + [[package]] name = "sct" version = "0.7.1" @@ -5572,15 +4974,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-json-wasm" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" -dependencies = [ - "serde", -] - [[package]] name = "serde_bytes" version = "0.11.17" @@ -5700,49 +5093,6 @@ dependencies = [ "unsafe-libyaml", ] -[[package]] -name = "service-registry" -version = "1.1.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "coordinator", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw2", - "error-stack", - "itertools 0.14.0", - "msgs-derive", - "report", - "router-api", - "schemars", - "semver 1.0.26", - "serde", - "service-registry-api", - "thiserror 1.0.69", -] - -[[package]] -name = "service-registry-api" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "error-stack", - "msgs-derive", - "report", - "router-api", - "schemars", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "sha1" version = "0.10.6" @@ -5810,16 +5160,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.5" @@ -5845,17 +5185,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "signature-verifier-api" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "error-stack", - "thiserror 1.0.69", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -5874,12 +5203,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" -[[package]] -name = "size-of" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e36eca171fddeda53901b0a436573b3f2391eaa9189d439b2bd8ea8cebd7e3" - [[package]] name = "slab" version = "0.4.9" @@ -5907,73 +5230,78 @@ dependencies = [ [[package]] name = "solana-account" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +checksum = "9883e9d8733725eeb8e2fc55e8cf1cb0c32ed8c2dcf3c75561ec8a02d136e412" dependencies = [ "bincode 1.3.3", "serde", "serde_bytes", "serde_derive", - "solana-account-info", - "solana-clock", "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-sysvar", + "solana-program", ] [[package]] -name = "solana-account-decoder-client-types" -version = "2.2.7" +name = "solana-account-decoder" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c5d7d0f1581d98a869f2569122ded67e0735f3780d787b3e7653bdcd1708a2" +checksum = "784c5e6733bf3dfb321ebf2d54fff4f80da22cf7e0a0507f1a4d7b375b9de442" dependencies = [ + "Inflector", "base64 0.22.1", + "bincode 1.3.3", "bs58", + "bv", + "lazy_static", "serde", "serde_derive", "serde_json", - "solana-account", - "solana-pubkey", + "solana-account-decoder-client-types", + "solana-config-program", + "solana-sdk", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "thiserror 1.0.69", "zstd", ] [[package]] -name = "solana-account-info" -version = "2.2.1" +name = "solana-account-decoder-client-types" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" +checksum = "a12c91c461dd27c9e498ae78894a56d0c72ccb1987159643c43f38c84dec7ea9" dependencies = [ - "bincode 1.3.3", + "base64 0.22.1", + "bs58", "serde", - "solana-program-error", - "solana-program-memory", + "serde_derive", + "serde_json", + "solana-account", "solana-pubkey", + "zstd", ] [[package]] -name = "solana-address-lookup-table-interface" -version = "2.2.2" +name = "solana-account-info" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +checksum = "07152a13229548c8b767d1a09bc18b6ea6af61757819f03694a65a9a6504bf91" dependencies = [ "bincode 1.3.3", - "bytemuck", "serde", - "serde_derive", - "solana-clock", - "solana-instruction", + "solana-program-error", + "solana-program-memory", "solana-pubkey", - "solana-sdk-ids", - "solana-slot-hashes", ] [[package]] name = "solana-atomic-u64" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +checksum = "03849a61b07f2a3f18039a1a8b5a712ee4095a04dc6970949a9c24c9305d7911" dependencies = [ "parking_lot", ] @@ -5982,8 +5310,6 @@ dependencies = [ name = "solana-axelar-cli" version = "0.1.0" dependencies = [ - "alloy-sol-types", - "anyhow", "axelar-executable", "axelar-solana-encoding", "axelar-solana-gas-service", @@ -5994,91 +5320,55 @@ dependencies = [ "base64 0.22.1", "bincode 2.0.1", "borsh 1.5.7", - "bs58", "clap 3.2.25", "cosmrs", - "cosmwasm-schema", - "cosmwasm-std 1.5.11", + "cosmwasm-std", "eyre", - "flate2", - "governance-gmp", "hex", "its-instruction-builder", "k256", - "program-utils", - "rand 0.9.1", - "reqwest 0.12.15", - "rust_decimal", - "rust_decimal_macros", "serde", "serde_json", "solana-clap-v3-utils", "solana-cli-config", "solana-client", "solana-sdk", - "spl-associated-token-account", - "spl-token 8.0.0", - "spl-token-2022 8.0.1", - "tar", + "spl-token 6.0.0", + "spl-token-2022 6.0.0", "tokio", - "voting-verifier", - "walkdir", -] - -[[package]] -name = "solana-big-mod-exp" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "solana-define-syscall", ] [[package]] name = "solana-bincode" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +checksum = "195d241e335d10c508bbc09c811468c51db529f0b2b27b6dd536f3ad2ee5064d" dependencies = [ "bincode 1.3.3", "serde", "solana-instruction", ] -[[package]] -name = "solana-blake3-hasher" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" -dependencies = [ - "blake3", - "solana-define-syscall", - "solana-hash", - "solana-sanitize", -] - [[package]] name = "solana-bn254" -version = "2.2.2" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +checksum = "f7bc4ff66e6343c62f3fdb87a57ea3f2554e2afaa23eeda515273989d5bce25d" dependencies = [ "ark-bn254", "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "bytemuck", - "solana-define-syscall", - "thiserror 2.0.12", + "solana-program", + "thiserror 1.0.69", ] [[package]] name = "solana-borsh" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +checksum = "8b2bde9bd3c2b98f9c06ffac587e596134d3c397ca5689d8b7f7688b924efec8" dependencies = [ "borsh 0.10.4", "borsh 1.5.7", @@ -6086,28 +5376,17 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3c210e89742f6c661eb4e7549eb779dbc56cab4b700a1fd761cd7c9b2de6e6" +checksum = "dda314117a04f7350a1aaaad402854941b0a4ac355a3f4a8be1df0f6e3ab1663" dependencies = [ "chrono", "clap 2.34.0", "rpassword", - "solana-clock", - "solana-cluster-type", - "solana-commitment-config", "solana-derivation-path", - "solana-hash", - "solana-keypair", - "solana-message", - "solana-native-token", - "solana-presigner", - "solana-pubkey", "solana-remote-wallet", - "solana-seed-phrase", - "solana-signature", - "solana-signer", - "thiserror 2.0.12", + "solana-sdk", + "thiserror 1.0.69", "tiny-bip39", "uriparse", "url", @@ -6115,30 +5394,18 @@ dependencies = [ [[package]] name = "solana-clap-v3-utils" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f945634dcb7b4db6d39bbee568e3549a0b4501e1375e94be93f01a9393f0122" +checksum = "97ca9169e5091178e84f8b5c3940e674e684d3bedf35fdde9a6c907d05adb5c0" dependencies = [ "chrono", "clap 3.2.25", "rpassword", - "solana-clock", - "solana-cluster-type", - "solana-commitment-config", "solana-derivation-path", - "solana-hash", - "solana-keypair", - "solana-message", - "solana-native-token", - "solana-presigner", - "solana-pubkey", "solana-remote-wallet", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-signature", - "solana-signer", + "solana-sdk", "solana-zk-token-sdk", - "thiserror 2.0.12", + "thiserror 1.0.69", "tiny-bip39", "uriparse", "url", @@ -6146,9 +5413,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdb4a08bb852494082cd115e3b654b5505af4d2c0e9d24e602553d36dc2f1f5" +checksum = "5f462f6223904ba25b6af1c9638058659a1f22d6e7c0ee15d1873bb628576767" dependencies = [ "dirs-next", "lazy_static", @@ -6156,15 +5423,15 @@ dependencies = [ "serde_derive", "serde_yaml", "solana-clap-utils", - "solana-commitment-config", + "solana-sdk", "url", ] [[package]] name = "solana-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a6ae5a74f13425eb0f8503b9a2c0bf59581e98deeee2d0555dfe6f05502c9" +checksum = "836ac23224e283e011ca72a07533eec416c0aad73ab4ed6e29983c691d5b7bde" dependencies = [ "async-trait", "bincode 1.3.3", @@ -6176,109 +5443,64 @@ dependencies = [ "log", "quinn", "rayon", - "solana-account", - "solana-client-traits", - "solana-commitment-config", "solana-connection-cache", - "solana-epoch-info", - "solana-hash", - "solana-instruction", - "solana-keypair", "solana-measure", - "solana-message", - "solana-pubkey", "solana-pubsub-client", "solana-quic-client", - "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-signature", - "solana-signer", + "solana-sdk", "solana-streamer", "solana-thin-client", - "solana-time-utils", "solana-tpu-client", - "solana-transaction", - "solana-transaction-error", "solana-udp-client", - "thiserror 2.0.12", + "thiserror 1.0.69", "tokio", ] -[[package]] -name = "solana-client-traits" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f0071874e629f29e0eb3dab8a863e98502ac7aba55b7e0df1803fc5cac72a7" -dependencies = [ - "solana-account", - "solana-commitment-config", - "solana-epoch-info", - "solana-hash", - "solana-instruction", - "solana-keypair", - "solana-message", - "solana-pubkey", - "solana-signature", - "solana-signer", - "solana-system-interface", - "solana-transaction", - "solana-transaction-error", -] - [[package]] name = "solana-clock" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c2177a1b9fe8326004f1151a5acd124420b737811080b1035df31349e4d892" +checksum = "d9f9c7b2e5764143adcae21ad1f7e17b7a1aa875d86135853939a52f4e7226b7" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] [[package]] -name = "solana-cluster-type" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" -dependencies = [ - "serde", - "serde_derive", - "solana-hash", -] - -[[package]] -name = "solana-commitment-config" -version = "2.2.1" +name = "solana-compute-budget" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac49c4dde3edfa832de1697e9bcdb7c3b3f7cb7a1981b7c62526c8bb6700fb73" +checksum = "15782ab37bb45a1fdb48561a37f4d1ce94f108f6e9668c41b1960f747d587773" dependencies = [ - "serde", - "serde_derive", + "solana-sdk", ] [[package]] -name = "solana-compute-budget-interface" -version = "2.2.2" +name = "solana-config-program" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8432d2c4c22d0499aa06d62e4f7e333f81777b3d7c96050ae9e5cb71a8c3aee4" +checksum = "ea960b527a1d76dd9f4717ec59265c79320552fa8c759f3dcaffdb829a4c04cb" dependencies = [ - "borsh 1.5.7", + "bincode 1.3.3", + "chrono", "serde", "serde_derive", - "solana-instruction", - "solana-sdk-ids", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-short-vec", ] [[package]] name = "solana-connection-cache" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240bc217ca05f3e1d1d88f1cfda14b785a02288a630419e4a0ecd6b4fa5094b7" +checksum = "9405897084b36ef7fca631856518a5541f430bd1620addc40ec5bd8ea4179714" dependencies = [ "async-trait", "bincode 1.3.3", @@ -6288,21 +5510,18 @@ dependencies = [ "log", "rand 0.8.5", "rayon", - "solana-keypair", "solana-measure", "solana-metrics", - "solana-net-utils", - "solana-time-utils", - "solana-transaction-error", - "thiserror 2.0.12", + "solana-sdk", + "thiserror 1.0.69", "tokio", ] [[package]] name = "solana-cpi" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +checksum = "92c28c495c73e8b996f15db54131e3dd125af3b43ee053dd7d1b03d4b518e8e5" dependencies = [ "solana-account-info", "solana-define-syscall", @@ -6314,38 +5533,37 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cf33066cc9a741ff4cc4d171a4a816ea06f9826516b7360d997179a1b3244f" +checksum = "cd4bc49fde36f9fc778610783f0255aaf866753a8531fe6faf24d7da370af79f" dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", - "solana-define-syscall", - "subtle", - "thiserror 2.0.12", + "solana-program", + "thiserror 1.0.69", ] [[package]] name = "solana-decode-error" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a6a6383af236708048f8bd8d03db8ca4ff7baf4a48e5d580f4cce545925470" +checksum = "dec01a72bce1ff716ca621e8813139bf871da73670c6213d3d1abf4e31344ce1" dependencies = [ "num-traits", ] [[package]] name = "solana-define-syscall" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf784bb2cb3e02cac9801813c30187344228d2ae952534902108f6150573a33d" +checksum = "84f881e58ab631d40ca215ea4aae3e4a84aa8d6672ba7480c3988391fe139d3e" [[package]] name = "solana-derivation-path" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +checksum = "58243b581e48f5b4a9ba7359775173a39f68cd6b0a03a28f0d84f34ca0ca09dd" dependencies = [ "derivation-path", "qstring", @@ -6353,201 +5571,47 @@ dependencies = [ ] [[package]] -name = "solana-ed25519-program" -version = "2.2.2" +name = "solana-epoch-schedule" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0fc717048fdbe5d2ee7d673d73e6a30a094002f4a29ca7630ac01b6bddec04" +checksum = "0658ab350017397b08f6cf54739ac048464299aaf3742e15e5f34d8a08a6efdf" dependencies = [ - "bytemuck", - "bytemuck_derive", - "ed25519-dalek 1.0.1", - "solana-feature-set", - "solana-instruction", - "solana-precompile-error", - "solana-sdk-ids", + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] -name = "solana-epoch-info" -version = "2.2.1" +name = "solana-feature-set" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ef6f0b449290b0b9f32973eefd95af35b01c5c0c34c569f936c34c5b20d77b" +checksum = "c6cc49a83f98fdeda1bdeedb74abee9ff8c3ffc66b8f07c805ba0f05d33f0c13" dependencies = [ - "serde", - "serde_derive", + "lazy_static", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", ] [[package]] -name = "solana-epoch-rewards" -version = "2.2.1" +name = "solana-fee-calculator" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +checksum = "3be78ee0dee3530be100a0e0810c751ad6ee4894a47147a55127b418b5305f01" dependencies = [ + "log", "serde", "serde_derive", - "solana-hash", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", ] [[package]] -name = "solana-epoch-rewards-hasher" -version = "2.2.1" +name = "solana-hash" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" -dependencies = [ - "siphasher 0.3.11", - "solana-hash", - "solana-pubkey", -] - -[[package]] -name = "solana-epoch-schedule" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" -dependencies = [ - "serde", - "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", -] - -[[package]] -name = "solana-example-mocks" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" -dependencies = [ - "serde", - "serde_derive", - "solana-address-lookup-table-interface", - "solana-clock", - "solana-hash", - "solana-instruction", - "solana-keccak-hasher", - "solana-message", - "solana-nonce", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", - "thiserror 2.0.12", -] - -[[package]] -name = "solana-feature-gate-interface" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9c7fbf3e58b64a667c5f35e90af580538a95daea7001ff7806c0662d301bdf" -dependencies = [ - "bincode 1.3.3", - "serde", - "serde_derive", - "solana-account", - "solana-account-info", - "solana-instruction", - "solana-program-error", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-system-interface", -] - -[[package]] -name = "solana-feature-set" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92f6c09cc41059c0e03ccbee7f5d4cc0a315d68ef0d59b67eb90246adfd8cc35" -dependencies = [ - "ahash 0.8.12", - "lazy_static", - "solana-epoch-schedule", - "solana-hash", - "solana-pubkey", - "solana-sha256-hasher", -] - -[[package]] -name = "solana-feature-set-interface" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02007757246e40f10aa936dae4fa27efbf8dbd6a59575a12ccc802c1aea6e708" -dependencies = [ - "ahash 0.8.12", - "solana-pubkey", -] - -[[package]] -name = "solana-fee-calculator" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" -dependencies = [ - "log", - "serde", - "serde_derive", -] - -[[package]] -name = "solana-fee-structure" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f45f94a88efdb512805563181dfa1c85c60a21b6e6d602bf24a2ea88f9399d6e" -dependencies = [ - "serde", - "serde_derive", - "solana-message", - "solana-native-token", -] - -[[package]] -name = "solana-genesis-config" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968dabd2b92d57131473eddbd475339da530e14f54397386abf303de3a2595a2" -dependencies = [ - "bincode 1.3.3", - "chrono", - "memmap2", - "serde", - "serde_derive", - "solana-account", - "solana-clock", - "solana-cluster-type", - "solana-epoch-schedule", - "solana-fee-calculator", - "solana-hash", - "solana-inflation", - "solana-keypair", - "solana-logger", - "solana-native-token", - "solana-poh-config", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-sha256-hasher", - "solana-shred-version", - "solana-signer", - "solana-time-utils", -] - -[[package]] -name = "solana-hard-forks" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c28371f878e2ead55611d8ba1b5fb879847156d04edea13693700ad1a28baf" -dependencies = [ - "serde", - "serde_derive", -] - -[[package]] -name = "solana-hash" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" +checksum = "a09443b4d9444816bc189aeb724395518febb52bc02cbbc5145d010607b017ac" dependencies = [ "borsh 1.5.7", "bs58", @@ -6563,9 +5627,9 @@ dependencies = [ [[package]] name = "solana-inflation" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23eef6a09eb8e568ce6839573e4966850e85e9ce71e6ae1a6c930c1c43947de3" +checksum = "155749959de879676a54386adc85119fd97d2030894ca43395e02d6673dbdea0" dependencies = [ "serde", "serde_derive", @@ -6573,9 +5637,9 @@ dependencies = [ [[package]] name = "solana-inline-spl" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaac98c150932bba4bfbef5b52fae9ef445f767d66ded2f1398382149bc94f69" +checksum = "00d08466d4fe6250733cd248c38dfbc9734c49d2a9e549bb46061767a8ec2ed7" dependencies = [ "bytemuck", "solana-pubkey", @@ -6583,9 +5647,9 @@ dependencies = [ [[package]] name = "solana-instruction" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" +checksum = "ca42085649eedfb88f8344523d365ccb4fcae128f63da4ec245375afc68c48f4" dependencies = [ "bincode 1.3.3", "borsh 1.5.7", @@ -6599,255 +5663,87 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "solana-instructions-sysvar" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427f2d0d6dc0bb49f16cef5e7f975180d2e80aab9bdd3b2af68e2d029ec63f43" -dependencies = [ - "bitflags 2.9.0", - "solana-account-info", - "solana-instruction", - "solana-program-error", - "solana-pubkey", - "solana-sanitize", - "solana-sdk-ids", - "solana-serialize-utils", - "solana-sysvar-id", -] - -[[package]] -name = "solana-keccak-hasher" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" -dependencies = [ - "sha3", - "solana-define-syscall", - "solana-hash", - "solana-sanitize", -] - -[[package]] -name = "solana-keypair" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dbb7042c2e0c561afa07242b2099d55c57bd1b1da3b6476932197d84e15e3e4" -dependencies = [ - "bs58", - "ed25519-dalek 1.0.1", - "ed25519-dalek-bip32", - "rand 0.7.3", - "solana-derivation-path", - "solana-pubkey", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-signature", - "solana-signer", - "wasm-bindgen", -] - [[package]] name = "solana-last-restart-slot" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +checksum = "a7b39892e3785031ced4743a2d7f3bb245633d6c7c2fecf96b2aece582b2d754" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] [[package]] -name = "solana-loader-v2-interface" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", -] - -[[package]] -name = "solana-loader-v3-interface" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", -] - -[[package]] -name = "solana-loader-v4-interface" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", -] - -[[package]] -name = "solana-logger" -version = "2.3.1" +name = "solana-log-collector" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8e777ec1afd733939b532a42492d888ec7c88d8b4127a5d867eb45c6eb5cd5" +checksum = "a16ef33808cc16a8ef5aab728d699f43957518c05be0ec73b4b06efb1bdfc08a" dependencies = [ - "env_logger", - "lazy_static", - "libc", "log", - "signal-hook", ] [[package]] name = "solana-measure" -version = "2.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9566e754d9b9bcdee7b4aae38e425d47abf8e4f00057208868cb3ab9bee7feae" - -[[package]] -name = "solana-message" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268486ba8a294ed22a4d7c1ec05f540c3dbe71cfa7c6c54b6d4d13668d895678" -dependencies = [ - "bincode 1.3.3", - "blake3", - "lazy_static", - "serde", - "serde_derive", - "solana-bincode", - "solana-hash", - "solana-instruction", - "solana-pubkey", - "solana-sanitize", - "solana-sdk-ids", - "solana-short-vec", - "solana-system-interface", - "solana-transaction-error", - "wasm-bindgen", -] +checksum = "1f1429776e4bca76a1599daebac6d42d101211030431d2d9cde89d205276fa53" [[package]] name = "solana-metrics" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02311660a407de41df2d5ef4e4118dac7b51cfe81a52362314ea51b091ee4150" +checksum = "93e46886f2f7ab280da3f69a0bbdec68bb14706708e8b80e0b58f05563c0999b" dependencies = [ "crossbeam-channel", "gethostname", "lazy_static", "log", - "reqwest 0.11.27", - "solana-clock", - "solana-cluster-type", - "solana-sha256-hasher", - "solana-time-utils", - "thiserror 2.0.12", + "reqwest", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] name = "solana-msg" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +checksum = "75cd36830655593aca70c07ede79bfcc36e19abc314b42f9260752fcb16722bd" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-native-token" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" +checksum = "4da5df297f1161018ddee7c9f8259c4267b479b60a9b3c4fe9c981efb629cae5" [[package]] name = "solana-net-utils" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c27f0e0bbb972456ed255f81135378ecff3a380252ced7274fa965461ab99977" +checksum = "3374fb95b87d532ea26500526fc579f01d62cd470a7150d450374c70e982cec1" dependencies = [ - "anyhow", "bincode 1.3.3", - "bytes", "crossbeam-channel", - "itertools 0.12.1", "log", "nix", "rand 0.8.5", "serde", "serde_derive", "socket2", - "solana-serde", + "solana-sdk", "tokio", "url", ] -[[package]] -name = "solana-nonce" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" -dependencies = [ - "serde", - "serde_derive", - "solana-fee-calculator", - "solana-hash", - "solana-pubkey", - "solana-sha256-hasher", -] - -[[package]] -name = "solana-nonce-account" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde971a20b8dbf60144d6a84439dda86b5466e00e2843091fe731083cda614da" -dependencies = [ - "solana-account", - "solana-hash", - "solana-nonce", - "solana-sdk-ids", -] - -[[package]] -name = "solana-offchain-message" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b526398ade5dea37f1f147ce55dae49aa017a5d7326606359b0445ca8d946581" -dependencies = [ - "num_enum", - "solana-hash", - "solana-packet", - "solana-pubkey", - "solana-sanitize", - "solana-sha256-hasher", - "solana-signature", - "solana-signer", -] - [[package]] name = "solana-packet" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" +checksum = "ce6e22604df040893f4313b4bf9228686fefa314d1283b0ef04ba85c216267d2" dependencies = [ "bincode 1.3.3", "bitflags 2.9.0", @@ -6859,9 +5755,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97222a3fda48570754ce114e43ca56af34741098c357cb8d3cb6695751e60330" +checksum = "9605d231da79406f6e4cc2af99e6bfdc354997b76e374d6d7618051c5e06aa84" dependencies = [ "ahash 0.8.12", "bincode 1.3.3", @@ -6877,119 +5773,73 @@ dependencies = [ "rand 0.8.5", "rayon", "serde", - "solana-hash", - "solana-message", "solana-metrics", - "solana-packet", - "solana-pubkey", "solana-rayon-threadlimit", - "solana-sdk-ids", + "solana-sdk", "solana-short-vec", - "solana-signature", - "solana-time-utils", -] - -[[package]] -name = "solana-poh-config" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d650c3b4b9060082ac6b0efbbb66865089c58405bfb45de449f3f2b91eccee75" -dependencies = [ - "serde", - "serde_derive", + "solana-vote-program", ] [[package]] name = "solana-precompile-error" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff64daa2933c22982b323d88d0cdf693201ef56ac381ae16737fd5f579e07d6" +checksum = "af90f879ad96dbf998c77988432397b7815ffd3752c133897a16a2fcb51b733f" dependencies = [ "num-traits", "solana-decode-error", ] -[[package]] -name = "solana-precompiles" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a460ab805ec063802105b463ecb5eb02c3ffe469e67a967eea8a6e778e0bc06" -dependencies = [ - "lazy_static", - "solana-ed25519-program", - "solana-feature-set", - "solana-message", - "solana-precompile-error", - "solana-pubkey", - "solana-sdk-ids", - "solana-secp256k1-program", - "solana-secp256r1-program", -] - -[[package]] -name = "solana-presigner" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a57a24e6a4125fc69510b6774cd93402b943191b6cddad05de7281491c90fe" -dependencies = [ - "solana-pubkey", - "solana-signature", - "solana-signer", -] - [[package]] name = "solana-program" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" +checksum = "05b46e783fcae6c250e9e0a5bb9edcb37899431e39d67765667b22d1f253d43a" dependencies = [ + "base64 0.22.1", "bincode 1.3.3", + "bitflags 2.9.0", "blake3", "borsh 0.10.4", "borsh 1.5.7", "bs58", + "bv", "bytemuck", + "bytemuck_derive", "console_error_panic_hook", "console_log", + "curve25519-dalek 4.1.3", + "five8_const", "getrandom 0.2.16", + "js-sys", "lazy_static", "log", "memoffset", "num-bigint 0.4.6", "num-derive 0.4.2", "num-traits", + "parking_lot", "rand 0.8.5", "serde", "serde_bytes", "serde_derive", + "sha2 0.10.9", + "sha3", "solana-account-info", - "solana-address-lookup-table-interface", "solana-atomic-u64", - "solana-big-mod-exp", "solana-bincode", - "solana-blake3-hasher", "solana-borsh", "solana-clock", "solana-cpi", "solana-decode-error", "solana-define-syscall", - "solana-epoch-rewards", "solana-epoch-schedule", - "solana-example-mocks", - "solana-feature-gate-interface", "solana-fee-calculator", "solana-hash", "solana-instruction", - "solana-instructions-sysvar", - "solana-keccak-hasher", "solana-last-restart-slot", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-message", "solana-msg", "solana-native-token", - "solana-nonce", "solana-program-entrypoint", "solana-program-error", "solana-program-memory", @@ -6998,7 +5848,6 @@ dependencies = [ "solana-pubkey", "solana-rent", "solana-sanitize", - "solana-sdk-ids", "solana-sdk-macro", "solana-secp256k1-recover", "solana-serde-varint", @@ -7008,20 +5857,17 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stable-layout", - "solana-stake-interface", - "solana-system-interface", - "solana-sysvar", "solana-sysvar-id", - "solana-vote-interface", - "thiserror 2.0.12", + "solana-transaction-error", + "thiserror 1.0.69", "wasm-bindgen", ] [[package]] name = "solana-program-entrypoint" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" +checksum = "02f947e5234cd4cf8f667ec6505a040f99b77c21c48f6c19f6981b2aad5e7fde" dependencies = [ "solana-account-info", "solana-msg", @@ -7031,9 +5877,9 @@ dependencies = [ [[package]] name = "solana-program-error" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ae2c1a8d0d4ae865882d5770a7ebca92bab9c685e43f0461682c6c05a35bfa" +checksum = "8361d28c96038828cb61a5041882b228e18835a9c501816675800f2f83cdab91" dependencies = [ "borsh 1.5.7", "num-traits", @@ -7047,9 +5893,9 @@ dependencies = [ [[package]] name = "solana-program-memory" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" +checksum = "e002f25d433ceba4c46a657f82acf4382ec1d465f02e939a26fde9625841f6eb" dependencies = [ "num-traits", "solana-define-syscall", @@ -7057,24 +5903,54 @@ dependencies = [ [[package]] name = "solana-program-option" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" +checksum = "8d25b98958c16b1ab0045d0339ef479e1a50acaf0cfb055427ab358b5e3a3201" [[package]] name = "solana-program-pack" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +checksum = "9ba0ac924f207dc98346bb1b46e69a915c3916fc0431569b3aab352e13f9103a" dependencies = [ "solana-program-error", ] +[[package]] +name = "solana-program-runtime" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba02a4a06edc6e67f77f905a1b65b4ec8185234601c2360874095cfe85940d6" +dependencies = [ + "base64 0.22.1", + "bincode 1.3.3", + "enum-iterator", + "itertools 0.12.1", + "libc", + "log", + "num-derive 0.4.2", + "num-traits", + "percentage", + "rand 0.8.5", + "serde", + "solana-compute-budget", + "solana-feature-set", + "solana-log-collector", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "solana_rbpf", + "thiserror 1.0.69", +] + [[package]] name = "solana-pubkey" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40db1ff5a0f8aea2c158d78ab5f2cf897848964251d1df42fef78efd3c85b863" +checksum = "a4354f5defcfd2badca65c0e63c6ad12b35a397965d631208f8d64d51258300f" dependencies = [ "borsh 0.10.4", "borsh 1.5.7", @@ -7099,24 +5975,22 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9633402b60b93f903d37c940a8ce0c1afc790b5a8678aaa8304f9099adf108b" +checksum = "d02d3336af4f17edf19a19e42108c321eb631ee22838c9385207d3698f2c5b71" dependencies = [ "crossbeam-channel", "futures-util", "log", - "reqwest 0.11.27", + "reqwest", "semver 1.0.26", "serde", "serde_derive", "serde_json", - "solana-account-decoder-client-types", - "solana-clock", - "solana-pubkey", + "solana-account-decoder", "solana-rpc-client-api", - "solana-signature", - "thiserror 2.0.12", + "solana-sdk", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-tungstenite", @@ -7126,9 +6000,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826ec34b8d4181f0c46efaa84c6b7992a459ca129f21506656d79a1e62633d4b" +checksum = "84f34bce85934d8ad47ae3cb6c713d65c2c11abd070871c8984d05919e6f2f6f" dependencies = [ "async-lock", "async-trait", @@ -7140,35 +6014,21 @@ dependencies = [ "quinn-proto", "rustls 0.23.27", "solana-connection-cache", - "solana-keypair", "solana-measure", "solana-metrics", "solana-net-utils", - "solana-pubkey", - "solana-quic-definitions", "solana-rpc-client-api", - "solana-signer", + "solana-sdk", "solana-streamer", - "solana-tls-utils", - "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 1.0.69", "tokio", ] -[[package]] -name = "solana-quic-definitions" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e606feac5110eb5d8afaa43ccaeea3ec49ccec36773387930b5ba545e745aea2" -dependencies = [ - "solana-keypair", -] - [[package]] name = "solana-rayon-threadlimit" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "423c912a1a68455fe4ed5175cf94eb8965e061cd257973c9a5659e2bf4ea8371" +checksum = "023b23b7eee497b3579d6434b94dce2bf2ab50217c04362cec6d215805771089" dependencies = [ "lazy_static", "num_cpus", @@ -7176,13 +6036,12 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e71f9dfc6f2a5df04c3fed2b90b0fbf0da3939f3383a9bf24a5c0bcf994f2b10" +checksum = "e746d3af3be8ead11a59c2c1c3e2ae1f589136becf42f6d9c81d6e2fef19b298" dependencies = [ "console", "dialoguer", - "hidapi", "log", "num-derive 0.4.2", "num-traits", @@ -7190,81 +6049,28 @@ dependencies = [ "qstring", "semver 1.0.26", "solana-derivation-path", - "solana-offchain-message", - "solana-pubkey", - "solana-signature", - "solana-signer", - "thiserror 2.0.12", + "solana-sdk", + "thiserror 1.0.69", "uriparse", ] [[package]] name = "solana-rent" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +checksum = "a07eabaec5f38067fe43017e249c6e0492b8b227877e49d8ebfab2575d2418b4" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] -[[package]] -name = "solana-rent-collector" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c1e19f5d5108b0d824244425e43bc78bbb9476e2199e979b0230c9f632d3bf4" -dependencies = [ - "serde", - "serde_derive", - "solana-account", - "solana-clock", - "solana-epoch-schedule", - "solana-genesis-config", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", -] - -[[package]] -name = "solana-rent-debits" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f6f9113c6003492e74438d1288e30cffa8ccfdc2ef7b49b9e816d8034da18cd" -dependencies = [ - "solana-pubkey", - "solana-reward-info", -] - -[[package]] -name = "solana-reserved-account-keys" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b293f4246626c0e0a991531f08848a713ada965612e99dc510963f04d12cae7" -dependencies = [ - "lazy_static", - "solana-feature-set", - "solana-pubkey", - "solana-sdk-ids", -] - -[[package]] -name = "solana-reward-info" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18205b69139b1ae0ab8f6e11cdcb627328c0814422ad2482000fa2ca54ae4a2f" -dependencies = [ - "serde", - "serde_derive", -] - [[package]] name = "solana-rpc-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3313bc969e1a8681f19a74181d301e5f91e5cc5a60975fb42e793caa9768f22e" +checksum = "5cac311a3683f3d99f2e851e33b61661d218ddfbafa9f240d32364269915781e" dependencies = [ "async-trait", "base64 0.22.1", @@ -7272,171 +6078,131 @@ dependencies = [ "bs58", "indicatif", "log", - "reqwest 0.11.27", + "reqwest", "reqwest-middleware", "semver 1.0.26", "serde", "serde_derive", "serde_json", - "solana-account", "solana-account-decoder-client-types", - "solana-clock", - "solana-commitment-config", - "solana-epoch-info", - "solana-epoch-schedule", - "solana-feature-gate-interface", - "solana-hash", - "solana-instruction", - "solana-message", - "solana-pubkey", "solana-rpc-client-api", - "solana-signature", - "solana-transaction", - "solana-transaction-error", + "solana-sdk", "solana-transaction-status-client-types", "solana-version", + "solana-vote-program", "tokio", ] [[package]] name = "solana-rpc-client-api" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc3276b526100d0f55a7d1db2366781acdc75ce9fe4a9d1bc9c85a885a503f8" +checksum = "26415f02e95eb387400743548efe0de461fe25f068ebfa078e131a2c3d29c28e" dependencies = [ "anyhow", "base64 0.22.1", "bs58", "jsonrpc-core", - "reqwest 0.11.27", + "reqwest", "reqwest-middleware", "semver 1.0.26", "serde", "serde_derive", "serde_json", - "solana-account", "solana-account-decoder-client-types", - "solana-clock", - "solana-commitment-config", - "solana-fee-calculator", - "solana-inflation", "solana-inline-spl", - "solana-pubkey", - "solana-signer", - "solana-transaction-error", + "solana-sdk", "solana-transaction-status-client-types", "solana-version", - "thiserror 2.0.12", + "thiserror 1.0.69", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "294874298fb4e52729bb0229e0cdda326d4393b7122b92823aa46e99960cb920" +checksum = "16ec439fb7273298cd38d67cdf01f1bf257a4d27a868de6cd90316054ece4095" dependencies = [ - "solana-account", - "solana-commitment-config", - "solana-hash", - "solana-message", - "solana-nonce", - "solana-pubkey", "solana-rpc-client", - "solana-sdk-ids", - "thiserror 2.0.12", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] name = "solana-sanitize" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" +checksum = "c8fa264f9669e88631f85374be08739c96865ee95985f72c1ff1660c2e431ada" [[package]] name = "solana-sdk" -version = "2.2.2" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8af90d2ce445440e0548fa4a5f96fe8b265c22041a68c942012ffadd029667d" +checksum = "a1ffc5dca597787a132dfa074425ec50ab27f611f4d7c02b08ce40592951fdc0" dependencies = [ "bincode 1.3.3", + "bitflags 2.9.0", + "borsh 1.5.7", "bs58", + "bytemuck", + "bytemuck_derive", + "byteorder", + "chrono", + "digest 0.10.7", + "ed25519-dalek 1.0.1", + "ed25519-dalek-bip32", "getrandom 0.1.16", + "hmac 0.12.1", + "itertools 0.12.1", "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "pbkdf2 0.11.0", + "rand 0.7.3", + "rand 0.8.5", "serde", + "serde_bytes", + "serde_derive", "serde_json", + "serde_with", + "sha2 0.10.9", + "sha3", + "siphasher 0.3.11", "solana-account", "solana-bn254", - "solana-client-traits", - "solana-cluster-type", - "solana-commitment-config", - "solana-compute-budget-interface", "solana-decode-error", "solana-derivation-path", - "solana-ed25519-program", - "solana-epoch-info", - "solana-epoch-rewards-hasher", "solana-feature-set", - "solana-fee-structure", - "solana-genesis-config", - "solana-hard-forks", "solana-inflation", "solana-instruction", - "solana-keypair", - "solana-message", "solana-native-token", - "solana-nonce-account", - "solana-offchain-message", "solana-packet", - "solana-poh-config", "solana-precompile-error", - "solana-precompiles", - "solana-presigner", "solana-program", "solana-program-memory", "solana-pubkey", - "solana-quic-definitions", - "solana-rent-collector", - "solana-rent-debits", - "solana-reserved-account-keys", - "solana-reward-info", "solana-sanitize", - "solana-sdk-ids", "solana-sdk-macro", - "solana-secp256k1-program", "solana-secp256k1-recover", "solana-secp256r1-program", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-serde", "solana-serde-varint", "solana-short-vec", - "solana-shred-version", "solana-signature", - "solana-signer", - "solana-system-transaction", - "solana-time-utils", - "solana-transaction", - "solana-transaction-context", "solana-transaction-error", - "solana-validator-exit", - "thiserror 2.0.12", + "thiserror 1.0.69", "wasm-bindgen", ] -[[package]] -name = "solana-sdk-ids" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" -dependencies = [ - "solana-pubkey", -] - [[package]] name = "solana-sdk-macro" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +checksum = "803197b117cc578a9ad51c4acd6ac1a97fa7ba5c9520ea84c3be8a93f3cd2d4c" dependencies = [ "bs58", "proc-macro2", @@ -7444,48 +6210,30 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "solana-secp256k1-program" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" -dependencies = [ - "bincode 1.3.3", - "digest 0.10.7", - "libsecp256k1", - "serde", - "serde_derive", - "sha3", - "solana-feature-set", - "solana-instruction", - "solana-precompile-error", - "solana-sdk-ids", -] - [[package]] name = "solana-secp256k1-recover" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +checksum = "ababa7063abe56073062c7134d1ad12da167d51e723f5fe1f1242070f0f7c317" dependencies = [ "borsh 1.5.7", "libsecp256k1", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 1.0.69", ] [[package]] name = "solana-secp256r1-program" -version = "2.2.2" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cda2aa1bbaceda14763c4f142a00b486f2f262cfd901bd0410649ad0404d5f7" +checksum = "c9f79fce30c4061577ede8e8ef9f599faf9446a2513390c9a9a211d4a6251d50" dependencies = [ "bytemuck", "openssl", "solana-feature-set", "solana-instruction", "solana-precompile-error", - "solana-sdk-ids", + "solana-pubkey", ] [[package]] @@ -7494,49 +6242,20 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" -[[package]] -name = "solana-seed-derivable" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" -dependencies = [ - "solana-derivation-path", -] - -[[package]] -name = "solana-seed-phrase" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" -dependencies = [ - "hmac 0.12.1", - "pbkdf2 0.11.0", - "sha2 0.10.9", -] - -[[package]] -name = "solana-serde" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1931484a408af466e14171556a47adaa215953c7f48b24e5f6b0282763818b04" -dependencies = [ - "serde", -] - [[package]] name = "solana-serde-varint" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" +checksum = "b515f701151b09a7b863e299a6d3f926a0ef6e1670c6ad8e68bd38931cf473d6" dependencies = [ "serde", ] [[package]] name = "solana-serialize-utils" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +checksum = "8126ee504595bc21afd4d9e1900bbf576c8709c79d7e6e2b30882303c642d978" dependencies = [ "solana-instruction", "solana-pubkey", @@ -7545,9 +6264,9 @@ dependencies = [ [[package]] name = "solana-sha256-hasher" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" +checksum = "25803e2ab53494854fc1f28e84b60008520afd2770a0ac2e7a600c9b5ca72e5f" dependencies = [ "sha2 0.10.9", "solana-define-syscall", @@ -7556,112 +6275,67 @@ dependencies = [ [[package]] name = "solana-short-vec" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +checksum = "86e20c907a5bc4593a2937598b28cd99074c01c15b556d3322545fa3ab6db5b3" dependencies = [ "serde", ] -[[package]] -name = "solana-shred-version" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afd3db0461089d1ad1a78d9ba3f15b563899ca2386351d38428faa5350c60a98" -dependencies = [ - "solana-hard-forks", - "solana-hash", - "solana-sha256-hasher", -] - [[package]] name = "solana-signature" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d251c8f3dc015f320b4161daac7f108156c837428e5a8cc61136d25beb11d6" +checksum = "a19fa5def6ba3accd0ca884e2c9092ee51c47bec02b14a4079e46471bba639c0" dependencies = [ "bs58", "ed25519-dalek 1.0.1", + "generic-array", "rand 0.8.5", "serde", - "serde-big-array", "serde_derive", "solana-sanitize", ] -[[package]] -name = "solana-signer" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" -dependencies = [ - "solana-pubkey", - "solana-signature", - "solana-transaction-error", -] - [[package]] name = "solana-slot-hashes" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +checksum = "454d61ee168c4c66740ec86b13fa95f632becb09802f84412c1bb860f63e5529" dependencies = [ "serde", "serde_derive", "solana-hash", - "solana-sdk-ids", "solana-sysvar-id", ] [[package]] name = "solana-slot-history" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +checksum = "ec510f43152f6fb32422f88781c7dbce0d10792a1ee1ac0f297fd811d6b0cba7" dependencies = [ "bv", "serde", "serde_derive", - "solana-sdk-ids", "solana-sysvar-id", ] [[package]] name = "solana-stable-layout" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" -dependencies = [ - "solana-instruction", - "solana-pubkey", -] - -[[package]] -name = "solana-stake-interface" -version = "1.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +checksum = "17fc772c03ba8b918f5e7b296e48c3798bc0dc3f6bc94db4eed91e123682e3bb" dependencies = [ - "borsh 0.10.4", - "borsh 1.5.7", - "num-traits", - "serde", - "serde_derive", - "solana-clock", - "solana-cpi", - "solana-decode-error", "solana-instruction", - "solana-program-error", "solana-pubkey", - "solana-system-interface", - "solana-sysvar-id", ] [[package]] name = "solana-streamer" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eaf5b216717d1d551716f3190878d028c689dabac40c8889767cead7e447481" +checksum = "701464fed002cc3c9592e1a732bcc431d503bbb135abed841fce75b81f818685" dependencies = [ "async-channel", "bytes", @@ -7684,234 +6358,80 @@ dependencies = [ "rustls 0.23.27", "smallvec", "socket2", - "solana-keypair", "solana-measure", "solana-metrics", - "solana-net-utils", - "solana-packet", "solana-perf", - "solana-pubkey", - "solana-quic-definitions", - "solana-signature", - "solana-signer", - "solana-time-utils", - "solana-tls-utils", - "solana-transaction-error", + "solana-sdk", "solana-transaction-metrics-tracker", - "thiserror 2.0.12", + "thiserror 1.0.69", "tokio", "tokio-util", "x509-parser", ] -[[package]] -name = "solana-system-interface" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" -dependencies = [ - "js-sys", - "num-traits", - "serde", - "serde_derive", - "solana-decode-error", - "solana-instruction", - "solana-pubkey", - "wasm-bindgen", -] - -[[package]] -name = "solana-system-transaction" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd98a25e5bcba8b6be8bcbb7b84b24c2a6a8178d7fb0e3077a916855ceba91a" -dependencies = [ - "solana-hash", - "solana-keypair", - "solana-message", - "solana-pubkey", - "solana-signer", - "solana-system-interface", - "solana-transaction", -] - -[[package]] -name = "solana-sysvar" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" -dependencies = [ - "base64 0.22.1", - "bincode 1.3.3", - "bytemuck", - "bytemuck_derive", - "lazy_static", - "serde", - "serde_derive", - "solana-account-info", - "solana-clock", - "solana-define-syscall", - "solana-epoch-rewards", - "solana-epoch-schedule", - "solana-fee-calculator", - "solana-hash", - "solana-instruction", - "solana-instructions-sysvar", - "solana-last-restart-slot", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", - "solana-pubkey", - "solana-rent", - "solana-sanitize", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-slot-hashes", - "solana-slot-history", - "solana-stake-interface", - "solana-sysvar-id", -] - [[package]] name = "solana-sysvar-id" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +checksum = "fbed881fb1222ba420cf5a80034df9b0728fa369d15fe45619585a470dcdc085" dependencies = [ "solana-pubkey", - "solana-sdk-ids", ] [[package]] name = "solana-thin-client" -version = "2.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255bda447fbff4526b6b19b16b3652281ec2b7c4952d019b369a5f4a9dba4e5c" -dependencies = [ - "bincode 1.3.3", - "log", - "rayon", - "solana-account", - "solana-client-traits", - "solana-clock", - "solana-commitment-config", - "solana-connection-cache", - "solana-epoch-info", - "solana-hash", - "solana-instruction", - "solana-keypair", - "solana-message", - "solana-pubkey", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-signature", - "solana-signer", - "solana-system-interface", - "solana-transaction", - "solana-transaction-error", -] - -[[package]] -name = "solana-time-utils" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" - -[[package]] -name = "solana-tls-utils" -version = "2.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f227b3813b6c26c8ed38910b90a0b641baedb2ad075ea51ccfbff1992ee394" -dependencies = [ - "rustls 0.23.27", - "solana-keypair", - "solana-pubkey", - "solana-signer", - "x509-parser", -] - -[[package]] -name = "solana-tpu-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc74ecb664add683a18bb9f484a30ca8c9d71f3addcd3a771eaaaaec12125fd" +checksum = "9c6e16a5a41281ead22e097e9dc5f5aa6a367db3cbcfd8e9a5a54ffefad3e926" dependencies = [ - "async-trait", "bincode 1.3.3", - "futures-util", - "indexmap 2.9.0", - "indicatif", "log", "rayon", - "solana-client-traits", - "solana-clock", - "solana-commitment-config", "solana-connection-cache", - "solana-epoch-info", - "solana-measure", - "solana-message", - "solana-net-utils", - "solana-pubkey", - "solana-pubsub-client", - "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", - "solana-signature", - "solana-signer", - "solana-transaction", - "solana-transaction-error", - "thiserror 2.0.12", - "tokio", + "solana-sdk", ] [[package]] -name = "solana-transaction" -version = "2.2.2" +name = "solana-timings" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abec848d081beb15a324c633cd0e0ab33033318063230389895cae503ec9b544" +checksum = "85f01ea17f0e09155059114d593d51bdf15c4092784461eea541aac39a0ddce6" dependencies = [ - "bincode 1.3.3", - "serde", - "serde_derive", - "solana-bincode", - "solana-feature-set", - "solana-hash", - "solana-instruction", - "solana-keypair", - "solana-message", - "solana-precompiles", - "solana-pubkey", - "solana-sanitize", - "solana-sdk-ids", - "solana-short-vec", - "solana-signature", - "solana-signer", - "solana-system-interface", - "solana-transaction-error", - "wasm-bindgen", + "eager", + "enum-iterator", + "solana-sdk", ] -[[package]] -name = "solana-transaction-context" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022de04cbba05377f68bf848c8c1322ead733f88a657bf792bb40f3257b8218" -dependencies = [ - "bincode 1.3.3", - "serde", - "serde_derive", - "solana-account", - "solana-instruction", - "solana-pubkey", - "solana-rent", - "solana-signature", +[[package]] +name = "solana-tpu-client" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b8387ef2fc6c0f7d9cd50df25ef5a95583cf7bd79bcc52a4c7c5f5c64c32ca9" +dependencies = [ + "async-trait", + "bincode 1.3.3", + "futures-util", + "indexmap 2.9.0", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror 1.0.69", + "tokio", ] [[package]] name = "solana-transaction-error" -version = "2.2.1" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +checksum = "7c552b10f781c04d166c83b2ac55434a4a4aab421bb3742b2cabe56bb7d4ec21" dependencies = [ "serde", "serde_derive", @@ -7921,26 +6441,25 @@ dependencies = [ [[package]] name = "solana-transaction-metrics-tracker" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4c03abfcb923aaf71c228e81b54a804aa224a48577477d8e1096c3a1429d21b" +checksum = "9d311e4790b03224b54ac01cacc42e9b8b086cf6311589c6f4b7053cfff31afa" dependencies = [ "base64 0.22.1", "bincode 1.3.3", "lazy_static", "log", "rand 0.8.5", - "solana-packet", "solana-perf", + "solana-sdk", "solana-short-vec", - "solana-signature", ] [[package]] name = "solana-transaction-status-client-types" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aaef59e8a54fc3a2dabfd85c32e35493c5e228f9d1efbcdcdc3c0819dddf7fd" +checksum = "6e211744f1af854aae9fc6757a099cd045aa036a6402689c85dabb028b2d7203" dependencies = [ "base64 0.22.1", "bincode 1.3.3", @@ -7949,81 +6468,89 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder-client-types", - "solana-commitment-config", - "solana-message", - "solana-reward-info", + "solana-sdk", "solana-signature", - "solana-transaction", - "solana-transaction-context", - "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-type-overrides" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cc0330accc29f5b203351a32db915ece2d81e8fcb2d5bde0ed19ae7cc86dc81" +dependencies = [ + "lazy_static", + "rand 0.8.5", ] [[package]] name = "solana-udp-client" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3e085a6adf81d51f678624934ffe266bd45a1c105849992b1af933c80bbf19" +checksum = "93efff1549a3ad32d70f79dba4114a54f47a9361e14fddf8cc03c7d571be391b" dependencies = [ "async-trait", "solana-connection-cache", - "solana-keypair", "solana-net-utils", + "solana-sdk", "solana-streamer", - "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 1.0.69", "tokio", ] -[[package]] -name = "solana-validator-exit" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" - [[package]] name = "solana-version" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a58e01912dc3d5ff4391fe49476461b3b9ebc4215f3713d2fe3ffcfeda7f8e2" +checksum = "20a1b5edec7fd5030d721007b176396ba833962b5aba992cab4fcd49c5e8189f" dependencies = [ - "agave-feature-set", "semver 1.0.26", "serde", "serde_derive", + "solana-feature-set", "solana-sanitize", "solana-serde-varint", ] [[package]] -name = "solana-vote-interface" -version = "2.2.4" +name = "solana-vote" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93aaf79fd5265468a5eb66abbbf349483fea427ba818e82cc9c6325e4a8b4e6c" +dependencies = [ + "itertools 0.12.1", + "log", + "serde", + "serde_derive", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-vote-program" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f039b0788337bedc6c5450d2f237718f938defb5ce0e0ad8ef507e78dcd370" +checksum = "721724f7752c9bd1c5acfd07247fad977336914c3495672e414bd51e0239d563" dependencies = [ "bincode 1.3.3", + "log", "num-derive 0.4.2", "num-traits", "serde", "serde_derive", - "solana-clock", - "solana-decode-error", - "solana-hash", - "solana-instruction", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-serde-varint", - "solana-serialize-utils", - "solana-short-vec", - "solana-system-interface", + "solana-feature-set", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] name = "solana-zk-sdk" -version = "2.2.14" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd14204c32f51f4ddf52ac24904417db13e54bd3b518e839e2e6ad9cca8ffef8" +checksum = "9ea998fc273c7d4b17c793c95b93536cc7cc272ed3b10d3d242586b3c319e02e" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -8043,30 +6570,26 @@ dependencies = [ "serde_json", "sha3", "solana-derivation-path", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-signature", - "solana-signer", + "solana-program", + "solana-sdk", "subtle", - "thiserror 2.0.12", + "thiserror 1.0.69", "wasm-bindgen", "zeroize", ] [[package]] name = "solana-zk-token-sdk" -version = "2.2.7" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06d91b7c7651e776b848b67b6b58f032566be4cd554e6f6283bdf415e3a70b61" +checksum = "2d6c7b5f14ddd4a2914f3346aac9cb7a79411fe03f7478e219147616e188ae88" dependencies = [ "aes-gcm-siv", "base64 0.22.1", "bincode 1.3.3", "bytemuck", "bytemuck_derive", + "byteorder", "curve25519-dalek 4.1.3", "itertools 0.12.1", "lazy_static", @@ -8080,18 +6603,31 @@ dependencies = [ "sha3", "solana-curve25519", "solana-derivation-path", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-signature", - "solana-signer", + "solana-program", + "solana-sdk", "subtle", - "thiserror 2.0.12", + "thiserror 1.0.69", "zeroize", ] +[[package]] +name = "solana_rbpf" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror 1.0.69", + "winapi", +] + [[package]] name = "spinning_top" version = "0.3.0" @@ -8137,6 +6673,17 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "spl-discriminator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + [[package]] name = "spl-discriminator" version = "0.4.1" @@ -8182,31 +6729,17 @@ dependencies = [ "bytemuck", "solana-program", "solana-zk-sdk", - "spl-pod", - "spl-token-confidential-transfer-proof-extraction 0.2.1", + "spl-pod 0.5.0", + "spl-token-confidential-transfer-proof-extraction", ] [[package]] -name = "spl-elgamal-registry" -version = "0.2.0" +name = "spl-memo" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65edfeed09cd4231e595616aa96022214f9c9d2be02dea62c2b30d5695a6833a" +checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" dependencies = [ - "bytemuck", - "solana-account-info", - "solana-cpi", - "solana-instruction", - "solana-msg", - "solana-program-entrypoint", - "solana-program-error", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-system-interface", - "solana-sysvar", - "solana-zk-sdk", - "spl-pod", - "spl-token-confidential-transfer-proof-extraction 0.3.0", + "solana-program", ] [[package]] @@ -8225,9 +6758,23 @@ dependencies = [ [[package]] name = "spl-pod" -version = "0.5.1" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.5.0", +] + +[[package]] +name = "spl-pod" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +checksum = "41a7d5950993e1ff2680bd989df298eeb169367fb2f9deeef1f132de6e4e8016" dependencies = [ "borsh 1.5.7", "bytemuck", @@ -8241,35 +6788,33 @@ dependencies = [ "solana-program-option", "solana-pubkey", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 1.0.69", ] [[package]] name = "spl-program-error" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" dependencies = [ "num-derive 0.4.2", "num-traits", "solana-program", - "spl-program-error-derive 0.4.1", + "spl-program-error-derive", "thiserror 1.0.69", ] [[package]] name = "spl-program-error" -version = "0.7.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdebc8b42553070b75aa5106f071fef2eb798c64a7ec63375da4b1f058688c6" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" dependencies = [ "num-derive 0.4.2", "num-traits", - "solana-decode-error", - "solana-msg", - "solana-program-error", - "spl-program-error-derive 0.5.0", - "thiserror 2.0.12", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", ] [[package]] @@ -8285,15 +6830,17 @@ dependencies = [ ] [[package]] -name = "spl-program-error-derive" -version = "0.5.0" +name = "spl-tlv-account-resolution" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2539e259c66910d78593475540e8072f0b10f0f61d7607bbf7593899ed52d0" +checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.9", - "syn 2.0.101", + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.1", + "spl-program-error 0.5.0", + "spl-type-length-value 0.5.0", ] [[package]] @@ -8311,35 +6858,13 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-pubkey", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", "spl-program-error 0.6.0", "spl-type-length-value 0.7.0", "thiserror 1.0.69", ] -[[package]] -name = "spl-tlv-account-resolution" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1408e961215688715d5a1063cbdcf982de225c45f99c82b4f7d7e1dd22b998d7" -dependencies = [ - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "solana-account-info", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "spl-discriminator", - "spl-pod", - "spl-program-error 0.7.0", - "spl-type-length-value 0.8.0", - "thiserror 2.0.12", -] - [[package]] name = "spl-token" version = "6.0.0" @@ -8371,31 +6896,27 @@ dependencies = [ ] [[package]] -name = "spl-token" -version = "8.0.0" +name = "spl-token-2022" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053067c6a82c705004f91dae058b11b4780407e9ccd6799dc9e7d0fab5f242da" +checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" dependencies = [ "arrayref", "bytemuck", "num-derive 0.4.2", "num-traits", "num_enum", - "solana-account-info", - "solana-cpi", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", - "solana-program-option", - "solana-program-pack", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-sysvar", - "thiserror 2.0.12", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo 5.0.0", + "spl-pod 0.3.1", + "spl-token 6.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "spl-transfer-hook-interface 0.7.0", + "spl-type-length-value 0.5.0", + "thiserror 1.0.69", ] [[package]] @@ -8405,20 +6926,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" dependencies = [ "arrayref", + "base64 0.22.1", "bytemuck", "num-derive 0.4.2", "num-traits", "num_enum", + "serde", + "serde_with", "solana-program", "solana-security-txt", "solana-zk-sdk", - "spl-elgamal-registry 0.1.1", - "spl-memo", - "spl-pod", + "spl-elgamal-registry", + "spl-memo 6.0.0", + "spl-pod 0.5.0", "spl-token 7.0.0", - "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1", - "spl-token-confidential-transfer-proof-extraction 0.2.1", - "spl-token-confidential-transfer-proof-generation 0.2.0", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", "spl-token-group-interface 0.5.0", "spl-token-metadata-interface 0.6.0", "spl-transfer-hook-interface 0.9.0", @@ -8426,108 +6950,29 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "spl-token-2022" -version = "8.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f0dfbb079eebaee55e793e92ca5f433744f4b71ee04880bfd6beefba5973e5" -dependencies = [ - "arrayref", - "base64 0.22.1", - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "num_enum", - "serde", - "serde_with", - "solana-account-info", - "solana-clock", - "solana-cpi", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-native-token", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", - "solana-program-option", - "solana-program-pack", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-security-txt", - "solana-system-interface", - "solana-sysvar", - "solana-zk-sdk", - "spl-elgamal-registry 0.2.0", - "spl-memo", - "spl-pod", - "spl-token 8.0.0", - "spl-token-confidential-transfer-ciphertext-arithmetic 0.3.0", - "spl-token-confidential-transfer-proof-extraction 0.3.0", - "spl-token-confidential-transfer-proof-generation 0.4.0", - "spl-token-group-interface 0.6.0", - "spl-token-metadata-interface 0.7.0", - "spl-transfer-hook-interface 0.10.0", - "spl-type-length-value 0.8.0", - "thiserror 2.0.12", -] - -[[package]] -name = "spl-token-confidential-transfer-ciphertext-arithmetic" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" -dependencies = [ - "base64 0.22.1", - "bytemuck", - "solana-curve25519", - "solana-zk-sdk", -] - [[package]] name = "spl-token-confidential-transfer-ciphertext-arithmetic" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ab20faf7b5edaa79acd240e0f21d5a2ef936aa99ed98f698573a2825b299c4" -dependencies = [ - "base64 0.22.1", - "bytemuck", - "solana-curve25519", - "solana-zk-sdk", -] - -[[package]] -name = "spl-token-confidential-transfer-proof-extraction" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" dependencies = [ + "base64 0.22.1", "bytemuck", "solana-curve25519", - "solana-program", "solana-zk-sdk", - "spl-pod", - "thiserror 2.0.12", ] [[package]] name = "spl-token-confidential-transfer-proof-extraction" -version = "0.3.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe2629860ff04c17bafa9ba4bed8850a404ecac81074113e1f840dbd0ebb7bd6" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" dependencies = [ "bytemuck", - "solana-account-info", "solana-curve25519", - "solana-instruction", - "solana-instructions-sysvar", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "solana-sdk-ids", + "solana-program", "solana-zk-sdk", - "spl-pod", + "spl-pod 0.5.0", "thiserror 2.0.12", ] @@ -8543,14 +6988,16 @@ dependencies = [ ] [[package]] -name = "spl-token-confidential-transfer-proof-generation" -version = "0.4.0" +name = "spl-token-group-interface" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae5b124840d4aed474cef101d946a798b806b46a509ee4df91021e1ab1cef3ef" +checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" dependencies = [ - "curve25519-dalek 4.1.3", - "solana-zk-sdk", - "thiserror 2.0.12", + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.1", + "spl-program-error 0.5.0", ] [[package]] @@ -8567,28 +7014,23 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-pubkey", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", "thiserror 1.0.69", ] [[package]] -name = "spl-token-group-interface" -version = "0.6.0" +name = "spl-token-metadata-interface" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5597b4cd76f85ce7cd206045b7dc22da8c25516573d42d267c8d1fd128db5129" +checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" dependencies = [ - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "spl-discriminator", - "spl-pod", - "thiserror 2.0.12", + "borsh 1.5.7", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.1", + "spl-program-error 0.5.0", + "spl-type-length-value 0.5.0", ] [[package]] @@ -8606,31 +7048,26 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-pubkey", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", "spl-type-length-value 0.7.0", "thiserror 1.0.69", ] [[package]] -name = "spl-token-metadata-interface" +name = "spl-transfer-hook-interface" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304d6e06f0de0c13a621464b1fd5d4b1bebf60d15ca71a44d3839958e0da16ee" +checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" dependencies = [ - "borsh 1.5.7", - "num-derive 0.4.2", - "num-traits", - "solana-borsh", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "spl-discriminator", - "spl-pod", - "spl-type-length-value 0.8.0", - "thiserror 2.0.12", + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.1", + "spl-program-error 0.5.0", + "spl-tlv-account-resolution 0.7.0", + "spl-type-length-value 0.5.0", ] [[package]] @@ -8650,8 +7087,8 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-pubkey", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", "spl-program-error 0.6.0", "spl-tlv-account-resolution 0.9.0", "spl-type-length-value 0.7.0", @@ -8659,28 +7096,16 @@ dependencies = [ ] [[package]] -name = "spl-transfer-hook-interface" -version = "0.10.0" +name = "spl-type-length-value" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e905b849b6aba63bde8c4badac944ebb6c8e6e14817029cbe1bc16829133bd" +checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" dependencies = [ - "arrayref", "bytemuck", - "num-derive 0.4.2", - "num-traits", - "solana-account-info", - "solana-cpi", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "spl-discriminator", - "spl-pod", - "spl-program-error 0.7.0", - "spl-tlv-account-resolution 0.10.0", - "spl-type-length-value 0.8.0", - "thiserror 2.0.12", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.1", + "spl-program-error 0.5.0", ] [[package]] @@ -8696,64 +7121,17 @@ dependencies = [ "solana-decode-error", "solana-msg", "solana-program-error", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", "thiserror 1.0.69", ] -[[package]] -name = "spl-type-length-value" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d417eb548214fa822d93f84444024b4e57c13ed6719d4dcc68eec24fb481e9f5" -dependencies = [ - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "solana-account-info", - "solana-decode-error", - "solana-msg", - "solana-program-error", - "spl-discriminator", - "spl-pod", - "thiserror 2.0.12", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "starknet-checked-felt" -version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "alloy-primitives", - "error-stack", - "hex", - "serde", - "starknet-types-core", - "thiserror 1.0.69", -] - -[[package]] -name = "starknet-types-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4037bcb26ce7c508448d221e570d075196fd4f6912ae6380981098937af9522a" -dependencies = [ - "lambdaworks-crypto", - "lambdaworks-math", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "serde", - "size-of", - "zeroize", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -8847,7 +7225,7 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "sui-types" version = "1.0.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" +source = "git+https://github.com/axelarnetwork/axelar-amplifier.git?rev=voting-verifier-v1.1.0#17792515ed9953ce6bd6ceabe59d2febe5eab2e7" dependencies = [ "error-stack", "hex", @@ -8895,15 +7273,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - [[package]] name = "synstructure" version = "0.12.6" @@ -8935,18 +7304,7 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.9.4", - "system-configuration-sys 0.6.0", + "system-configuration-sys", ] [[package]] @@ -8959,33 +7317,12 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "task-local-extensions" version = "0.1.4" @@ -9085,7 +7422,7 @@ dependencies = [ "peg", "pin-project", "rand 0.8.5", - "reqwest 0.11.27", + "reqwest", "semver 1.0.26", "serde", "serde_bytes", @@ -9291,16 +7628,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -9311,16 +7638,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls 0.23.27", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.17" @@ -9342,7 +7659,7 @@ dependencies = [ "log", "rustls 0.21.12", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", "tungstenite", "webpki-roots 0.25.4", ] @@ -9421,17 +7738,17 @@ dependencies = [ "axum", "base64 0.21.7", "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", + "h2", + "http", + "http-body", + "hyper", "hyper-timeout", "percent-encoding", "pin-project", "prost", "tokio", "tokio-stream", - "tower 0.4.13", + "tower", "tower-layer", "tower-service", "tracing", @@ -9457,21 +7774,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 1.0.2", - "tokio", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-layer" version = "0.3.3" @@ -9531,7 +7833,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.12", + "http", "httparse", "log", "rand 0.8.5", @@ -9663,6 +7965,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -9765,29 +8076,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" [[package]] -name = "voting-verifier" -version = "1.1.0" -source = "git+https://github.com/eigerco/axelar-amplifier.git?rev=3f036ec#3f036ec2bb4bf9c3c420617e501d6637bb96c88c" -dependencies = [ - "axelar-wasm-std", - "client", - "cosmwasm-schema", - "cosmwasm-std 2.2.2", - "cw-storage-plus", - "cw2", - "error-stack", - "itertools 0.14.0", - "msgs-derive", - "multisig", - "report", - "rewards", - "router-api", - "semver 1.0.26", - "serde_json", - "service-registry", - "service-registry-api", - "thiserror 1.0.69", -] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "wait-timeout" @@ -9909,19 +8201,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -10026,7 +8305,7 @@ dependencies = [ "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.0", + "windows-strings", ] [[package]] @@ -10057,17 +8336,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - [[package]] name = "windows-result" version = "0.3.2" @@ -10077,15 +8345,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-strings" version = "0.4.0" @@ -10170,29 +8429,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -10211,12 +8454,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -10235,12 +8472,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -10259,24 +8490,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -10295,12 +8514,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -10319,12 +8532,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -10343,12 +8550,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -10367,12 +8568,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.7.10" @@ -10434,16 +8629,6 @@ dependencies = [ "time", ] -[[package]] -name = "xattr" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" -dependencies = [ - "libc", - "rustix", -] - [[package]] name = "yoke" version = "0.8.0" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 43ff7ee3c..017b2c665 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -4,56 +4,39 @@ version = "0.1.0" edition = "2024" [dependencies] -axelar-solana-gateway = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ +axelar-solana-gateway = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ "no-entrypoint", ] } -axelar-solana-gas-service = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ +axelar-solana-gas-service = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ "no-entrypoint", ] } -axelar-solana-governance = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ +axelar-solana-governance = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ "no-entrypoint", ] } -axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24", features = [ +axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ "no-entrypoint" ] } -axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } -axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } -governance-gmp = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } -program-utils = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } -its-instruction-builder = { git = "https://github.com/eigerco/solana-axelar.git", rev = "1c97f24" } +axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } +axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } +its-instruction-builder = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } -axelar-wasm-std = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec" } -voting-verifier = { git = "https://github.com/eigerco/axelar-amplifier.git", rev = "3f036ec", features = [ - "library", -] } +axelar-wasm-std = { git = "https://github.com/axelarnetwork/axelar-amplifier.git", rev = "voting-verifier-v1.1.0" } -alloy-sol-types = "0.7.6" -anyhow = "1.0.98" base64 = "0.22.1" bincode = { version = "2.0.1", features = ["serde"] } borsh = "1.5.1" -bs58 = "0.5.1" clap = { version = "3.2", features = ["derive", "env"] } cosmrs = { version = "0.16", features = ["cosmwasm", "rpc", "grpc"] } -cosmwasm-schema = "2" cosmwasm-std = "1.5" eyre = "0.6.11" -flate2 = { version = "1.1.1", default-features = false, features = ["zlib"] } hex = { version = "0.4.3", features = ["serde"] } k256 = { version = "0.13", features = ["pkcs8", "pem", "ecdsa"] } -rand = "0.9.1" -reqwest = { version = "0.12", features = ["json", "stream"] } -rust_decimal = "1.37.1" -rust_decimal_macros = "1.37.1" serde = { version = "1.0.219", features = ["derive"] } serde_json = { version = "1.0.140", features = ["preserve_order"] } -solana-clap-v3-utils = "2.2.7" -solana-cli-config = "2.2.7" -solana-client = "2.2.7" -solana-sdk = "2.2.2" -spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } -spl-token = { version = "8.0.0", features = ["no-entrypoint"] } -spl-token-2022 = { version = "8.0.1", features = ["no-entrypoint"] } -tar = "0.4.44" +solana-clap-v3-utils = "2" +solana-cli-config = "2" +solana-client = "2" +solana-sdk = "2" +spl-token = { version = "6", features = ["no-entrypoint"] } +spl-token-2022 = { version = "6", features = ["no-entrypoint"] } tokio = { version = "1", features = ["full"] } -walkdir = "2.5.0" From f4e94205e7a3dd78c8f7a0d10b43b97acf0e9366 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 10:06:33 +0200 Subject: [PATCH 39/59] fix(solana): adjust code to latest solana-axelar The Gateway Config PDA has been removed as seed in several places, we need to adjust. Signed-off-by: Guilherme Felipe da Silva --- solana/src/gateway.rs | 13 ++++--------- solana/src/its.rs | 12 ++++-------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index d607493ec..59a0244a7 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -437,10 +437,8 @@ async fn append_verification_flow_instructions( )?); } - let (verification_session_pda, _bump) = axelar_solana_gateway::get_signature_verification_pda( - gateway_config_pda, - &execute_data.payload_merkle_root, - ); + let (verification_session_pda, _bump) = + axelar_solana_gateway::get_signature_verification_pda(&execute_data.payload_merkle_root); Ok(verification_session_pda) } @@ -843,11 +841,8 @@ async fn execute( )?); if let Ok(destination_address) = Pubkey::from_str(&message.destination_address) { - let (message_payload_pda, _) = axelar_solana_gateway::find_message_payload_pda( - gateway_config_pda, - command_id, - *fee_payer, - ); + let (message_payload_pda, _) = + axelar_solana_gateway::find_message_payload_pda(command_id, *fee_payer); // Handle special destination addresses if destination_address == axelar_solana_its::id() { diff --git a/solana/src/its.rs b/solana/src/its.rs index 6662d8531..4df31814b 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -11,9 +11,9 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, - read_json_file_from_path, write_json_to_file_path, + encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, + CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -933,10 +933,7 @@ async fn init( let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; let its_hub_address = String::deserialize(&chains_info[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY])?; - let its_root_config = axelar_solana_its::find_its_root_pda( - &axelar_solana_gateway::get_gateway_root_config_pda().0, - ) - .0; + let its_root_config = axelar_solana_its::find_its_root_pda().0; chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] [ITS_KEY] = serde_json::json!({ @@ -950,7 +947,6 @@ async fn init( Ok(vec![axelar_solana_its::instruction::initialize( *fee_payer, - axelar_solana_gateway::get_gateway_root_config_pda().0, init_args.operator, ChainNameOnAxelar::from(config.network_type).0, its_hub_address, From c9acc936d74cbf90b919dac27d57005541eeb2c6 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 10:31:36 +0200 Subject: [PATCH 40/59] chore(solana): configure linter Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.toml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 017b2c665..125bc31d5 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -40,3 +40,20 @@ solana-sdk = "2" spl-token = { version = "6", features = ["no-entrypoint"] } spl-token-2022 = { version = "6", features = ["no-entrypoint"] } tokio = { version = "1", features = ["full"] } + +[workspace.lints.clippy] +cargo = { priority = -1, level = "deny" } +complexity = { priority = -2, level = "deny" } +correctness = { priority = -4, level = "deny" } +nursery = { priority = -9, level = "deny" } +pedantic = { priority = -8, level = "deny" } +perf = { priority = -3, level = "deny" } +restriction = { priority = -5, level = "deny" } +style = { priority = -6, level = "deny" } +suspicious = { priority = -7, level = "deny" } + +[workspace.lints.rust] +rust_2018_idioms = { level = "allow", priority = 0 } +unreachable_pub = { level = "warn", priority = -1 } +unused_imports = { level = "warn", priority = -1 } +unused_must_use = { level = "deny", priority = -1 } From b899b29c0724d95cf88342b8ed7ad374d51ce0a8 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 10:31:49 +0200 Subject: [PATCH 41/59] chore(solana): be consistent with import granularity rustfmt has a configuration for this, but it's unfortunately still nightly. Signed-off-by: Guilherme Felipe da Silva --- solana/src/broadcast.rs | 26 ++++++++++++-------------- solana/src/combine.rs | 3 ++- solana/src/config.rs | 3 ++- solana/src/gas_service.rs | 18 ++++++++---------- solana/src/gateway.rs | 19 +++++++++---------- solana/src/governance.rs | 26 ++++++++++++-------------- solana/src/its.rs | 10 ++++++---- solana/src/main.rs | 2 +- solana/src/multisig_prover_types.rs | 4 ---- solana/src/send.rs | 18 ++++++++---------- solana/src/sign.rs | 3 ++- solana/src/types.rs | 7 +++---- solana/src/utils.rs | 10 ++++++---- 13 files changed, 71 insertions(+), 78 deletions(-) diff --git a/solana/src/broadcast.rs b/solana/src/broadcast.rs index a9cad1885..d1f4e33e9 100644 --- a/solana/src/broadcast.rs +++ b/solana/src/broadcast.rs @@ -4,20 +4,18 @@ use std::str::FromStr; use axelar_solana_gateway::num_traits::FromPrimitive; use eyre::eyre; -use solana_client::{ - client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, - rpc_response::RpcSimulateTransactionResult, -}; -use solana_sdk::{ - commitment_config::CommitmentConfig, - hash::Hash, - instruction::Instruction as SolanaInstruction, - instruction::InstructionError, - message::Message, - pubkey::Pubkey, - signature::Signature, - transaction::{Transaction, TransactionError}, -}; +use solana_client::client_error::ClientErrorKind; +use solana_client::rpc_client::RpcClient; +use solana_client::rpc_request::RpcResponseErrorData; +use solana_client::rpc_response::RpcSimulateTransactionResult; +use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::hash::Hash; +use solana_sdk::instruction::Instruction as SolanaInstruction; +use solana_sdk::instruction::InstructionError; +use solana_sdk::message::Message; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Signature; +use solana_sdk::transaction::{Transaction, TransactionError}; use crate::config::Config; use crate::types::SignedSolanaTransaction; diff --git a/solana/src/combine.rs b/solana/src/combine.rs index 5581545e1..8e7db89e7 100644 --- a/solana/src/combine.rs +++ b/solana/src/combine.rs @@ -2,7 +2,8 @@ use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::str::FromStr; -use solana_sdk::{pubkey::Pubkey, signature::Signature as SolanaSignature}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Signature as SolanaSignature; use crate::config::Config; use crate::types::{NetworkType, PartialSignature, SignedSolanaTransaction}; diff --git a/solana/src/config.rs b/solana/src/config.rs index 2b5f8228b..8d2921a71 100644 --- a/solana/src/config.rs +++ b/solana/src/config.rs @@ -1,6 +1,7 @@ use eyre::eyre; +use std::fs; use std::path::PathBuf; -use std::{fs, str::FromStr}; +use std::str::FromStr; use crate::types::ChainsInfoFile; use crate::types::NetworkType; diff --git a/solana/src/gas_service.rs b/solana/src/gas_service.rs index 0229c51f6..b8d653075 100644 --- a/solana/src/gas_service.rs +++ b/solana/src/gas_service.rs @@ -1,15 +1,13 @@ use clap::{Parser, Subcommand}; -use solana_sdk::{ - instruction::Instruction, pubkey::Pubkey, transaction::Transaction as SolanaTransaction, -}; +use solana_sdk::instruction::Instruction; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::transaction::Transaction as SolanaTransaction; -use crate::{ - config::Config, - types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, - utils::{ - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, - CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - }, +use crate::config::Config; +use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::utils::{ + ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, }; #[derive(Subcommand, Debug)] diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 59a0244a7..131368c88 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -2,8 +2,6 @@ use std::collections::BTreeMap; use std::str::FromStr; use std::sync::LazyLock; -use crate::multisig_prover_types::msg::ProofStatus; -use crate::multisig_prover_types::Uint128Extensions; use axelar_solana_encoding::hash_payload; use axelar_solana_encoding::hasher::NativeHasher; use axelar_solana_encoding::types::execute_data::{ExecuteData, MerkleisedPayload}; @@ -22,23 +20,24 @@ use serde::Deserialize; use serde_json::json; use solana_sdk::hash::Hash; use solana_sdk::instruction::Instruction; +use solana_sdk::message::Message as SolanaMessage; use solana_sdk::packet::PACKET_DATA_SIZE; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::Transaction; +use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; +use crate::multisig_prover_types::Uint128Extensions; +use crate::multisig_prover_types::msg::ProofStatus; use crate::types::{ ChainNameOnAxelar, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, - DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, - OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, + self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, + GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, + PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, }; -use solana_sdk::message::Message as SolanaMessage; -use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(Subcommand, Debug)] pub(crate) enum Commands { @@ -759,7 +758,7 @@ static MAX_CHUNK_SIZE: LazyLock = LazyLock::new(|| { let mut writer = bincode::enc::write::SizeWriter::default(); bincode::serde::encode_into_writer( - &Transaction { + &SolanaTransaction { signatures: vec![ solana_sdk::signature::Signature::default(); baseline_msg.header.num_required_signatures.into() diff --git a/solana/src/governance.rs b/solana/src/governance.rs index 89fdd7394..f0c2a392c 100644 --- a/solana/src/governance.rs +++ b/solana/src/governance.rs @@ -1,20 +1,18 @@ use axelar_solana_governance::instructions::builder::IxBuilder; use base64::Engine; use clap::{Args, Subcommand}; -use solana_sdk::{ - instruction::AccountMeta, instruction::Instruction, pubkey::Pubkey, - transaction::Transaction as SolanaTransaction, -}; - -use crate::{ - config::Config, - types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}, - utils::{ - ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, - GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, - UPGRADE_AUTHORITY_KEY, fetch_latest_blockhash, parse_account_meta_string, - read_json_file_from_path, write_json_to_file_path, - }, +use solana_sdk::instruction::AccountMeta; +use solana_sdk::instruction::Instruction; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::transaction::Transaction as SolanaTransaction; + +use crate::config::Config; +use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::utils::{ + ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, + GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, UPGRADE_AUTHORITY_KEY, + fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, + write_json_to_file_path, }; #[derive(Subcommand, Debug)] diff --git a/solana/src/its.rs b/solana/src/its.rs index 4df31814b..64e9b155f 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -1,4 +1,6 @@ -use std::{fs::File, io::Write, time::SystemTime}; +use std::fs::File; +use std::io::Write; +use std::time::SystemTime; use axelar_solana_its::state; use clap::{Parser, Subcommand}; @@ -11,9 +13,9 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - encode_its_destination, fetch_latest_blockhash, read_json_file_from_path, - write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, - CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, + ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, + ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, + read_json_file_from_path, write_json_to_file_path, }; #[derive(Subcommand, Debug)] diff --git a/solana/src/main.rs b/solana/src/main.rs index 1ca0dec44..f9cc27b1f 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -21,7 +21,7 @@ use clap::{FromArgMatches, IntoApp, Parser, Subcommand}; use combine::CombineArgs; use eyre::eyre; use generate::GenerateArgs; -use send::{sign_and_send_transactions, SendArgs}; +use send::{SendArgs, sign_and_send_transactions}; use sign::SignArgs; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; diff --git a/solana/src/multisig_prover_types.rs b/solana/src/multisig_prover_types.rs index c254ef7df..3ff20dc03 100644 --- a/solana/src/multisig_prover_types.rs +++ b/solana/src/multisig_prover_types.rs @@ -13,10 +13,6 @@ pub trait Uint128Extensions { // Implement the trait for Uint128 impl Uint128Extensions for Uint128 { fn u128(&self) -> u128 { - // Since we can't access the internal value directly, - // For our use case, we just need a value > 0 - // Our implementation is intended to be simple and functional - // rather than correct for all cases self.into_inner().u128() } } diff --git a/solana/src/send.rs b/solana/src/send.rs index 5b3139e16..3c609f8fd 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -1,16 +1,14 @@ use axelar_solana_gateway::num_traits::FromPrimitive; use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; -use solana_client::{ - client_error::ClientErrorKind, rpc_client::RpcClient, rpc_request::RpcResponseErrorData, - rpc_response::RpcSimulateTransactionResult, -}; -use solana_sdk::{ - commitment_config::CommitmentConfig, - instruction::InstructionError, - pubkey::Pubkey, - transaction::{Transaction, TransactionError}, -}; +use solana_client::client_error::ClientErrorKind; +use solana_client::rpc_client::RpcClient; +use solana_client::rpc_request::RpcResponseErrorData; +use solana_client::rpc_response::RpcSimulateTransactionResult; +use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::instruction::InstructionError; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::transaction::{Transaction, TransactionError}; use crate::config::Config; use crate::types::SerializableSolanaTransaction; diff --git a/solana/src/sign.rs b/solana/src/sign.rs index 65dc6919f..c21081172 100644 --- a/solana/src/sign.rs +++ b/solana/src/sign.rs @@ -4,7 +4,8 @@ use std::str::FromStr; use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; -use solana_sdk::{pubkey::Pubkey, signer::Signer}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signer::Signer; use crate::types::PartialSignature; use crate::utils; diff --git a/solana/src/types.rs b/solana/src/types.rs index e37eaebb7..ca9a97f27 100644 --- a/solana/src/types.rs +++ b/solana/src/types.rs @@ -7,10 +7,9 @@ use clap::ArgEnum; use eyre::eyre; use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::{Deserialize, Serialize}; -use solana_sdk::{ - instruction::Instruction as SolanaInstruction, pubkey::Pubkey, - transaction::Transaction as SolanaTransaction, -}; +use solana_sdk::instruction::Instruction as SolanaInstruction; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] pub enum NetworkType { diff --git a/solana/src/utils.rs b/solana/src/utils.rs index 6df12e54d..d653d5f3c 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -11,11 +11,13 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use solana_client::rpc_client::RpcClient; use solana_sdk::account_utils::StateMut; +use solana_sdk::compute_budget::ComputeBudgetInstruction; +use solana_sdk::hash::Hash; +use solana_sdk::instruction::Instruction; +use solana_sdk::keccak::hashv; use solana_sdk::nonce::state::Versions; -use solana_sdk::{ - compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction, keccak::hashv, - pubkey::Pubkey, signature::Signature, -}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Signature; use crate::config::Config; use crate::types::{ From 185ab69c5738d44c6dcdb9c2c67258797903948d Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 12:18:08 +0200 Subject: [PATCH 42/59] fix(solana): fix all clippy errors Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.toml | 81 +++++++- solana/src/broadcast.rs | 201 +++++++++--------- solana/src/combine.rs | 157 ++++++++------ solana/src/config.rs | 22 +- solana/src/gas_service.rs | 6 +- solana/src/gateway.rs | 62 +++--- solana/src/generate.rs | 18 +- solana/src/governance.rs | 18 +- solana/src/its.rs | 195 +++++++++--------- solana/src/main.rs | 38 ++-- solana/src/misc.rs | 8 +- solana/src/multisig_prover_types.rs | 32 +-- solana/src/send.rs | 307 +++++++++++++++------------- solana/src/sign.rs | 42 ++-- solana/src/types.rs | 98 ++++----- solana/src/utils.rs | 32 +-- 16 files changed, 704 insertions(+), 613 deletions(-) diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 125bc31d5..3c55927e8 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -41,7 +41,7 @@ spl-token = { version = "6", features = ["no-entrypoint"] } spl-token-2022 = { version = "6", features = ["no-entrypoint"] } tokio = { version = "1", features = ["full"] } -[workspace.lints.clippy] +[lints.clippy] cargo = { priority = -1, level = "deny" } complexity = { priority = -2, level = "deny" } correctness = { priority = -4, level = "deny" } @@ -52,7 +52,84 @@ restriction = { priority = -5, level = "deny" } style = { priority = -6, level = "deny" } suspicious = { priority = -7, level = "deny" } -[workspace.lints.rust] +# Selectively disable specific lints +absolute_paths = "allow" +allow_attributes = "allow" +allow_attributes_without_reason = "allow" +arbitrary_source_item_ordering = "allow" +arithmetic_side_effects = "allow" +as_conversions = "allow" +assertions_on_result_states = "allow" +blanket_clippy_restriction_lints = "allow" +cargo_common_metadata = "allow" +cast_lossless = "allow" +dbg_macro = "allow" +default_numeric_fallback = "allow" +doc_lazy_continuation = "allow" +doc_markdown = "allow" +exhaustive_enums = "allow" +exhaustive_structs = "allow" +expect_used = "allow" +explicit_deref_methods = "allow" +explicit_iter_loop = "allow" +field_scoped_visibility_modifiers = "allow" +future_not_send = "allow" +host_endian_bytes = "allow" +implicit_clone = "allow" +implicit_return = "allow" +inconsistent_struct_constructor = "allow" +indexing_slicing = "allow" +iter_over_hash_type = "allow" +large_futures = "allow" +manual_inspect = "allow" +map_err_ignore = "allow" +min_ident_chars = "allow" +missing_const_for_fn = "allow" +missing_docs_in_private_items = "allow" +missing_errors_doc = "allow" +missing_inline_in_public_items = "allow" +missing_panics_doc = "allow" +missing_trait_methods = "allow" +mod_module_files = "allow" +module_name_repetitions = "allow" +multiple_crate_versions = "allow" +must_use_candidate = "allow" +needless_lifetimes = "allow" +needless_pass_by_value = "allow" +negative_feature_names = "allow" +non_minimal_cfg = "allow" +option_if_let_else = "allow" +pattern_type_mismatch = "allow" +precedence = "allow" +print_stderr = "allow" +print_stdout = "allow" +pub_use = "allow" +pub_with_shorthand = "allow" +question_mark_used = "allow" +redundant_clone = "allow" +redundant_pub_crate = "allow" +ref_patterns = "allow" +renamed_function_params = "allow" +self_named_module_files = "allow" +separated_literal_suffix = "allow" +shadow_reuse = "allow" +shadow_unrelated = "allow" +similar_names = "allow" +single_call_fn = "allow" +single_char_lifetime_names = "allow" +std_instead_of_alloc = "allow" +std_instead_of_core = "allow" +transmute_ptr_to_ptr = "allow" +undocumented_unsafe_blocks = "allow" +unnecessary_wraps = "allow" +unseparated_literal_suffix = "allow" +unused_trait_names = "allow" +unwrap_used = "allow" +use_debug = "allow" +use_self = "allow" +wildcard_imports = "allow" + +[lints.rust] rust_2018_idioms = { level = "allow", priority = 0 } unreachable_pub = { level = "warn", priority = -1 } unused_imports = { level = "warn", priority = -1 } diff --git a/solana/src/broadcast.rs b/solana/src/broadcast.rs index d1f4e33e9..244d02605 100644 --- a/solana/src/broadcast.rs +++ b/solana/src/broadcast.rs @@ -22,19 +22,13 @@ use crate::types::SignedSolanaTransaction; use crate::utils::{self, print_transaction_result}; #[derive(Debug, Clone)] -pub struct BroadcastArgs { - pub signed_tx_path: PathBuf, +pub(crate) struct BroadcastArgs { + pub(crate) signed_tx_path: PathBuf, } -fn submit_solana_transaction( - url: &str, +fn construct_transaction( signed_tx_data: &SignedSolanaTransaction, -) -> eyre::Result { - println!( - "Reconstructing Solana transaction for broadcasting via RPC: {}", - url - ); - +) -> eyre::Result<(Transaction, bool)> { let fee_payer = Pubkey::from_str(&signed_tx_data.unsigned_tx_data.params.fee_payer)?; let recent_blockhash = Hash::from_str(&signed_tx_data.unsigned_tx_data.params.blockhash_for_message)?; @@ -63,18 +57,14 @@ fn submit_solana_transaction( let mut missing_sig_for_required_signer = false; for (index, key) in message.account_keys.iter().enumerate() { if message.is_signer(index) { - match signatures_map.remove(key) { - Some(signature) => { - ordered_signatures.push(signature); - } - None => { - eprintln!( - "Critical Error during broadcast reconstruction: Missing signature for required signer {} (index {}).", - key, index - ); - ordered_signatures.push(Signature::default()); - missing_sig_for_required_signer = true; - } + if let Some(signature) = signatures_map.remove(key) { + ordered_signatures.push(signature); + } else { + eprintln!( + "Critical Error during broadcast reconstruction: Missing signature for required signer {key} (index {index})." + ); + ordered_signatures.push(Signature::default()); + missing_sig_for_required_signer = true; } } } @@ -85,15 +75,18 @@ fn submit_solana_transaction( ); } - if !signatures_map.is_empty() { + let has_unused_signatures = if signatures_map.is_empty() { + false + } else { println!( "Warning: The following signatures were provided but not required by the transaction message: {:?}", signatures_map .keys() - .map(|pk| pk.to_string()) + .map(std::string::ToString::to_string) .collect::>() ); - } + true + }; let mut transaction = Transaction::new_unsigned(message); @@ -107,40 +100,94 @@ fn submit_solana_transaction( transaction.signatures = ordered_signatures; transaction.message.recent_blockhash = recent_blockhash; - println!( - "Transaction reconstructed with blockhash: {}", - recent_blockhash - ); + println!("Transaction reconstructed with blockhash: {recent_blockhash}"); if let Err(e) = transaction.verify() { - eyre::bail!( - "Constructed transaction failed structural verification: {}", - e - ); + eyre::bail!("Constructed transaction failed structural verification: {e}"); } - println!("Connecting to RPC client at {}", url); - let rpc_client = RpcClient::new_with_commitment(url.to_string(), CommitmentConfig::confirmed()); - let tx_to_send = transaction; + Ok((transaction, has_unused_signatures)) +} - match rpc_client.simulate_transaction(&tx_to_send) { +fn simulate_transaction(rpc_client: &RpcClient, tx: &Transaction) { + match rpc_client.simulate_transaction(tx) { Ok(sim_result) => { if let Some(units) = sim_result.value.units_consumed { - println!("Transaction simulation used {} compute units", units); - // If we're using significant compute units (>70% of default), we should log this - if units > 150_000 { - println!( - "WARNING: Transaction using significant compute units ({}). If this transaction fails with 'exceeded CUs meter', you'll need to add compute budget.", - units - ); - } + println!("Transaction simulation used {units} compute units"); } } Err(err) => { - println!("Simulation warning: {:?}", err); + println!("Simulation warning: {err:?}"); } + } +} + +fn handle_transaction_error( + client_err: solana_client::client_error::ClientError, +) -> eyre::Result { + let should_continue = if let ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { + data: + RpcResponseErrorData::SendTransactionPreflightFailure(RpcSimulateTransactionResult { + err: + Some(TransactionError::InstructionError(_, InstructionError::Custom(err_code))), + .. + }), + .. + }, + ) = client_err.kind() + { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else if let ClientErrorKind::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(err_code), + )) = client_err.kind() + { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else { + false }; + if should_continue { + println!( + "Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction" + ); + Ok(Signature::default()) + } else { + #[allow(clippy::wildcard_enum_match_arm)] + match client_err.kind() { + ClientErrorKind::RpcError(solana_client::rpc_request::RpcError::RpcResponseError { + data: RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), + .. + }) => { + eprintln!(" -> Preflight Simulation Failure Result: {sim_result:?}"); + } + ClientErrorKind::TransactionError(tx_err) => { + eprintln!(" -> Transaction Error Detail: {tx_err:?}"); + } + _ => { /* Don't need to print any detail */ } + } + + Err(eyre!("RPC client error: {client_err}")) + } +} + +fn submit_solana_transaction( + url: &str, + signed_tx_data: &SignedSolanaTransaction, +) -> eyre::Result { + println!("Reconstructing Solana transaction for broadcasting via RPC: {url}"); + + let (transaction, _) = construct_transaction(signed_tx_data)?; + + println!("Connecting to RPC client at {url}"); + let rpc_client = RpcClient::new_with_commitment(url.to_owned(), CommitmentConfig::confirmed()); + let tx_to_send = transaction; + + simulate_transaction(&rpc_client, &tx_to_send); + println!("Broadcasting transaction..."); match rpc_client.send_and_confirm_transaction_with_spinner(&tx_to_send) { Ok(tx_signature) => { @@ -148,63 +195,16 @@ fn submit_solana_transaction( Ok(tx_signature) } Err(client_err) => { - eprintln!("Error during RPC broadcast/confirmation: {}", client_err); - - let should_continue = if let ClientErrorKind::RpcError( - solana_client::rpc_request::RpcError::RpcResponseError { - data: - RpcResponseErrorData::SendTransactionPreflightFailure( - RpcSimulateTransactionResult { - err: - Some(TransactionError::InstructionError( - _, - InstructionError::Custom(err_code), - )), - .. - }, - ), - .. - }, - ) = client_err.kind() - { - axelar_solana_gateway::error::GatewayError::from_u32(*err_code) - .is_some_and(|gw_err| gw_err.should_relayer_proceed()) - } else if let ClientErrorKind::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(err_code), - )) = client_err.kind() - { - axelar_solana_gateway::error::GatewayError::from_u32(*err_code) - .is_some_and(|gw_err| gw_err.should_relayer_proceed()) - } else { - false - }; - - if should_continue { - println!( - "Transaction error: GatewayError, but it's a recoverable error - continuing with next transaction" - ); - Ok(Signature::default()) - } else { - if let ClientErrorKind::RpcError( - solana_client::rpc_request::RpcError::RpcResponseError { - data: RpcResponseErrorData::SendTransactionPreflightFailure(sim_result), - .. - }, - ) = client_err.kind() - { - eprintln!(" -> Preflight Simulation Failure Result: {:?}", sim_result); - } else if let ClientErrorKind::TransactionError(tx_err) = client_err.kind() { - eprintln!(" -> Transaction Error Detail: {:?}", tx_err); - } - - Err(eyre!("RPC client error: {}", client_err)) - } + eprintln!("Error during RPC broadcast/confirmation: {client_err}"); + handle_transaction_error(client_err) } } } -pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> eyre::Result<()> { +pub(crate) fn broadcast_solana_transaction( + args: &BroadcastArgs, + config: &Config, +) -> eyre::Result<()> { println!("Starting Solana transaction broadcast..."); let signed_tx_data = match utils::load_signed_solana_transaction(&args.signed_tx_path) { @@ -213,8 +213,7 @@ pub fn broadcast_solana_transaction(args: &BroadcastArgs, config: &Config) -> ey eyre::bail!( "Failed to parse transaction file. Make sure you're using a signed transaction file (*.signed.json) \ generated by the 'combine' command, not directly from 'sign' or 'generate'. \ - If you've only signed with one key, run 'combine' first: {}", - e + If you've only signed with one key, run 'combine' first: {e}", ); } Err(e) => return Err(e), diff --git a/solana/src/combine.rs b/solana/src/combine.rs index 8e7db89e7..a9dde27f7 100644 --- a/solana/src/combine.rs +++ b/solana/src/combine.rs @@ -10,10 +10,10 @@ use crate::types::{NetworkType, PartialSignature, SignedSolanaTransaction}; use crate::utils; #[derive(Debug, Clone)] -pub struct CombineArgs { - pub unsigned_tx_path: PathBuf, - pub signature_paths: Vec, - pub output_dir: Option, +pub(crate) struct CombineArgs { + pub(crate) unsigned_tx_path: PathBuf, + pub(crate) signature_paths: Vec, + pub(crate) output_dir: Option, } fn get_required_signers_from_instructions( @@ -36,39 +36,14 @@ fn get_required_signers_from_instructions( Ok(signers) } -pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::Result<()> { - println!("Starting Solana signature combination..."); - - let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; - println!( - "Loaded unsigned transaction data from: {}", - args.unsigned_tx_path.display() - ); - - let fee_payer = Pubkey::from_str(&unsigned_tx.params.fee_payer)?; - let nonce_authority_pubkey: Option = unsigned_tx - .params - .nonce_authority - .as_ref() - .map(|s| Pubkey::from_str(s)) - .transpose()?; - let required_signers = get_required_signers_from_instructions( - &unsigned_tx.instructions, - &fee_payer, - nonce_authority_pubkey.as_ref(), - )?; - println!( - "Required signers determined from unsigned data: {:?}", - required_signers - .iter() - .map(|pk| pk.to_string()) - .collect::>() - ); - +fn load_and_validate_signatures( + signature_paths: &[PathBuf], + required_signers: &HashSet, +) -> eyre::Result> { let mut signatures_map: HashMap = HashMap::new(); let mut loaded_paths = HashSet::new(); - for sig_path in &args.signature_paths { + for sig_path in signature_paths { if !loaded_paths.insert(sig_path.clone()) { println!( "Skipping duplicate signature file path: {}", @@ -80,19 +55,17 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::R println!("Loaded signature from path: {}", sig_path.display()); let signer_pubkey = Pubkey::from_str(&partial_sig.signer_pubkey)?; let signature = SolanaSignature::from_str(&partial_sig.signature)?; - println!(" -> Signer: {}, Signature: {}", signer_pubkey, signature); + println!(" -> Signer: {signer_pubkey}, Signature: {signature}"); if !required_signers.contains(&signer_pubkey) { println!( - "Warning: Signature provided by {} who is not listed as a required signer. Including it anyway.", - signer_pubkey + "Warning: Signature provided by {signer_pubkey} who is not listed as a required signer. Including it anyway." ); } if let Some(existing_sig) = signatures_map.insert(signer_pubkey, signature) { if existing_sig != signature { eyre::bail!( - "Conflicting signatures provided for the same signer: {}.", - signer_pubkey + "Conflicting signatures provided for the same signer: {signer_pubkey}." ); } } @@ -101,48 +74,47 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::R if signatures_map.is_empty() { eyre::bail!("No valid signatures were loaded from the provided paths."); } + println!("Loaded {} unique signatures.", signatures_map.len()); + Ok(signatures_map) +} + +fn verify_signatures( + signatures_map: &HashMap, + required_signers: &HashSet, + message_bytes: &[u8], +) -> eyre::Result<()> { let mut missing_signers = Vec::new(); - for required_signer in &required_signers { + for required_signer in required_signers { if !signatures_map.contains_key(required_signer) { missing_signers.push(required_signer.to_string()); } } if !missing_signers.is_empty() { - eyre::bail!("Missing required signatures for: {:?}", missing_signers); + eyre::bail!("Missing required signatures for: {missing_signers:?}"); } println!("Validation OK: All required signers have provided signatures."); - let message_bytes = hex::decode(&unsigned_tx.signable_message_hex)?; - for (signer_pubkey, signature) in &signatures_map { - if !signature.verify(signer_pubkey.as_ref(), &message_bytes) { - eyre::bail!( - "Signature verification failed for signer: {}", - signer_pubkey - ); + for (signer_pubkey, signature) in signatures_map.iter() { + if !signature.verify(signer_pubkey.as_ref(), message_bytes) { + eyre::bail!("Signature verification failed for signer: {signer_pubkey}"); } } - let partial_signatures_vec: Vec = signatures_map - .into_iter() - .map(|(pubkey, sig)| PartialSignature { - signer_pubkey: pubkey.to_string(), - signature: sig.to_string(), - }) - .collect(); - - let signed_tx = SignedSolanaTransaction { - unsigned_tx_data: unsigned_tx, - signatures: partial_signatures_vec, - }; + Ok(()) +} +fn save_combined_transaction( + args: &CombineArgs, + signed_tx: &SignedSolanaTransaction, +) -> eyre::Result<()> { let output_dir = args.output_dir.clone().unwrap_or_else(|| { - args.unsigned_tx_path - .parent() - .map(|p| p.to_path_buf()) - .unwrap_or_else(|| std::path::PathBuf::from(".")) + args.unsigned_tx_path.parent().map_or_else( + || std::path::PathBuf::from("."), + std::path::Path::to_path_buf, + ) }); std::fs::create_dir_all(&output_dir)?; @@ -155,15 +127,68 @@ pub fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::R let tx_name = unsigned_file_stem.replace(".unsigned", ""); - let signed_filename = format!("{}.signed.json", tx_name); + let signed_filename = format!("{tx_name}.signed.json"); let signed_tx_path = output_dir.join(signed_filename); - utils::save_signed_solana_transaction(&signed_tx, &signed_tx_path)?; + utils::save_signed_solana_transaction(signed_tx, &signed_tx_path)?; println!( "Combined signed Solana transaction data saved to: {}", signed_tx_path.display() ); + Ok(()) +} + +pub(crate) fn combine_solana_signatures(args: &CombineArgs, config: &Config) -> eyre::Result<()> { + println!("Starting Solana signature combination..."); + + let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; + println!( + "Loaded unsigned transaction data from: {}", + args.unsigned_tx_path.display() + ); + + let fee_payer = Pubkey::from_str(&unsigned_tx.params.fee_payer)?; + let nonce_authority_pubkey: Option = unsigned_tx + .params + .nonce_authority + .as_ref() + .map(|s| Pubkey::from_str(s)) + .transpose()?; + let required_signers = get_required_signers_from_instructions( + &unsigned_tx.instructions, + &fee_payer, + nonce_authority_pubkey.as_ref(), + )?; + println!( + "Required signers determined from unsigned data: {:?}", + required_signers + .iter() + .map(std::string::ToString::to_string) + .collect::>() + ); + + let signatures_map = load_and_validate_signatures(&args.signature_paths, &required_signers)?; + + let message_bytes = hex::decode(&unsigned_tx.signable_message_hex)?; + verify_signatures(&signatures_map, &required_signers, &message_bytes)?; + + // Create signed transaction object + let partial_signatures_vec: Vec = signatures_map + .into_iter() + .map(|(pubkey, sig)| PartialSignature { + signer_pubkey: pubkey.to_string(), + signature: sig.to_string(), + }) + .collect(); + + let signed_tx = SignedSolanaTransaction { + unsigned_tx_data: unsigned_tx, + signatures: partial_signatures_vec, + }; + + save_combined_transaction(args, &signed_tx)?; + if config.network_type == NetworkType::Mainnet { println!( "-> Combined transaction file should be transferred to an online machine for broadcasting." diff --git a/solana/src/config.rs b/solana/src/config.rs index 8d2921a71..7ff7cfad5 100644 --- a/solana/src/config.rs +++ b/solana/src/config.rs @@ -7,21 +7,27 @@ use crate::types::ChainsInfoFile; use crate::types::NetworkType; #[derive(Debug)] -pub struct Config { - pub url: String, - pub output_dir: PathBuf, - pub network_type: NetworkType, - pub chains_info_file: PathBuf, +pub(crate) struct Config { + pub(crate) url: String, + pub(crate) output_dir: PathBuf, + pub(crate) network_type: NetworkType, + pub(crate) chains_info_file: PathBuf, } impl Config { - pub fn new(url: String, output_dir: PathBuf, chains_info_dir: PathBuf) -> eyre::Result { - println!("URL: {}", url); + pub(crate) fn new( + url: String, + output_dir: PathBuf, + chains_info_dir: PathBuf, + ) -> eyre::Result { + println!("URL: {url}"); if !output_dir.exists() { fs::create_dir_all(&output_dir) .map_err(|e| eyre!("Failed to create output directory: {}", e))?; println!("Created output directory: {}", output_dir.display()); - } else if !output_dir.is_dir() { + } + + if !output_dir.is_dir() { eyre::bail!( "Specified output path exists but is not a directory: {}", output_dir.display() diff --git a/solana/src/gas_service.rs b/solana/src/gas_service.rs index b8d653075..26d9df436 100644 --- a/solana/src/gas_service.rs +++ b/solana/src/gas_service.rs @@ -28,13 +28,13 @@ pub(crate) struct InitArgs { salt: String, } -pub(crate) async fn build_transaction( +pub(crate) fn build_transaction( fee_payer: &Pubkey, command: Commands, config: &Config, ) -> eyre::Result> { let instructions = match command { - Commands::Init(init_args) => init(fee_payer, init_args, config).await?, + Commands::Init(init_args) => init(fee_payer, init_args, config)?, }; // Get blockhash @@ -71,7 +71,7 @@ pub(crate) async fn build_transaction( Ok(serializable_transactions) } -async fn init( +fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 131368c88..04da3992a 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -229,13 +229,11 @@ pub(crate) async fn build_transaction( ) -> eyre::Result> { let instructions = match command { Commands::Init(init_args) => init(fee_payer, init_args, config).await?, - Commands::CallContract(call_contract_args) => { - call_contract(fee_payer, call_contract_args).await? - } + Commands::CallContract(call_contract_args) => call_contract(fee_payer, call_contract_args)?, Commands::TransferOperatorship(transfer_operatorship_args) => { - transfer_operatorship(fee_payer, transfer_operatorship_args).await? + transfer_operatorship(fee_payer, transfer_operatorship_args)? } - Commands::Approve(approve_args) => approve(fee_payer, approve_args, config).await?, + Commands::Approve(approve_args) => approve(fee_payer, approve_args, config)?, Commands::Rotate(rotate_args) => rotate(fee_payer, rotate_args, config).await?, Commands::SubmitProof(submit_proof_args) => { submit_proof(fee_payer, submit_proof_args, config).await? @@ -271,11 +269,11 @@ async fn query( query_data: Vec, ) -> eyre::Result { if !endpoint.starts_with("https://") { - endpoint = format!("https://{}", endpoint); + endpoint = format!("https://{endpoint}"); } - let mut c = query_client::QueryClient::connect(endpoint).await?; - let res = c + let res = query_client::QueryClient::connect(endpoint) + .await? .smart_contract_state( cosmrs::proto::cosmwasm::wasm::v1::QuerySmartContractStateRequest { address: address.to_string(), @@ -291,8 +289,8 @@ async fn query( } async fn get_verifier_set( - signer: &Option, - signer_set: &Option, + signer: Option<&String>, + signer_set: Option<&String>, nonce: Option, config: &Config, chains_info: &serde_json::Value, @@ -309,13 +307,13 @@ async fn get_verifier_set( .try_into() .map_err(|_| eyre!("Invalid encoded point conversion"))?, ); - let signers = BTreeMap::from([(pubkey, 1_u128)]); + let signers = BTreeMap::from([(pubkey, 1u128)]); let nonce = nonce.ok_or_else(|| eyre!("Nonce is required"))?; Ok(VerifierSet { nonce, signers, - quorum: 1_u128, + quorum: 1u128, }) } else if let Some(signer_set) = signer_set { let signer_set: SerializeableVerifierSet = serde_json::from_str(signer_set)?; @@ -353,7 +351,7 @@ async fn get_verifier_set( } } -async fn construct_execute_data( +fn construct_execute_data( signer_set: &SigningVerifierSet, payload: Payload, domain_separator: [u8; 32], @@ -400,16 +398,16 @@ async fn construct_execute_data( Ok(execute_data) } -async fn build_signing_verifier_set(secret: k256::SecretKey, nonce: u64) -> SigningVerifierSet { +fn build_signing_verifier_set(secret: k256::SecretKey, nonce: u64) -> SigningVerifierSet { let signer = LocalSigner { secret, - weight: 1_u128, + weight: 1u128, }; SigningVerifierSet::new(vec![signer], nonce) } -async fn append_verification_flow_instructions( +fn append_verification_flow_instructions( fee_payer: &Pubkey, instructions: &mut Vec, execute_data: &ExecuteData, @@ -451,8 +449,8 @@ async fn init( read_json_file_from_path(&config.chains_info_file).unwrap_or_default(); let (gateway_config_pda, _bump) = axelar_solana_gateway::get_gateway_root_config_pda(); let verifier_set = get_verifier_set( - &init_args.signer, - &init_args.signer_set, + init_args.signer.as_ref(), + init_args.signer_set.as_ref(), init_args.nonce, config, &chains_info, @@ -493,7 +491,7 @@ async fn init( ]) } -async fn call_contract( +fn call_contract( fee_payer: &Pubkey, call_contract_args: CallContractArgs, ) -> eyre::Result> { @@ -513,7 +511,7 @@ async fn call_contract( )?]) } -async fn transfer_operatorship( +fn transfer_operatorship( fee_payer: &Pubkey, transfer_operatorship_args: TransferOperatorshipArgs, ) -> eyre::Result> { @@ -526,15 +524,14 @@ async fn transfer_operatorship( ]) } -async fn approve( +fn approve( fee_payer: &Pubkey, approve_args: ApproveArgs, config: &Config, ) -> eyre::Result> { let mut instructions = vec![]; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let signer_set = - build_signing_verifier_set(approve_args.signer.clone(), approve_args.nonce).await; + let signer_set = build_signing_verifier_set(approve_args.signer.clone(), approve_args.nonce); let domain_separator = domain_separator(&chains_info, config.network_type)?; let payload_bytes = hex::decode( approve_args @@ -555,14 +552,13 @@ async fn approve( }; let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; let gmp_payload = Payload::Messages(Messages(vec![message])); - let execute_data = construct_execute_data(&signer_set, gmp_payload, domain_separator).await?; + let execute_data = construct_execute_data(&signer_set, gmp_payload, domain_separator)?; let verification_session_pda = append_verification_flow_instructions( fee_payer, &mut instructions, &execute_data, &gateway_config_pda, - ) - .await?; + )?; let MerkleisedPayload::NewMessages { mut messages } = execute_data.payload_items else { eyre::bail!("Expected Messages payload"); }; @@ -595,10 +591,10 @@ async fn rotate( ) -> eyre::Result> { let mut instructions = vec![]; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let signer_set = build_signing_verifier_set(rotate_args.signer, rotate_args.nonce).await; + let signer_set = build_signing_verifier_set(rotate_args.signer, rotate_args.nonce); let new_verifier_set = get_verifier_set( - &rotate_args.new_signer, - &rotate_args.new_signer_set, + rotate_args.new_signer.as_ref(), + rotate_args.new_signer_set.as_ref(), rotate_args.new_nonce, config, &chains_info, @@ -617,14 +613,13 @@ async fn rotate( axelar_solana_gateway::get_verifier_set_tracker_pda(new_verifier_set_hash); let gateway_config_pda = axelar_solana_gateway::get_gateway_root_config_pda().0; let payload = Payload::NewVerifierSet(new_verifier_set.clone()); - let execute_data = construct_execute_data(&signer_set, payload, domain_separator).await?; + let execute_data = construct_execute_data(&signer_set, payload, domain_separator)?; let verification_session_pda = append_verification_flow_instructions( fee_payer, &mut instructions, &execute_data, &gateway_config_pda, - ) - .await?; + )?; instructions.push(axelar_solana_gateway::instructions::rotate_signers( gateway_config_pda, @@ -675,8 +670,7 @@ async fn submit_proof( &mut instructions, &execute_data, &gateway_config_pda, - ) - .await?; + )?; match execute_data.payload_items { MerkleisedPayload::VerifierSetRotation { diff --git a/solana/src/generate.rs b/solana/src/generate.rs index 7dd2bab69..5cd476f3a 100644 --- a/solana/src/generate.rs +++ b/solana/src/generate.rs @@ -5,14 +5,14 @@ use crate::types::SerializableSolanaTransaction; use crate::utils::{self, fetch_nonce_data_and_verify}; #[derive(Debug, Clone)] -pub struct GenerateArgs { - pub fee_payer: Pubkey, - pub nonce_account: Pubkey, - pub nonce_authority: Pubkey, - pub output_dir: std::path::PathBuf, +pub(crate) struct GenerateArgs { + pub(crate) fee_payer: Pubkey, + pub(crate) nonce_account: Pubkey, + pub(crate) nonce_authority: Pubkey, + pub(crate) output_dir: std::path::PathBuf, } -pub fn generate_from_transactions( +pub(crate) fn generate_from_transactions( args: &GenerateArgs, config: &Config, mut transactions: Vec, @@ -28,7 +28,7 @@ pub fn generate_from_transactions( let blockhash = fetch_nonce_data_and_verify(&config.url, &args.nonce_account, &args.nonce_authority)?; - println!("Using Nonce (Blockhash) from account: {}", blockhash); + println!("Using Nonce (Blockhash) from account: {blockhash}"); for tx in &mut transactions { tx.params.nonce_account = Some(args.nonce_account.to_string()); @@ -84,9 +84,9 @@ pub fn generate_from_transactions( let unsigned_tx = tx.to_unsigned(); let unsigned_tx_filename = if transactions.len() > 1 { - format!("{}.{}.unsigned.json", filename, i) + format!("{filename}.{i}.unsigned.json") } else { - format!("{}.unsigned.json", filename) + format!("{filename}.unsigned.json") }; let unsigned_tx_path = args.output_dir.join(&unsigned_tx_filename); diff --git a/solana/src/governance.rs b/solana/src/governance.rs index f0c2a392c..7bf4e0104 100644 --- a/solana/src/governance.rs +++ b/solana/src/governance.rs @@ -94,7 +94,7 @@ pub(crate) struct TransferOperatorshipArgs { operator: Pubkey, } -pub(crate) async fn build_instruction( +pub(crate) fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, @@ -102,20 +102,20 @@ pub(crate) async fn build_instruction( let (config_pda, _) = axelar_solana_governance::state::GovernanceConfig::pda(); match command { - Commands::Init(init_args) => init(fee_payer, init_args, config, &config_pda).await, - Commands::ExecuteProposal(args) => execute_proposal(fee_payer, args, &config_pda).await, + Commands::Init(init_args) => init(fee_payer, init_args, config, &config_pda), + Commands::ExecuteProposal(args) => execute_proposal(fee_payer, args, &config_pda), Commands::ExecuteOperatorProposal(args) => { - execute_operator_proposal(fee_payer, args, &config_pda).await + execute_operator_proposal(fee_payer, args, &config_pda) } } } -pub(crate) async fn build_transaction( +pub(crate) fn build_transaction( fee_payer: &Pubkey, command: Commands, config: &Config, ) -> eyre::Result> { - let instructions = build_instruction(fee_payer, command, config).await?; + let instructions = build_instruction(fee_payer, command, config)?; // Get blockhash let blockhash = fetch_latest_blockhash(&config.url)?; @@ -151,7 +151,7 @@ pub(crate) async fn build_transaction( Ok(serializable_transactions) } -async fn init( +fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, @@ -187,7 +187,7 @@ async fn init( ]) } -async fn execute_proposal( +fn execute_proposal( fee_payer: &Pubkey, args: ExecuteProposalArgs, config_pda: &Pubkey, @@ -216,7 +216,7 @@ async fn execute_proposal( ]) } -async fn execute_operator_proposal( +fn execute_operator_proposal( fee_payer: &Pubkey, args: ExecuteOperatorProposalArgs, config_pda: &Pubkey, diff --git a/solana/src/its.rs b/solana/src/its.rs index 64e9b155f..4cb1bc818 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -747,7 +747,7 @@ fn parse_token_program(s: &str) -> Result { match s.to_lowercase().as_str() { "spl_token" => Ok(spl_token::id()), "spl_token_2022" => Ok(spl_token_2022::id()), - _ => Err(format!("Invalid token program: {}", s)), + _ => Err(format!("Invalid token program: {s}")), } } @@ -757,24 +757,23 @@ fn parse_token_manager_type(s: &str) -> Result Ok(state::token_manager::Type::MintBurn), "mintburnfrom" | "mint_burn_from" => Ok(state::token_manager::Type::MintBurnFrom), "lockunlockfee" | "lock_unlock_fee" => Ok(state::token_manager::Type::LockUnlockFee), - _ => Err(format!("Invalid token manager type: {}", s)), + _ => Err(format!("Invalid token manager type: {s}")), } } fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre::Result { let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - match maybe_arg { - Some(id) => Ok(id), - None => { - let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY][ADDRESS_KEY], - ).map_err(|_| eyre!( - "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ - Please update the file or pass a value to --gas-service"))?; - - Ok(id) - } + if let Some(id) = maybe_arg { + Ok(id) + } else { + let id = Pubkey::deserialize( + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][ADDRESS_KEY], + ).map_err(|_| eyre!( + "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-service"))?; + + Ok(id) } } @@ -783,115 +782,110 @@ fn try_infer_gas_service_config_account( config: &Config, ) -> eyre::Result { let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - match maybe_arg { - Some(id) => Ok(id), - None => { - let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], - ).map_err(|_| eyre!( - "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ - Please update the file or pass a value to --gas-config-account"))?; - - Ok(id) - } + if let Some(id) = maybe_arg { + Ok(id) + } else { + let id = Pubkey::deserialize( + &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], + ).map_err(|_| eyre!( + "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ + Please update the file or pass a value to --gas-config-account"))?; + + Ok(id) } } -pub(crate) async fn build_instruction( +pub(crate) fn build_instruction( fee_payer: &Pubkey, command: Commands, config: &Config, ) -> eyre::Result> { match command { - Commands::Init(init_args) => init(fee_payer, init_args, config).await, - Commands::Pause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: true }).await, - Commands::Unpause => { - set_pause_status(fee_payer, SetPauseStatusArgs { paused: false }).await - } + Commands::Init(init_args) => init(fee_payer, init_args, config), + Commands::Pause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: true }), + Commands::Unpause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: false }), Commands::SetTrustedChain(set_trusted_chain_args) => { - set_trusted_chain(fee_payer, set_trusted_chain_args).await + set_trusted_chain(fee_payer, set_trusted_chain_args) } - Commands::RemoveTrustedChain(args) => remove_trusted_chain(fee_payer, args).await, + Commands::RemoveTrustedChain(args) => remove_trusted_chain(fee_payer, args), Commands::ApproveDeployRemoteInterchainToken(args) => { - approve_deploy_remote_interchain_token(fee_payer, args, config).await + approve_deploy_remote_interchain_token(fee_payer, args, config) } Commands::RevokeDeployRemoteInterchainToken(args) => { - revoke_deploy_remote_interchain_token(fee_payer, args).await + revoke_deploy_remote_interchain_token(fee_payer, args) } Commands::RegisterCanonicalInterchainToken(args) => { - register_canonical_interchain_token(fee_payer, args).await + register_canonical_interchain_token(fee_payer, args) } Commands::DeployRemoteCanonicalInterchainToken(args) => { - deploy_remote_canonical_interchain_token(fee_payer, args, config).await + deploy_remote_canonical_interchain_token(fee_payer, args, config) } - Commands::DeployInterchainToken(args) => deploy_interchain_token(fee_payer, args).await, + Commands::DeployInterchainToken(args) => deploy_interchain_token(fee_payer, args), Commands::DeployRemoteInterchainToken(args) => { - deploy_remote_interchain_token(fee_payer, args, config).await + deploy_remote_interchain_token(fee_payer, args, config) } Commands::DeployRemoteInterchainTokenWithMinter(args) => { - deploy_remote_interchain_token_with_minter(fee_payer, args, config).await - } - Commands::RegisterTokenMetadata(args) => { - register_token_metadata(fee_payer, args, config).await + deploy_remote_interchain_token_with_minter(fee_payer, args, config) } - Commands::RegisterCustomToken(args) => register_custom_token(fee_payer, args).await, - Commands::LinkToken(args) => link_token(fee_payer, args, config).await, - Commands::InterchainTransfer(args) => interchain_transfer(fee_payer, args, config).await, + Commands::RegisterTokenMetadata(args) => register_token_metadata(fee_payer, args, config), + Commands::RegisterCustomToken(args) => register_custom_token(fee_payer, args), + Commands::LinkToken(args) => link_token(fee_payer, args, config), + Commands::InterchainTransfer(args) => interchain_transfer(fee_payer, args, config), Commands::CallContractWithInterchainToken(args) => { - call_contract_with_interchain_token(fee_payer, args, config).await + call_contract_with_interchain_token(fee_payer, args, config) } Commands::CallContractWithInterchainTokenOffchainData(args) => { - call_contract_with_interchain_token_offchain_data(fee_payer, args, config).await + call_contract_with_interchain_token_offchain_data(fee_payer, args, config) } - Commands::SetFlowLimit(args) => set_flow_limit(fee_payer, args).await, - Commands::TransferOperatorship(args) => transfer_operatorship(fee_payer, args).await, - Commands::ProposeOperatorship(args) => propose_operatorship(fee_payer, args).await, - Commands::AcceptOperatorship(args) => accept_operatorship(fee_payer, args).await, + Commands::SetFlowLimit(args) => set_flow_limit(fee_payer, args), + Commands::TransferOperatorship(args) => transfer_operatorship(fee_payer, args), + Commands::ProposeOperatorship(args) => propose_operatorship(fee_payer, args), + Commands::AcceptOperatorship(args) => accept_operatorship(fee_payer, args), Commands::TokenManager(command) => match command { TokenManagerCommand::SetFlowLimit(args) => { - token_manager_set_flow_limit(fee_payer, args).await + token_manager_set_flow_limit(fee_payer, args) } TokenManagerCommand::AddFlowLimiter(args) => { - token_manager_add_flow_limiter(fee_payer, args).await + token_manager_add_flow_limiter(fee_payer, args) } TokenManagerCommand::RemoveFlowLimiter(args) => { - token_manager_remove_flow_limiter(fee_payer, args).await + token_manager_remove_flow_limiter(fee_payer, args) } TokenManagerCommand::TransferOperatorship(args) => { - token_manager_transfer_operatorship(fee_payer, args).await + token_manager_transfer_operatorship(fee_payer, args) } TokenManagerCommand::ProposeOperatorship(args) => { - token_manager_propose_operatorship(fee_payer, args).await + token_manager_propose_operatorship(fee_payer, args) } TokenManagerCommand::AcceptOperatorship(args) => { - token_manager_accept_operatorship(fee_payer, args).await + token_manager_accept_operatorship(fee_payer, args) } TokenManagerCommand::HandoverMintAuthority(args) => { - token_manager_handover_mint_authority(fee_payer, args).await + token_manager_handover_mint_authority(fee_payer, args) } }, Commands::InterchainToken(command) => match command { - InterchainTokenCommand::Mint(args) => interchain_token_mint(fee_payer, args).await, + InterchainTokenCommand::Mint(args) => interchain_token_mint(fee_payer, args), InterchainTokenCommand::TransferMintership(args) => { - interchain_token_transfer_mintership(fee_payer, args).await + interchain_token_transfer_mintership(fee_payer, args) } InterchainTokenCommand::ProposeMintership(args) => { - interchain_token_propose_mintership(fee_payer, args).await + interchain_token_propose_mintership(fee_payer, args) } InterchainTokenCommand::AcceptMintership(args) => { - interchain_token_accept_mintership(fee_payer, args).await + interchain_token_accept_mintership(fee_payer, args) } }, } } -pub(crate) async fn build_transaction( +pub(crate) fn build_transaction( fee_payer: &Pubkey, command: Commands, config: &Config, ) -> eyre::Result> { - let instructions = build_instruction(fee_payer, command, config).await?; + let instructions = build_instruction(fee_payer, command, config)?; // Get blockhash let blockhash = fetch_latest_blockhash(&config.url)?; @@ -927,7 +921,7 @@ pub(crate) async fn build_transaction( Ok(serializable_transactions) } -async fn init( +fn init( fee_payer: &Pubkey, init_args: InitArgs, config: &Config, @@ -955,7 +949,7 @@ async fn init( )?]) } -async fn set_pause_status( +fn set_pause_status( fee_payer: &Pubkey, set_pause_args: SetPauseStatusArgs, ) -> eyre::Result> { @@ -965,7 +959,7 @@ async fn set_pause_status( )?]) } -async fn set_trusted_chain( +fn set_trusted_chain( fee_payer: &Pubkey, set_trusted_chain_args: TrustedChainArgs, ) -> eyre::Result> { @@ -975,7 +969,7 @@ async fn set_trusted_chain( )?]) } -async fn remove_trusted_chain( +fn remove_trusted_chain( fee_payer: &Pubkey, remove_trusted_chain_args: TrustedChainArgs, ) -> eyre::Result> { @@ -985,7 +979,7 @@ async fn remove_trusted_chain( )?]) } -async fn approve_deploy_remote_interchain_token( +fn approve_deploy_remote_interchain_token( fee_payer: &Pubkey, args: ApproveDeployRemoteInterchainTokenArgs, config: &Config, @@ -1008,7 +1002,7 @@ async fn approve_deploy_remote_interchain_token( ]) } -async fn revoke_deploy_remote_interchain_token( +fn revoke_deploy_remote_interchain_token( fee_payer: &Pubkey, args: RevokeDeployRemoteInterchainTokenArgs, ) -> eyre::Result> { @@ -1022,7 +1016,7 @@ async fn revoke_deploy_remote_interchain_token( ]) } -async fn register_canonical_interchain_token( +fn register_canonical_interchain_token( fee_payer: &Pubkey, args: RegisterCanonicalInterchainTokenArgs, ) -> eyre::Result> { @@ -1038,7 +1032,7 @@ async fn register_canonical_interchain_token( ]) } -async fn deploy_remote_canonical_interchain_token( +fn deploy_remote_canonical_interchain_token( fee_payer: &Pubkey, args: DeployRemoteCanonicalInterchainTokenArgs, config: &Config, @@ -1057,7 +1051,7 @@ async fn deploy_remote_canonical_interchain_token( ]) } -async fn deploy_interchain_token( +fn deploy_interchain_token( fee_payer: &Pubkey, args: DeployInterchainTokenArgs, ) -> eyre::Result> { @@ -1077,7 +1071,7 @@ async fn deploy_interchain_token( ]) } -async fn deploy_remote_interchain_token( +fn deploy_remote_interchain_token( fee_payer: &Pubkey, args: DeployRemoteInterchainTokenArgs, config: &Config, @@ -1096,7 +1090,7 @@ async fn deploy_remote_interchain_token( ]) } -async fn deploy_remote_interchain_token_with_minter( +fn deploy_remote_interchain_token_with_minter( fee_payer: &Pubkey, args: DeployRemoteInterchainTokenWithMinterArgs, config: &Config, @@ -1123,7 +1117,7 @@ async fn deploy_remote_interchain_token_with_minter( ]) } -async fn register_token_metadata( +fn register_token_metadata( fee_payer: &Pubkey, args: RegisterTokenMetadataArgs, config: &Config, @@ -1142,7 +1136,7 @@ async fn register_token_metadata( ]) } -async fn register_custom_token( +fn register_custom_token( fee_payer: &Pubkey, args: RegisterCustomTokenArgs, ) -> eyre::Result> { @@ -1159,7 +1153,7 @@ async fn register_custom_token( )?]) } -async fn link_token( +fn link_token( fee_payer: &Pubkey, args: LinkTokenArgs, config: &Config, @@ -1180,7 +1174,7 @@ async fn link_token( )?]) } -async fn interchain_transfer( +fn interchain_transfer( fee_payer: &Pubkey, args: InterchainTransferArgs, config: &Config, @@ -1216,7 +1210,7 @@ async fn interchain_transfer( )?]) } -async fn call_contract_with_interchain_token( +fn call_contract_with_interchain_token( fee_payer: &Pubkey, args: CallContractWithInterchainTokenArgs, config: &Config, @@ -1253,7 +1247,7 @@ async fn call_contract_with_interchain_token( ]) } -async fn call_contract_with_interchain_token_offchain_data( +fn call_contract_with_interchain_token_offchain_data( fee_payer: &Pubkey, args: CallContractWithInterchainTokenOffchainDataArgs, config: &Config, @@ -1295,10 +1289,7 @@ async fn call_contract_with_interchain_token_offchain_data( Ok(vec![instruction]) } -async fn set_flow_limit( - fee_payer: &Pubkey, - args: SetFlowLimitArgs, -) -> eyre::Result> { +fn set_flow_limit(fee_payer: &Pubkey, args: SetFlowLimitArgs) -> eyre::Result> { Ok(vec![axelar_solana_its::instruction::set_flow_limit( *fee_payer, args.token_id, @@ -1306,7 +1297,7 @@ async fn set_flow_limit( )?]) } -async fn transfer_operatorship( +fn transfer_operatorship( fee_payer: &Pubkey, args: TransferOperatorshipArgs, ) -> eyre::Result> { @@ -1315,7 +1306,7 @@ async fn transfer_operatorship( )?]) } -async fn propose_operatorship( +fn propose_operatorship( fee_payer: &Pubkey, args: TransferOperatorshipArgs, // Reuses args from transfer ) -> eyre::Result> { @@ -1324,7 +1315,7 @@ async fn propose_operatorship( )?]) } -async fn accept_operatorship( +fn accept_operatorship( fee_payer: &Pubkey, args: AcceptOperatorshipArgs, ) -> eyre::Result> { @@ -1333,7 +1324,7 @@ async fn accept_operatorship( )?]) } -async fn token_manager_set_flow_limit( +fn token_manager_set_flow_limit( fee_payer: &Pubkey, args: TokenManagerSetFlowLimitArgs, ) -> eyre::Result> { @@ -1346,7 +1337,7 @@ async fn token_manager_set_flow_limit( ]) } -async fn token_manager_add_flow_limiter( +fn token_manager_add_flow_limiter( fee_payer: &Pubkey, args: TokenManagerAddFlowLimiterArgs, ) -> eyre::Result> { @@ -1359,7 +1350,7 @@ async fn token_manager_add_flow_limiter( ]) } -async fn token_manager_remove_flow_limiter( +fn token_manager_remove_flow_limiter( fee_payer: &Pubkey, args: TokenManagerRemoveFlowLimiterArgs, ) -> eyre::Result> { @@ -1372,7 +1363,7 @@ async fn token_manager_remove_flow_limiter( ]) } -async fn token_manager_transfer_operatorship( +fn token_manager_transfer_operatorship( fee_payer: &Pubkey, args: TokenManagerTransferOperatorshipArgs, ) -> eyre::Result> { @@ -1385,7 +1376,7 @@ async fn token_manager_transfer_operatorship( ]) } -async fn token_manager_propose_operatorship( +fn token_manager_propose_operatorship( fee_payer: &Pubkey, args: TokenManagerProposeOperatorshipArgs, ) -> eyre::Result> { @@ -1398,7 +1389,7 @@ async fn token_manager_propose_operatorship( ]) } -async fn token_manager_accept_operatorship( +fn token_manager_accept_operatorship( fee_payer: &Pubkey, args: TokenManagerAcceptOperatorshipArgs, ) -> eyre::Result> { @@ -1411,7 +1402,7 @@ async fn token_manager_accept_operatorship( ]) } -async fn token_manager_handover_mint_authority( +fn token_manager_handover_mint_authority( fee_payer: &Pubkey, args: TokenManagerHandoverMintAuthorityArgs, ) -> eyre::Result> { @@ -1425,13 +1416,13 @@ async fn token_manager_handover_mint_authority( ]) } -async fn interchain_token_mint( +fn interchain_token_mint( fee_payer: &Pubkey, args: InterchainTokenMintArgs, ) -> eyre::Result> { Ok(vec![ axelar_solana_its::instruction::interchain_token::mint( - args.token_id, // Note: payer is not the first argument here + args.token_id, args.mint, args.to, *fee_payer, // Payer is the minter in this context @@ -1441,7 +1432,7 @@ async fn interchain_token_mint( ]) } -async fn interchain_token_transfer_mintership( +fn interchain_token_transfer_mintership( fee_payer: &Pubkey, args: InterchainTokenTransferMintershipArgs, ) -> eyre::Result> { @@ -1454,7 +1445,7 @@ async fn interchain_token_transfer_mintership( ]) } -async fn interchain_token_propose_mintership( +fn interchain_token_propose_mintership( fee_payer: &Pubkey, args: InterchainTokenProposeMintershipArgs, ) -> eyre::Result> { @@ -1467,7 +1458,7 @@ async fn interchain_token_propose_mintership( ]) } -async fn interchain_token_accept_mintership( +fn interchain_token_accept_mintership( fee_payer: &Pubkey, args: InterchainTokenAcceptMintershipArgs, ) -> eyre::Result> { diff --git a/solana/src/main.rs b/solana/src/main.rs index f9cc27b1f..b6aa3625f 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -200,7 +200,7 @@ struct MiscCommandArgs { #[tokio::main] async fn main() { if let Err(e) = run().await { - eprintln!("\nError: {:?}", e); + eprintln!("\nError: {e:?}"); exit(1); } } @@ -214,21 +214,21 @@ async fn run() -> eyre::Result<()> { match cli.command { Command::Send(args) => { let mut signer_keys = args.signer_keys; - let fee_payer = match args.fee_payer { - Some(fee_payer) => fee_payer, - None => { - let config_file = solana_cli_config::CONFIG_FILE - .as_ref() - .ok_or_else(|| eyre!("Missing Solana config file"))?; - let cli_config = solana_cli_config::Config::load(config_file)?; - let signer = - signer_from_path(&matches, &cli_config.keypair_path, "signer", &mut None) - .map_err(|e| eyre!("Failed to load fee payer: {}", e))?; - - signer_keys.push(cli_config.keypair_path); - signer.pubkey() - } + let fee_payer = if let Some(fee_payer) = args.fee_payer { + fee_payer + } else { + let config_file = solana_cli_config::CONFIG_FILE + .as_ref() + .ok_or_else(|| eyre!("Missing Solana config file"))?; + let cli_config = solana_cli_config::Config::load(config_file)?; + let signer = + signer_from_path(&matches, &cli_config.keypair_path, "signer", &mut None) + .map_err(|e| eyre!("Failed to load fee payer: {e}"))?; + + signer_keys.push(cli_config.keypair_path); + signer.pubkey() }; + let send_args = SendArgs { fee_payer, signers: signer_keys, @@ -292,13 +292,11 @@ async fn build_transaction( gateway::build_transaction(fee_payer, command, config).await } InstructionSubcommand::GasService(command) => { - gas_service::build_transaction(fee_payer, command, config).await - } - InstructionSubcommand::Its(command) => { - its::build_transaction(fee_payer, command, config).await + gas_service::build_transaction(fee_payer, command, config) } + InstructionSubcommand::Its(command) => its::build_transaction(fee_payer, command, config), InstructionSubcommand::Governance(command) => { - governance::build_transaction(fee_payer, command, config).await + governance::build_transaction(fee_payer, command, config) } } } diff --git a/solana/src/misc.rs b/solana/src/misc.rs index 1173cb76c..1f9c47dd8 100644 --- a/solana/src/misc.rs +++ b/solana/src/misc.rs @@ -9,13 +9,13 @@ use solana_sdk::pubkey::Pubkey; /// Commands for miscellaneous utilities #[derive(Subcommand, Debug)] -pub enum Commands { +pub(crate) enum Commands { /// Build an axelar-executable message BuildAxelarMessage(BuildAxelarMessageArgs), } #[derive(Args, Debug)] -pub struct BuildAxelarMessageArgs { +pub(crate) struct BuildAxelarMessageArgs { /// Accounts in the format of "pubkey:is_signer:is_writable" (e.g., "HQ57JcVZEMkpfEYJRJqnoH6wQdrNqNP6TDvzqnpPYBXQ:true:false"). The order should be the same as expected by the destination program. #[clap(long, multiple_values = true)] accounts: Vec, @@ -30,7 +30,7 @@ pub struct BuildAxelarMessageArgs { } /// Build a message for miscellaneous utilities -pub fn do_misc(args: Commands) -> Result<()> { +pub(crate) fn do_misc(args: Commands) -> Result<()> { match args { Commands::BuildAxelarMessage(args) => build_axelar_message(args), } @@ -74,7 +74,7 @@ fn build_axelar_message(args: BuildAxelarMessageArgs) -> Result<()> { // Encode the payload let encoded = axelar_message .encode() - .map_err(|e| eyre::eyre!("Failed to encode message: {}", e))?; + .map_err(|e| eyre::eyre!("Failed to encode message: {e}"))?; // Print the encoded payload as a hex string println!("{}", hex::encode(encoded)); diff --git a/solana/src/multisig_prover_types.rs b/solana/src/multisig_prover_types.rs index 3ff20dc03..4e41fc620 100644 --- a/solana/src/multisig_prover_types.rs +++ b/solana/src/multisig_prover_types.rs @@ -6,7 +6,7 @@ use cosmwasm_std::HexBinary; use serde::{Deserialize, Serialize}; // Extension trait to add u128() method to Uint128 -pub trait Uint128Extensions { +pub(crate) trait Uint128Extensions { fn u128(&self) -> u128; } @@ -20,47 +20,47 @@ impl Uint128Extensions for Uint128 { /// The status of a proof #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(rename_all = "snake_case")] -pub enum ProofStatus { +pub(crate) enum ProofStatus { Pending, Completed { execute_data: Vec }, } /// The response from querying a proof #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct ProofResponse { - pub status: ProofStatus, +pub(crate) struct ProofResponse { + pub(crate) status: ProofStatus, } /// The public key of a signer #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Signer { - pub pub_key: HexBinary, - pub weight: Uint128, +pub(crate) struct Signer { + pub(crate) pub_key: HexBinary, + pub(crate) weight: Uint128, } /// A set of verifiers #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct VerifierSet { - pub signers: std::collections::BTreeMap, - pub threshold: Uint128, - pub created_at: u64, +pub(crate) struct VerifierSet { + pub(crate) signers: std::collections::BTreeMap, + pub(crate) threshold: Uint128, + pub(crate) created_at: u64, } /// The response from querying a verifier set #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct VerifierSetResponse { - pub verifier_set: VerifierSet, +pub(crate) struct VerifierSetResponse { + pub(crate) verifier_set: VerifierSet, } /// The query message for the multisig prover #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(rename_all = "snake_case")] -pub enum QueryMsg { +pub(crate) enum QueryMsg { CurrentVerifierSet, Proof { multisig_session_id: u64 }, } /// A module to replicate the structure of multisig_prover::msg -pub mod msg { - pub use super::*; +pub(crate) mod msg { + pub(crate) use super::*; } diff --git a/solana/src/send.rs b/solana/src/send.rs index 3c609f8fd..f64c5d33c 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -18,9 +18,161 @@ use crate::utils::{ }; #[derive(Debug, Clone)] -pub struct SendArgs { - pub fee_payer: Pubkey, - pub signers: Vec, +pub(crate) struct SendArgs { + pub(crate) fee_payer: Pubkey, + pub(crate) signers: Vec, +} + +fn load_signers( + signers_paths: &[String], + transaction: &Transaction, +) -> eyre::Result>> { + if signers_paths.len() < transaction.signatures.len() { + eyre::bail!("Not enough signers provided"); + } + + let mut signers = Vec::with_capacity(transaction.signatures.len()); + let signer_context = clap::ArgMatches::default(); // Dummy context + + for signer in signers_paths.iter() { + let signer = signer_from_path(&signer_context, signer, "signer", &mut None) + .map_err(|e| eyre!("Failed to load signer '{signer}': {e}"))?; + + signers.push(signer); + } + + Ok(signers) +} + +fn optimize_transaction( + transaction: &Transaction, + signers: &[Box], + rpc_client: &RpcClient, + blockhash: &solana_sdk::hash::Hash, +) -> eyre::Result { + let mut transaction = transaction.clone(); + + let has_compute_budget = transaction.message.instructions.iter().any(|ix| { + let program_id = transaction.message.account_keys[ix.program_id_index as usize]; + program_id == solana_sdk::compute_budget::id() + }); + + if has_compute_budget { + println!("Transaction already has compute budget instructions, skipping optimization"); + transaction.sign(signers, *blockhash); + return Ok(transaction); + } + + println!("Simulating transaction before sending..."); + transaction.sign(signers, *blockhash); + + match rpc_client.simulate_transaction(&transaction) { + Ok(sim_result) => { + if let Some(units) = sim_result.value.units_consumed { + println!("Simulation used {units} compute units"); + + if units > 150_000 { + println!("Transaction needs significant compute units, adding compute budget"); + return add_compute_budget_to_transaction(&transaction, signers, blockhash); + } + } + } + Err(err) => { + println!("Simulation failed: {err:?}, proceeding with regular transaction"); + transaction.sign(signers, *blockhash); + } + } + + Ok(transaction) +} + +fn add_compute_budget_to_transaction( + transaction: &Transaction, + signers: &[Box], + blockhash: &solana_sdk::hash::Hash, +) -> eyre::Result { + let message = &transaction.message; + + let original_instructions: Vec = message + .instructions + .iter() + .map(|compiled_ix| solana_sdk::instruction::Instruction { + program_id: message.account_keys[compiled_ix.program_id_index as usize], + accounts: compiled_ix + .accounts + .iter() + .map(|account_idx| { + let pubkey = message.account_keys[*account_idx as usize]; + solana_sdk::instruction::AccountMeta { + pubkey, + is_signer: message.is_signer(*account_idx as usize), + is_writable: message.is_maybe_writable(*account_idx as usize, None), + } + }) + .collect(), + data: compiled_ix.data.clone(), + }) + .collect(); + + let compute_budget_instructions = + create_compute_budget_instructions(DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE); + + let mut all_instructions = compute_budget_instructions; + all_instructions.extend(original_instructions); + + let fee_payer = transaction.message.account_keys[0]; + + let message = solana_sdk::message::Message::new_with_blockhash( + &all_instructions, + Some(&fee_payer), + blockhash, + ); + + let mut optimized_tx = Transaction::new_unsigned(message); + optimized_tx.sign(signers, *blockhash); + + println!( + "Added compute budget: {DEFAULT_COMPUTE_UNITS} units with {DEFAULT_PRIORITY_FEE} micro-lamports priority fee" + ); + + Ok(optimized_tx) +} + +fn handle_transaction_error(err: solana_client::client_error::ClientError) -> eyre::Result { + let should_continue = if let ClientErrorKind::RpcError( + solana_client::rpc_request::RpcError::RpcResponseError { + data: + RpcResponseErrorData::SendTransactionPreflightFailure(RpcSimulateTransactionResult { + err: + Some(TransactionError::InstructionError(_, InstructionError::Custom(err_code))), + .. + }), + .. + }, + ) = err.kind() + { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else if let ClientErrorKind::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(err_code), + )) = err.kind() + { + axelar_solana_gateway::error::GatewayError::from_u32(*err_code) + .is_some_and(|gw_err| gw_err.should_relayer_proceed()) + } else { + false + }; + + if should_continue { + println!( + "Transaction error: GatewayError (code: {:?}), but continuing with next transaction as it's recoverable", + err.kind() + ); + Ok(true) + } else { + eyre::bail!("Transaction simulation error: {err:?}"); + } } pub(crate) fn sign_and_send_transactions( @@ -32,155 +184,20 @@ pub(crate) fn sign_and_send_transactions( let mut results = Vec::new(); for serializable_tx in serializable_txs { - let mut transaction = serializable_tx.transaction; - - if send_args.signers.len() < transaction.signatures.len() { - eyre::bail!("Not enough signers provided"); - } - - let mut signers = Vec::with_capacity(transaction.signatures.len()); - let signer_context = clap::ArgMatches::default(); // Dummy context - - for signer in send_args.signers.iter() { - let signer = signer_from_path(&signer_context, signer, "signer", &mut None) - .map_err(|e| eyre!("Failed to load signer '{}': {}", signer, e))?; - - signers.push(signer); - } - + let transaction = serializable_tx.transaction; + let signers = load_signers(&send_args.signers, &transaction)?; let blockhash = rpc_client.get_latest_blockhash()?; - let has_compute_budget = transaction.message.instructions.iter().any(|ix| { - let program_id = transaction.message.account_keys[ix.program_id_index as usize]; - program_id == solana_sdk::compute_budget::id() - }); - - transaction.sign(&signers, blockhash); - - if !has_compute_budget { - println!("Simulating transaction before sending..."); - match rpc_client.simulate_transaction(&transaction) { - Ok(sim_result) => { - if let Some(units) = sim_result.value.units_consumed { - println!("Simulation used {} compute units", units); - - if units > 150_000 { - println!( - "Transaction needs significant compute units, adding compute budget" - ); - - let message = &transaction.message; - - let original_instructions: Vec = - message - .instructions - .iter() - .map(|compiled_ix| solana_sdk::instruction::Instruction { - program_id: message.account_keys - [compiled_ix.program_id_index as usize], - accounts: compiled_ix - .accounts - .iter() - .map(|account_idx| { - let pubkey = - message.account_keys[*account_idx as usize]; - solana_sdk::instruction::AccountMeta { - pubkey, - is_signer: message - .is_signer(*account_idx as usize), - is_writable: message.is_maybe_writable( - *account_idx as usize, - None, - ), - } - }) - .collect(), - data: compiled_ix.data.clone(), - }) - .collect(); - - let compute_budget_instructions = create_compute_budget_instructions( - DEFAULT_COMPUTE_UNITS, - DEFAULT_PRIORITY_FEE, - ); - - let mut all_instructions = compute_budget_instructions; - all_instructions.extend(original_instructions); - - let fee_payer = transaction.message.account_keys[0]; - - let message = solana_sdk::message::Message::new_with_blockhash( - &all_instructions, - Some(&fee_payer), - &blockhash, - ); - - let mut optimized_tx = Transaction::new_unsigned(message); - optimized_tx.sign(&signers, blockhash); - - transaction = optimized_tx; - println!( - "Added compute budget: {} units with {} micro-lamports priority fee", - DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE - ); - } - } - } - Err(err) => { - println!( - "Simulation failed: {:?}, proceeding with regular transaction", - err - ); - transaction.sign(&signers, blockhash); - } - }; - } else { - println!("Transaction already has compute budget instructions, skipping optimization"); - } + let optimized_tx = optimize_transaction(&transaction, &signers, &rpc_client, &blockhash)?; - match rpc_client.send_and_confirm_transaction(&transaction) { + match rpc_client.send_and_confirm_transaction(&optimized_tx) { Ok(signature) => { results.push(signature); } Err(err) => { - let should_continue = if let ClientErrorKind::RpcError( - solana_client::rpc_request::RpcError::RpcResponseError { - data: - RpcResponseErrorData::SendTransactionPreflightFailure( - RpcSimulateTransactionResult { - err: - Some(TransactionError::InstructionError( - _, - InstructionError::Custom(err_code), - )), - .. - }, - ), - .. - }, - ) = err.kind() - { - axelar_solana_gateway::error::GatewayError::from_u32(*err_code) - .is_some_and(|gw_err| gw_err.should_relayer_proceed()) - } else if let ClientErrorKind::TransactionError( - TransactionError::InstructionError(_, InstructionError::Custom(err_code)), - ) = err.kind() - { - axelar_solana_gateway::error::GatewayError::from_u32(*err_code) - .is_some_and(|gw_err| gw_err.should_relayer_proceed()) - } else { - false - }; - - if should_continue { - println!( - "Transaction error: GatewayError (code: {:?}), but continuing with next transaction as it's recoverable", - err.kind() - ); - continue; - } else { - println!("Transaction error: {:?}", err); - eyre::bail!("Transaction simulation error: {:?}", err); + eprintln!("Error during transaction: {err}"); + if !handle_transaction_error(err)? { + return Err(eyre!("Transaction error")); } } } diff --git a/solana/src/sign.rs b/solana/src/sign.rs index c21081172..ee669cc99 100644 --- a/solana/src/sign.rs +++ b/solana/src/sign.rs @@ -11,10 +11,10 @@ use crate::types::PartialSignature; use crate::utils; #[derive(Debug, Clone)] -pub struct SignArgs { - pub unsigned_tx_path: PathBuf, - pub signer_key: String, - pub output_dir: Option, +pub(crate) struct SignArgs { + pub(crate) unsigned_tx_path: PathBuf, + pub(crate) signer_key: String, + pub(crate) output_dir: Option, } fn get_required_signers_from_instructions( @@ -39,7 +39,7 @@ fn get_required_signers_from_instructions( Ok(signers) } -pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { +pub(crate) fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { println!("Starting Solana transaction signing..."); let unsigned_tx = utils::load_unsigned_solana_transaction(&args.unsigned_tx_path)?; @@ -48,12 +48,8 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { args.unsigned_tx_path.display() ); - let message_bytes = hex::decode(&unsigned_tx.signable_message_hex).map_err(|e| { - eyre!( - "Failed to decode signable_message_hex from unsigned tx file: {}", - e - ) - })?; + let message_bytes = hex::decode(&unsigned_tx.signable_message_hex) + .map_err(|e| eyre!("Failed to decode signable_message_hex from unsigned tx file: {e}"))?; println!( "Decoded message bytes ({} bytes) to sign.", message_bytes.len() @@ -65,13 +61,13 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { .map_err(|e| eyre!("Failed to load signer '{}': {}", args.signer_key, e))?; let signer_pubkey = signer.pubkey(); - println!("Signer loaded successfully. Pubkey: {}", signer_pubkey); + println!("Signer loaded successfully. Pubkey: {signer_pubkey}"); println!("Signing message with loaded signer..."); let signature = signer .try_sign_message(&message_bytes) .map_err(|e| eyre!("Failed to sign message using '{}': {}", args.signer_key, e))?; - println!("Generated signature: {}", signature); + println!("Generated signature: {signature}"); let partial_signature = PartialSignature { signer_pubkey: signer_pubkey.to_string(), @@ -92,15 +88,11 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { nonce_authority_pubkey.as_ref(), )?; - if !required_signers.contains(&signer_pubkey) { - println!( - "Warning: Signer {} provided a signature, but is not found in the list of required signers (Fee Payer, Nonce Authority, or Instruction Signers).", - signer_pubkey - ); + if required_signers.contains(&signer_pubkey) { + println!("Validation OK: Signer {signer_pubkey} is required by the transaction."); } else { println!( - "Validation OK: Signer {} is required by the transaction.", - signer_pubkey + "Warning: Signer {signer_pubkey} provided a signature, but is not found in the list of required signers (Fee Payer, Nonce Authority, or Instruction Signers)." ); } @@ -109,10 +101,10 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { println!(" Signature: {}", partial_signature.signature); let output_dir = args.output_dir.clone().unwrap_or_else(|| { - args.unsigned_tx_path - .parent() - .map(|p| p.to_path_buf()) - .unwrap_or_else(|| std::path::PathBuf::from(".")) + args.unsigned_tx_path.parent().map_or_else( + || std::path::PathBuf::from("."), + std::path::Path::to_path_buf, + ) }); std::fs::create_dir_all(&output_dir)?; @@ -126,7 +118,7 @@ pub fn sign_solana_transaction(args: &SignArgs) -> eyre::Result<()> { let tx_name = unsigned_file_stem.replace(".unsigned", ""); let pubkey_str = signer_pubkey.to_string(); - let sig_filename = format!("{}.{}.partial.sig", tx_name, pubkey_str); + let sig_filename = format!("{tx_name}.{pubkey_str}.partial.sig"); let sig_path = output_dir.join(sig_filename); utils::save_partial_signature(&partial_signature, &sig_path)?; diff --git a/solana/src/types.rs b/solana/src/types.rs index ca9a97f27..f47553549 100644 --- a/solana/src/types.rs +++ b/solana/src/types.rs @@ -12,7 +12,7 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] -pub enum NetworkType { +pub(crate) enum NetworkType { Mainnet, Testnet, Devnet, @@ -28,11 +28,11 @@ impl FromStr for NetworkType { .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) .or_else(|| s.contains("devnet").then_some(NetworkType::Devnet)) .or_else(|| s.contains("local").then_some(NetworkType::Localnet)) - .ok_or_else(|| eyre!("Invalid network type: {}", s)) + .ok_or_else(|| eyre!("Invalid network type: {s}")) } } -pub struct ChainsInfoFile(pub String); +pub(crate) struct ChainsInfoFile(pub(crate) String); impl From for String { fn from(value: ChainsInfoFile) -> Self { value.0 @@ -50,7 +50,7 @@ impl From for ChainsInfoFile { } } -pub struct ChainNameOnAxelar(pub String); +pub(crate) struct ChainNameOnAxelar(pub(crate) String); impl From for ChainNameOnAxelar { fn from(value: NetworkType) -> Self { @@ -64,30 +64,30 @@ impl From for ChainNameOnAxelar { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SolanaTransactionParams { - pub fee_payer: String, +pub(crate) struct SolanaTransactionParams { + pub(crate) fee_payer: String, #[serde(skip_serializing_if = "Option::is_none")] - pub recent_blockhash: Option, + pub(crate) recent_blockhash: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub nonce_account: Option, + pub(crate) nonce_account: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub nonce_authority: Option, - pub blockhash_for_message: String, + pub(crate) nonce_authority: Option, + pub(crate) blockhash_for_message: String, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SerializableInstruction { - pub program_id: String, - pub accounts: Vec, +pub(crate) struct SerializableInstruction { + pub(crate) program_id: String, + pub(crate) accounts: Vec, #[serde(with = "hex::serde")] - pub data: Vec, + pub(crate) data: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SerializableAccountMeta { - pub pubkey: String, - pub is_signer: bool, - pub is_writable: bool, +pub(crate) struct SerializableAccountMeta { + pub(crate) pubkey: String, + pub(crate) is_signer: bool, + pub(crate) is_writable: bool, } impl TryFrom<&SerializableInstruction> for SolanaInstruction { @@ -134,40 +134,40 @@ impl From<&SolanaInstruction> for SerializableInstruction { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct UnsignedSolanaTransaction { - pub params: SolanaTransactionParams, - pub instructions: Vec, - pub signable_message_hex: String, +pub(crate) struct UnsignedSolanaTransaction { + pub(crate) params: SolanaTransactionParams, + pub(crate) instructions: Vec, + pub(crate) signable_message_hex: String, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct PartialSignature { - pub signer_pubkey: String, - pub signature: String, +pub(crate) struct PartialSignature { + pub(crate) signer_pubkey: String, + pub(crate) signature: String, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SignedSolanaTransaction { - pub unsigned_tx_data: UnsignedSolanaTransaction, - pub signatures: Vec, +pub(crate) struct SignedSolanaTransaction { + pub(crate) unsigned_tx_data: UnsignedSolanaTransaction, + pub(crate) signatures: Vec, } /// A wrapper around SolanaTransaction that can be serialized and deserialized #[derive(Debug, Clone)] -pub struct SerializableSolanaTransaction { - pub transaction: SolanaTransaction, - pub params: SolanaTransactionParams, +pub(crate) struct SerializableSolanaTransaction { + pub(crate) transaction: SolanaTransaction, + pub(crate) params: SolanaTransactionParams, } impl SerializableSolanaTransaction { - pub fn new(transaction: SolanaTransaction, params: SolanaTransactionParams) -> Self { + pub(crate) fn new(transaction: SolanaTransaction, params: SolanaTransactionParams) -> Self { Self { transaction, params, } } - pub fn to_unsigned(&self) -> UnsignedSolanaTransaction { + pub(crate) fn to_unsigned(&self) -> UnsignedSolanaTransaction { let message = self.transaction.message.clone(); let message_bytes = message.serialize(); let signable_message_hex = hex::encode(&message_bytes); @@ -206,10 +206,10 @@ impl SerializableSolanaTransaction { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct SerializeableVerifierSet { - pub signers: BTreeMap, - pub nonce: u64, - pub threshold: u128, +pub(crate) struct SerializeableVerifierSet { + pub(crate) signers: BTreeMap, + pub(crate) nonce: u64, + pub(crate) threshold: u128, } impl From for VerifierSet { @@ -236,13 +236,13 @@ impl From for VerifierSet { /// Uitility verifier set representation that has access to the signing keys #[derive(Clone, Debug)] -pub struct SigningVerifierSet { +pub(crate) struct SigningVerifierSet { /// signers that have access to the given verifier set - pub signers: Vec, + pub(crate) signers: Vec, /// the nonce for the verifier set - pub nonce: u64, + pub(crate) nonce: u64, /// quorum for the verifier set - pub quorum: u128, + pub(crate) quorum: u128, } impl SigningVerifierSet { @@ -250,7 +250,7 @@ impl SigningVerifierSet { /// /// # Panics /// if the calculated quorum is larger than u128 - pub fn new(signers: Vec, nonce: u64) -> Self { + pub(crate) fn new(signers: Vec, nonce: u64) -> Self { let quorum = signers .iter() .map(|signer| signer.weight) @@ -261,7 +261,11 @@ impl SigningVerifierSet { /// Create a new `SigningVerifierSet` with a custom quorum #[must_use] - pub const fn new_with_quorum(signers: Vec, nonce: u64, quorum: u128) -> Self { + pub(crate) const fn new_with_quorum( + signers: Vec, + nonce: u64, + quorum: u128, + ) -> Self { Self { signers, nonce, @@ -271,7 +275,7 @@ impl SigningVerifierSet { /// Transform into the verifier set that the gateway expects to operate on #[must_use] - pub fn verifier_set(&self) -> VerifierSet { + pub(crate) fn verifier_set(&self) -> VerifierSet { let signers = self .signers .iter() @@ -300,8 +304,8 @@ impl SigningVerifierSet { /// Single test signer #[derive(Clone, Debug)] -pub struct LocalSigner { - pub secret: k256::SecretKey, +pub(crate) struct LocalSigner { + pub(crate) secret: k256::SecretKey, /// associated weight - pub weight: u128, + pub(crate) weight: u128, } diff --git a/solana/src/utils.rs b/solana/src/utils.rs index d653d5f3c..fa0d471c9 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -146,13 +146,10 @@ pub(crate) fn encode_its_destination( /// Parses a string representation of an AccountMeta. /// Format: "pubkey:is_signer:is_writable" (e.g., "SomePubkey...:false:true") -pub fn parse_account_meta_string(s: &str) -> eyre::Result { +pub(crate) fn parse_account_meta_string(s: &str) -> eyre::Result { let parts: Vec<&str> = s.split(':').collect(); if parts.len() != 3 { - eyre::bail!( - "Invalid AccountMeta format: '{}'. Expected 'pubkey:is_signer:is_writable'", - s - ); + eyre::bail!("Invalid AccountMeta format: '{s}'. Expected 'pubkey:is_signer:is_writable'"); } let pubkey = Pubkey::from_str(parts[0])?; @@ -183,8 +180,8 @@ pub(crate) fn print_transaction_result( match result { Ok(tx_signature) => { println!("------------------------------------------"); - println!("✅ Solana Transaction successfully broadcast and confirmed!"); - println!(" Transaction Signature (ID): {}", tx_signature); + println!("\u{2705} Solana Transaction successfully broadcast and confirmed!"); + println!(" Transaction Signature (ID): {tx_signature}"); println!(" RPC Endpoint: {}", config.url); let explorer_base_url = "https://explorer.solana.com/tx/"; let cluster_param = match config.network_type { @@ -193,17 +190,14 @@ pub(crate) fn print_transaction_result( NetworkType::Devnet => "?cluster=devnet", NetworkType::Localnet => "?cluster=custom", }; - println!( - " Explorer Link: {}{}{}", - explorer_base_url, tx_signature, cluster_param - ); + println!(" Explorer Link: {explorer_base_url}{tx_signature}{cluster_param}"); println!("------------------------------------------"); Ok(()) } Err(e) => { eprintln!("------------------------------------------"); - eprintln!("❌ Solana Transaction broadcast failed."); + eprintln!("\u{274c} Solana Transaction broadcast failed."); eprintln!("------------------------------------------"); Err(e) @@ -248,7 +242,7 @@ pub(crate) fn parse_secret_key(raw: &str) -> eyre::Result { } pub(crate) fn fetch_latest_blockhash(rpc_url: &str) -> eyre::Result { - let rpc_client = RpcClient::new(rpc_url.to_string()); + let rpc_client = RpcClient::new(rpc_url.to_owned()); Ok(rpc_client.get_latest_blockhash()?) } @@ -257,7 +251,7 @@ pub(crate) fn fetch_nonce_data_and_verify( nonce_account_pubkey: &Pubkey, expected_nonce_authority: &Pubkey, ) -> eyre::Result { - let rpc_client = RpcClient::new(rpc_url.to_string()); + let rpc_client = RpcClient::new(rpc_url.to_owned()); let nonce_account = rpc_client.get_account(nonce_account_pubkey)?; if !solana_sdk::system_program::check_id(&nonce_account.owner) { @@ -270,12 +264,7 @@ pub(crate) fn fetch_nonce_data_and_verify( } let nonce_state: solana_sdk::nonce::state::State = StateMut::::state(&nonce_account) - .map_err(|_| { - eyre!( - "Failed to deserialize nonce account {}", - nonce_account_pubkey - ) - })? + .map_err(|_| eyre!("Failed to deserialize nonce account {nonce_account_pubkey}"))? .into(); match nonce_state { @@ -295,8 +284,7 @@ pub(crate) fn fetch_nonce_data_and_verify( Ok(data.blockhash()) } solana_sdk::nonce::state::State::Uninitialized => Err(eyre!( - "Nonce account {} is uninitialized", - nonce_account_pubkey + "Nonce account {nonce_account_pubkey} is uninitialized" )), } } From 315134b9ebf3d8e708d41586bcfd96cf615b2550 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 14:33:01 +0200 Subject: [PATCH 43/59] fix(solana): fix shellcheck issues Signed-off-by: Guilherme Felipe da Silva --- solana/solana-axelar-cli | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/solana/solana-axelar-cli b/solana/solana-axelar-cli index fbc7230a3..492bd9501 100755 --- a/solana/solana-axelar-cli +++ b/solana/solana-axelar-cli @@ -1,6 +1,10 @@ -#!/bin/env bash +#!/bin/sh -project_dir="$(dirname ${0})" -chains_info_dir="${project_dir}/../axelar-chains-config/info/" +project_dir=$(dirname "${0}") +chains_info_dir="${project_dir:?}/../axelar-chains-config/info/" -cargo run --manifest-path="${project_dir}/Cargo.toml" -- --chains-info-dir="${chains_info_dir}" ${@} +cargo run \ + --manifest-path="${project_dir:?}/Cargo.toml" \ + -- \ + --chains-info-dir="${chains_info_dir:?}" \ + "${@}" From bf12f5cdb8e9c272302f807f2bf6df7f6a27812c Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 15:52:48 +0200 Subject: [PATCH 44/59] fix(solana): add solana ITS address encoding Signed-off-by: Guilherme Felipe da Silva --- common/utils.js | 30 ++++++++++++++++++++++++++++++ package.json | 1 + solana/src/its.rs | 16 ++++++++-------- solana/src/utils.rs | 2 +- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/common/utils.js b/common/utils.js index b10dca4cd..ff7346bdd 100644 --- a/common/utils.js +++ b/common/utils.js @@ -15,6 +15,7 @@ const { const { normalizeBech32 } = require('@cosmjs/encoding'); const fetch = require('node-fetch'); const StellarSdk = require('@stellar/stellar-sdk'); +const bs58 = require('bs58'); const pascalToSnake = (str) => str.replace(/([A-Z])/g, (group) => `_${group.toLowerCase()}`).replace(/^_/, ''); @@ -22,6 +23,7 @@ const pascalToKebab = (str) => str.replace(/([A-Z])/g, (group) => `-${group.toLo const VERSION_REGEX = /^\d+\.\d+\.\d+$/; const SHORT_COMMIT_HASH_REGEX = /^[a-f0-9]{7,}$/; +const SVM_BASE58_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/; function loadConfig(env) { return require(`${__dirname}/../axelar-chains-config/info/${env}.json`); @@ -305,6 +307,19 @@ function isValidStellarContract(address) { return StellarSdk.StrKey.isValidContract(address); } +/** + * Basic validatation to check if the provided string *might* be a valid SVM + * address. One needs to ensure that it's 32 bytes long after decoding. + * + * See https://solana.com/developers/guides/advanced/exchange#basic-verification. + * + * @param {string} address - The base58 encoded Solana address to validate + * @returns {boolean} - True if the address is valid, false otherwise + */ +function isValidSvmAddressFormat(address) { + return SVM_BASE58_ADDRESS_REGEX.test(address) +} + const validationFunctions = { isNonEmptyString, isNumber, @@ -318,6 +333,7 @@ const validationFunctions = { isValidStellarAddress, isValidStellarAccount, isValidStellarContract, + isValidSvmAddressFormat, }; function validateParameters(parameters) { @@ -588,10 +604,19 @@ function asciiToBytes(string) { return hexlify(Buffer.from(string, 'ascii')); } +function trySolanaAddressBytesFromBase58(string) { + const decoded = bs58.default.decode(string); + if (decoded.length !== 32) { + throw new Error(`Invalid Solana address: ${string}`); + } + return hexlify(decoded); +} + /** * Encodes the destination address for Interchain Token Service (ITS) transfers. * This function ensures proper encoding of the destination address based on the destination chain type. * Note: - Stellar addresses are converted to ASCII byte arrays. + * - Solana (svm) addresses are decoded from base58 and hexlified. * - EVM and Sui addresses are returned as-is (default behavior). * - Additional encoding logic can be added for new chain types. */ @@ -607,6 +632,10 @@ function encodeITSDestination(config, destinationChain, destinationAddress) { validateParameters({ isValidStellarAddress: { destinationAddress } }); return asciiToBytes(destinationAddress); + case 'svm': + validateParameters({ isValidSvmAddressFormat: { destinationAddress } }); + return trySolanaAddressBytesFromBase58(destinationAddress); + case 'evm': case 'sui': default: // EVM, Sui, and other chains (return as-is) @@ -665,6 +694,7 @@ module.exports = { isValidStellarAddress, isValidStellarAccount, isValidStellarContract, + isValidSvmAddressFormat, getCurrentVerifierSet, asciiToBytes, encodeITSDestination, diff --git a/package.json b/package.json index 2eea2e9ee..025f31712 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@mysten/sui": "^1.3.0", "@stellar/stellar-sdk": "^13.0.0", "axios": "^1.7.2", + "bs58": "^6.0.0", "csv-parser": "^3.0.0", "path": "^0.12.7", "toml": "^3.0.0", diff --git a/solana/src/its.rs b/solana/src/its.rs index 4cb1bc818..92dc60cfa 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -13,9 +13,9 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, encode_its_destination, fetch_latest_blockhash, - read_json_file_from_path, write_json_to_file_path, + decode_its_destination, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, + CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -985,7 +985,7 @@ fn approve_deploy_remote_interchain_token( config: &Config, ) -> eyre::Result> { let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_minter = encode_its_destination( + let destination_minter = decode_its_destination( &chains_info, &args.destination_chain, args.destination_minter, @@ -1098,7 +1098,7 @@ fn deploy_remote_interchain_token_with_minter( let gas_service = try_infer_gas_service_id(args.gas_service, config)?; let gas_config_account = try_infer_gas_service_config_account(args.gas_config_account, config)?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_minter = encode_its_destination( + let destination_minter = decode_its_destination( &chains_info, &args.destination_chain, args.destination_minter, @@ -1187,7 +1187,7 @@ fn interchain_transfer( .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = encode_its_destination( + let destination_address = decode_its_destination( &chains_info, &args.destination_chain, args.destination_address, @@ -1222,7 +1222,7 @@ fn call_contract_with_interchain_token( .as_secs() .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = encode_its_destination( + let destination_address = decode_its_destination( &chains_info, &args.destination_chain, args.destination_address, @@ -1259,7 +1259,7 @@ fn call_contract_with_interchain_token_offchain_data( .as_secs() .try_into()?; let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - let destination_address = encode_its_destination( + let destination_address = decode_its_destination( &chains_info, &args.destination_chain, args.destination_address, diff --git a/solana/src/utils.rs b/solana/src/utils.rs index fa0d471c9..328af6e20 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -129,7 +129,7 @@ pub(crate) fn save_signed_solana_transaction( write_json_to_file_path(tx, path) } -pub(crate) fn encode_its_destination( +pub(crate) fn decode_its_destination( chains_info: &serde_json::Value, destination_chain: &str, destination_address: String, From 8918d9647d619f702f4f4b8bf04723eaddef31c2 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 16:52:51 +0200 Subject: [PATCH 45/59] chore(solana): be consistent with placeholders For some examples placeholders were being used, for others fake values. Let's be consistent. Signed-off-by: Guilherme Felipe da Silva --- solana/README.md | 122 +++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/solana/README.md b/solana/README.md index b38b496e0..b134ae723 100644 --- a/solana/README.md +++ b/solana/README.md @@ -66,7 +66,7 @@ popd Deploy the gateway program. If `--authority` is omitted, the current Solana CLI keypair is set as upgrade-authority. ```sh -solana program-v4 deploy --program-keypair path/to/gateway-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so +solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so ``` ### Gas Service @@ -74,7 +74,7 @@ solana program-v4 deploy --program-keypair path/to/gateway-program-keypair.json Deploy the gas service program ```sh -solana program-v4 deploy --program-keypair path/to/gas-service-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so +solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so ``` ### Interchain Token Service @@ -82,7 +82,7 @@ solana program-v4 deploy --program-keypair path/to/gas-service-program-keypair.j Deploy the ITS program ```sh -solana program-v4 deploy --program-keypair path/to/its-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so +solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so ``` ### Governance @@ -90,7 +90,7 @@ solana program-v4 deploy --program-keypair path/to/its-program-keypair.json --au Deploy the governance program ```sh -solana program-v4 deploy --program-keypair path/to/governance-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so +solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so ``` ### Multicall @@ -98,7 +98,7 @@ solana program-v4 deploy --program-keypair path/to/governance-program-keypair.js Deploy the multicall program ```sh -solana program-v4 deploy --program-keypair path/to/multicall-program-keypair.json --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so +solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so ``` ## Upgrades @@ -107,7 +107,7 @@ To upgrade a program, a similar command is used as for the initial deployment, b ```sh -solana program-v4 deploy --program-id +solana program-v4 deploy --program-id ``` For upgrades with offline signing, recovery of failed deployments, and other information about Solana program deployment, please check the [official docs](https://solana.com/docs/programs/deploying). @@ -170,9 +170,9 @@ solana/solana-axelar-cli send gateway --help ```sh solana/solana-axelar-cli send gateway init \ - --previous-signers-retention 3 \ - --minimum-rotation-delay 86400 \ - --operator + --previous-signers-retention \ + --minimum-rotation-delay \ + --operator ``` #### Call Contract @@ -181,9 +181,9 @@ Send a message to another chain: ```sh solana/solana-axelar-cli send gateway call-contract \ - --destination-chain avalanche \ - --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ - --payload 0x1234 + --destination-chain \ + --destination-address \ + --payload ``` #### Submit Proof @@ -192,7 +192,7 @@ Submit a proof constructed on Amplifier to the Solana gateway contract: ```sh solana/solana-axelar-cli send gateway submit-proof \ - --multisig-session-id 123456 + --multisig-session-id ``` #### Execute Message @@ -201,20 +201,20 @@ Execute a cross-chain message that was approved on the Solana gateway: ```sh solana/solana-axelar-cli send gateway execute \ - --source-chain avalanche \ - --message-id '0x0bcbbfc9b006db6958f3fce75f11fdc306b45e8e43396211f414f40d2d6db7c5-0' \ - --source-address 0xba76c6980428A0b10CFC5d8ccb61949677A61233 \ - --destination-address \ - --payload 0x1234 + --source-chain \ + --message-id \ + --source-address \ + --destination-address \ + --payload ``` #### Rotate Signers ```sh solana/solana-axelar-cli send gateway rotate \ - --signer \ - --nonce 123 \ - --new-nonce 456 + --signer \ + --nonce \ + --new-nonce ``` #### Transfer Operatorship @@ -237,17 +237,17 @@ solana/solana-axelar-cli send its --help #### Initialize ITS ```sh -solana/solana-axelar-cli send its init --operator +solana/solana-axelar-cli send its init --operator ``` #### Set/Remove Trusted Chain ```sh # Add a trusted chain -solana/solana-axelar-cli send its set-trusted-chain --chain-name avalanche +solana/solana-axelar-cli send its set-trusted-chain --chain-name # Remove a trusted chain -solana/solana-axelar-cli send its remove-trusted-chain --chain-name avalanche +solana/solana-axelar-cli send its remove-trusted-chain --chain-name ``` #### Deploy Interchain Token @@ -255,10 +255,10 @@ solana/solana-axelar-cli send its remove-trusted-chain --chain-name avalanche ```sh solana/solana-axelar-cli send its deploy-interchain-token \ --salt \ - --name "My Token" \ - --symbol "MTK" \ - --decimals 8 \ - --initial-supply 1000000000 + --name \ + --symbol \ + --decimals \ + --initial-supply ``` #### Deploy Remote Interchain Token @@ -266,8 +266,8 @@ solana/solana-axelar-cli send its deploy-interchain-token \ ```sh solana/solana-axelar-cli send its deploy-remote-interchain-token \ --salt \ - --destination-chain avalanche \ - --gas-value 500000 + --destination-chain \ + --gas-value ``` #### Register Canonical Token @@ -275,7 +275,7 @@ solana/solana-axelar-cli send its deploy-remote-interchain-token \ ```sh solana/solana-axelar-cli send its register-canonical-interchain-token \ --mint \ - --token-program spl_token + --token-program ``` #### Deploy Remote Canonical Token @@ -283,37 +283,37 @@ solana/solana-axelar-cli send its register-canonical-interchain-token \ ```sh solana/solana-axelar-cli send its deploy-remote-canonical-interchain-token \ --mint \ - --destination-chain avalanche \ - --gas-value 500000 + --destination-chain \ + --gas-value ``` #### Interchain Transfer ```sh solana/solana-axelar-cli send its interchain-transfer \ - --source-account \ + --source-account \ --token-id \ - --destination-chain avalanche \ - --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ - --amount 1000000 \ + --destination-chain \ + --destination-address \ + --amount \ --mint \ - --token-program spl_token \ - --gas-value 500000 + --token-program \ + --gas-value ``` #### Call Contract With Interchain Token ```sh solana/solana-axelar-cli send its call-contract-with-interchain-token \ - --source-account \ + --source-account \ --token-id \ - --destination-chain avalanche \ - --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ - --amount 1000000 \ + --destination-chain \ + --destination-address \ + --amount \ --mint \ - --data 0x1234 \ - --token-program spl_token \ - --gas-value 500000 + --data \ + --token-program \ + --gas-value ``` #### Set Flow Limit @@ -321,7 +321,7 @@ solana/solana-axelar-cli send its call-contract-with-interchain-token \ ```sh solana/solana-axelar-cli send its set-flow-limit \ --token-id \ - --flow-limit 1000000 + --flow-limit ``` #### Pausable Functionality @@ -343,12 +343,12 @@ solana/solana-axelar-cli send its unpause # Set flow limit on a token manager solana/solana-axelar-cli send its token-manager set-flow-limit \ --token-id \ - --flow-limit 1000000 + --flow-limit # Add flow limiter to a token manager solana/solana-axelar-cli send its token-manager add-flow-limiter \ --token-id \ - --flow-limiter + --flow-limiter ``` #### InterchainToken Operations @@ -359,8 +359,8 @@ solana/solana-axelar-cli send its interchain-token mint \ --token-id \ --mint \ --to \ - --token-program spl_token \ - --amount 1000000 + --token-program \ + --amount ``` #### Transfer Operatorship @@ -395,7 +395,7 @@ Durable nonces are necessary for offline signing to ensure transactions remain v ```sh # Create a nonce account (requires SOL for rent exemption) -solana create-nonce-account --nonce-authority +solana create-nonce-account --nonce-authority ``` #### 1. Generate the unsigned transaction @@ -406,9 +406,9 @@ solana/solana-axelar-cli generate \ --nonce-account \ --nonce-authority \ gateway call-contract \ - --destination-chain avalanche \ - --destination-address 0x4F4495243837681061C4743b74B3eEdf548D56A5 \ - --payload 0x1234 + --destination-chain \ + --destination-address \ + --payload ``` This will generate a file like `./output/gateway_init.unsigned.json` in the default output directory. You can specify a custom output directory with `--output-dir /path/to/directory`. @@ -417,15 +417,15 @@ This will generate a file like `./output/gateway_init.unsigned.json` in the defa ```sh solana/solana-axelar-cli sign \ - ./output/gateway_init.unsigned.json \ - --signer /path/to/keypair.json + \ + --signer ``` For Ledger: ```sh solana/solana-axelar-cli sign \ - ./output/gateway_init.unsigned.json \ + \ --signer usb://ledger ``` @@ -435,8 +435,8 @@ This will generate signature files like `./output/gateway_init.5hW1cNgX6N8RhvHHi ```sh solana/solana-axelar-cli combine \ - --unsigned-tx-path ./output/gateway_init.unsigned.json \ - --signatures ./output/gateway_init.5hW1cNgX6N8RhvHHiX6nAnKbZftG1K3ckNBuJdRSPFPK.partial.sig ./output/gateway_init.DL6NBsMvnEMbUJ5XHeLMyfGpmEukV2i7ZVukGCfxWvP5.partial.sig + --unsigned-tx-path \ + --signatures [...] ``` This will generate a file like `./output/gateway_init.signed.json`. @@ -445,5 +445,5 @@ This will generate a file like `./output/gateway_init.signed.json`. ```sh solana/solana-axelar-cli broadcast \ - ./output/gateway_init.signed.json + ``` From ffe2629eca3ab2bb5faa8f38d2400ff570566f9b Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 22:07:47 +0200 Subject: [PATCH 46/59] refactor(solana): env and private key consistency Make the way the environment and private key are passed to the CLI consistent with what the other chains are doing. Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.lock | 10 ++++++ solana/Cargo.toml | 1 + solana/README.md | 55 ++++++++++++++++------------ solana/src/gateway.rs | 10 +++--- solana/src/main.rs | 83 ++++++++++++++++++++++--------------------- solana/src/send.rs | 22 +++++++----- 6 files changed, 105 insertions(+), 76 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 45f363808..d75a4c3a0 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -1940,6 +1940,15 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +dependencies = [ + "clap 3.2.25", +] + [[package]] name = "dunce" version = "1.0.5" @@ -5323,6 +5332,7 @@ dependencies = [ "clap 3.2.25", "cosmrs", "cosmwasm-std", + "dotenvy", "eyre", "hex", "its-instruction-builder", diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 3c55927e8..9b460dbaf 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -40,6 +40,7 @@ solana-sdk = "2" spl-token = { version = "6", features = ["no-entrypoint"] } spl-token-2022 = { version = "6", features = ["no-entrypoint"] } tokio = { version = "1", features = ["full"] } +dotenvy = { version = "0.15.7", features = ["cli"] } [lints.clippy] cargo = { priority = -1, level = "deny" } diff --git a/solana/README.md b/solana/README.md index b134ae723..953aff209 100644 --- a/solana/README.md +++ b/solana/README.md @@ -139,24 +139,46 @@ Main commands: ### Network Configuration -Specify the Solana network to connect to: +There are a few different ways you can specify the Solana network to connect to: + +By exporting the `ENV` variable in your shell: ```sh -export URL_OR_MONIKER= +export ENV= ``` -or, on every command: +By creating a `.env` file in the root of the project with the `ENV=` entry or, on every command: ```sh solana/solana-axelar-cli --url [OPTIONS] ``` -The URL can be a full RPC URL or a moniker: +The value can be a full RPC URL or a moniker: - `mainnet-beta`: Solana mainnet - `testnet`: Solana testnet - `devnet`: Solana devnet - `localhost`: Local Solana validator +If none of these options are provided, the value set in the default Solana CLI config file will be used (if available). + +### Wallet configuration + +Similarly to the network configuration, you can specify the wallet to use in a few different ways: + +By exporting the `PRIVATE_KEY` variable in your shell: + +```sh +export PRIVATE_KEY= +``` + +By creating a `.env` file in the root of the project with the `PRIVATE_KEY=` entry or, on every use of the `send` command: + +```sh +solana/solana-axelar-cli send --fee-payer [OPTIONS] +``` + +The value can be a path to a solana keypair JSON file (generated with `solana-keypair new`) or the USB path to a Ledger device (e.g.: usb://ledger). + ### Gateway To get help on gateway commands, run: @@ -411,39 +433,28 @@ solana/solana-axelar-cli generate \ --payload ``` -This will generate a file like `./output/gateway_init.unsigned.json` in the default output directory. You can specify a custom output directory with `--output-dir /path/to/directory`. +This will generate a file like `./output/gateway-init.unsigned.json` in the default output directory. You can specify a custom output directory with `--output-dir /path/to/directory`. #### 2. Sign the transaction (on each signing device) ```sh -solana/solana-axelar-cli sign \ - \ - --signer +solana/solana-axelar-cli sign ``` - -For Ledger: - +`PATH_TO_SIGNER_KEYPAIR` can be a local keypair file or a Ledger device. ```sh -solana/solana-axelar-cli sign \ - \ - --signer usb://ledger -``` -This will generate signature files like `./output/gateway_init.5hW1cNgX6N8RhvHHiX6nAnKbZftG1K3ckNBuJdRSPFPK.partial.sig` where the signer's full public key is included in the filename for uniqueness. +This will generate signature files like `./output/gateway-init.5hW1cNgX6N8RhvHHiX6nAnKbZftG1K3ckNBuJdRSPFPK.partial.sig` where the signer's full public key is included in the filename. #### 3. Combine all signatures ```sh -solana/solana-axelar-cli combine \ - --unsigned-tx-path \ - --signatures [...] +solana/solana-axelar-cli combine [...] ``` -This will generate a file like `./output/gateway_init.signed.json`. +This will generate a file like `./output/gateway-init.signed.json`. #### 4. Broadcast the transaction ```sh -solana/solana-axelar-cli broadcast \ - +solana/solana-axelar-cli broadcast ``` diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 04da3992a..a50f2e3f6 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -26,17 +26,17 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; -use crate::multisig_prover_types::Uint128Extensions; use crate::multisig_prover_types::msg::ProofStatus; +use crate::multisig_prover_types::Uint128Extensions; use crate::types::{ ChainNameOnAxelar, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ - self, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, - GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, OPERATOR_KEY, - PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, domain_separator, - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + self, domain_separator, fetch_latest_blockhash, read_json_file_from_path, + write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONTRACTS_KEY, + DOMAIN_SEPARATOR_KEY, GATEWAY_KEY, GRPC_KEY, MINIMUM_ROTATION_DELAY_KEY, MULTISIG_PROVER_KEY, + OPERATOR_KEY, PREVIOUS_SIGNERS_RETENTION_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] diff --git a/solana/src/main.rs b/solana/src/main.rs index b6aa3625f..e4f307ca8 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -19,9 +19,10 @@ use std::process::exit; use broadcast::BroadcastArgs; use clap::{FromArgMatches, IntoApp, Parser, Subcommand}; use combine::CombineArgs; +use dotenvy::dotenv; use eyre::eyre; use generate::GenerateArgs; -use send::{SendArgs, sign_and_send_transactions}; +use send::{sign_and_send_transactions, SendArgs}; use sign::SignArgs; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; @@ -44,14 +45,14 @@ struct Cli { command: Command, /// URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, - /// devnet, localhost]", + /// devnet, localhost]". Defaults to the Solana CLI config URL. #[clap( short, long, - env = "URL_OR_MONIKER", + env = "ENV", value_parser = parse_url_or_moniker, )] - url: String, + url: Option, /// Directory to store output files (unsigned tx, signatures, bundles) #[clap( @@ -92,12 +93,12 @@ enum Command { #[derive(Parser, Debug)] struct SendCommandArgs { - /// Fee Payer Pubkey (Base58 encoded string). Loads from Solana CLI config if not passed. - #[clap(long)] - fee_payer: Option, + /// Signing key identifier (path for keypair file or usb ledger). Defaults to the keypair + /// set in the Solana CLI config. + #[clap(long, env = "PRIVATE_KEY")] + fee_payer: Option, - /// List of signers (Base58 encoded strings). Fee payer should also be added here in case it's - /// not the default from Solana CLI config. + /// List of signing key identifiers (path for keypair file or usb ledger) signer_keys: Vec, #[clap(subcommand)] @@ -147,14 +148,13 @@ enum InstructionSubcommand { #[derive(Parser, Debug)] struct SignCommandArgs { + /// Signing key identifier (path for keypair file or usb ledger) + signer_key: String, + /// Path to the unsigned Solana transaction JSON file (*.unsigned.json) #[clap(parse(from_os_str))] unsigned_tx_path: PathBuf, - /// Signing key identifier (path for keypair file or usb ledger) - #[clap(long = "signer", short = 'k')] - signer_key: String, - /// Output directory for signature files /// If not specified, signatures will be placed in the same directory as the unsigned transaction #[clap(long = "output-dir", parse(from_os_str))] @@ -163,14 +163,13 @@ struct SignCommandArgs { #[derive(Parser, Debug)] struct CombineCommandArgs { - /// Path to the original unsigned Solana transaction JSON file (*.unsigned.json) - #[clap(long, parse(from_os_str))] - unsigned_tx_path: PathBuf, + /// Output directory for the combined signed transaction JSON + /// If not specified, will use the same directory as the unsigned transaction + #[clap(long = "output-dir", parse(from_os_str))] + output_dir: Option, /// Paths to the partial signature JSON files (*.partial.sig) to combine (provide at least one) #[clap( - long = "signatures", - short = 's', required = true, multiple_values = true, min_values = 1, @@ -178,10 +177,9 @@ struct CombineCommandArgs { )] signature_paths: Vec, - /// Output directory for the combined signed transaction JSON - /// If not specified, will use the same directory as the unsigned transaction - #[clap(long = "output-dir", parse(from_os_str))] - output_dir: Option, + /// Path to the original unsigned Solana transaction JSON file (*.unsigned.json) + #[clap(parse(from_os_str))] + unsigned_tx_path: PathBuf, } #[derive(Parser, Debug)] @@ -199,6 +197,8 @@ struct MiscCommandArgs { #[tokio::main] async fn main() { + dotenv().ok(); + if let Err(e) = run().await { eprintln!("\nError: {e:?}"); exit(1); @@ -209,34 +209,35 @@ async fn run() -> eyre::Result<()> { let matches = Cli::command().get_matches(); let cli = Cli::from_arg_matches(&matches)?; - let config = Config::new(cli.url, cli.output_dir, cli.chains_info_dir)?; + let maybe_solana_config = solana_cli_config::CONFIG_FILE + .as_ref() + .map(|config_file| solana_cli_config::Config::load(config_file).ok()) + .flatten(); + let url = cli + .url + .or_else(|| maybe_solana_config.as_ref().map(|c| c.json_rpc_url.clone())) + .ok_or_else(|| eyre!("No URL provided and no Solana CLI config found"))?; + + let config = Config::new(url, cli.output_dir, cli.chains_info_dir)?; match cli.command { Command::Send(args) => { - let mut signer_keys = args.signer_keys; - let fee_payer = if let Some(fee_payer) = args.fee_payer { - fee_payer - } else { - let config_file = solana_cli_config::CONFIG_FILE - .as_ref() - .ok_or_else(|| eyre!("Missing Solana config file"))?; - let cli_config = solana_cli_config::Config::load(config_file)?; - let signer = - signer_from_path(&matches, &cli_config.keypair_path, "signer", &mut None) - .map_err(|e| eyre!("Failed to load fee payer: {e}"))?; - - signer_keys.push(cli_config.keypair_path); - signer.pubkey() - }; + let key_path = args + .fee_payer + .or_else(|| maybe_solana_config.map(|c| c.keypair_path)) + .ok_or_else(|| eyre!("No fee payer provided and no Solana CLI config found"))?; + + let fee_payer = signer_from_path(&matches, &key_path, "fee-payer", &mut None) + .map_err(|e| eyre!("Failed to load fee payer: {e}"))?; let send_args = SendArgs { fee_payer, - signers: signer_keys, + signers: args.signer_keys, }; let transactions = - build_transaction(&send_args.fee_payer, args.instruction, &config).await?; - sign_and_send_transactions(&send_args, &config, transactions)?; + build_transaction(&send_args.fee_payer.pubkey(), args.instruction, &config).await?; + sign_and_send_transactions(send_args, &config, transactions)?; } Command::Generate(args) => { let output_dir = args.output_dir.unwrap_or_else(|| config.output_dir.clone()); diff --git a/solana/src/send.rs b/solana/src/send.rs index f64c5d33c..c02d1882d 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use axelar_solana_gateway::num_traits::FromPrimitive; use eyre::eyre; use solana_clap_v3_utils::keypair::signer_from_path; @@ -7,19 +9,19 @@ use solana_client::rpc_request::RpcResponseErrorData; use solana_client::rpc_response::RpcSimulateTransactionResult; use solana_sdk::commitment_config::CommitmentConfig; use solana_sdk::instruction::InstructionError; -use solana_sdk::pubkey::Pubkey; +use solana_sdk::signer::Signer; use solana_sdk::transaction::{Transaction, TransactionError}; use crate::config::Config; use crate::types::SerializableSolanaTransaction; use crate::utils::{ - DEFAULT_COMPUTE_UNITS, DEFAULT_PRIORITY_FEE, create_compute_budget_instructions, - print_transaction_result, + create_compute_budget_instructions, print_transaction_result, DEFAULT_COMPUTE_UNITS, + DEFAULT_PRIORITY_FEE, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct SendArgs { - pub(crate) fee_payer: Pubkey, + pub(crate) fee_payer: Box, pub(crate) signers: Vec, } @@ -176,18 +178,22 @@ fn handle_transaction_error(err: solana_client::client_error::ClientError) -> ey } pub(crate) fn sign_and_send_transactions( - send_args: &SendArgs, + send_args: SendArgs, config: &Config, serializable_txs: Vec, ) -> eyre::Result<()> { let rpc_client = RpcClient::new_with_commitment(&config.url, CommitmentConfig::confirmed()); let mut results = Vec::new(); + let SendArgs { fee_payer, signers } = send_args; + let shared_payer: Rc = Rc::from(fee_payer); + for serializable_tx in serializable_txs { let transaction = serializable_tx.transaction; - let signers = load_signers(&send_args.signers, &transaction)?; - let blockhash = rpc_client.get_latest_blockhash()?; + let mut signers = load_signers(&signers, &transaction)?; + signers.push(Box::new(shared_payer.clone())); + let blockhash = rpc_client.get_latest_blockhash()?; let optimized_tx = optimize_transaction(&transaction, &signers, &rpc_client, &blockhash)?; match rpc_client.send_and_confirm_transaction(&optimized_tx) { From 5678ba52609ceef07f5092b2969b67d414ca101e Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 14 May 2025 22:09:07 +0200 Subject: [PATCH 47/59] chore(solana): releases (WIP) Signed-off-by: Guilherme Felipe da Silva --- .../cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md | 1 + releases/solana/2025-05-GMP-vX.Y.Z.md | 233 +++++++++++++++++ releases/solana/2025-05-ITS-vX.Y.Z.md | 236 ++++++++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md create mode 100644 releases/solana/2025-05-GMP-vX.Y.Z.md create mode 100644 releases/solana/2025-05-ITS-vX.Y.Z.md diff --git a/releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md b/releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md new file mode 100644 index 000000000..1333ed77b --- /dev/null +++ b/releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md @@ -0,0 +1 @@ +TODO diff --git a/releases/solana/2025-05-GMP-vX.Y.Z.md b/releases/solana/2025-05-GMP-vX.Y.Z.md new file mode 100644 index 000000000..e9923c987 --- /dev/null +++ b/releases/solana/2025-05-GMP-vX.Y.Z.md @@ -0,0 +1,233 @@ +# Solana GMP vX.Y.Z + +| | **Owner** | +| -------------- | ------------------------------ | +| **Created By** | @ () | +| **Deployment** | @ () | + +| **Network** | **Deployment Status** | **Date** | +| -------------------- | --------------------- | ---------------- | +| **Devnet Amplifier** | Pending | | +| **Stagenet** | Pending | | +| **Testnet** | Pending | | +| **Mainnet** | Pending | | + +- [GitHub Release]() + +## Background + +This is the v.X.Y.Z Solana GMP release, introducing General Message Passing (GMP) capabilities for Solana blockchain. + +## Deployment + +### Prerequisites + +1. Install Solana CLI: + +```sh +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +``` + +2. Clone the solana-axelar repository. + +3. Build the Solana programs: + +```sh +# Go to the solana directory within the cloned repo +pushd solana-axelar/solana/ + +# Compile the Solana programs +cargo xtask build + +# Go back +popd +``` + +4. Set up environment configuration: + +```sh +# Create .env file with appropriate values +PRIVATE_KEY= +ENV= +CHAIN= # Use solana-testnet for devnet-amplifier, stagenet, testnet; use solana for mainnet +``` + +### Initial Solana Config + +Add Solana chain config to the `${ENV}.json` file under the `chains` key. + +#### Devnet-Amplifier / Stagenet / Testnet: + +```json +"solana-testnet": { + "name": "Solana", + "axelarId": "solana-testnet", + "rpc": "https://api.testnet.solana.com", + "networkType": "testnet", + "chainType": "svm", + "decimals": 9, + "finality": "32", + "approxFinalityWaitTime": 15, + "tokenSymbol": "SOL", + "explorer": { + "name": "Solana Explorer", + "url": "https://explorer.solana.com/?cluster=testnet" + }, + "contracts": {} +} +``` + +#### Mainnet: + +```json +"solana": { + "name": "Solana", + "axelarId": "solana", + "rpc": "https://api.mainnet-beta.solana.com", + "networkType": "mainnet", + "chainType": "svm", + "decimals": 9, + "finality": "32", + "approxFinalityWaitTime": 15, + "tokenSymbol": "SOL", + "explorer": { + "name": "Solana Explorer", + "url": "https://explorer.solana.com" + }, + "contracts": {} +} +``` + +### Deployment Steps + +1. Deploy Gateway program: + +```sh +solana program-v4 deploy \ + --program-keypair \ + --authority \ + solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so +``` + +2. Deploy Gas Service program: + +```sh +solana program-v4 deploy \ + --program-keypair \ + --authority \ + solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so +``` + +3. Deploy Governance program: + +```sh +solana program-v4 deploy \ + --program-keypair \ + --authority \ + solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so +``` + +4. Deploy Multicall program: + +```sh +solana program-v4 deploy \ + --program-keypair \ + --authority \ + solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so +``` + +| Network | `minimumRotationDelay` | `previousSignersRetention` | +| -------------------- | ---------------------- | -------------------------- | +| **Devnet-amplifier** | `0` | `15` | +| **Stagenet** | `300` | `15` | +| **Testnet** | `3600` | `15` | +| **Mainnet** | `86400` | `15` | + +5. Initialize Gateway: + +```sh +solana/solana-axelar-cli send gateway init \ + --previous-signers-retention \ + --minimum-rotation-delay \ + --operator +``` + +6. After deploying Solana contracts, deploy the Solana GMP Amplifier (separate documentation required). + +7. Rotate genesis verifier set on Solana Gateway: + +```sh +solana/solana-axelar-cli send gateway rotate \ + --signer \ + --nonce \ + --new-nonce +``` + +8. Update configuration with program addresses: + +After deployment, the contract addresses need to be added to the corresponding configuration files so that the CLI can interact with them. + +## Checklist + +The following checks should be performed after the rollout: + +### Verify Solana → EVM GMP call + +1. Send a GMP call: + +```sh +solana/solana-axelar-cli send gateway call-contract \ + --destination-chain \ + --destination-address \ + --payload +``` + +2. Route GMP call via Amplifier: + - Use the Amplifier relay mechanism to route the message. + +3. Submit proof with multisig session ID: + +```sh +# Change PRIVATE_KEY in .env to EVM +PRIVATE_KEY= + +node evm/gateway.js -n --action submitProof --multisigSessionId +``` + +4. Confirm message approval: + +```sh +node evm/gateway.js -n --action isContractCallApproved --commandID --sourceChain $CHAIN --sourceAddress --destination --payloadHash +``` + +### Verify EVM → Solana GMP Call + +1. Send a GMP call: + +```sh +node evm/gateway.js -n --action callContract --destinationChain $CHAIN --destination --payload +``` + +2. Route GMP call via Amplifier: + - Use the Amplifier relay mechanism to route the message. + +3. Submit proof with multisig session ID: + +```sh +# Change PRIVATE_KEY in .env to Solana +PRIVATE_KEY= + +solana/solana-axelar-cli send gateway submit-proof \ + --multisig-session-id +``` + +4. Execute message: + +```sh +solana/solana-axelar-cli send gateway execute \ + --source-chain \ + --message-id \ + --source-address \ + --destination-address \ + --payload +``` diff --git a/releases/solana/2025-05-ITS-vX.Y.Z.md b/releases/solana/2025-05-ITS-vX.Y.Z.md new file mode 100644 index 000000000..170027816 --- /dev/null +++ b/releases/solana/2025-05-ITS-vX.Y.Z.md @@ -0,0 +1,236 @@ +# Solana ITS vX.Y.Z + +| | **Owner** | +| -------------- | ------------------------------ | +| **Created By** | @ () | +| **Deployment** | @ () | + +| **Network** | **Deployment Status** | **Date** | +| -------------------- | --------------------- | ---------------- | +| **Devnet Amplifier** | Pending | | +| **Stagenet** | Pending | | +| **Testnet** | Pending | | +| **Mainnet** | Pending | | + +- [GitHub Release]() + +## Background + +This is the vX.Y.Z Solana ITS release, bringing Interchain Token Service capabilities to the Solana blockchain. + +## Deployment + +Ensure that [Solana GMP](../solana/2025-05-GMP-vX.Y.Z.md) is deployed first. + +### Set Up Environment + +Create an `.env` config: + +```yaml +# Set private key and network +PRIVATE_KEY= +ENV= +CHAIN= # Use solana-testnet for devnet-amplifier, stagenet, testnet; use solana for mainnet +``` + +### Deployment Steps + +1. Generate Solana keypair for ITS program (if not already done): + +```sh +solana-keygen new -o +``` + +2. Deploy Interchain Token Service: + +```sh +solana program-v4 deploy \ + --program-keypair \ + --authority \ + solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so +``` + +3. Initialize ITS: + +```sh +solana/solana-axelar-cli send its init --operator +``` + +4. Register Solana ITS on ITS Hub: + +ITS hub contract configuration in `$ENV.json` must include the following attributes per chain: + +```json +"axelar": { + "contracts": { + "InterchainTokenService": { + "$CHAIN": { + "maxUintBits": 53, + "maxDecimalsWhenTruncating": 255 + } + } + } +} +``` + +Please refer to `$DEPOSIT_VALUE` and `$RUN_AS_ACCOUNT` from Amplifier deployment documentation. + +- `--runAs $RUN_AS_ACCOUNT` is only required for devnet-amplifier. Do not use `--runAs` for stagenet, testnet, or mainnet. +- For mainnet, add a community post for the proposal. + +```sh +node cosmwasm/submit-proposal.js \ + its-hub-register-chains $CHAIN \ + -t "Register $CHAIN on ITS Hub" \ + -d "Register $CHAIN on ITS Hub" \ + --deposit $DEPOSIT_VALUE \ + --runAs $RUN_AS_ACCOUNT +``` + +5. Set up trusted chains on Solana: + +```sh +# Add all trusted chains to Solana ITS +solana/solana-axelar-cli send its set-trusted-chain --chain-name all +``` + +Alternatively, add specific chains: + +```sh +# Add a specific trusted chain +solana/solana-axelar-cli send its set-trusted-chain --chain-name +``` + +6. Set Solana as trusted chain on EVM ITS and other chain ITS implementations: + +```sh +# Change PRIVATE_KEY in .env to EVM +PRIVATE_KEY= + +node evm/its.js -n all --action setTrustedAddress --trustedChain $CHAIN --trustedAddress hub +``` + +## Checklist + +The following checks should be performed after the rollout. + +### Execute Command + +The GMP call needs to be routed via Amplifier before the `execute` call. + +### Solana to EVM + +- Note: The final execute step of the GMP call on EVM can be performed via: + +```sh +# Change PRIVATE_KEY in .env to EVM +PRIVATE_KEY= + +node evm/gateway.js -n --action execute --payload --sourceChain axelar --sourceAddress --messageId --destination +``` + +1. Deploy Native Interchain Token: + +```sh +solana/solana-axelar-cli send its deploy-interchain-token \ + --salt \ + --name \ + --symbol \ + --decimals \ + --initial-supply + +solana/solana-axelar-cli send its deploy-remote-interchain-token \ + --salt \ + --destination-chain \ + --gas-value +``` + +2. Interchain Token Transfer for Native Interchain Token: + +```sh +solana/solana-axelar-cli send its interchain-transfer \ + --source-account \ + --token-id \ + --destination-chain \ + --destination-address \ + --amount \ + --mint \ + --token-program \ + --gas-value +``` + +3. Deploy Remote Canonical Token: + +```sh +solana/solana-axelar-cli send its register-canonical-interchain-token \ + --mint \ + --token-program + +solana/solana-axelar-cli send its deploy-remote-canonical-interchain-token \ + --mint \ + --destination-chain \ + --gas-value +``` + +4. Interchain Token Transfer for Canonical Token: + +```sh +solana/solana-axelar-cli send its interchain-transfer \ + --source-account \ + --token-id \ + --destination-chain \ + --destination-address \ + --amount \ + --mint \ + --token-program \ + --gas-value +``` + +### EVM to Solana + +- Note: The final execute step of the GMP call on Solana can be performed via: + +```sh +# Change PRIVATE_KEY in .env to Solana +PRIVATE_KEY= + +solana/solana-axelar-cli send its execute \ + --source-chain \ + --message-id \ + --source-address \ + --payload +``` + +1. Deploy Native Interchain Token: + +```sh +node evm/interchainTokenFactory.js --action deployInterchainToken -n --destinationChain $CHAIN --salt --name --symbol --decimals + +node evm/interchainTokenFactory.js --action deployRemoteInterchainToken -n --destinationChain $CHAIN --salt --gasValue +``` + +2. Interchain Token Transfer for Native Interchain Token: + +```sh +node evm/its.js --action interchainTransfer -n --destinationChain $CHAIN --destinationAddress --tokenId --amount +``` + +3. Deploy Remote Canonical Token: + +```sh +node evm/interchainTokenFactory.js --action registerCanonicalInterchainToken -n --destinationChain $CHAIN --tokenAddress + +node evm/interchainTokenFactory.js --action deployRemoteCanonicalInterchainToken -n --destinationChain $CHAIN --tokenAddress --gasValue +``` + +4. Interchain Token Transfer for Canonical Token: + +```sh +node evm/its.js --action interchainTransfer -n --destinationChain $CHAIN --destinationAddress --tokenId --amount --gasValue +``` + +### Additional Checks + +- Verify token minting/burning on Solana +- Verify token transfers between Solana and other chains +- Test flow limits and pausable functionality if implemented \ No newline at end of file From 2681774d2e7875b9e4abcb2b5daf1d9f691db1ce Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 15 May 2025 12:05:20 +0200 Subject: [PATCH 48/59] chore(solana): add skeleton release files Signed-off-by: Guilherme Felipe da Silva --- ...vX.Y.Z.md => 2025-05-Solana-GMP-v1.0.0.md} | 0 ...05-GMP-vX.Y.Z.md => 2025-05-GMP-v1.0.0.md} | 98 +++++++++++-------- ...05-ITS-vX.Y.Z.md => 2025-05-ITS-v1.0.0.md} | 66 +++++-------- 3 files changed, 79 insertions(+), 85 deletions(-) rename releases/cosmwasm/{2025-05-Solana-GMP-vX.Y.Z.md => 2025-05-Solana-GMP-v1.0.0.md} (100%) rename releases/solana/{2025-05-GMP-vX.Y.Z.md => 2025-05-GMP-v1.0.0.md} (66%) rename releases/solana/{2025-05-ITS-vX.Y.Z.md => 2025-05-ITS-v1.0.0.md} (72%) diff --git a/releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md b/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md similarity index 100% rename from releases/cosmwasm/2025-05-Solana-GMP-vX.Y.Z.md rename to releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md diff --git a/releases/solana/2025-05-GMP-vX.Y.Z.md b/releases/solana/2025-05-GMP-v1.0.0.md similarity index 66% rename from releases/solana/2025-05-GMP-vX.Y.Z.md rename to releases/solana/2025-05-GMP-v1.0.0.md index e9923c987..83d6fc93f 100644 --- a/releases/solana/2025-05-GMP-vX.Y.Z.md +++ b/releases/solana/2025-05-GMP-v1.0.0.md @@ -1,4 +1,4 @@ -# Solana GMP vX.Y.Z +# Solana GMP v1.0.0 | | **Owner** | | -------------- | ------------------------------ | @@ -16,7 +16,7 @@ ## Background -This is the v.X.Y.Z Solana GMP release, introducing General Message Passing (GMP) capabilities for Solana blockchain. +This is the v1.0.0 Solana GMP release, introducing General Message Passing (GMP) capabilities for Solana blockchain. ## Deployment @@ -46,28 +46,51 @@ popd 4. Set up environment configuration: ```sh -# Create .env file with appropriate values -PRIVATE_KEY= -ENV= -CHAIN= # Use solana-testnet for devnet-amplifier, stagenet, testnet; use solana for mainnet +# Set default cluster +solana config set --url testnet # Use appropriate network: testnet, devnet, mainnet-beta, or localhost + +# Generate a new keypair if needed +solana-keygen new + +# Get funds +solana airdrop 2 ``` ### Initial Solana Config -Add Solana chain config to the `${ENV}.json` file under the `chains` key. +Add Solana chain config to the `axelar-chains-config/info/.json` file under the `chains` key. + +#### Devnet-amplifier: + +```json +"solana-devnet": { + "name": "Solana Devnet", + "axelarId": "solana-devnet", + "rpc": "https://api.devnet.solana.com", + "chainType": "svm", + "decimals": 9, + "finality": TBD, + "approxFinalityWaitTime": 13, + "tokenSymbol": "SOL", + "explorer": { + "name": "Solana Explorer", + "url": "https://explorer.solana.com/?cluster=devnet" + }, + "contracts": {} +} +``` -#### Devnet-Amplifier / Stagenet / Testnet: +#### Testnet: ```json "solana-testnet": { - "name": "Solana", + "name": "Solana Testnet", "axelarId": "solana-testnet", "rpc": "https://api.testnet.solana.com", - "networkType": "testnet", "chainType": "svm", "decimals": 9, - "finality": "32", - "approxFinalityWaitTime": 15, + "finality": TBD, + "approxFinalityWaitTime": 13, "tokenSymbol": "SOL", "explorer": { "name": "Solana Explorer", @@ -84,15 +107,14 @@ Add Solana chain config to the `${ENV}.json` file under the `chains` key. "name": "Solana", "axelarId": "solana", "rpc": "https://api.mainnet-beta.solana.com", - "networkType": "mainnet", "chainType": "svm", "decimals": 9, - "finality": "32", - "approxFinalityWaitTime": 15, + "finality": TBD, + "approxFinalityWaitTime": 13, "tokenSymbol": "SOL", "explorer": { "name": "Solana Explorer", - "url": "https://explorer.solana.com" + "url": "https://explorer.solana.com/" }, "contracts": {} } @@ -136,14 +158,18 @@ solana program-v4 deploy \ solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so ``` +5. After deploying Solana contracts, deploy the [Solana GMP Amplifier](../cosmwasm/2025-05-Solana-GMP-v1.0.0.md). + +### Initialization Steps + +1. Initialize Gateway: + | Network | `minimumRotationDelay` | `previousSignersRetention` | | -------------------- | ---------------------- | -------------------------- | -| **Devnet-amplifier** | `0` | `15` | -| **Stagenet** | `300` | `15` | -| **Testnet** | `3600` | `15` | -| **Mainnet** | `86400` | `15` | +| **Devnet-amplifier** | TBD | TBD | +| **Testnet** | TBD | TBD | +| **Mainnet** | TBD | TBD | -5. Initialize Gateway: ```sh solana/solana-axelar-cli send gateway init \ @@ -152,20 +178,7 @@ solana/solana-axelar-cli send gateway init \ --operator ``` -6. After deploying Solana contracts, deploy the Solana GMP Amplifier (separate documentation required). - -7. Rotate genesis verifier set on Solana Gateway: - -```sh -solana/solana-axelar-cli send gateway rotate \ - --signer \ - --nonce \ - --new-nonce -``` - -8. Update configuration with program addresses: - -After deployment, the contract addresses need to be added to the corresponding configuration files so that the CLI can interact with them. +This will query the `MultisigProver` for the `VerifierSet`. Thus, the Solana `MultisigProver` must be deployed before this step and its information available within the appropriate object in the `axelar-chains-config/info/.json` file. ## Checklist @@ -183,12 +196,13 @@ solana/solana-axelar-cli send gateway call-contract \ ``` 2. Route GMP call via Amplifier: - - Use the Amplifier relay mechanism to route the message. + +- 3. Submit proof with multisig session ID: ```sh -# Change PRIVATE_KEY in .env to EVM +# Set PRIVATE_KEY within .env PRIVATE_KEY= node evm/gateway.js -n --action submitProof --multisigSessionId @@ -197,7 +211,7 @@ node evm/gateway.js -n --action submitProof --multisigSessio 4. Confirm message approval: ```sh -node evm/gateway.js -n --action isContractCallApproved --commandID --sourceChain $CHAIN --sourceAddress --destination --payloadHash +node evm/gateway.js -n --action isContractCallApproved --commandID --sourceChain --sourceAddress --destination --payloadHash ``` ### Verify EVM → Solana GMP Call @@ -205,18 +219,16 @@ node evm/gateway.js -n --action isContractCallApproved --com 1. Send a GMP call: ```sh -node evm/gateway.js -n --action callContract --destinationChain $CHAIN --destination --payload +node evm/gateway.js -n --action callContract --destinationChain --destination --payload ``` 2. Route GMP call via Amplifier: - - Use the Amplifier relay mechanism to route the message. + +- 3. Submit proof with multisig session ID: ```sh -# Change PRIVATE_KEY in .env to Solana -PRIVATE_KEY= - solana/solana-axelar-cli send gateway submit-proof \ --multisig-session-id ``` diff --git a/releases/solana/2025-05-ITS-vX.Y.Z.md b/releases/solana/2025-05-ITS-v1.0.0.md similarity index 72% rename from releases/solana/2025-05-ITS-vX.Y.Z.md rename to releases/solana/2025-05-ITS-v1.0.0.md index 170027816..53c5b96df 100644 --- a/releases/solana/2025-05-ITS-vX.Y.Z.md +++ b/releases/solana/2025-05-ITS-v1.0.0.md @@ -1,4 +1,4 @@ -# Solana ITS vX.Y.Z +# Solana ITS v1.0.0 | | **Owner** | | -------------- | ------------------------------ | @@ -12,36 +12,27 @@ | **Testnet** | Pending | | | **Mainnet** | Pending | | -- [GitHub Release]() +- [Release]() ## Background -This is the vX.Y.Z Solana ITS release, bringing Interchain Token Service capabilities to the Solana blockchain. +This is the v1.0.0 Solana ITS release, bringing Interchain Token Service capabilities to the Solana blockchain. ## Deployment -Ensure that [Solana GMP](../solana/2025-05-GMP-vX.Y.Z.md) is deployed first. +Ensure that [Solana GMP](./2025-05-GMP-v1.0.0.md) is deployed first. ### Set Up Environment -Create an `.env` config: -```yaml -# Set private key and network -PRIVATE_KEY= -ENV= -CHAIN= # Use solana-testnet for devnet-amplifier, stagenet, testnet; use solana for mainnet +```sh +# Set default cluster +solana config set --url testnet # Use appropriate network: testnet, devnet, mainnet-beta, or localhost ``` ### Deployment Steps -1. Generate Solana keypair for ITS program (if not already done): - -```sh -solana-keygen new -o -``` - -2. Deploy Interchain Token Service: +1. Deploy Interchain Token Service: ```sh solana program-v4 deploy \ @@ -50,7 +41,7 @@ solana program-v4 deploy \ solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so ``` -3. Initialize ITS: +2. Initialize ITS: ```sh solana/solana-axelar-cli send its init --operator @@ -58,14 +49,14 @@ solana/solana-axelar-cli send its init --operator 4. Register Solana ITS on ITS Hub: -ITS hub contract configuration in `$ENV.json` must include the following attributes per chain: +ITS hub contract configuration in `axelar-chains-config/info/.json` must include the following attributes per chain: ```json "axelar": { "contracts": { "InterchainTokenService": { - "$CHAIN": { - "maxUintBits": 53, + "": { + "maxUintBits": 64, "maxDecimalsWhenTruncating": 255 } } @@ -75,14 +66,14 @@ ITS hub contract configuration in `$ENV.json` must include the following attribu Please refer to `$DEPOSIT_VALUE` and `$RUN_AS_ACCOUNT` from Amplifier deployment documentation. -- `--runAs $RUN_AS_ACCOUNT` is only required for devnet-amplifier. Do not use `--runAs` for stagenet, testnet, or mainnet. +- `--runAs $RUN_AS_ACCOUNT` is only required for devnet-amplifier. Do not use `--runAs` for testnet, or mainnet. - For mainnet, add a community post for the proposal. ```sh node cosmwasm/submit-proposal.js \ - its-hub-register-chains $CHAIN \ - -t "Register $CHAIN on ITS Hub" \ - -d "Register $CHAIN on ITS Hub" \ + its-hub-register-chains "solana" \ + -t "Register solana on ITS Hub" \ + -d "Register solana on ITS Hub" \ --deposit $DEPOSIT_VALUE \ --runAs $RUN_AS_ACCOUNT ``` @@ -104,10 +95,10 @@ solana/solana-axelar-cli send its set-trusted-chain --chain-name 6. Set Solana as trusted chain on EVM ITS and other chain ITS implementations: ```sh -# Change PRIVATE_KEY in .env to EVM +# Set PRIVATE_KEY in .env PRIVATE_KEY= -node evm/its.js -n all --action setTrustedAddress --trustedChain $CHAIN --trustedAddress hub +node evm/its.js -n all --action setTrustedAddress --trustedChain --trustedAddress hub ``` ## Checklist @@ -191,9 +182,6 @@ solana/solana-axelar-cli send its interchain-transfer \ - Note: The final execute step of the GMP call on Solana can be performed via: ```sh -# Change PRIVATE_KEY in .env to Solana -PRIVATE_KEY= - solana/solana-axelar-cli send its execute \ --source-chain \ --message-id \ @@ -204,33 +192,27 @@ solana/solana-axelar-cli send its execute \ 1. Deploy Native Interchain Token: ```sh -node evm/interchainTokenFactory.js --action deployInterchainToken -n --destinationChain $CHAIN --salt --name --symbol --decimals +node evm/interchainTokenFactory.js --action deployInterchainToken -n --destinationChain --salt --name --symbol --decimals -node evm/interchainTokenFactory.js --action deployRemoteInterchainToken -n --destinationChain $CHAIN --salt --gasValue +node evm/interchainTokenFactory.js --action deployRemoteInterchainToken -n --destinationChain --salt --gasValue ``` 2. Interchain Token Transfer for Native Interchain Token: ```sh -node evm/its.js --action interchainTransfer -n --destinationChain $CHAIN --destinationAddress --tokenId --amount +node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount ``` 3. Deploy Remote Canonical Token: ```sh -node evm/interchainTokenFactory.js --action registerCanonicalInterchainToken -n --destinationChain $CHAIN --tokenAddress +node evm/interchainTokenFactory.js --action registerCanonicalInterchainToken -n --destinationChain --tokenAddress -node evm/interchainTokenFactory.js --action deployRemoteCanonicalInterchainToken -n --destinationChain $CHAIN --tokenAddress --gasValue +node evm/interchainTokenFactory.js --action deployRemoteCanonicalInterchainToken -n --destinationChain --tokenAddress --gasValue ``` 4. Interchain Token Transfer for Canonical Token: ```sh -node evm/its.js --action interchainTransfer -n --destinationChain $CHAIN --destinationAddress --tokenId --amount --gasValue +node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount --gasValue ``` - -### Additional Checks - -- Verify token minting/burning on Solana -- Verify token transfers between Solana and other chains -- Test flow limits and pausable functionality if implemented \ No newline at end of file From 41f50a4dc40754316525ded197818fbc5f486bc6 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 15 May 2025 12:27:13 +0200 Subject: [PATCH 49/59] feat(solana): allow 'all' on ITS's set-trusted-chain Signed-off-by: Guilherme Felipe da Silva --- solana/src/its.rs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/solana/src/its.rs b/solana/src/its.rs index 92dc60cfa..f5c20675a 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -806,7 +806,7 @@ pub(crate) fn build_instruction( Commands::Pause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: true }), Commands::Unpause => set_pause_status(fee_payer, SetPauseStatusArgs { paused: false }), Commands::SetTrustedChain(set_trusted_chain_args) => { - set_trusted_chain(fee_payer, set_trusted_chain_args) + set_trusted_chain(fee_payer, set_trusted_chain_args, config) } Commands::RemoveTrustedChain(args) => remove_trusted_chain(fee_payer, args), Commands::ApproveDeployRemoteInterchainToken(args) => { @@ -962,11 +962,35 @@ fn set_pause_status( fn set_trusted_chain( fee_payer: &Pubkey, set_trusted_chain_args: TrustedChainArgs, + config: &Config, ) -> eyre::Result> { - Ok(vec![axelar_solana_its::instruction::set_trusted_chain( - *fee_payer, - set_trusted_chain_args.chain_name, - )?]) + if set_trusted_chain_args.chain_name.is_empty() { + eyre::bail!("Chain name cannot be empty"); + } + + let mut instructions = Vec::new(); + if set_trusted_chain_args.chain_name == "all" { + let chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; + + if let serde_json::Value::Object(ref chains) = chains_info[CHAINS_KEY] { + for chain in chains.keys() { + println!("Creating instruction to set {chain} as trusted on Solana ITS"); + instructions.push(axelar_solana_its::instruction::set_trusted_chain( + *fee_payer, + chain.clone(), + )?); + } + } else { + eyre::bail!("Failed to load all chains from chains info JSON file"); + } + } else { + instructions.push(axelar_solana_its::instruction::set_trusted_chain( + *fee_payer, + set_trusted_chain_args.chain_name, + )?); + } + + Ok(instructions) } fn remove_trusted_chain( From bf506bbc0fd74676d9f63e1a741b06c898d3e063 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 15 May 2025 12:30:39 +0200 Subject: [PATCH 50/59] refactor(solana): make set-trusted-chain take positional arg Signed-off-by: Guilherme Felipe da Silva --- releases/solana/2025-05-ITS-v1.0.0.md | 4 ++-- solana/README.md | 4 ++-- solana/src/its.rs | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/releases/solana/2025-05-ITS-v1.0.0.md b/releases/solana/2025-05-ITS-v1.0.0.md index 53c5b96df..986882fc9 100644 --- a/releases/solana/2025-05-ITS-v1.0.0.md +++ b/releases/solana/2025-05-ITS-v1.0.0.md @@ -82,14 +82,14 @@ node cosmwasm/submit-proposal.js \ ```sh # Add all trusted chains to Solana ITS -solana/solana-axelar-cli send its set-trusted-chain --chain-name all +solana/solana-axelar-cli send its set-trusted-chain all ``` Alternatively, add specific chains: ```sh # Add a specific trusted chain -solana/solana-axelar-cli send its set-trusted-chain --chain-name +solana/solana-axelar-cli send its set-trusted-chain ``` 6. Set Solana as trusted chain on EVM ITS and other chain ITS implementations: diff --git a/solana/README.md b/solana/README.md index 953aff209..cebce0134 100644 --- a/solana/README.md +++ b/solana/README.md @@ -266,10 +266,10 @@ solana/solana-axelar-cli send its init --operator ```sh # Add a trusted chain -solana/solana-axelar-cli send its set-trusted-chain --chain-name +solana/solana-axelar-cli send its set-trusted-chain # Remove a trusted chain -solana/solana-axelar-cli send its remove-trusted-chain --chain-name +solana/solana-axelar-cli send its remove-trusted-chain ``` #### Deploy Interchain Token diff --git a/solana/src/its.rs b/solana/src/its.rs index f5c20675a..35bae66dc 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -293,7 +293,6 @@ pub(crate) struct SetPauseStatusArgs { #[derive(Parser, Debug)] pub(crate) struct TrustedChainArgs { /// The name of the chain to set as trusted - #[clap(short, long)] chain_name: String, } From 84c7a3f87b34cca7b1674ad092e859ce285be66b Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 15 May 2025 12:31:06 +0200 Subject: [PATCH 51/59] fix(solana): fix number of signers check Signed-off-by: Guilherme Felipe da Silva --- solana/src/send.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solana/src/send.rs b/solana/src/send.rs index c02d1882d..50362bc9b 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -29,7 +29,8 @@ fn load_signers( signers_paths: &[String], transaction: &Transaction, ) -> eyre::Result>> { - if signers_paths.len() < transaction.signatures.len() { + // We relax one signer as it is the fee payer + if signers_paths.len() < transaction.signatures.len() - 1 { eyre::bail!("Not enough signers provided"); } From 30bd32eec5eba74b484b087a831ff9cede07e054 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Thu, 15 May 2025 15:04:58 +0200 Subject: [PATCH 52/59] fix(solana): some fixes to release docs Signed-off-by: Guilherme Felipe da Silva --- releases/solana/2025-05-GMP-v1.0.0.md | 12 ------------ releases/solana/2025-05-ITS-v1.0.0.md | 7 ++++--- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/releases/solana/2025-05-GMP-v1.0.0.md b/releases/solana/2025-05-GMP-v1.0.0.md index 83d6fc93f..ecfeb965f 100644 --- a/releases/solana/2025-05-GMP-v1.0.0.md +++ b/releases/solana/2025-05-GMP-v1.0.0.md @@ -231,15 +231,3 @@ node evm/gateway.js -n --action callContract --destinationChain < ```sh solana/solana-axelar-cli send gateway submit-proof \ --multisig-session-id -``` - -4. Execute message: - -```sh -solana/solana-axelar-cli send gateway execute \ - --source-chain \ - --message-id \ - --source-address \ - --destination-address \ - --payload -``` diff --git a/releases/solana/2025-05-ITS-v1.0.0.md b/releases/solana/2025-05-ITS-v1.0.0.md index 986882fc9..7489dc375 100644 --- a/releases/solana/2025-05-ITS-v1.0.0.md +++ b/releases/solana/2025-05-ITS-v1.0.0.md @@ -107,7 +107,7 @@ The following checks should be performed after the rollout. ### Execute Command -The GMP call needs to be routed via Amplifier before the `execute` call. +The GMP call needs to be routed via Amplifier and proof submited to the gateway before the `execute` call. ### Solana to EVM @@ -182,11 +182,12 @@ solana/solana-axelar-cli send its interchain-transfer \ - Note: The final execute step of the GMP call on Solana can be performed via: ```sh -solana/solana-axelar-cli send its execute \ +solana/solana-axelar-cli send gateway execute \ --source-chain \ --message-id \ --source-address \ - --payload + --payload \ + --destination ``` 1. Deploy Native Interchain Token: From 6ee630f8c94a6190965fbbf0b16efb89e0d47728 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Fri, 16 May 2025 16:05:45 +0200 Subject: [PATCH 53/59] feat(solana): add Solana GMP release doc This is, atm, merely a copy of the Steller counterpart with updated chain name. Signed-off-by: Guilherme Felipe da Silva --- .../cosmwasm/2025-05-Solana-GMP-v1.0.0.md | 344 +++++++++++++++++- 1 file changed, 343 insertions(+), 1 deletion(-) diff --git a/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md b/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md index 1333ed77b..f879aeb30 100644 --- a/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md +++ b/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md @@ -1 +1,343 @@ -TODO +# Solana GMP Amplifier + +| | **Owner** | +| -------------- | ------------------------------ | +| **Created By** | @ () | +| **Deployment** | @ () | + +| **Network** | **Deployment Status** | **Date** | +| -------------------- | --------------------- | ---------------- | +| **Devnet Amplifier** | Pending | | +| **Stagenet** | Pending | | +| **Testnet** | Pending | | +| **Mainnet** | Pending | | + +- [Amplifier Releases](https://github.com/axelarnetwork/axelar-amplifier/releases) +- [VotingVerifier v1.1.0](https://github.com/axelarnetwork/axelar-amplifier/releases/tag/voting-verifier-v1.1.0) +- [Gateway v1.1.1](https://github.com/axelarnetwork/axelar-amplifier/releases/tag/gateway-v1.1.1) +- [MultisigProver v1.1.1](https://github.com/axelarnetwork/axelar-amplifier/releases/tag/multisig-prover-v1.1.1) + +## Background + +These are the instructions for deploying Amplifier contracts for Solana connection. + +### Pre-requisites + +Ensure that the [External Gateway](../solana/2025-05-GMP-v1.0.0.md) is deployed first, as `VotingVerifier` needs the `sourceGatewayAddress` which is the External Gateway address. + +## Deployment + +- Create an `.env` config. `CHAIN` should be set to `Solana`. + +```yaml +MNEMONIC=xyz +ENV=xyz +CHAIN=xyz +``` + +- Confirm `VotingVerifier(v1.1.0)`, `Gateway(v1.1.1)` and `MultisigProver(v1.1.1)` contracts are already stored in `$ENV.json` + +```bash +VotingVerifier(v1.1.0) -> "storeCodeProposalCodeHash": "d9412440820a51bc48bf41a77ae39cfb33101ddc6562323845627ea2042bf708" +Gateway(v1.1.1) -> "storeCodeProposalCodeHash": "2ba600ee0d162184c9387eaf6fad655f1d75db548f93e379f0565cb2042d856f" +MultisigProver(v1.1.1) -> "storeCodeProposalCodeHash": "00428ef0483f103a6e1a5853c4b29466a83e5b180cc53a00d1ff9d022bc2f03a" +``` + +- Add config in `$ENV.json` to deploy Amplifier contracts. + +| Network | `governanceAddress` | `adminAddress` | +| -------------------- | ----------------------------------------------- | ----------------------------------------------- | +| **Devnet-amplifier** | `axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9` | `axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9` | +| **Stagenet** | `axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj` | `axelar1l7vz4m5g92kvga050vk9ycjynywdlk4zhs07dv` | +| **Testnet** | `axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj` | `axelar17qafmnc4hrfa96cq37wg5l68sxh354pj6eky35` | +| **Mainnet** | `axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj` | `axelar1pczf792wf3p3xssk4dmwfxrh6hcqnrjp70danj` | + +| Network | `serviceName` | `votingThreshold` | `signingThreshold` | `confirmationHeight` | +| -------------------- | ------------- | ----------------- | ------------------ | -------------------- | +| **Devnet-amplifier** | `validators` | `["6", "10"]` | `["6", "10"]` | `1` | +| **Stagenet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `1` | +| **Testnet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `1` | +| **Mainnet** | `amplifier` | `["2", "3"]` | `["2", "3"]` | `1` | + +```bash +# Add under `config.axelar.contracts.VotingVerifier` based on Network +\"$CHAIN\" : { + "governanceAddress": "[governance address]", + "serviceName": "[service name]", + "sourceGatewayAddress": "[external gateway address]", + "votingThreshold": "[voting threshold]", + "blockExpiry": 10, + "confirmationHeight": 1, + "msgIdFormat": "hex_tx_hash_and_event_index", + "addressFormat": "stellar" +} + +# Add under `config.axelar.contracts.MultisigProver` based on Network +\"$CHAIN\" : { + "governanceAddress": "[governance address]", + "adminAddress": "[admin address]", + "signingThreshold": "[signing threshold]", + "serviceName": "[service name]", + "verifierSetDiffThreshold": 0, + "encoder": "stellar_xdr", + "keyType": "ed25519" +} +``` + +### Instantiate Amplifier contracts + +| Network | `CONTRACT_ADMIN` | +| -------------------- | ----------------------------------------------- | +| **Devnet-amplifier** | `axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9` | +| **Stagenet** | `axelar12qvsvse32cjyw60ztysd3v655aj5urqeup82ky` | +| **Testnet** | `axelar12f2qn005d4vl03ssjq07quz6cja72w5ukuchv7` | +| **Mainnet** | `axelar1nctnr9x0qexemeld5w7w752rmqdsqqv92dw9am` | + +```bash +CONTRACT_ADMIN=[wasm contract admin address for the upgrade and migration based on network] +``` + +1. Instantiate `VotingVerifier` + +```bash +node ./cosmwasm/deploy-contract.js instantiate -c VotingVerifier --fetchCodeId --instantiate2 --admin $CONTRACT_ADMIN +``` + +2. Instantiate `Gateway` + +```bash +node ./cosmwasm/deploy-contract.js instantiate -c Gateway --fetchCodeId --instantiate2 --admin $CONTRACT_ADMIN +``` + +3. Instantiate `MultisigProver` + +```bash +node ./cosmwasm/deploy-contract.js instantiate -c MultisigProver --fetchCodeId --instantiate2 --admin $CONTRACT_ADMIN +``` + +4. Set environment variables + +- Network-specific environment variables: These variables need to be updated by the network. + +```bash +VOTING_VERIFIER=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.VotingVerifier[\"$CHAIN\"].address" | tr -d '"') +GATEWAY=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.Gateway[\"$CHAIN\"].address" | tr -d '"') +MULTISIG_PROVER=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.MultisigProver[\"$CHAIN\"].address" | tr -d '"') +MULTISIG=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.Multisig.address" | tr -d '"') +REWARDS=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.Rewards.address" | tr -d '"') +ROUTER=$(cat "./axelar-chains-config/info/\"$ENV\".json" | jq ".axelar.contracts.Router.address" | tr -d '"') +``` + +- Gov proposal environment variables. Update these for each network + +| Network | `PROVER_ADMIN` | `DEPOSIT_VALUE` | `REWARD_AMOUNT` | +| -------------------- | ----------------------------------------------- | --------------- | ------------------- | +| **Devnet-amplifier** | `axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9` | `100000000` | `1000000uamplifier` | +| **Stagenet** | `axelar1l7vz4m5g92kvga050vk9ycjynywdlk4zhs07dv` | `100000000` | `1000000uaxl` | +| **Testnet** | `axelar17qafmnc4hrfa96cq37wg5l68sxh354pj6eky35` | `2000000000` | `1000000uaxl` | +| **Mainnet** | `axelar1pczf792wf3p3xssk4dmwfxrh6hcqnrjp70danj` | `2000000000` | `1000000uaxl` | + +```bash +PROVER_ADMIN=[prover admin who is responsible for the contract's operations] +DEPOSIT_VALUE=[deposit value] +REWARD_AMOUNT=[reward amount] +RUN_AS_ACCOUNT=[wasm deployer/governance address] +``` + +- `--runAs $RUN_AS_ACCOUNT` is only required for devnet-amplifier. Do not use `--runAs` for stagenet, testnet, or mainnet. +- Add a community post for the mainnet proposal. i.e: https://community.axelar.network/t/proposal-add-its-hub-to-mainnet/3227 + +5. Register stellar gateway at the Router + +```bash +node cosmwasm/submit-proposal.js execute \ + -c Router \ + -t "Register Gateway for Solana" \ + -d "Register Gateway address for Solana at Router contract" \ + --runAs $RUN_AS_ACCOUNT \ + --deposit $DEPOSIT_VALUE \ + --msg "{ + \"register_chain\": { + \"chain\": \"$CHAIN\", + \"gateway_address\": \"$GATEWAY\", + \"msg_id_format\": \"hex_tx_hash_and_event_index\" + } + }" +``` + +- Approve Proposal (must be done within 5 minutes on devnet-amplifier/stagenet and 1 hour on testnet/mainnet) + +- Verify Gateway Registration: + +```bash +axelard q wasm contract-state smart $ROUTER "{\"chain_info\": \"$CHAIN\"}" --output json --node [axelar rpc address] | jq . +``` + +```bash +# You should see something like this: +{ + "data": { + "name": \"$CHAIN\", + "gateway": { + "address": "axelar1jah3ac59xke2r266yjhh45tugzsvnlzsefyvx6jgp0msk6tp7vqqaktuz2" + }, + "frozen_status": 0, + "msg_id_format": "hex_tx_hash_and_event_index" + } +} +``` + +6. Register prover contract on coordinator + +```bash +node cosmwasm/submit-proposal.js execute \ + -c Coordinator \ + -t "Register Multisig Prover for Solana" \ + -d "Register Multisig Prover address for Solana at Coordinator contract" \ + --runAs $RUN_AS_ACCOUNT \ + --deposit $DEPOSIT_VALUE \ + --msg "{ + \"register_prover_contract\": { + \"chain_name\": \"$CHAIN\", + \"new_prover_addr\": \"$MULTISIG_PROVER\" + } + }" +``` + +7. Authorize Solana Multisig prover on Multisig + +```bash +node cosmwasm/submit-proposal.js execute \ + -c Multisig \ + -t "Authorize Multisig Prover for Solana" \ + -d "Authorize Multisig Prover address for Solana at Multisig contract" \ + --runAs $RUN_AS_ACCOUNT \ + --deposit $DEPOSIT_VALUE \ + --msg "{ + \"authorize_callers\": { + \"contracts\": { + \"$MULTISIG_PROVER\": \"$CHAIN\" + } + } + }" +``` + +```bash +axelard q wasm contract-state smart $MULTISIG "{\"is_caller_authorized\": {\"contract_address\": \"$MULTISIG_PROVER\", \"chain_name\": \"$CHAIN\"}}" --output json | jq . + +# Result should look like: +{ + "data": true +} +``` + +8. Create reward pool for voting verifier + +#### Rewards + +| Network | `epoch_duration` | `participation_threshold` | `rewards_per_epoch` | +| -------------------- | ---------------- | ------------------------- | ------------------- | +| **Devnet-amplifier** | `100` | `[\"7\", \"10\"]` | `100` | +| **Stagenet** | `600` | `[\"7\", \"10\"]` | `100` | +| **Testnet** | `14845` | `[\"7\", \"10\"]` | `100` | +| **Mainnet** | `14845` | `[\"8\", \"10\"]` | `920000000` | + +```bash +node cosmwasm/submit-proposal.js execute \ + -c Rewards \ + -t "Create pool for Solana in Solana voting verifier" \ + -d "Create pool for Solana in Solana voting verifier" \ + --runAs $RUN_AS_ACCOUNT \ + --deposit $DEPOSIT_VALUE \ + --msg "{ + \"create_pool\": { + \"params\": { + \"epoch_duration\": \"\", + \"participation_threshold\": [], + \"rewards_per_epoch\": \"\" + }, + \"pool_id\": { + \"chain_name\": \"$CHAIN\", + \"contract\": \"$VOTING_VERIFIER\" + } + } + }" +``` + +9. Create reward pool for multisig + +```bash +node cosmwasm/submit-proposal.js execute \ + -c Rewards \ + -t "Create pool for Solana in axelar multisig" \ + -d "Create pool for Solana in axelar multisig" \ + --runAs $RUN_AS_ACCOUNT \ + --deposit $DEPOSIT_VALUE \ + --msg "{ + \"create_pool\": { + \"params\": { + \"epoch_duration\": \"\", + \"participation_threshold\": [], + \"rewards_per_epoch\": \"\" + }, + \"pool_id\": { + \"chain_name\": \"$CHAIN\", + \"contract\": \"$MULTISIG\" + } + } + }" +``` + +10. Update ampd with the Solana chain configuration. Verifiers should use their own Solana RPC node for the `http_url` in production. + +| Network | `http_url` | +| -------------------- | -------------------------------------- | +| **Devnet-amplifier** | `https://api.testnet.solana.com` | +| **Stagenet** | `https://api.testnet.solana.com` | +| **Testnet** | `https://api.testnet.solana.com` | +| **Mainnet** | `https://api.mainnet-beta.solana.com` | + +```bash +[[handlers]] +type="SolanaMsgVerifier" +http_url=[http_url] +cosmwasm_contract="$VOTING_VERIFIER" + +[[handlers]] +type="SolanaVerifierSetVerifier" +http_url=[http_url] +cosmwasm_contract="$VOTING_VERIFIER" +``` + +11. Update ampd with the Solana chain configuration. + +```bash +ampd register-public-key ed25519 + +ampd register-chain-support "[service name]" $CHAIN +``` + +12. Add funds to reward pools from a wallet containing the reward funds `$REWARD_AMOUNT` + +```bash +axelard tx wasm execute $REWARDS "{ \"add_rewards\": { \"pool_id\": { \"chain_name\": \"$CHAIN\", \"contract\": \"$MULTISIG\" } } }" --amount $REWARD_AMOUNT --from $WALLET +axelard tx wasm execute $REWARDS "{ \"add_rewards\": { \"pool_id\": { \"chain_name\": \"$CHAIN\", \"contract\": \"$VOTING_VERIFIER\" } } }" --amount $REWARD_AMOUNT --from $WALLET + +# Check reward pool to confirm funding worked +node cosmwasm/query.js rewards -n $CHAIN +``` + +13. Create genesis verifier set + +Note that this step can only be run once a sufficient number of verifiers have registered. + +```bash +axelard tx wasm execute $MULTISIG_PROVER '"update_verifier_set"' --from $PROVER_ADMIN --gas auto --gas-adjustment 1.2 + +# Query the multisig prover for active verifier set +axelard q wasm contract-state smart $MULTISIG_PROVER '"current_verifier_set"' +``` + +## Checklist + +The [Solana GMP checklist](../solana/2025-05-GMP-v1.0.0.md) will test GMP call. From 216fc060d1367e91d38c848fe7903239ffd6fd61 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 15:11:53 +0200 Subject: [PATCH 54/59] fix(solana): update solana cosmwasm GMP info Signed-off-by: Guilherme Felipe da Silva --- .../cosmwasm/2025-05-Solana-GMP-v1.0.0.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md b/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md index f879aeb30..f3acc6307 100644 --- a/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md +++ b/releases/cosmwasm/2025-05-Solana-GMP-v1.0.0.md @@ -27,7 +27,7 @@ Ensure that the [External Gateway](../solana/2025-05-GMP-v1.0.0.md) is deployed ## Deployment -- Create an `.env` config. `CHAIN` should be set to `Solana`. +- Create an `.env` config. `CHAIN` should be set to `solana`. ```yaml MNEMONIC=xyz @@ -54,10 +54,10 @@ MultisigProver(v1.1.1) -> "storeCodeProposalCodeHash": "00428ef0483f103a6e1a5853 | Network | `serviceName` | `votingThreshold` | `signingThreshold` | `confirmationHeight` | | -------------------- | ------------- | ----------------- | ------------------ | -------------------- | -| **Devnet-amplifier** | `validators` | `["6", "10"]` | `["6", "10"]` | `1` | -| **Stagenet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `1` | -| **Testnet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `1` | -| **Mainnet** | `amplifier` | `["2", "3"]` | `["2", "3"]` | `1` | +| **Devnet-amplifier** | `validators` | `["6", "10"]` | `["6", "10"]` | `31` | +| **Stagenet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `31` | +| **Testnet** | `amplifier` | `["51", "100"]` | `["51", "100"]` | `31` | +| **Mainnet** | `amplifier` | `["2", "3"]` | `["2", "3"]` | `31` | ```bash # Add under `config.axelar.contracts.VotingVerifier` based on Network @@ -67,9 +67,9 @@ MultisigProver(v1.1.1) -> "storeCodeProposalCodeHash": "00428ef0483f103a6e1a5853 "sourceGatewayAddress": "[external gateway address]", "votingThreshold": "[voting threshold]", "blockExpiry": 10, - "confirmationHeight": 1, - "msgIdFormat": "hex_tx_hash_and_event_index", - "addressFormat": "stellar" + "confirmationHeight": 31, + "msgIdFormat": "base58_tx_signature_and_log_index", + "addressFormat": "solana" } # Add under `config.axelar.contracts.MultisigProver` based on Network @@ -79,8 +79,8 @@ MultisigProver(v1.1.1) -> "storeCodeProposalCodeHash": "00428ef0483f103a6e1a5853 "signingThreshold": "[signing threshold]", "serviceName": "[service name]", "verifierSetDiffThreshold": 0, - "encoder": "stellar_xdr", - "keyType": "ed25519" + "encoder": "borsh", + "keyType": "ecdsa" } ``` @@ -147,7 +147,7 @@ RUN_AS_ACCOUNT=[wasm deployer/governance address] - `--runAs $RUN_AS_ACCOUNT` is only required for devnet-amplifier. Do not use `--runAs` for stagenet, testnet, or mainnet. - Add a community post for the mainnet proposal. i.e: https://community.axelar.network/t/proposal-add-its-hub-to-mainnet/3227 -5. Register stellar gateway at the Router +5. Register Solana gateway at the Router ```bash node cosmwasm/submit-proposal.js execute \ @@ -160,7 +160,7 @@ node cosmwasm/submit-proposal.js execute \ \"register_chain\": { \"chain\": \"$CHAIN\", \"gateway_address\": \"$GATEWAY\", - \"msg_id_format\": \"hex_tx_hash_and_event_index\" + \"msg_id_format\": \"base58_tx_signature_and_log_index\" } }" ``` @@ -182,7 +182,7 @@ axelard q wasm contract-state smart $ROUTER "{\"chain_info\": \"$CHAIN\"}" --out "address": "axelar1jah3ac59xke2r266yjhh45tugzsvnlzsefyvx6jgp0msk6tp7vqqaktuz2" }, "frozen_status": 0, - "msg_id_format": "hex_tx_hash_and_event_index" + "msg_id_format": "base58_tx_signature_and_log_index", } } ``` @@ -292,9 +292,9 @@ node cosmwasm/submit-proposal.js execute \ | Network | `http_url` | | -------------------- | -------------------------------------- | -| **Devnet-amplifier** | `https://api.testnet.solana.com` | -| **Stagenet** | `https://api.testnet.solana.com` | -| **Testnet** | `https://api.testnet.solana.com` | +| **Devnet-amplifier** | `https://api.devnet.solana.com` | +| **Stagenet** | `https://api.devnet.solana.com` | +| **Testnet** | `https://api.devnet.solana.com` | | **Mainnet** | `https://api.mainnet-beta.solana.com` | ```bash @@ -312,7 +312,7 @@ cosmwasm_contract="$VOTING_VERIFIER" 11. Update ampd with the Solana chain configuration. ```bash -ampd register-public-key ed25519 +ampd register-public-key ecdsa ampd register-chain-support "[service name]" $CHAIN ``` From 88ffd7561ac26a4c77182ab319d73729c428e49e Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 15:24:50 +0200 Subject: [PATCH 55/59] fix(solana): chain name and axelar env Address some review comments that pointed out there's no direct map between solana clusters and axelar env. Solana devnet should likely be used for everything other than mainnet. Solana mainnet-beta should be used with axelar mainnet. This will be emphasized in the docs as well. Signed-off-by: Guilherme Felipe da Silva --- solana/src/config.rs | 5 ++-- solana/src/gas_service.rs | 9 +++---- solana/src/gateway.rs | 12 ++++----- solana/src/governance.rs | 34 +++++++++++------------- solana/src/its.rs | 13 +++++----- solana/src/main.rs | 13 ++++++---- solana/src/types.rs | 54 +++++++++++++++++++++++++++------------ solana/src/utils.rs | 16 +++++------- 8 files changed, 86 insertions(+), 70 deletions(-) diff --git a/solana/src/config.rs b/solana/src/config.rs index 7ff7cfad5..b21af1a27 100644 --- a/solana/src/config.rs +++ b/solana/src/config.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use crate::types::ChainsInfoFile; use crate::types::NetworkType; +use crate::AxelarNetwork; #[derive(Debug)] pub(crate) struct Config { @@ -19,8 +20,8 @@ impl Config { url: String, output_dir: PathBuf, chains_info_dir: PathBuf, + axelar_network: AxelarNetwork, ) -> eyre::Result { - println!("URL: {url}"); if !output_dir.exists() { fs::create_dir_all(&output_dir) .map_err(|e| eyre!("Failed to create output directory: {}", e))?; @@ -35,7 +36,7 @@ impl Config { } let network_type = NetworkType::from_str(&url)?; - let chains_info_filename: String = ChainsInfoFile::from(network_type).into(); + let chains_info_filename: String = ChainsInfoFile::from(axelar_network).into(); let chains_info_file = chains_info_dir.join(chains_info_filename); Ok(Self { diff --git a/solana/src/gas_service.rs b/solana/src/gas_service.rs index 26d9df436..cad882ef2 100644 --- a/solana/src/gas_service.rs +++ b/solana/src/gas_service.rs @@ -4,10 +4,10 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; -use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::types::{SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ - ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, - fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, + fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, + CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GAS_SERVICE_KEY, SOLANA_CHAIN_KEY, }; #[derive(Subcommand, Debug)] @@ -82,8 +82,7 @@ fn init( axelar_solana_gas_service::get_config_pda(&program_id, &salt_hash, &init_args.authority); let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GAS_SERVICE_KEY] = serde_json::json!({ + chains_info[CHAINS_KEY][SOLANA_CHAIN_KEY][CONTRACTS_KEY][GAS_SERVICE_KEY] = serde_json::json!({ ADDRESS_KEY: axelar_solana_gateway::id().to_string(), CONFIG_ACCOUNT_KEY: config_pda.to_string(), }); diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index a50f2e3f6..80ef6e07a 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -29,7 +29,7 @@ use crate::config::Config; use crate::multisig_prover_types::msg::ProofStatus; use crate::multisig_prover_types::Uint128Extensions; use crate::types::{ - ChainNameOnAxelar, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, + ChainAxelarId, LocalSigner, SerializableSolanaTransaction, SerializeableVerifierSet, SigningVerifierSet, SolanaTransactionParams, }; use crate::utils::{ @@ -323,7 +323,7 @@ async fn get_verifier_set( let multisig_prover_address = { let address = String::deserialize( &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] - [ChainNameOnAxelar::from(config.network_type).0][ADDRESS_KEY], + [ChainAxelarId::from(config.network_type).0][ADDRESS_KEY], )?; cosmrs::AccountId::from_str(&address).unwrap() @@ -465,7 +465,7 @@ async fn init( let payer = *fee_payer; let upgrade_authority = payer; - chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + chains_info[CHAINS_KEY][ChainAxelarId::from(config.network_type).0][CONTRACTS_KEY] [GATEWAY_KEY] = json!({ ADDRESS_KEY: axelar_solana_gateway::id().to_string(), UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), @@ -546,7 +546,7 @@ fn approve( id: approve_args.message_id, }, source_address: approve_args.source_address, - destination_chain: ChainNameOnAxelar::from(config.network_type).0, + destination_chain: ChainAxelarId::from(config.network_type).0, destination_address: approve_args.destination_address, payload_hash, }; @@ -643,7 +643,7 @@ async fn submit_proof( let multisig_prover_address = { let address = String::deserialize( &chains_info[AXELAR_KEY][CONTRACTS_KEY][MULTISIG_PROVER_KEY] - [ChainNameOnAxelar::from(config.network_type).0][ADDRESS_KEY], + [ChainAxelarId::from(config.network_type).0][ADDRESS_KEY], )?; cosmrs::AccountId::from_str(&address).unwrap() @@ -781,7 +781,7 @@ async fn execute( id: execute_args.message_id, }, source_address: execute_args.source_address, - destination_chain: ChainNameOnAxelar::from(config.network_type).0, + destination_chain: ChainAxelarId::from(config.network_type).0, destination_address: execute_args.destination_address, payload_hash: solana_sdk::keccak::hashv(&[&hex::decode( execute_args diff --git a/solana/src/governance.rs b/solana/src/governance.rs index 7bf4e0104..0b7e86fd2 100644 --- a/solana/src/governance.rs +++ b/solana/src/governance.rs @@ -7,12 +7,13 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; -use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::types::{SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::utils::SOLANA_CHAIN_KEY; use crate::utils::{ - ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, GOVERNANCE_ADDRESS_KEY, - GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, UPGRADE_AUTHORITY_KEY, fetch_latest_blockhash, parse_account_meta_string, read_json_file_from_path, - write_json_to_file_path, + write_json_to_file_path, ADDRESS_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, CONTRACTS_KEY, + GOVERNANCE_ADDRESS_KEY, GOVERNANCE_CHAIN_KEY, GOVERNANCE_KEY, MINIMUM_PROPOSAL_ETA_DELAY_KEY, + UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -168,8 +169,7 @@ fn init( ); let mut chains_info: serde_json::Value = read_json_file_from_path(&config.chains_info_file)?; - chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [GOVERNANCE_KEY] = serde_json::json!({ + chains_info[CHAINS_KEY][SOLANA_CHAIN_KEY][CONTRACTS_KEY][GOVERNANCE_KEY] = serde_json::json!({ ADDRESS_KEY: axelar_solana_gateway::id().to_string(), CONFIG_ACCOUNT_KEY: config_pda.to_string(), UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), @@ -180,11 +180,9 @@ fn init( write_json_to_file_path(&chains_info, &config.chains_info_file)?; - Ok(vec![ - IxBuilder::new() - .initialize_config(fee_payer, config_pda, governance_config) - .build(), - ]) + Ok(vec![IxBuilder::new() + .initialize_config(fee_payer, config_pda, governance_config) + .build()]) } fn execute_proposal( @@ -211,9 +209,9 @@ fn execute_proposal( calldata_bytes, ); - Ok(vec![ - builder.execute_proposal(fee_payer, config_pda).build(), - ]) + Ok(vec![builder + .execute_proposal(fee_payer, config_pda) + .build()]) } fn execute_operator_proposal( @@ -237,9 +235,7 @@ fn execute_operator_proposal( calldata_bytes, ); - Ok(vec![ - builder - .execute_operator_proposal(fee_payer, config_pda, &args.operator) - .build(), - ]) + Ok(vec![builder + .execute_operator_proposal(fee_payer, config_pda, &args.operator) + .build()]) } diff --git a/solana/src/its.rs b/solana/src/its.rs index 35bae66dc..4bc47029b 100644 --- a/solana/src/its.rs +++ b/solana/src/its.rs @@ -11,11 +11,11 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::Transaction as SolanaTransaction; use crate::config::Config; -use crate::types::{ChainNameOnAxelar, SerializableSolanaTransaction, SolanaTransactionParams}; +use crate::types::{ChainAxelarId, SerializableSolanaTransaction, SolanaTransactionParams}; use crate::utils::{ decode_its_destination, fetch_latest_blockhash, read_json_file_from_path, write_json_to_file_path, ADDRESS_KEY, AXELAR_KEY, CHAINS_KEY, CONFIG_ACCOUNT_KEY, - CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, UPGRADE_AUTHORITY_KEY, + CONTRACTS_KEY, GAS_SERVICE_KEY, ITS_KEY, OPERATOR_KEY, SOLANA_CHAIN_KEY, UPGRADE_AUTHORITY_KEY, }; #[derive(Subcommand, Debug)] @@ -766,7 +766,7 @@ fn try_infer_gas_service_id(maybe_arg: Option, config: &Config) -> eyre: Ok(id) } else { let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + &chains_info[SOLANA_CHAIN_KEY][CONTRACTS_KEY] [GAS_SERVICE_KEY][ADDRESS_KEY], ).map_err(|_| eyre!( "Could not get the gas service id from the chains info JSON file. Is it already deployed? \ @@ -785,7 +785,7 @@ fn try_infer_gas_service_config_account( Ok(id) } else { let id = Pubkey::deserialize( - &chains_info[ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] + &chains_info[SOLANA_CHAIN_KEY][CONTRACTS_KEY] [GAS_SERVICE_KEY][CONFIG_ACCOUNT_KEY], ).map_err(|_| eyre!( "Could not get the gas service config PDA from the chains info JSON file. Is it already deployed? \ @@ -930,8 +930,7 @@ fn init( String::deserialize(&chains_info[AXELAR_KEY][CONTRACTS_KEY][ITS_KEY][ADDRESS_KEY])?; let its_root_config = axelar_solana_its::find_its_root_pda().0; - chains_info[CHAINS_KEY][ChainNameOnAxelar::from(config.network_type).0][CONTRACTS_KEY] - [ITS_KEY] = serde_json::json!({ + chains_info[CHAINS_KEY][SOLANA_CHAIN_KEY][CONTRACTS_KEY][ITS_KEY] = serde_json::json!({ ADDRESS_KEY: axelar_solana_gateway::id().to_string(), CONFIG_ACCOUNT_KEY: its_root_config.to_string(), UPGRADE_AUTHORITY_KEY: fee_payer.to_string(), @@ -943,7 +942,7 @@ fn init( Ok(vec![axelar_solana_its::instruction::initialize( *fee_payer, init_args.operator, - ChainNameOnAxelar::from(config.network_type).0, + ChainAxelarId::from(config.network_type).0, its_hub_address, )?]) } diff --git a/solana/src/main.rs b/solana/src/main.rs index e4f307ca8..5e90c52cb 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -27,7 +27,7 @@ use sign::SignArgs; use solana_clap_v3_utils::input_parsers::parse_url_or_moniker; use solana_clap_v3_utils::keypair::signer_from_path; use solana_sdk::pubkey::Pubkey; -use types::SerializableSolanaTransaction; +use types::{AxelarNetwork, SerializableSolanaTransaction}; use crate::broadcast::broadcast_solana_transaction; use crate::combine::combine_solana_signatures; @@ -44,12 +44,15 @@ struct Cli { #[clap(subcommand)] command: Command, + /// Axelar environment to use. Options: [mainnet, testnet, devnet-amplifier, local]. + #[clap(long, env = "ENV", arg_enum)] + env: AxelarNetwork, /// URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, - /// devnet, localhost]". Defaults to the Solana CLI config URL. + /// devnet, localhost]". Defaults to the value set in the Solana CLI config. #[clap( short, long, - env = "ENV", + env = "CLUSTER", value_parser = parse_url_or_moniker, )] url: Option, @@ -197,7 +200,7 @@ struct MiscCommandArgs { #[tokio::main] async fn main() { - dotenv().ok(); + let _ = dotenv().ok(); if let Err(e) = run().await { eprintln!("\nError: {e:?}"); @@ -218,7 +221,7 @@ async fn run() -> eyre::Result<()> { .or_else(|| maybe_solana_config.as_ref().map(|c| c.json_rpc_url.clone())) .ok_or_else(|| eyre!("No URL provided and no Solana CLI config found"))?; - let config = Config::new(url, cli.output_dir, cli.chains_info_dir)?; + let config = Config::new(url, cli.output_dir, cli.chains_info_dir, cli.env)?; match cli.command { Command::Send(args) => { diff --git a/solana/src/types.rs b/solana/src/types.rs index f47553549..65e614138 100644 --- a/solana/src/types.rs +++ b/solana/src/types.rs @@ -13,21 +13,41 @@ use solana_sdk::transaction::Transaction as SolanaTransaction; #[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum NetworkType { + Local, + Devnet, + Testnet, Mainnet, +} + +#[derive(ArgEnum, Debug, Copy, Clone, PartialEq, Eq)] +pub(crate) enum AxelarNetwork { + DevnetAmplifier, Testnet, - Devnet, - Localnet, + Mainnet, + None, +} + +impl FromStr for AxelarNetwork { + type Err = eyre::Error; + + fn from_str(s: &str) -> eyre::Result { + s.contains("devnet-amplifier") + .then_some(AxelarNetwork::DevnetAmplifier) + .or_else(|| s.contains("testnet").then_some(AxelarNetwork::Testnet)) + .or_else(|| s.contains("mainnet").then_some(AxelarNetwork::Mainnet)) + .ok_or_else(|| eyre!("Invalid Axelar network type: {s}")) + } } impl FromStr for NetworkType { type Err = eyre::Error; fn from_str(s: &str) -> eyre::Result { - s.contains("mainnet") - .then_some(NetworkType::Mainnet) - .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) + s.contains("local") + .then_some(NetworkType::Local) .or_else(|| s.contains("devnet").then_some(NetworkType::Devnet)) - .or_else(|| s.contains("local").then_some(NetworkType::Localnet)) + .or_else(|| s.contains("testnet").then_some(NetworkType::Testnet)) + .or_else(|| s.contains("mainnet").then_some(NetworkType::Mainnet)) .ok_or_else(|| eyre!("Invalid network type: {s}")) } } @@ -39,26 +59,26 @@ impl From for String { } } -impl From for ChainsInfoFile { - fn from(value: NetworkType) -> Self { +impl From for ChainsInfoFile { + fn from(value: AxelarNetwork) -> Self { match value { - NetworkType::Mainnet => Self("mainnet.json".to_owned()), - NetworkType::Testnet => Self("testnet.json".to_owned()), - NetworkType::Devnet => Self("devnet-amplifier.json".to_owned()), - NetworkType::Localnet => Self("local.json".to_owned()), + AxelarNetwork::Mainnet => Self("mainnet.json".to_owned()), + AxelarNetwork::Testnet => Self("testnet.json".to_owned()), + AxelarNetwork::DevnetAmplifier => Self("devnet-amplifier.json".to_owned()), + AxelarNetwork::None => Self("local.json".to_owned()), } } } -pub(crate) struct ChainNameOnAxelar(pub(crate) String); +pub(crate) struct ChainAxelarId(pub(crate) String); -impl From for ChainNameOnAxelar { +impl From for ChainAxelarId { fn from(value: NetworkType) -> Self { match value { - NetworkType::Mainnet => Self("solana".to_owned()), - NetworkType::Testnet => Self("solana-testnet".to_owned()), + NetworkType::Local => Self("solana-localnet".to_owned()), NetworkType::Devnet => Self("solana-devnet".to_owned()), - NetworkType::Localnet => Self("solana-localnet".to_owned()), + NetworkType::Testnet => Self("solana-testnet".to_owned()), + NetworkType::Mainnet => Self("solana".to_owned()), } } } diff --git a/solana/src/utils.rs b/solana/src/utils.rs index 328af6e20..6e55d915f 100644 --- a/solana/src/utils.rs +++ b/solana/src/utils.rs @@ -21,8 +21,7 @@ use solana_sdk::signature::Signature; use crate::config::Config; use crate::types::{ - ChainNameOnAxelar, NetworkType, PartialSignature, SignedSolanaTransaction, - UnsignedSolanaTransaction, + NetworkType, PartialSignature, SignedSolanaTransaction, UnsignedSolanaTransaction, }; pub(crate) use solana_sdk::instruction::AccountMeta; @@ -61,6 +60,7 @@ pub(crate) const MULTISIG_PROVER_KEY: &str = "MultisigProver"; pub(crate) const OPERATOR_KEY: &str = "operator"; pub(crate) const PREVIOUS_SIGNERS_RETENTION_KEY: &str = "previousSignersRetention"; pub(crate) const ROUTER_KEY: &str = "Router"; +pub(crate) const SOLANA_CHAIN_KEY: &str = "solana"; pub(crate) const UPGRADE_AUTHORITY_KEY: &str = "upgradeAuthority"; pub(crate) fn read_json_file(file: &File) -> eyre::Result { @@ -185,10 +185,10 @@ pub(crate) fn print_transaction_result( println!(" RPC Endpoint: {}", config.url); let explorer_base_url = "https://explorer.solana.com/tx/"; let cluster_param = match config.network_type { - NetworkType::Mainnet => "", - NetworkType::Testnet => "?cluster=testnet", + NetworkType::Local => "?cluster=custom", NetworkType::Devnet => "?cluster=devnet", - NetworkType::Localnet => "?cluster=custom", + NetworkType::Testnet => "?cluster=testnet", + NetworkType::Mainnet => "", }; println!(" Explorer Link: {explorer_base_url}{tx_signature}{cluster_param}"); println!("------------------------------------------"); @@ -209,13 +209,11 @@ pub(crate) fn domain_separator( chains_info: &serde_json::Value, network_type: NetworkType, ) -> eyre::Result<[u8; 32]> { - if network_type == NetworkType::Localnet { + if network_type == NetworkType::Local { return Ok([0; 32]); } - let axelar_id = String::deserialize( - &chains_info[CHAINS_KEY][ChainNameOnAxelar::from(network_type).0][AXELAR_ID_KEY], - )?; + let axelar_id = String::deserialize(&chains_info[CHAINS_KEY][SOLANA_CHAIN_KEY][AXELAR_ID_KEY])?; let router_address = String::deserialize( &chains_info[CHAINS_KEY][AXELAR_KEY][CONTRACTS_KEY][ROUTER_KEY][ADDRESS_KEY], )?; From f0f45364318d31809e6a9a995cfd02f3753a125d Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 15:28:04 +0200 Subject: [PATCH 56/59] fix(solana): fix send missing signers Signed-off-by: Guilherme Felipe da Silva --- solana/src/send.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/solana/src/send.rs b/solana/src/send.rs index 50362bc9b..1aa0c37d0 100644 --- a/solana/src/send.rs +++ b/solana/src/send.rs @@ -31,7 +31,11 @@ fn load_signers( ) -> eyre::Result>> { // We relax one signer as it is the fee payer if signers_paths.len() < transaction.signatures.len() - 1 { - eyre::bail!("Not enough signers provided"); + eyre::bail!( + "Not enough signers provided: {}/{}", + signers_paths.len(), + transaction.signatures.len() - 1 + ); } let mut signers = Vec::with_capacity(transaction.signatures.len()); @@ -192,7 +196,7 @@ pub(crate) fn sign_and_send_transactions( for serializable_tx in serializable_txs { let transaction = serializable_tx.transaction; let mut signers = load_signers(&signers, &transaction)?; - signers.push(Box::new(shared_payer.clone())); + signers.push(Box::new(Rc::clone(&shared_payer))); let blockhash = rpc_client.get_latest_blockhash()?; let optimized_tx = optimize_transaction(&transaction, &signers, &rpc_client, &blockhash)?; From 9d76afd7773676d53b1396f410962d611c1731c5 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 15:29:33 +0200 Subject: [PATCH 57/59] feat(solana): add `query` subcommand On solana, transactions are not used to query the ledger, instead we use get_account RPC method to fetch account information. Signed-off-by: Guilherme Felipe da Silva --- solana/Cargo.lock | 99 ++++++++++++++++++++++----- solana/Cargo.toml | 18 ++--- solana/src/gateway.rs | 153 ++++++++++++++++++++++++++++++++++++++---- solana/src/main.rs | 24 ++++++- solana/src/misc.rs | 4 +- 5 files changed, 258 insertions(+), 40 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index d75a4c3a0..4e521e70f 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -466,6 +466,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "async-channel" version = "1.9.0" @@ -577,7 +583,7 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axelar-executable" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-sol-types", "axelar-solana-encoding", @@ -592,7 +598,7 @@ dependencies = [ [[package]] name = "axelar-message-primitives" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -608,7 +614,7 @@ dependencies = [ [[package]] name = "axelar-solana-encoding" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "arrayref", "borsh 1.5.7", @@ -625,7 +631,7 @@ dependencies = [ [[package]] name = "axelar-solana-gas-service" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "axelar-solana-gas-service-events", "borsh 1.5.7", @@ -639,7 +645,7 @@ dependencies = [ [[package]] name = "axelar-solana-gas-service-events" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "event-utils", "solana-program", @@ -648,7 +654,7 @@ dependencies = [ [[package]] name = "axelar-solana-gateway" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "axelar-message-primitives", "axelar-solana-encoding", @@ -672,7 +678,7 @@ dependencies = [ [[package]] name = "axelar-solana-governance" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-sol-types", "axelar-executable", @@ -689,7 +695,7 @@ dependencies = [ [[package]] name = "axelar-solana-its" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -707,7 +713,7 @@ dependencies = [ "program-utils", "role-management", "solana-program", - "spl-associated-token-account", + "spl-associated-token-account 6.0.0", "spl-token-2022 6.0.0", "typed-builder", ] @@ -2192,7 +2198,7 @@ dependencies = [ [[package]] name = "event-macros" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "keccak-const", "quote", @@ -2202,7 +2208,7 @@ dependencies = [ [[package]] name = "event-utils" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "axelar-message-primitives", "base64 0.21.7", @@ -2476,6 +2482,19 @@ dependencies = [ "slab", ] +[[package]] +name = "gateway-event-stack" +version = "0.1.0" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" +dependencies = [ + "axelar-solana-gas-service-events", + "axelar-solana-gateway", + "base64 0.21.7", + "event-utils", + "solana-sdk", + "tracing", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2547,7 +2566,7 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "governance-gmp" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -3015,7 +3034,7 @@ dependencies = [ [[package]] name = "interchain-token-transfer-gmp" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -3076,7 +3095,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "its-instruction-builder" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "async-recursion", "axelar-executable", @@ -3977,7 +3996,7 @@ dependencies = [ [[package]] name = "program-utils" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "borsh 1.5.7", "bytemuck", @@ -4022,7 +4041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.101", @@ -4508,7 +4527,7 @@ dependencies = [ [[package]] name = "role-management" version = "0.1.0" -source = "git+https://github.com/eigerco/solana-axelar.git?rev=52a8328#52a8328e83d09bd600ff6086a95869d7b5ae964f" +source = "git+https://github.com/eigerco/solana-axelar.git?rev=660f0db#660f0db35f91c7e8d3910ad21f5f3b103734d532" dependencies = [ "bincode 1.3.3", "bitflags 2.9.0", @@ -5334,6 +5353,7 @@ dependencies = [ "cosmwasm-std", "dotenvy", "eyre", + "gateway-event-stack", "hex", "its-instruction-builder", "k256", @@ -5343,6 +5363,7 @@ dependencies = [ "solana-cli-config", "solana-client", "solana-sdk", + "solana-transaction-status", "spl-token 6.0.0", "spl-token-2022 6.0.0", "tokio", @@ -6465,6 +6486,34 @@ dependencies = [ "solana-short-vec", ] +[[package]] +name = "solana-transaction-status" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d551f506a53022863458d85e4088de58f6938cc0a27d6454bc055ee5fd42ea3f" +dependencies = [ + "Inflector", + "base64 0.22.1", + "bincode 1.3.3", + "borsh 1.5.7", + "bs58", + "lazy_static", + "log", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status-client-types", + "spl-associated-token-account 4.0.0", + "spl-memo 5.0.0", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "thiserror 1.0.69", +] + [[package]] name = "solana-transaction-status-client-types" version = "2.1.16" @@ -6657,6 +6706,22 @@ dependencies = [ "der", ] +[[package]] +name = "spl-associated-token-account" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68034596cf4804880d265f834af1ff2f821ad5293e41fa0f8f59086c181fc38e" +dependencies = [ + "assert_matches", + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "thiserror 1.0.69", +] + [[package]] name = "spl-associated-token-account" version = "6.0.0" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 9b460dbaf..3b5e0a3e5 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -4,21 +4,22 @@ version = "0.1.0" edition = "2024" [dependencies] -axelar-solana-gateway = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ +axelar-solana-gateway = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db", features = [ "no-entrypoint", ] } -axelar-solana-gas-service = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ +axelar-solana-gas-service = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db", features = [ "no-entrypoint", ] } -axelar-solana-governance = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ +axelar-solana-governance = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db", features = [ "no-entrypoint", ] } -axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328", features = [ +axelar-solana-its = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db", features = [ "no-entrypoint" ] } -axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } -axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } -its-instruction-builder = { git = "https://github.com/eigerco/solana-axelar.git", rev = "52a8328" } +axelar-solana-encoding = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db" } +axelar-executable = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db" } +gateway-event-stack = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db" } +its-instruction-builder = { git = "https://github.com/eigerco/solana-axelar.git", rev = "660f0db" } axelar-wasm-std = { git = "https://github.com/axelarnetwork/axelar-amplifier.git", rev = "voting-verifier-v1.1.0" } @@ -28,6 +29,7 @@ borsh = "1.5.1" clap = { version = "3.2", features = ["derive", "env"] } cosmrs = { version = "0.16", features = ["cosmwasm", "rpc", "grpc"] } cosmwasm-std = "1.5" +dotenvy = { version = "0.15.7", features = ["cli"] } eyre = "0.6.11" hex = { version = "0.4.3", features = ["serde"] } k256 = { version = "0.13", features = ["pkcs8", "pem", "ecdsa"] } @@ -37,10 +39,10 @@ solana-clap-v3-utils = "2" solana-cli-config = "2" solana-client = "2" solana-sdk = "2" +solana-transaction-status = "2" spl-token = { version = "6", features = ["no-entrypoint"] } spl-token-2022 = { version = "6", features = ["no-entrypoint"] } tokio = { version = "1", features = ["full"] } -dotenvy = { version = "0.15.7", features = ["cli"] } [lints.clippy] cargo = { priority = -1, level = "deny" } diff --git a/solana/src/gateway.rs b/solana/src/gateway.rs index 80ef6e07a..25c87aea7 100644 --- a/solana/src/gateway.rs +++ b/solana/src/gateway.rs @@ -11,19 +11,24 @@ use axelar_solana_encoding::types::pubkey::{PublicKey, Signature}; use axelar_solana_encoding::types::verifier_set::VerifierSet; use axelar_solana_gateway::state::config::RotationDelaySecs; use axelar_solana_gateway::state::incoming_message::command_id; -use clap::{ArgGroup, Parser, Subcommand}; +use axelar_solana_gateway::BytemuckedPda; +use clap::{ArgGroup, Args, Parser, Subcommand}; use cosmrs::proto::cosmwasm::wasm::v1::query_client; use eyre::eyre; +use gateway_event_stack::{MatchContext, ProgramInvocationState}; use k256::ecdsa::SigningKey; use k256::elliptic_curve::sec1::ToEncodedPoint; use serde::Deserialize; use serde_json::json; +use solana_client::rpc_client::RpcClient; use solana_sdk::hash::Hash; use solana_sdk::instruction::Instruction; use solana_sdk::message::Message as SolanaMessage; use solana_sdk::packet::PACKET_DATA_SIZE; use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Signature as SolanaSignature; use solana_sdk::transaction::Transaction as SolanaTransaction; +use solana_transaction_status::UiTransactionEncoding; use crate::config::Config; use crate::multisig_prover_types::msg::ProofStatus; @@ -66,6 +71,35 @@ pub(crate) enum Commands { Execute(ExecuteArgs), } +/// Commands for querying gateway related data +#[derive(Subcommand, Debug)] +pub(crate) enum QueryCommands { + /// Get GatewayEvents from a transaction + Events(EventsArgs), + + /// Query message status on Gateway + MessageStatus(MessageStatusArgs), +} + +#[derive(Args, Debug)] +pub(crate) struct EventsArgs { + /// The transaction signature to get events from + signature: String, + + /// Print all event data + #[clap(long)] + full: bool, +} + +#[derive(Args, Debug)] +pub(crate) struct MessageStatusArgs { + /// The name of the chain from which the message was sent as it is registered with Axelar + source_chain: String, + + /// Message ID + full: String, +} + #[derive(Parser, Debug)] #[clap( group( @@ -263,7 +297,7 @@ pub(crate) async fn build_transaction( Ok(serializable_transactions) } -async fn query( +async fn query_axelar( mut endpoint: String, address: cosmrs::AccountId, query_data: Vec, @@ -329,12 +363,13 @@ async fn get_verifier_set( cosmrs::AccountId::from_str(&address).unwrap() }; let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; - let multisig_prover_response = query::( - axelar_grpc_endpoint, - multisig_prover_address, - serde_json::to_vec(&crate::multisig_prover_types::QueryMsg::CurrentVerifierSet)?, - ) - .await?; + let multisig_prover_response = + query_axelar::( + axelar_grpc_endpoint, + multisig_prover_address, + serde_json::to_vec(&crate::multisig_prover_types::QueryMsg::CurrentVerifierSet)?, + ) + .await?; let mut signers = BTreeMap::new(); for signer in multisig_prover_response.verifier_set.signers.values() { @@ -495,16 +530,13 @@ fn call_contract( fee_payer: &Pubkey, call_contract_args: CallContractArgs, ) -> eyre::Result> { - let (signing_pda, signing_pda_bump) = - axelar_solana_gateway::get_call_contract_signing_pda(*fee_payer); let payload = hex::decode(call_contract_args.payload)?; Ok(vec![axelar_solana_gateway::instructions::call_contract( axelar_solana_gateway::id(), axelar_solana_gateway::get_gateway_root_config_pda().0, *fee_payer, - signing_pda, - signing_pda_bump, + None, call_contract_args.destination_chain, call_contract_args.destination_address, payload, @@ -572,6 +604,11 @@ fn approve( let (incoming_message_pda, _bump) = axelar_solana_gateway::get_incoming_message_pda(&command_id); + println!( + "Building instruction to approve message from {} with id: {}", + merkleised_message.leaf.message.cc_id.chain, merkleised_message.leaf.message.cc_id.id + ); + instructions.push(axelar_solana_gateway::instructions::approve_message( merkleised_message, execute_data.payload_merkle_root, @@ -649,7 +686,7 @@ async fn submit_proof( cosmrs::AccountId::from_str(&address).unwrap() }; let axelar_grpc_endpoint = String::deserialize(&chains_info[AXELAR_KEY][GRPC_KEY])?; - let multisig_prover_response = query::( + let multisig_prover_response = query_axelar::( axelar_grpc_endpoint, multisig_prover_address, serde_json::to_vec(&crate::multisig_prover_types::QueryMsg::Proof { @@ -676,6 +713,7 @@ async fn submit_proof( MerkleisedPayload::VerifierSetRotation { new_verifier_set_merkle_root, } => { + println!("Building instruction to rotate signers"); let (verifier_set_tracker_pda, _bump) = axelar_solana_gateway::get_verifier_set_tracker_pda( execute_data.signing_verifier_set_merkle_root, @@ -694,6 +732,10 @@ async fn submit_proof( } MerkleisedPayload::NewMessages { messages } => { for message in messages { + println!( + "Building instruction to approve message from {} with id: {}", + message.leaf.message.cc_id.chain, message.leaf.message.cc_id.id + ); let command_id = command_id( message.leaf.message.cc_id.chain.as_str(), message.leaf.message.cc_id.id.as_str(), @@ -877,3 +919,88 @@ async fn execute( Ok(instructions) } + +pub(crate) fn query(command: QueryCommands, config: &Config) -> eyre::Result<()> { + match command { + QueryCommands::Events(args) => events(args, config), + QueryCommands::MessageStatus(args) => message_status(args, config), + } +} + +fn events(args: EventsArgs, config: &Config) -> eyre::Result<()> { + let rpc_client = RpcClient::new(config.url.clone()); + let signature = SolanaSignature::from_str(&args.signature)?; + let transaction = rpc_client.get_transaction(&signature, UiTransactionEncoding::Base58)?; + + let log_messages = transaction + .transaction + .meta + .ok_or_else(|| eyre!("Transaction missing metadata"))? + .log_messages + .ok_or_else(|| eyre!("Transaction missing log messages"))?; + + let gateway_id_string = axelar_solana_gateway::id().to_string(); + let gateway_match_ctx = MatchContext::new(&gateway_id_string); + + let invocations = gateway_event_stack::build_program_event_stack( + &gateway_match_ctx, + &log_messages, + gateway_event_stack::parse_gateway_logs, + ); + + for (i, invocation) in invocations.into_iter().enumerate() { + println!("\u{2728} Invocation index [{i}]: "); + let events = match invocation { + ProgramInvocationState::InProgress(items) + | ProgramInvocationState::Failed(items) + | ProgramInvocationState::Succeeded(items) => items, + }; + + if events.is_empty() { + println!("\t\u{1F4EA} No gateway events found"); + } + + for event in events { + print!("\t\u{1F4EC} Event index [{}]: ", event.0); + let raw_output = format!("{:#?}", event.1); + + let output = if args.full { + &raw_output + } else { + raw_output.split_once('(').unwrap().0 + }; + + println!("{output}"); + } + } + + Ok(()) +} + +fn message_status(args: MessageStatusArgs, config: &Config) -> eyre::Result<()> { + let rpc_client = RpcClient::new(config.url.clone()); + let command_id = command_id(&args.source_chain, &args.full); + let (incoming_message_pda, _) = axelar_solana_gateway::get_incoming_message_pda(&command_id); + let raw_incoming_message = + rpc_client + .get_account_data(&incoming_message_pda) + .map_err(|_| { + eyre!("Couldn't fetch information about given message. Are the details correct?") + })?; + + match axelar_solana_gateway::state::incoming_message::IncomingMessage::read( + &raw_incoming_message, + ) { + Some(incoming_message) => { + let status = if incoming_message.status.is_approved() { + String::from("Approved") + } else { + String::from("Executed") + }; + println!("Message status: {status}"); + } + None => eyre::bail!("Failed to deserialize message data"), + }; + + Ok(()) +} diff --git a/solana/src/main.rs b/solana/src/main.rs index 5e90c52cb..0d2261ba2 100644 --- a/solana/src/main.rs +++ b/solana/src/main.rs @@ -47,6 +47,7 @@ struct Cli { /// Axelar environment to use. Options: [mainnet, testnet, devnet-amplifier, local]. #[clap(long, env = "ENV", arg_enum)] env: AxelarNetwork, + /// URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, /// devnet, localhost]". Defaults to the value set in the Solana CLI config. #[clap( @@ -92,6 +93,9 @@ enum Command { /// Miscellaneous utilities. Misc(MiscCommandArgs), + + /// Query data from Solana. + Query(QueryCommandArgs), } #[derive(Parser, Debug)] @@ -198,6 +202,19 @@ struct MiscCommandArgs { instruction: misc::Commands, } +#[derive(Parser, Debug)] +struct QueryCommandArgs { + #[clap(subcommand)] + instruction: QueryInstructionSubcommand, +} + +#[derive(Subcommand, Debug)] +enum QueryInstructionSubcommand { + /// Commands to query data from the AxelarGateway program on Solana + #[clap(subcommand)] + Gateway(gateway::QueryCommands), +} + #[tokio::main] async fn main() { let _ = dotenv().ok(); @@ -280,8 +297,13 @@ async fn run() -> eyre::Result<()> { broadcast_solana_transaction(&broadcast_args, &config)?; } Command::Misc(args) => { - do_misc(args.instruction)?; + do_misc(args.instruction, &config)?; } + Command::Query(args) => match args.instruction { + QueryInstructionSubcommand::Gateway(command) => { + gateway::query(command, &config)?; + } + }, } Ok(()) } diff --git a/solana/src/misc.rs b/solana/src/misc.rs index 1f9c47dd8..21e76beed 100644 --- a/solana/src/misc.rs +++ b/solana/src/misc.rs @@ -7,6 +7,8 @@ use eyre::Result; use solana_sdk::instruction::AccountMeta; use solana_sdk::pubkey::Pubkey; +use crate::Config; + /// Commands for miscellaneous utilities #[derive(Subcommand, Debug)] pub(crate) enum Commands { @@ -30,7 +32,7 @@ pub(crate) struct BuildAxelarMessageArgs { } /// Build a message for miscellaneous utilities -pub(crate) fn do_misc(args: Commands) -> Result<()> { +pub(crate) fn do_misc(args: Commands, _config: &Config) -> Result<()> { match args { Commands::BuildAxelarMessage(args) => build_axelar_message(args), } From b4999660453d7c4d17dc67dbb315cf34256185bd Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 15:30:26 +0200 Subject: [PATCH 58/59] chore(solana): update release docs Signed-off-by: Guilherme Felipe da Silva --- releases/solana/2025-05-GMP-v1.0.0.md | 206 +++++++++++++++++--------- releases/solana/2025-05-ITS-v1.0.0.md | 102 +++++++++++-- 2 files changed, 226 insertions(+), 82 deletions(-) diff --git a/releases/solana/2025-05-GMP-v1.0.0.md b/releases/solana/2025-05-GMP-v1.0.0.md index ecfeb965f..14fdf70b0 100644 --- a/releases/solana/2025-05-GMP-v1.0.0.md +++ b/releases/solana/2025-05-GMP-v1.0.0.md @@ -22,55 +22,97 @@ This is the v1.0.0 Solana GMP release, introducing General Message Passing (GMP) ### Prerequisites -1. Install Solana CLI: +1. Ensure you have Rust installed. If you don't: ```sh -sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -2. Clone the solana-axelar repository. +2. Install Solana CLI: -3. Build the Solana programs: +```sh +sh -c "$(curl -sSfL https://release.anza.xyz/v2.2.14/install)" +``` + +3. Install `solana-verify`, for verifiable builds: + +```sh +cargo install solana-verify --locked 0.4.4 +``` + +4. Clone the solana-axelar repository and checkout the appropriate version. + +5. Build the Solana programs: + +In order to get verifiable builds, we use `solana-verify` tool. Set the `BASE_IMAGE` variable: + +```sh +export BASE_IMAGE="solanafoundation/solana-verifiable-build@sha256:979b09eef544de4502a92e28a724a8498a08e2fe506e8905b642e613760403d3" +``` ```sh # Go to the solana directory within the cloned repo -pushd solana-axelar/solana/ +pushd solana-axelar/ # Compile the Solana programs -cargo xtask build +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_gateway +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_gas_service +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_governance +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_multicall # Go back popd ``` -4. Set up environment configuration: +6. Set up environment configuration: + +Create an `.env` config. `CLUSTER` should be set to `mainnet-beta` when `ENV` is set to `mainnet`, and to `devnet` otherwise. + +```yaml +ENV= +CLUSTER= +``` + +#### Devnet-amplifier / Stagenet / Testnet ```sh # Set default cluster -solana config set --url testnet # Use appropriate network: testnet, devnet, mainnet-beta, or localhost +solana config set --url devnet # Generate a new keypair if needed -solana-keygen new +solana-keygen new # Get funds solana airdrop 2 ``` +#### Mainnet + +```sh +# Set default cluster +solana config set --url mainnet-beta + +# Generate a new keypair if needed +solana-keygen new +``` + +In this case the wallet needs to be funded with real `SOL`. + ### Initial Solana Config -Add Solana chain config to the `axelar-chains-config/info/.json` file under the `chains` key. +Add Solana chain config to the `axelar-chains-config/info/.json` file under the `chains` key. -#### Devnet-amplifier: +#### Devnet-amplifier / Stagenet/ Testnet ```json -"solana-devnet": { +"solana": { "name": "Solana Devnet", "axelarId": "solana-devnet", "rpc": "https://api.devnet.solana.com", "chainType": "svm", "decimals": 9, - "finality": TBD, - "approxFinalityWaitTime": 13, + "finality": "31", + "approxFinalityWaitTime": 1, "tokenSymbol": "SOL", "explorer": { "name": "Solana Explorer", @@ -80,26 +122,6 @@ Add Solana chain config to the `axelar-chains-config/info/ +GATEWAY_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_gateway.so" + +GAS_SERVICE_PROGRAM_KEYPAIR_PATH= +GAS_SERVICE_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_gas_service.so" + +GOVERNANCE_PROGRAM_KEYPAIR_PATH= +GOVERNANCE_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_governance.so" + +MULTICALL_PROGRAM_KEYPAIR_PATH= +MULTICALL_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_multicall.so" + +UPGRADE_AUTHORITY_PUBKEY= +``` + +2. Deploy and verify Gateway program: ```sh -solana program-v4 deploy \ - --program-keypair \ - --authority \ - solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so +solana program-v4 deploy --program-keypair $GATEWAY_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GATEWAY_PROGRAM_PATH + + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GATEWAY_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -2. Deploy Gas Service program: +3. Deploy and verify Gas Service program: ```sh -solana program-v4 deploy \ - --program-keypair \ - --authority \ - solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so +solana program-v4 deploy --program-keypair $GAS_SERVICE_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GAS_SERVICE_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GAS_SERVICE_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -3. Deploy Governance program: +4. Deploy and verify Governance program: ```sh -solana program-v4 deploy \ - --program-keypair \ - --authority \ - solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so +solana program-v4 deploy --program-keypair $GOVERNANCE_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GOVERNANCE_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GOVERNANCE_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -4. Deploy Multicall program: +5. Deploy Multicall program: ```sh -solana program-v4 deploy \ - --program-keypair \ - --authority \ - solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so +solana program-v4 deploy --program-keypair $MULTICALL_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $MULTICALL_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $MULTICALL_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -5. After deploying Solana contracts, deploy the [Solana GMP Amplifier](../cosmwasm/2025-05-Solana-GMP-v1.0.0.md). +6. After deploying Solana contracts, deploy the [Solana GMP Amplifier](../cosmwasm/2025-05-Solana-GMP-v1.0.0.md). ### Initialization Steps @@ -166,20 +202,39 @@ solana program-v4 deploy \ | Network | `minimumRotationDelay` | `previousSignersRetention` | | -------------------- | ---------------------- | -------------------------- | -| **Devnet-amplifier** | TBD | TBD | -| **Testnet** | TBD | TBD | -| **Mainnet** | TBD | TBD | +| **Devnet-amplifier** | `0` | `15` | +| **Stagenet** | `300` | `15` | +| **Testnet** | `3600` | `15` | +| **Mainnet** | `86400` | `15` | ```sh solana/solana-axelar-cli send gateway init \ - --previous-signers-retention \ + --previous-signers-retention 15 \ --minimum-rotation-delay \ - --operator + --operator ``` This will query the `MultisigProver` for the `VerifierSet`. Thus, the Solana `MultisigProver` must be deployed before this step and its information available within the appropriate object in the `axelar-chains-config/info/.json` file. +2. Initialize Gas Service: + +```sh +solana/solana-axelar-cli send gas-service init \ + --authority \ + --salt +``` + +3. Initialize Governance: + +```sh +solana/solana-axelar-cli send governance init \ + --governance-chain \ + --governance-address \ + --minimum-proposal-eta-delay \ + --operator +``` + ## Checklist The following checks should be performed after the rollout: @@ -195,20 +250,26 @@ solana/solana-axelar-cli send gateway call-contract \ --payload ``` -2. Route GMP call via Amplifier: +2. Get the event index using the previous transaction signature from the previous step. You should look for the index of the `CallContract` event: + +```sh +solana/solana-axelar-cli query gateway events +``` + +3. Route GMP call via Amplifier using the event index from the previous step as `TX_EVENT`: - -3. Submit proof with multisig session ID: +4. Submit proof with multisig session ID: ```sh -# Set PRIVATE_KEY within .env +# Change `PRIVATE_KEY in `.env` to EVM PRIVATE_KEY= node evm/gateway.js -n --action submitProof --multisigSessionId ``` -4. Confirm message approval: +5. Confirm message approval: ```sh node evm/gateway.js -n --action isContractCallApproved --commandID --sourceChain --sourceAddress --destination --payloadHash @@ -231,3 +292,16 @@ node evm/gateway.js -n --action callContract --destinationChain < ```sh solana/solana-axelar-cli send gateway submit-proof \ --multisig-session-id +``` + +4. Confirm the message has been approved: + +```sh +solana/solana-axelar-cli query gateway message-status +``` + +You should see: + +``` +Message Status: Approved +``` diff --git a/releases/solana/2025-05-ITS-v1.0.0.md b/releases/solana/2025-05-ITS-v1.0.0.md index 7489dc375..42626242c 100644 --- a/releases/solana/2025-05-ITS-v1.0.0.md +++ b/releases/solana/2025-05-ITS-v1.0.0.md @@ -20,42 +20,112 @@ This is the v1.0.0 Solana ITS release, bringing Interchain Token Service capabil ## Deployment +### Prerequisites + Ensure that [Solana GMP](./2025-05-GMP-v1.0.0.md) is deployed first. -### Set Up Environment +1. Clone the solana-axelar repository and checkout the appropriate version. + +2. Build the Solana InterchainTokenService: + +In order to get verifiable builds, we use `solana-verify` tool. Set the `BASE_IMAGE` variable: +```sh +export BASE_IMAGE="solanafoundation/solana-verifiable-build@sha256:979b09eef544de4502a92e28a724a8498a08e2fe506e8905b642e613760403d3" +``` + +```sh +# Go to the solana directory within the cloned repo +pushd solana-axelar/solana/ + +# Compile Solana InterchainTokenService +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_its + +# Go back +popd +``` + +4. Set up environment configuration: + +Create an `.env` config. `CLUSTER` should be set to `mainnet-beta` when `ENV` is set to `mainnet`, and to `devnet` otherwise. + +```yaml +ENV= +CLUSTER= +``` + +#### Devnet-amplifier / Stagenet / Testnet ```sh # Set default cluster -solana config set --url testnet # Use appropriate network: testnet, devnet, mainnet-beta, or localhost +solana config set --url devnet + +# Generate a new keypair if needed +solana-keygen new + +# Get funds +solana airdrop 2 ``` +#### Mainnet + +```sh +# Set default cluster +solana config set --url mainnet-beta + +# Generate a new keypair if needed +solana-keygen new +``` + +In this case the wallet needs to be funded with real `SOL`. + ### Deployment Steps +1. Declare enviroment variables: +```sh +ITS_PROGRAM_KEYPAIR_PATH= +ITS_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_its.so" +UPGRADE_AUTHORITY_PUBKEY= +``` + 1. Deploy Interchain Token Service: ```sh -solana program-v4 deploy \ - --program-keypair \ - --authority \ - solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so +solana program-v4 deploy --program-keypair $ITS_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $ITS_PROGRAM_PATH ``` 2. Initialize ITS: ```sh -solana/solana-axelar-cli send its init --operator +solana/solana-axelar-cli send its init --operator ``` 4. Register Solana ITS on ITS Hub: -ITS hub contract configuration in `axelar-chains-config/info/.json` must include the following attributes per chain: +ITS hub contract configuration in `axelar-chains-config/info/.json` must include the following attributes per chain: + +#### Devnet-amplifier / Stagenet / Testnet + +```json +"axelar": { + "contracts": { + "InterchainTokenService": { + "solana-devnet": { + "maxUintBits": 64, + "maxDecimalsWhenTruncating": 255 + } + } + } +} +``` + +#### Mainnet ```json "axelar": { "contracts": { "InterchainTokenService": { - "": { + "solana": { "maxUintBits": 64, "maxDecimalsWhenTruncating": 255 } @@ -98,7 +168,7 @@ solana/solana-axelar-cli send its set-trusted-chain # Set PRIVATE_KEY in .env PRIVATE_KEY= -node evm/its.js -n all --action setTrustedAddress --trustedChain --trustedAddress hub +node evm/its.js -n all --action setTrustedAddress --trustedChain --trustedAddress hub ``` ## Checklist @@ -193,27 +263,27 @@ solana/solana-axelar-cli send gateway execute \ 1. Deploy Native Interchain Token: ```sh -node evm/interchainTokenFactory.js --action deployInterchainToken -n --destinationChain --salt --name --symbol --decimals +node evm/interchainTokenFactory.js --action deployInterchainToken -n --destinationChain --salt --name --symbol --decimals -node evm/interchainTokenFactory.js --action deployRemoteInterchainToken -n --destinationChain --salt --gasValue +node evm/interchainTokenFactory.js --action deployRemoteInterchainToken -n --destinationChain --salt --gasValue ``` 2. Interchain Token Transfer for Native Interchain Token: ```sh -node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount +node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount ``` 3. Deploy Remote Canonical Token: ```sh -node evm/interchainTokenFactory.js --action registerCanonicalInterchainToken -n --destinationChain --tokenAddress +node evm/interchainTokenFactory.js --action registerCanonicalInterchainToken -n --destinationChain --tokenAddress -node evm/interchainTokenFactory.js --action deployRemoteCanonicalInterchainToken -n --destinationChain --tokenAddress --gasValue +node evm/interchainTokenFactory.js --action deployRemoteCanonicalInterchainToken -n --destinationChain --tokenAddress --gasValue ``` 4. Interchain Token Transfer for Canonical Token: ```sh -node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount --gasValue +node evm/its.js --action interchainTransfer -n --destinationChain --destinationAddress --tokenId --amount --gasValue ``` From aceaf0d7c242e6185d661abe3ceb0944a56847d7 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe da Silva Date: Wed, 21 May 2025 16:02:46 +0200 Subject: [PATCH 59/59] chore(solana): update readme Signed-off-by: Guilherme Felipe da Silva --- solana/README.md | 107 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/solana/README.md b/solana/README.md index cebce0134..862529a3f 100644 --- a/solana/README.md +++ b/solana/README.md @@ -2,19 +2,29 @@ ## Instalation -Install Solana CLI +1. Ensure you have Rust installed. If you don't: ```sh -sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -For more info on how to install the Solana tooling, check the official documentation [here](https://solana.com/docs/intro/installation). +2. Install Solana CLI: -Create a new Solana keypair +```sh +sh -c "$(curl -sSfL https://release.anza.xyz/v2.2.14/install)" +``` + +3. Install `solana-verify`, for verifiable builds: + +```sh +cargo install solana-verify --locked 0.4.4 +``` + +4. Create a new Solana keypair ```sh # Set default cluster -solana config set --url testnet +solana config set --url devnet # Generate a new keypair solana-keygen new @@ -27,7 +37,7 @@ solana-keygen new --force ``` -Testnet funds can be obtained via [this link](https://faucet.solana.com/) or using the Solana CLI: +5. Devnet funds can be obtained via [this link](https://faucet.solana.com/) or using the Solana CLI: ```sh solana airdrop 2 @@ -41,7 +51,7 @@ Setup 2. Compile the Solana programs. > [!IMPORTANT] -> For the initial deployment of Solana programs to any of the clusters (devnet, testnet, and mainnet-beta), the program keypairs are required. The pubkey is the program ID and is hardcoded in the program using the `declare_id` macro. In case a new set of keypairs is required, a new release of the crates needs to happen afterwards (due to the id being hardcoded). Updating the ids can be done within the `solana-axelar/solana` directory by invoking: +> For the initial deployment of Solana programs to any of the clusters (devnet, testnet, and mainnet-beta), the program keypairs are required. The pubkey is the program ID and is hardcoded in the program using the `declare_id` macro. In case a new set of keypairs is required, a new release of the crates needs to happen afterwards (due to the id being hardcoded). Updating the ids can be done within the `solana-axelar` directory by invoking: > ```sh > cargo xtask update-ids > ``` @@ -50,55 +60,99 @@ Setup > [!NOTE] > Initial deployment of Solana programs doesn't support offline signing, the process needs to be done online. When deploying, an `upgrade-authority` can be set, which will later be able to perform program upgrades — upgrades support offline signing. +In order to get verifiable builds, we use `solana-verify` tool. For more information on how to use the tool - including when multisig is used (which is expected as upgrade authority for mainnet deployments) - visit the [Solana guide for verifiable builds](https://solana.com/developers/guides/advanced/verified-builds). + +Set the `BASE_IMAGE` variable: + +```sh +export BASE_IMAGE="solanafoundation/solana-verifiable-build@sha256:979b09eef544de4502a92e28a724a8498a08e2fe506e8905b642e613760403d3" +``` + ```sh # Go to the solana directory within the cloned repo -pushd solana-axelar/solana/ +pushd solana-axelar # Compile the Solana programs -cargo xtask build +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_gas_service +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_gateway +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_governance +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_its +solana-verify build --base-image $BASE_IMAGE --library-name axelar_solana_multicall # Go back popd ``` +3. Declare enviroment variables: + +```sh +GATEWAY_PROGRAM_KEYPAIR_PATH= +GATEWAY_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_gateway.so" + +GAS_SERVICE_PROGRAM_KEYPAIR_PATH= +GAS_SERVICE_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_gas_service.so" + +GOVERNANCE_PROGRAM_KEYPAIR_PATH= +GOVERNANCE_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_governance.so" + +MULTICALL_PROGRAM_KEYPAIR_PATH= +MULTICALL_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_multicall.so" + +ITS_PROGRAM_KEYPAIR_PATH= +ITS_PROGRAM_PATH="solana-axelar/target/deploy/axelar_solana_its.so" + +UPGRADE_AUTHORITY_PUBKEY= +``` + ### Gateway -Deploy the gateway program. If `--authority` is omitted, the current Solana CLI keypair is set as upgrade-authority. +Deploy and verify the gateway program. If `--authority` is omitted, the current Solana CLI keypair is set as upgrade-authority. ```sh -solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gateway.so +solana program-v4 deploy --program-keypair $GATEWAY_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GATEWAY_PROGRAM_PATH + + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GATEWAY_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` ### Gas Service -Deploy the gas service program +Deploy and verify the gas service program ```sh -solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_gas_service.so +solana program-v4 deploy --program-keypair $GAS_SERVICE_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GAS_SERVICE_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GAS_SERVICE_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -### Interchain Token Service +### Governance -Deploy the ITS program +Deploy and verify the governance program ```sh -solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_its.so +solana program-v4 deploy --program-keypair $GOVERNANCE_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $GOVERNANCE_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $GOVERNANCE_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -### Governance +### Multicall -Deploy the governance program +Deploy and verify the multicall program ```sh -solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_governance.so +solana program-v4 deploy --program-keypair $MULTICALL_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $MULTICALL_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $MULTICALL_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` -### Multicall +### Interchain Token Service -Deploy the multicall program +Deploy and verify the ITS program ```sh -solana program-v4 deploy --program-keypair --authority solana-axelar/solana/target/sbf-solana-solana/release/axelar_solana_multicall.so +solana program-v4 deploy --program-keypair $ITS_PROGRAM_KEYPAIR_PATH --authority $UPGRADE_AUTHORITY_PUBKEY $ITS_PROGRAM_PATH + +solana-verify verify-from-repo --remote --base-image $BASE_IMAGE --commit-hash $COMMIT_HASH --program-id $(solana address -k $ITS_PROGRAM_KEYPAIR_PATH) https://github.com/eigerco/solana-axelar ``` ## Upgrades @@ -134,20 +188,21 @@ Main commands: - `combine`: Combine multiple partial signatures into a single file - `broadcast`: Broadcast a combined signed transaction to the Solana network - `misc`: Miscellaneous utilities +- `query`: Commands used to query accounts or emitted events -`send` and `generate` have associated subcommands for specific contract interactions. +`send`, `generate`, and `query` have associated subcommands for specific contract interactions. ### Network Configuration There are a few different ways you can specify the Solana network to connect to: -By exporting the `ENV` variable in your shell: +By exporting the `CLUSTER` variable in your shell: ```sh -export ENV= +export CLUSTER= ``` -By creating a `.env` file in the root of the project with the `ENV=` entry or, on every command: +By creating a `.env` file in the root of the project with the `CLUSTEr=` entry or, on every command: ```sh solana/solana-axelar-cli --url [OPTIONS]