From 3665d1134b756c48cdc110a8f1496edd21b5b802 Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Wed, 23 Oct 2024 12:20:28 -0500 Subject: [PATCH 1/6] cp --- .../src/wallet/local_ether_wallet.rs | 93 ++++++++----------- .../tests/it/a3_micropayment_flow_tests.rs | 46 ++++----- 2 files changed, 62 insertions(+), 77 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs index 9dbb2e463..e867f915b 100644 --- a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs +++ b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs @@ -246,17 +246,17 @@ impl LocalEthersWallet { pub async fn internal_sign_transaction( &self, - tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction, + tx: TypedTransaction, ) -> Result { - unimplemented!("after refactor"); - // let typed_tx = Self::convert_to_typed_transaction(tx)?; - // let signature = self - // .wallet - // .sign_transaction(&typed_tx) - // .map_err(|e| WalletError::SigningError(e.to_string())) - // .await?; - - // Ok(signature) + // unimplemented!("after refactor"); + // let typed_tx = Self::convert_to_typed_transaction(tx); + let signature = self + .wallet + .sign_transaction(&tx) + .map_err(|e| WalletError::SigningError(e.to_string())) + .await?; + + Ok(signature) } pub async fn internal_send_transaction( @@ -278,6 +278,8 @@ impl LocalEthersWallet { let signer = SignerMiddleware::new(self.provider.clone(), self.wallet.clone()); + eprintln!("tx_request: {:?}", tx_request); + let pending_tx = signer .send_transaction(tx_request, None) .await @@ -301,44 +303,28 @@ impl LocalEthersWallet { } } - pub fn convert_to_typed_transaction(tx: Transaction) -> Result { - unimplemented!("after refactor"); - - // Code from LLM. It doesn't seem correct - // let to_address = EthersAddress::from_str(&tx.to_address_id.unwrap_or_default()) - // .map_err(|e| WalletError::InvalidAddress(e.to_string()))?; - - // let value = U256::from_dec_str(&tx.value.unwrap_or_default()) - // .map_err(|e| WalletError::ConversionError(e.to_string()))?; - - // let data = tx.unsigned_payload.into_bytes(); - - // let mut eip1559_request = Eip1559TransactionRequest::new().to(to_address).value(value).data(data); - - // if let Some(chain_id) = tx.chain_id { - // eip1559_request = eip1559_request.chain_id(chain_id); - // } - - // if let Some(nonce) = tx.nonce { - // eip1559_request = eip1559_request.nonce(nonce); - // } - - // if let Some(gas_limit) = tx.gas_limit { - // eip1559_request = eip1559_request.gas(U256::from(gas_limit)); - // } - - // if let Some(max_fee_per_gas) = tx.max_fee_per_gas { - // eip1559_request = eip1559_request.max_fee_per_gas(U256::from(max_fee_per_gas)); - // } - - // if let Some(max_priority_fee_per_gas) = tx.max_priority_fee_per_gas { - // eip1559_request = eip1559_request.max_priority_fee_per_gas(U256::from(max_priority_fee_per_gas)); - // } - - // Ok(TypedTransaction::Eip1559(eip1559_request)) + pub fn convert_to_typed_transaction(tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction) -> TypedTransaction { + let mut typed_tx = TypedTransaction::default(); + typed_tx.set_to(NameOrAddress::Address( + EthersAddress::from_str(&tx.to_address_id.unwrap()).unwrap(), + )); + typed_tx.set_data(tx.unsigned_payload.into_bytes().into()); + typed_tx } } +// // Implement conversion from mixed::Transaction to TypedTransaction +// impl From for TypedTransaction { +// fn from(tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction) -> Self { +// let mut typed_tx = TypedTransaction::default(); +// typed_tx.set_to(NameOrAddress::Address( +// EthersAddress::from_str(&tx.to_address_id.unwrap()).unwrap(), +// )); +// typed_tx.set_data(tx.unsigned_payload.into_bytes().into()); +// typed_tx +// } +// } + impl IsWallet for LocalEthersWallet {} impl PaymentWallet for LocalEthersWallet { @@ -382,15 +368,14 @@ impl SendActions for LocalEthersWallet { &self, tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction, ) -> Pin> + Send + 'static>> { - unimplemented!("after refactor"); - // let self_clone = self.clone(); - // let fut = async move { - // let typed_tx = Self::convert_to_typed_transaction(tx)?; - // let signature = self_clone.internal_sign_transaction(typed_tx).await?; - // Ok(signature.to_string()) - // }; - - // Box::pin(fut) + let self_clone = self.clone(); + let fut = async move { + let typed_tx = Self::convert_to_typed_transaction(tx); + let signature = self_clone.internal_sign_transaction(typed_tx).await?; + Ok(signature.to_string()) + }; + + Box::pin(fut) } } diff --git a/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs b/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs index e62b6f948..96b61df69 100644 --- a/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs +++ b/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs @@ -5,7 +5,7 @@ use shinkai_message_primitives::schemas::shinkai_name::ShinkaiName; use shinkai_message_primitives::schemas::shinkai_tool_offering::{ AssetPayment, ShinkaiToolOffering, ToolPrice, UsageType, UsageTypeInquiry, }; -use shinkai_message_primitives::schemas::wallet_complementary::WalletRole; +use shinkai_message_primitives::schemas::wallet_complementary::{WalletRole, WalletSource}; use shinkai_message_primitives::schemas::wallet_mixed::{Asset, NetworkIdentifier}; use shinkai_message_primitives::shinkai_utils::encryption::{ encryption_public_key_to_string, encryption_secret_key_to_string, unsafe_deterministic_encryption_keypair, @@ -32,7 +32,7 @@ use crate::it::utils::test_boilerplate::{default_embedding_model, supported_embe #[cfg(feature = "console")] use console_subscriber; -// #[test] +#[test] fn micropayment_flow_test() { #[cfg(feature = "console")] { @@ -440,40 +440,40 @@ fn micropayment_flow_test() { { eprintln!("Add wallet to node2"); // Local Ethers Wallet - // // Add wallet to node2 - // let (sender, receiver) = async_channel::bounded(1); - // node2_commands_sender - // .send(NodeCommand::V2ApiRestoreLocalEthersWallet { - // bearer: api_v2_key.to_string(), - // network: NetworkIdentifier::BaseSepolia, - // source: WalletSource::Mnemonic(std::env::var("RESTORE_WALLET_MNEMONICS_NODE2").unwrap()), - // role: WalletRole::Both, - // res: sender, - // }) - // .await - // .unwrap(); - // let resp = receiver.recv().await.unwrap(); - // eprintln!("resp restore wallet to node2: {:?}", resp); - - // Coinbase MPC Wallet - // For Development purposes, we use the Coinbase MPC Wallet // Add wallet to node2 let (sender, receiver) = async_channel::bounded(1); node2_commands_sender - .send(NodeCommand::V2ApiRestoreCoinbaseMPCWallet { + .send(NodeCommand::V2ApiRestoreLocalEthersWallet { bearer: api_v2_key.to_string(), network: NetworkIdentifier::BaseSepolia, - config: None, - wallet_id: std::env::var("COINBASE_API_WALLET_ID").unwrap(), + source: WalletSource::Mnemonic(std::env::var("RESTORE_WALLET_MNEMONICS_NODE2").unwrap()), role: WalletRole::Both, res: sender, }) .await .unwrap(); - let resp = receiver.recv().await.unwrap(); eprintln!("resp restore wallet to node2: {:?}", resp); + // Coinbase MPC Wallet + // For Development purposes, we use the Coinbase MPC Wallet + // Add wallet to node2 + // let (sender, receiver) = async_channel::bounded(1); + // node2_commands_sender + // .send(NodeCommand::V2ApiRestoreCoinbaseMPCWallet { + // bearer: api_v2_key.to_string(), + // network: NetworkIdentifier::BaseSepolia, + // config: None, + // wallet_id: std::env::var("COINBASE_API_WALLET_ID").unwrap(), + // role: WalletRole::Both, + // res: sender, + // }) + // .await + // .unwrap(); + + // let resp = receiver.recv().await.unwrap(); + // eprintln!("resp restore wallet to node2: {:?}", resp); + // Check if the response is an error and panic if it is if let Err(e) = resp { panic!("Failed to restore wallet: {:?}", e); From 57766a7ece4206b8171753a070c56a4f5ae24786 Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Thu, 24 Oct 2024 18:18:40 -0500 Subject: [PATCH 2/6] fix --- .../src/wallet/local_ether_wallet.rs | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs index e867f915b..3bd421e29 100644 --- a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs +++ b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs @@ -94,6 +94,14 @@ impl LocalEthersWallet { let wallet = EthersLocalWallet::new(&mut rand::thread_rng()).with_chain_id(network.chain_id); let address = format!("0x{:x}", wallet.address()); + // Print the private key + let private_key_bytes = wallet.signer().to_bytes(); + println!( + "Generated private key: {} for address: {}", + hex::encode(private_key_bytes), + address + ); + let provider = Provider::::try_from(network.default_rpc()).map_err(|e| WalletError::InvalidRpcUrl(e.to_string()))?; @@ -126,6 +134,12 @@ impl LocalEthersWallet { .map_err(|e| WalletError::Bip39Error(e.to_string()))?; let secret_key = SecretKey::from_slice(child_xprv.private_key().to_bytes().as_slice())?; + // Print the private key + println!( + "Recovered private key from mnemonic: {}", + hex::encode(secret_key.to_bytes()) + ); + EthersLocalWallet::from(secret_key).with_chain_id(network.chain_id) } WalletSource::PrivateKey(private_key) => { @@ -233,23 +247,7 @@ impl LocalEthersWallet { Ok(tx.into()) } - // pub async fn internal_sign_transaction(&self, tx_request: TypedTransaction) -> Result { - // let typed_tx: TypedTransaction = tx_request.into(); - // let signature = self - // .wallet - // .sign_transaction(&typed_tx) - // .map_err(|e| WalletError::SigningError(e.to_string())) - // .await?; - - // Ok(signature) - // } - - pub async fn internal_sign_transaction( - &self, - tx: TypedTransaction, - ) -> Result { - // unimplemented!("after refactor"); - // let typed_tx = Self::convert_to_typed_transaction(tx); + pub async fn internal_sign_transaction(&self, tx: TypedTransaction) -> Result { let signature = self .wallet .sign_transaction(&tx) @@ -266,6 +264,14 @@ impl LocalEthersWallet { send_amount: U256, invoice_id: String, ) -> Result { + // Add detailed logging here + eprintln!("Preparing ERC20 transfer transaction:"); + eprintln!("Contract Address: {:?}", to_wallet.address_id); + eprintln!("Token: {:?}", token); + eprintln!("Send Amount: {:?}", send_amount); + eprintln!("Provider URL: {:?}", self.provider.url()); + eprintln!("Invoice ID: {:?}", invoice_id); + let tx_request = Self::prepare_transaction_request( self, to_wallet, @@ -277,7 +283,6 @@ impl LocalEthersWallet { .await?; let signer = SignerMiddleware::new(self.provider.clone(), self.wallet.clone()); - eprintln!("tx_request: {:?}", tx_request); let pending_tx = signer @@ -303,7 +308,9 @@ impl LocalEthersWallet { } } - pub fn convert_to_typed_transaction(tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction) -> TypedTransaction { + pub fn convert_to_typed_transaction( + tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction, + ) -> TypedTransaction { let mut typed_tx = TypedTransaction::default(); typed_tx.set_to(NameOrAddress::Address( EthersAddress::from_str(&tx.to_address_id.unwrap()).unwrap(), @@ -371,6 +378,7 @@ impl SendActions for LocalEthersWallet { let self_clone = self.clone(); let fut = async move { let typed_tx = Self::convert_to_typed_transaction(tx); + eprintln!("typed_tx: {:?}", typed_tx); let signature = self_clone.internal_sign_transaction(typed_tx).await?; Ok(signature.to_string()) }; @@ -712,7 +720,7 @@ mod tests { } // Note: not working in the CI/CD pipeline - // #[tokio::test] + #[tokio::test] async fn test_anvil_current_block() { eprintln!("Starting test_anvil_current_block"); let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; From 25afe6a90c9970f3ca734c3e1847b836a7e3e453 Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Thu, 24 Oct 2024 21:43:40 -0500 Subject: [PATCH 3/6] better error msgng --- .../src/wallet/local_ether_wallet.rs | 18 +++---- .../shinkai-node/src/wallet/wallet_error.rs | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs index 3bd421e29..7d5b28b9e 100644 --- a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs +++ b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs @@ -169,7 +169,7 @@ impl LocalEthersWallet { } pub async fn prepare_transaction_request( - _from_wallet: &LocalEthersWallet, + from_wallet: &LocalEthersWallet, to_wallet: PublicAddress, token: Option, send_amount: U256, @@ -186,7 +186,9 @@ impl LocalEthersWallet { println!("chain_id: {:?}", chain_id); println!("provider: {:?}", provider); - let mut tx = Eip1559TransactionRequest::new().chain_id(chain_id); + let mut tx = Eip1559TransactionRequest::new() + .chain_id(chain_id) + .from(from_wallet.wallet.address()); if let Some(token) = token { println!("token: {:?}", token); @@ -264,14 +266,6 @@ impl LocalEthersWallet { send_amount: U256, invoice_id: String, ) -> Result { - // Add detailed logging here - eprintln!("Preparing ERC20 transfer transaction:"); - eprintln!("Contract Address: {:?}", to_wallet.address_id); - eprintln!("Token: {:?}", token); - eprintln!("Send Amount: {:?}", send_amount); - eprintln!("Provider URL: {:?}", self.provider.url()); - eprintln!("Invoice ID: {:?}", invoice_id); - let tx_request = Self::prepare_transaction_request( self, to_wallet, @@ -288,11 +282,11 @@ impl LocalEthersWallet { let pending_tx = signer .send_transaction(tx_request, None) .await - .map_err(|e| WalletError::ProviderError(e.to_string()))?; + .map_err(|e| WalletError::ProviderError(format!("SignerMiddleware error: {:?}", e)))?; let receipt = pending_tx .await - .map_err(|e| WalletError::ProviderError(e.to_string()))?; + .map_err(|e| WalletError::ProviderError(format!("Pending transaction error: {:?}", e)))?; if let Some(receipt) = receipt { let tx_hash = receipt.transaction_hash; diff --git a/shinkai-bin/shinkai-node/src/wallet/wallet_error.rs b/shinkai-bin/shinkai-node/src/wallet/wallet_error.rs index 96345cace..61ac66f31 100644 --- a/shinkai-bin/shinkai-node/src/wallet/wallet_error.rs +++ b/shinkai-bin/shinkai-node/src/wallet/wallet_error.rs @@ -10,6 +10,11 @@ pub enum WalletError { EllipticCurveError(elliptic_curve::Error), HexError(FromHexError), ProviderError(String), + DetailedJsonRpcError { + code: i32, + message: String, + data: Option, + }, NetworkMismatch, InvalidAmount(String), InvalidAddress(String), @@ -33,6 +38,7 @@ pub enum WalletError { LanceDBError(String), ParsingError(String), MissingToAddress, + InsufficientBalance(String), // Add other error types as needed } @@ -45,6 +51,9 @@ impl fmt::Display for WalletError { WalletError::EllipticCurveError(e) => write!(f, "EllipticCurveError: {}", e), WalletError::HexError(e) => write!(f, "HexError: {}", e), WalletError::ProviderError(e) => write!(f, "ProviderError: {}", e), + WalletError::DetailedJsonRpcError { code, message, data } => { + write!(f, "JSON-RPC error: code {}, message: {}, data: {:?}", code, message, data) + }, WalletError::NetworkMismatch => write!(f, "NetworkMismatch"), WalletError::InvalidAmount(e) => write!(f, "InvalidAmount: {}", e), WalletError::InvalidAddress(e) => write!(f, "InvalidAddress: {}", e), @@ -70,6 +79,7 @@ impl fmt::Display for WalletError { WalletError::LanceDBError(e) => write!(f, "LanceDBError: {}", e), WalletError::ParsingError(e) => write!(f, "ParsingError: {}", e), WalletError::MissingToAddress => write!(f, "MissingToAddress"), + WalletError::InsufficientBalance(e) => write!(f, "InsufficientBalance: {}", e), } } } @@ -106,6 +116,8 @@ impl Error for WalletError { WalletError::LanceDBError(_) => None, WalletError::ParsingError(_) => None, WalletError::MissingToAddress => None, + WalletError::InsufficientBalance(_) => None, + WalletError::DetailedJsonRpcError { .. } => None, } } } @@ -133,3 +145,40 @@ impl From for WalletError { WalletError::FunctionExecutionError(error.to_string()) } } + +impl From for WalletError { + fn from(error: ethers::providers::ProviderError) -> Self { + match error { + ethers::providers::ProviderError::JsonRpcClientError(e) => { + WalletError::ProviderError(format!("JsonRpcClientError: {:?}", e)) + }, + ethers::providers::ProviderError::EnsError(e) => { + WalletError::ProviderError(format!("EnsError: {}", e)) + }, + ethers::providers::ProviderError::EnsNotOwned(e) => { + WalletError::ProviderError(format!("EnsNotOwned: {}", e)) + }, + ethers::providers::ProviderError::SerdeJson(e) => { + WalletError::ProviderError(format!("SerdeJson: {}", e)) + }, + ethers::providers::ProviderError::HexError(e) => { + WalletError::ProviderError(format!("HexError: {}", e)) + }, + ethers::providers::ProviderError::HTTPError(e) => { + WalletError::ProviderError(format!("HTTPError: {}", e)) + }, + ethers::providers::ProviderError::CustomError(e) => { + WalletError::ProviderError(format!("CustomError: {}", e)) + }, + ethers::providers::ProviderError::UnsupportedRPC => { + WalletError::ProviderError("UnsupportedRPC".to_string()) + }, + ethers::providers::ProviderError::UnsupportedNodeClient => { + WalletError::ProviderError("UnsupportedNodeClient".to_string()) + }, + ethers::providers::ProviderError::SignerUnavailable => { + WalletError::ProviderError("SignerUnavailable".to_string()) + }, + } + } +} From 769b50e85d9fa902956b781e1076debae92ad9a0 Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Thu, 24 Oct 2024 21:46:02 -0500 Subject: [PATCH 4/6] remove extra logging --- .../src/wallet/local_ether_wallet.rs | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs index 7d5b28b9e..38b3463f1 100644 --- a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs +++ b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs @@ -96,12 +96,6 @@ impl LocalEthersWallet { // Print the private key let private_key_bytes = wallet.signer().to_bytes(); - println!( - "Generated private key: {} for address: {}", - hex::encode(private_key_bytes), - address - ); - let provider = Provider::::try_from(network.default_rpc()).map_err(|e| WalletError::InvalidRpcUrl(e.to_string()))?; @@ -134,12 +128,6 @@ impl LocalEthersWallet { .map_err(|e| WalletError::Bip39Error(e.to_string()))?; let secret_key = SecretKey::from_slice(child_xprv.private_key().to_bytes().as_slice())?; - // Print the private key - println!( - "Recovered private key from mnemonic: {}", - hex::encode(secret_key.to_bytes()) - ); - EthersLocalWallet::from(secret_key).with_chain_id(network.chain_id) } WalletSource::PrivateKey(private_key) => { @@ -150,7 +138,6 @@ impl LocalEthersWallet { }; let address = to_checksum(&wallet.address(), None); - println!("recovered wallet's address: {}", address); let provider = Provider::::try_from(network.default_rpc()).map_err(|e| WalletError::InvalidRpcUrl(e.to_string()))?; @@ -183,15 +170,12 @@ impl LocalEthersWallet { .await .map_err(|e| WalletError::ProviderError(e.to_string()))? .low_u64(); - println!("chain_id: {:?}", chain_id); - println!("provider: {:?}", provider); let mut tx = Eip1559TransactionRequest::new() .chain_id(chain_id) .from(from_wallet.wallet.address()); if let Some(token) = token { - println!("token: {:?}", token); let contract_address = token .contract_address .ok_or_else(|| WalletError::MissingContractAddress(token.asset_id.clone()))? @@ -242,10 +226,6 @@ impl LocalEthersWallet { .max_fee_per_gas(adjusted_max_fee_per_gas) .max_priority_fee_per_gas(max_priority_fee_per_gas); - // Debug prints - println!("Max Fee Per Gas: {:?}", tx.max_fee_per_gas); - println!("Max Priority Fee Per Gas: {:?}", tx.max_priority_fee_per_gas); - Ok(tx.into()) } @@ -314,18 +294,6 @@ impl LocalEthersWallet { } } -// // Implement conversion from mixed::Transaction to TypedTransaction -// impl From for TypedTransaction { -// fn from(tx: shinkai_message_primitives::schemas::wallet_mixed::Transaction) -> Self { -// let mut typed_tx = TypedTransaction::default(); -// typed_tx.set_to(NameOrAddress::Address( -// EthersAddress::from_str(&tx.to_address_id.unwrap()).unwrap(), -// )); -// typed_tx.set_data(tx.unsigned_payload.into_bytes().into()); -// typed_tx -// } -// } - impl IsWallet for LocalEthersWallet {} impl PaymentWallet for LocalEthersWallet { @@ -381,28 +349,6 @@ impl SendActions for LocalEthersWallet { } } -// Implement conversion from mixed::Transaction to TypedTransaction -// impl From for TypedTransaction { -// fn from(tx: Transaction) -> Self { -// let mut typed_tx = TypedTransaction::default(); -// typed_tx.set_to(NameOrAddress::Address( -// EthersAddress::from_str(&tx.to_address_id.unwrap()).unwrap(), -// )); -// typed_tx.set_data(tx.unsigned_payload.into_bytes().into()); -// typed_tx -// } -// } - -// fn transaction_to_typed_transaction(tx: Transaction) -> Result { -// let mut typed_tx = TypedTransaction::default(); -// typed_tx.set_to(NameOrAddress::Address( -// EthersAddress::from_str(&tx.to_address_id.ok_or(WalletError::MissingToAddress)?) -// .map_err(|e| WalletError::InvalidAddress(e.to_string()))?, -// )); -// typed_tx.set_data(tx.unsigned_payload.into_bytes().into()); -// Ok(typed_tx) -// } - impl CommonActions for LocalEthersWallet { fn get_payment_address(&self) -> PublicAddress { self.address.clone().into() From 7720bc0394a3b824929d433d8670f2149b1a9b07 Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Fri, 25 Oct 2024 00:13:39 -0500 Subject: [PATCH 5/6] fixes --- .../shinkai-node/src/managers/tool_router.rs | 33 +++++++++++++++++-- .../v2_api/api_v2_commands_my_agent_offers.rs | 15 ++++++++- .../src/wallet/local_ether_wallet.rs | 2 +- .../shinkai-db/src/schemas/ws_types.rs | 1 + 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/managers/tool_router.rs b/shinkai-bin/shinkai-node/src/managers/tool_router.rs index 6491bd344..c1b8bb9b0 100644 --- a/shinkai-bin/shinkai-node/src/managers/tool_router.rs +++ b/shinkai-bin/shinkai-node/src/managers/tool_router.rs @@ -539,7 +539,6 @@ impl ToolRouter { } }; - // Get wallet balances // Get wallet balances let balances = match my_agent_payments_manager.get_balances().await { Ok(balances) => balances, @@ -679,9 +678,10 @@ impl ToolRouter { description: network_tool.description.clone(), usage_type: network_tool.usage_type.clone(), invoice_id: internal_invoice_request.unique_id.clone(), - invoice: notification_content_value, + invoice: notification_content_value.clone(), function_args: function_args.clone(), - wallet_balances: balances_value, + wallet_balances: balances_value.clone(), + error_message: None, }; let widget = WSMessageType::Widget(WidgetMetadata::PaymentRequest(payment_metadata)); @@ -701,6 +701,33 @@ impl ToolRouter { loop { if start_time.elapsed() > timeout { + // Send a timeout notification via WebSocket + { + let ws_manager = context.ws_manager_trait(); + + if let Some(ws_manager) = &ws_manager { + let ws_manager = ws_manager.lock().await; + let job = context.full_job(); + + let topic = WSTopic::Widget; + let subtopic = job.conversation_inbox_name.to_string(); + let update = "Timeout while waiting for invoice payment".to_string(); + let payment_metadata = PaymentMetadata { + tool_key: network_tool.name.clone(), + description: network_tool.description.clone(), + usage_type: network_tool.usage_type.clone(), + invoice_id: internal_invoice_request.unique_id.clone(), + invoice: notification_content_value.clone(), + function_args: function_args.clone(), + wallet_balances: balances_value.clone(), + error_message: Some(update.clone()), + }; + + let widget = WSMessageType::Widget(WidgetMetadata::PaymentRequest(payment_metadata)); + ws_manager.queue_message(topic, subtopic, update, widget, false).await; + } + } + return Err(LLMProviderError::FunctionExecutionError( "Timeout while waiting for invoice payment".to_string(), )); diff --git a/shinkai-bin/shinkai-node/src/network/v2_api/api_v2_commands_my_agent_offers.rs b/shinkai-bin/shinkai-node/src/network/v2_api/api_v2_commands_my_agent_offers.rs index 75f8904ef..232871a3f 100644 --- a/shinkai-bin/shinkai-node/src/network/v2_api/api_v2_commands_my_agent_offers.rs +++ b/shinkai-bin/shinkai-node/src/network/v2_api/api_v2_commands_my_agent_offers.rs @@ -9,6 +9,7 @@ use shinkai_lancedb::lance_db::shinkai_lance_db::LanceShinkaiDb; use shinkai_message_primitives::schemas::shinkai_tool_offering::UsageTypeInquiry; use shinkai_tools_primitives::tools::shinkai_tool::ShinkaiTool; use tokio::sync::{Mutex, RwLock}; +use regex::Regex; use crate::network::{ agent_payments_manager::my_agent_offerings_manager::MyAgentOfferingsManager, node_error::NodeError, Node, @@ -228,10 +229,22 @@ impl Node { { Ok(payment) => payment, Err(e) => { + // Use regex to extract a more human-readable error message + let error_message = e.to_string(); + let human_readable_message = if let Ok(regex) = regex::Regex::new(r#"message: \\"(.*?)\\""#) { + if let Some(captures) = regex.captures(&error_message) { + captures.get(1).map_or(error_message.clone(), |m| m.as_str().to_string()) + } else { + error_message.clone() + } + } else { + error_message.clone() + }; + let api_error = APIError { code: StatusCode::INTERNAL_SERVER_ERROR.as_u16(), error: "Internal Server Error".to_string(), - message: format!("Failed to pay invoice: {}", e), + message: format!("Failed to pay invoice: {}", human_readable_message), }; let _ = res.send(Err(api_error)).await; return Ok(()); diff --git a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs index 38b3463f1..5b6af5135 100644 --- a/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs +++ b/shinkai-bin/shinkai-node/src/wallet/local_ether_wallet.rs @@ -660,7 +660,7 @@ mod tests { } // Note: not working in the CI/CD pipeline - #[tokio::test] + // #[tokio::test] async fn test_anvil_current_block() { eprintln!("Starting test_anvil_current_block"); let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; diff --git a/shinkai-libs/shinkai-db/src/schemas/ws_types.rs b/shinkai-libs/shinkai-db/src/schemas/ws_types.rs index d84407f76..d88534f3a 100644 --- a/shinkai-libs/shinkai-db/src/schemas/ws_types.rs +++ b/shinkai-libs/shinkai-db/src/schemas/ws_types.rs @@ -44,6 +44,7 @@ pub struct PaymentMetadata { pub invoice: Value, pub function_args: serde_json::Map, pub wallet_balances: Value, + pub error_message: Option, } #[derive(Debug)] From ee1bc2743630978452ced805d11c6f7880af642b Mon Sep 17 00:00:00 2001 From: Nico Arqueros Date: Fri, 25 Oct 2024 12:04:02 -0500 Subject: [PATCH 6/6] improve dns hanlding --- Cargo.lock | 106 ++++++++++++++++++ .../src/managers/identity_manager.rs | 8 +- .../src/managers/identity_network_manager.rs | 5 +- .../tests/it/a3_micropayment_flow_tests.rs | 2 +- .../shinkai-crypto-identities/Cargo.toml | 1 + .../src/shinkai_registry.rs | 47 +++++++- 6 files changed, 159 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 657f2d649..662f3e0a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3623,6 +3623,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -5264,6 +5276,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -5635,6 +5657,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.7", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.10.0" @@ -6612,6 +6646,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "lz4-sys" version = "1.11.1+lz4-1.10.0" @@ -9103,6 +9146,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error 1.2.3", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -10076,6 +10129,7 @@ dependencies = [ "tiny-bip39", "tokio", "tokio-util 0.6.10", + "trust-dns-resolver", "x25519-dalek", ] @@ -11821,6 +11875,52 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" +[[package]] +name = "trust-dns-proto" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand 0.8.5", + "smallvec 1.13.2", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url 2.5.2", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot 0.12.3", + "rand 0.8.5", + "resolv-conf", + "smallvec 1.13.2", + "thiserror", + "tokio", + "tracing", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -12534,6 +12634,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" diff --git a/shinkai-bin/shinkai-node/src/managers/identity_manager.rs b/shinkai-bin/shinkai-node/src/managers/identity_manager.rs index 6e25bd936..47e69d306 100644 --- a/shinkai-bin/shinkai-node/src/managers/identity_manager.rs +++ b/shinkai-bin/shinkai-node/src/managers/identity_manager.rs @@ -396,11 +396,11 @@ impl IdentityManagerTrait for IdentityManager { IdentityPermissions::None, )) } - Err(_) => Err("Failed to get first address".to_string()), + Err(e) => Err(format!("Failed to get first address: {}", e)), }, - Err(_) => Err(format!( - "Failed to get identity network manager for profile name: {}", - full_profile_name + Err(e) => Err(format!( + "Failed to get identity network manager for profile name: {} with error: {}", + full_profile_name, e )), } } diff --git a/shinkai-bin/shinkai-node/src/managers/identity_network_manager.rs b/shinkai-bin/shinkai-node/src/managers/identity_network_manager.rs index 4b96ea563..b252017bf 100644 --- a/shinkai-bin/shinkai-node/src/managers/identity_network_manager.rs +++ b/shinkai-bin/shinkai-node/src/managers/identity_network_manager.rs @@ -45,7 +45,10 @@ impl IdentityNetworkManager { // Check if any of the address_or_proxy_nodes ends with .sepolia-shinkai if record.address_or_proxy_nodes.iter().any(|node| { - node.ends_with(".sepolia-shinkai") || node.ends_with(".shinkai") || node.ends_with(".arb-sep-shinkai") + let node_base = node.split(':').next().unwrap_or(node); + node_base.ends_with(".sepolia-shinkai") || + node_base.ends_with(".shinkai") || + node_base.ends_with(".arb-sep-shinkai") }) { // Call the proxy node to get the actual data let proxy_identity = record.address_or_proxy_nodes.clone(); diff --git a/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs b/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs index 96b61df69..d9a99263e 100644 --- a/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs +++ b/shinkai-bin/shinkai-node/tests/it/a3_micropayment_flow_tests.rs @@ -32,7 +32,7 @@ use crate::it::utils::test_boilerplate::{default_embedding_model, supported_embe #[cfg(feature = "console")] use console_subscriber; -#[test] +// #[test] fn micropayment_flow_test() { #[cfg(feature = "console")] { diff --git a/shinkai-libs/shinkai-crypto-identities/Cargo.toml b/shinkai-libs/shinkai-crypto-identities/Cargo.toml index 94f5a4265..392e96e38 100644 --- a/shinkai-libs/shinkai-crypto-identities/Cargo.toml +++ b/shinkai-libs/shinkai-crypto-identities/Cargo.toml @@ -21,6 +21,7 @@ ethers = "2.0" dashmap = "5.5.3" tiny-bip39 = "0.8.0" lazy_static = "1.5.0" +trust-dns-resolver = "0.23.2" [dependencies.serde] version = "1.0.188" diff --git a/shinkai-libs/shinkai-crypto-identities/src/shinkai_registry.rs b/shinkai-libs/shinkai-crypto-identities/src/shinkai_registry.rs index c50421427..8721df59b 100644 --- a/shinkai-libs/shinkai-crypto-identities/src/shinkai_registry.rs +++ b/shinkai-libs/shinkai-crypto-identities/src/shinkai_registry.rs @@ -13,12 +13,14 @@ use shinkai_message_primitives::shinkai_utils::signatures::string_to_signature_p use std::convert::TryFrom; use std::fmt; use std::fs; -use std::net::{AddrParseError, SocketAddr}; +use std::net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; use std::time::SystemTime; use std::time::{Duration, UNIX_EPOCH}; use tokio::net::lookup_host; use tokio::task; +use trust_dns_resolver::config::*; +use trust_dns_resolver::TokioAsyncResolver; use x25519_dalek::PublicKey; lazy_static! { @@ -127,13 +129,49 @@ impl OnchainIdentity { match address.parse::() { Ok(addr) => Ok(addr), Err(_) => { - // If direct parsing fails, attempt DNS resolution - let resolved_addresses = lookup_host(address) + // Attempt a normal DNS lookup first + if let Ok(mut addrs) = lookup_host(address.clone()).await { + if let Some(addr) = addrs.next() { + return Ok(addr); + } + } + + // Split the address into host and port parts + let (host, port) = match address.rsplit_once(':') { + Some((h, p)) => (h, p.parse().unwrap_or(9552)), + None => (address.as_str(), 9552), + }; + + // Configure resolver with Google DNS and relaxed options + let mut opts = ResolverOpts::default(); + opts.validate = false; // Disable strict validation + opts.use_hosts_file = false; // Don't check hosts file + + let resolver = TokioAsyncResolver::tokio( + ResolverConfig::from_parts( + None, + vec![], + NameServerConfigGroup::from_ips_clear( + &[ + IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), // Cloudflare DNS primary + IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)), // Cloudflare DNS secondary + ], + 53, + true, + ), + ), + opts, + ); + + let resolved_addresses = resolver + .lookup_ip(host) .await .map_err(|e| ShinkaiRegistryError::CustomError(format!("DNS resolution error: {}", e)))?; + resolved_addresses - .into_iter() + .iter() .next() + .map(|ip| SocketAddr::new(ip, port)) .ok_or_else(|| ShinkaiRegistryError::CustomError("No address resolved".to_string())) } } @@ -342,6 +380,7 @@ impl ShinkaiRegistry { Ok(result) => { let last_updated = UNIX_EPOCH + Duration::from_secs(result.7.low_u64()); let last_updated = DateTime::::from(last_updated); + eprintln!("result: {:?}", result); return Ok(OnchainIdentity { shinkai_identity: identity,