diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e955d276..dc6e245e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "carpe" -version = "1.0.5" +version = "1.1.1" authors = ["0LNetworkCommunity"] default-run = "carpe" description = "a wallet for OpenLibra" diff --git a/src-tauri/src/commands/tx.rs b/src-tauri/src/commands/tx.rs index e3338d74..648b1612 100644 --- a/src-tauri/src/commands/tx.rs +++ b/src-tauri/src/commands/tx.rs @@ -1,10 +1,10 @@ //! transaction scripts use std::str::FromStr; -use crate::key_manager::{get_private_key, inject_private_key_to_cfg}; +use crate::key_manager::get_private_key; use crate::{carpe_error::CarpeError, configs::get_cfg}; -use libra_txs::submit_transaction::Sender; +use libra_types::exports::ChainId; use libra_types::exports::{AccountAddress, AccountKey}; fn make_account_key(address: &AccountAddress) -> anyhow::Result { @@ -12,14 +12,76 @@ fn make_account_key(address: &AccountAddress) -> anyhow::Result { Ok(AccountKey::from_private_key(pk)) } +/// Creates a new Sender with proper handling of legacy addresses. +/// This function centralizes the logic for creating a transaction sender +/// with proper chain ID and legacy address support. +async fn create_sender_with_legacy( + sender_address: AccountAddress, + legacy: bool, +) -> Result< + ( + libra_txs::submit_transaction::Sender, + libra_types::core_types::app_cfg::AppCfg, + ), + CarpeError, +> { + // Get configuration + let config = get_cfg()?; + + // Get private key for the sender + let pk = get_private_key(&sender_address)?; + let account_key = AccountKey::from_private_key(pk); + + // Get URL from config + let url = config.pick_url(None)?; + + // Create the client + let client = libra_types::exports::Client::new(url.clone()); + + // Get chain ID from the live network with fallback to config + println!("Fetching current chain ID from network..."); + let chain_id = match client.get_index().await { + Ok(metadata) => { + let chain_id_value = metadata.into_inner().chain_id; + println!("Network chain ID: {}", chain_id_value); + ChainId::new(chain_id_value) + } + Err(e) => { + println!( + "Warning: Failed to get chain ID from network: {}. Using default from config.", + e + ); + // Fallback to config chain ID + let config_chain_id = config.workspace.default_chain_id.id(); + println!("Using config chain ID: {}", config_chain_id); + ChainId::new(config_chain_id) + } + }; + + // Initialize the sender with the legacy flag + let mut sender = libra_txs::submit_transaction::Sender::new( + account_key, + chain_id, + Some(client), + legacy, // Pass the legacy flag here + ) + .await?; + + // Set the transaction cost + let tx_cost = config.tx_configs.get_cost(None); + sender.set_tx_cost(&tx_cost); + + Ok((sender, config)) +} + #[tauri::command(async)] pub async fn coin_transfer( _sender: AccountAddress, receiver: &str, amount: u64, - _legacy: bool, + legacy: bool, ) -> Result<(), CarpeError> { - // NOTE: unsure Serde was catching all cases check serialization + // Parse receiver address, add 0x prefix if needed let receiver_account = match AccountAddress::from_str(receiver) { Ok(a) => a, Err(e) => { @@ -29,17 +91,36 @@ pub async fn coin_transfer( } }; - let mut config = get_cfg()?; - inject_private_key_to_cfg(&mut config, _sender)?; - let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string())).await?; - sender + // Use the common function to create a sender with legacy address support + let (mut sender, _) = create_sender_with_legacy(_sender, legacy).await?; + + println!( + "Attempting transfer from {} to {} of {} coins", + _sender, receiver_account, amount + ); + + // Use the transfer method - the last parameter is 'estimate_only' + match sender .transfer(receiver_account, amount as f64, false) - .await?; - Ok(()) + .await + { + Ok(_) => { + println!("Transaction completed successfully"); + Ok(()) + } + Err(e) => { + println!("Transaction failed: {}", e); + Err(CarpeError::misc(&format!("Transaction failed: {}", e))) + } + } } #[tauri::command(async)] -pub async fn vouch_transaction(_sender: AccountAddress, receiver: &str) -> Result<(), CarpeError> { +pub async fn vouch_transaction( + _sender: AccountAddress, + receiver: &str, + legacy: bool, +) -> Result<(), CarpeError> { let receiver_account = match AccountAddress::from_str(receiver) { Ok(a) => a, Err(e) => { @@ -51,16 +132,18 @@ pub async fn vouch_transaction(_sender: AccountAddress, receiver: &str) -> Resul } }; - let mut config = get_cfg()?; - inject_private_key_to_cfg(&mut config, _sender)?; + // Use the common function to create a sender with legacy address support + let (mut sender, _) = create_sender_with_legacy(_sender, legacy).await?; - let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string())).await?; - - // Try the revoke vouch function path + // Function path for vouching let function_path = "0x1::vouch_txs::vouch_for"; // Format address as a Move address literal (with 0x prefix) let formatted_address = format!("0x{}", receiver_account.to_hex()); + println!( + "Calling {} with argument: {}", + function_path, formatted_address + ); match sender .generic( @@ -72,24 +155,22 @@ pub async fn vouch_transaction(_sender: AccountAddress, receiver: &str) -> Resul { Ok(_) => { println!("Successfully called {}", function_path); - return Ok(()); + Ok(()) } Err(e) => { println!("Failed to call {}: {}", function_path, e); + Err(CarpeError::misc(&format!( + "Failed to call vouch function: {}", + e + ))) } } - // If we get here, all attempts failed - Err(CarpeError::misc( - "Failed to call vouch function with any known path or argument format", - )) } #[tauri::command(async)] -pub async fn rejoin_transaction(_sender: AccountAddress) -> Result<(), CarpeError> { - let mut config = get_cfg()?; - inject_private_key_to_cfg(&mut config, _sender)?; - - let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string())).await?; +pub async fn rejoin_transaction(_sender: AccountAddress, legacy: bool) -> Result<(), CarpeError> { + // Use the common function to create a sender with legacy address support + let (mut sender, _) = create_sender_with_legacy(_sender, legacy).await?; match sender .generic( @@ -112,6 +193,7 @@ pub async fn rejoin_transaction(_sender: AccountAddress) -> Result<(), CarpeErro pub async fn revoke_vouch_transaction( _sender: AccountAddress, receiver: &str, + legacy: bool, ) -> Result<(), CarpeError> { let receiver_account = match AccountAddress::from_str(receiver) { Ok(a) => a, @@ -124,10 +206,8 @@ pub async fn revoke_vouch_transaction( } }; - let mut config = get_cfg()?; - inject_private_key_to_cfg(&mut config, _sender)?; - - let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string())).await?; + // Use the common function to create a sender with legacy address support + let (mut sender, _) = create_sender_with_legacy(_sender, legacy).await?; // Try the revoke vouch function path let function_path = "0x1::vouch_txs::revoke"; @@ -158,6 +238,7 @@ pub async fn revoke_vouch_transaction( pub async fn cw_reauth_transaction( _sender: AccountAddress, wallet_address: &str, + legacy: bool, ) -> Result<(), CarpeError> { // Parse the wallet address let wallet_account = match AccountAddress::from_str(wallet_address) { @@ -171,10 +252,8 @@ pub async fn cw_reauth_transaction( } }; - let mut config = get_cfg()?; - inject_private_key_to_cfg(&mut config, _sender)?; - - let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string())).await?; + // Use the common function to create a sender with legacy address support + let (mut sender, _) = create_sender_with_legacy(_sender, legacy).await?; // Try the community wallet reauthorization function path let function_path = "0x1::donor_voice_txs::vote_reauth_tx"; diff --git a/src/components/txs/CwReauthForm.svelte b/src/components/txs/CwReauthForm.svelte index 010d0da6..6c46c047 100644 --- a/src/components/txs/CwReauthForm.svelte +++ b/src/components/txs/CwReauthForm.svelte @@ -36,7 +36,8 @@ await invoke("cw_reauth_transaction", { sender: account.account, - walletAddress: selectedWallet // Pass the selected wallet address to reauthorize + walletAddress: selectedWallet, // Pass the selected wallet address to reauthorize + legacy: account.account.startsWith('0'.repeat(32)) // Use same legacy detection as other forms }) notify_success($_('txs.cwreauth.success')) diff --git a/src/components/txs/RevokeForm.svelte b/src/components/txs/RevokeForm.svelte index dd5f8b76..75f8e006 100644 --- a/src/components/txs/RevokeForm.svelte +++ b/src/components/txs/RevokeForm.svelte @@ -59,7 +59,8 @@ await invoke("revoke_vouch_transaction", { sender: account.account, - receiver: receiver + receiver: receiver, + legacy: account.account.startsWith('0'.repeat(32)) // Use same legacy detection as in other forms }) notify_success($_('txs.revoke.success')) diff --git a/src/components/txs/VouchForm.svelte b/src/components/txs/VouchForm.svelte index b65c29f8..86f1b6e3 100644 --- a/src/components/txs/VouchForm.svelte +++ b/src/components/txs/VouchForm.svelte @@ -88,7 +88,7 @@ await invoke("vouch_transaction", { sender: account.account, receiver: receiver, - legacy: false + legacy: account.account.startsWith('0'.repeat(32)) // Use same legacy detection as in Transactions }) notify_success($_('txs.vouch.success')) diff --git a/src/components/wallet/MigrationStatus.svelte b/src/components/wallet/MigrationStatus.svelte index 0dba1526..0a0ea1ca 100644 --- a/src/components/wallet/MigrationStatus.svelte +++ b/src/components/wallet/MigrationStatus.svelte @@ -47,8 +47,11 @@ // Show loading state while processing isLoading = true; - // Call the rejoin_transaction Tauri function directly - await invoke('rejoin_transaction', { sender: account }); + // Call the rejoin_transaction Tauri function directly with legacy flag + await invoke('rejoin_transaction', { + sender: account, + legacy: account.startsWith('0'.repeat(32)) // Use same legacy detection as other transactions + }); // Refresh status checks after successful rejoin await checkMigrationStatus();