From c3e02f63549fe4e5f86c637e8085bc6ca13fca16 Mon Sep 17 00:00:00 2001 From: quentin Date: Wed, 23 Oct 2024 13:43:58 +0200 Subject: [PATCH 1/2] started to handle "execution failed error signaled by smart contract" error in simulated calls --- tester/core/tests/network_simulate.rs | 65 ++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/tester/core/tests/network_simulate.rs b/tester/core/tests/network_simulate.rs index 81f8e1e..69036d6 100644 --- a/tester/core/tests/network_simulate.rs +++ b/tester/core/tests/network_simulate.rs @@ -10,7 +10,7 @@ use tokio::sync::Mutex; use novax::Address; use novax::errors::NovaXError; -use novax::executor::{BaseSimulationNetworkExecutor, SimulationNetworkExecutor}; +use novax::executor::{BaseSimulationNetworkExecutor, SimulationNetworkExecutor, TokenTransfer}; use novax::tester::tester::TesterContract; use novax_request::error::request::RequestError; use novax_request::gateway::client::GatewayClient; @@ -65,6 +65,14 @@ fn get_autoscale_zap_in_xexchange_two_different_tokens_transaction() -> (StatusC (status, data) } +// I got an error with this transaction when coding the autoscale's API, so I add a dedicated test. +fn get_autoscale_zap_in_error_signaled_in_smart_contract() -> (StatusCode, String) { + let status = StatusCode::OK; + let data = r#"{"data":{"txGasUnits":0,"returnMessage":"unknown error, code: 12: error signalled by smartcontract","smartContractResults":{},"logs":{"address":"","events":[{"address":"erd1n7ed3f6rkqvwkpfevulvhyl4hskx2vqyleed5lqfq9jp2csfw8esg88f5g","identifier":"ESDTTransfer","topics":["V0VHTEQtYTI4YzU5","","JxA=","AAAAAAAAAAAFAJa/uBBkEBAjdy0aVtjEEdbBrlGLBGM="],"data":"","additionalData":null},{"address":"erd1qqqqqqqqqqqqqpgqj6lmsyryzqgzxaedrftd33q36mq6u5vtq33sp6p0k6","identifier":"signalError","topics":["n7LYp0OwGOsFOWc+y5P1vCxlMAT+ctp8CQFkFWIJcfM=","ZXJyb3Igc2lnbmFsbGVkIGJ5IHNtYXJ0Y29udHJhY3Q="],"data":"QDY1Nzg2NTYzNzU3NDY5NmY2ZTIwNjY2MTY5NmM2NTY0","additionalData":null},{"address":"erd1n7ed3f6rkqvwkpfevulvhyl4hskx2vqyleed5lqfq9jp2csfw8esg88f5g","identifier":"internalVMErrors","topics":["AAAAAAAAAAAFAJa/uBBkEBAjdy0aVtjEEdbBrlGLBGM=","emFwSW4="],"data":"CglydW50aW1lLmdvOjg1NiBbZXhlY3V0aW9uIGZhaWxlZF0gW3phcEluXQoJcnVudGltZS5nbzo4NTYgW2V4ZWN1dGlvbiBmYWlsZWRdIFt6YXBJbl0KCXJ1bnRpbWUuZ286ODU2IFtlcnJvciBzaWduYWxsZWQgYnkgc21hcnRjb250cmFjdF0KCXJ1bnRpbWUuZ286ODU2IFtlcnJvciBzaWduYWxsZWQgYnkgc21hcnRjb250cmFjdF0gW3N3YXBUb2tlbnNGaXhlZElucHV0XQoJcnVudGltZS5nbzo4NTYgW2Vycm9yIHNpZ25hbGxlZCBieSBzbWFydGNvbnRyYWN0XSBbc3dhcFRva2Vuc0ZpeGVkSW5wdXRdCglydW50aW1lLmdvOjg1NiBbZXJyb3Igc2lnbmFsbGVkIGJ5IHNtYXJ0Y29udHJhY3RdIFtzd2FwVG9rZW5zRml4ZWRJbnB1dF0KCXJ1bnRpbWUuZ286ODUzIFtTbGlwcGFnZSBleGNlZWRlZF0=","additionalData":null}]}},"error":"","code":"successful"}"#.to_string(); + + (status, data) +} + struct MockClient { url: String } @@ -116,6 +124,8 @@ impl GatewayClient for MockClient { get_autoscale_swap_and_deposit_transaction() } else if data == r#"{"nonce":5,"value":"0","receiver":"erd1qqqqqqqqqqqqqpgqj6lmsyryzqgzxaedrftd33q36mq6u5vtq33sp6p0k6","sender":"erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g","gasPrice":1000000000,"gasLimit":600000000,"data":"emFwSW5AMDAwMDAwMDAwMDAwMDAwMDAwMDUwMDU4MTM3MjE0YjBlMTRjMjk0ODYwYTE2YzExMDQyYWE3MWFiYzE3MjA3Y2ViMDAwMDAwMDIwMDAwMDAwYzU3NDU0NzRjNDQyZDYxMzIzODYzMzUzOTAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NUBAMDAwMDAwMGI1NTUzNDQ0MzJkMzMzNTMwNjMzNDY1MDAwMDAwMDAwMDAwMDAwMDA1MDBmZDk2YTFjZDI4N2YzNmIwZDE0YzZjNDc2ODFmOGY2YjdhODlmOTExNTIzMzAwMDAwMDA4NjU3ODYzNjg2MTZlNjc2NTAwMDAwMDAyMDAwMDAwMGI1NTUzNDQ0MzJkMzMzNTMwNjMzNDY1MDAwMDAwMDEwMTAwMDAwMDBjNTc0NTQ3NGM0NDJkNjEzMjM4NjMzNTM5MDAwMDAwMDAwMDAwMDAwMDA1MDA1ODEzNzIxNGIwZTE0YzI5NDg2MGExNmMxMTA0MmFhNzFhYmMxNzIwN2NlYjAwMDAwMDE0NzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NDAwMDAwMDAyMDAwMDAwMGM1NzQ1NDc0YzQ0MmQ2MTMyMzg2MzM1MzkwMDAwMDAwMTAxQDAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NTAwMDAwMDAwMDAwMDAwMDAwNTAwZmQ5NmExY2QyODdmMzZiMGQxNGM2YzQ3NjgxZjhmNmI3YTg5ZjkxMTUyMzMwMDAwMDAwODY1Nzg2MzY4NjE2ZTY3NjUwMDAwMDAwMjAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NTAwMDAwMDAxMDE=","chainId":"D","version":1}"# { get_autoscale_zap_in_xexchange_two_different_tokens_transaction() + } else if data == r#"{"nonce":5,"value":"0","receiver":"erd1qqqqqqqqqqqqqpgqj6lmsyryzqgzxaedrftd33q36mq6u5vtq33sp6p0k6","sender":"erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g","gasPrice":1000000000,"gasLimit":600000000,"data":"RVNEVFRyYW5zZmVyQDU3NDU0NzRjNDQyZDYxMzIzODYzMzUzOUAyNzEwQDdhNjE3MDQ5NmVAMDAwMDAwMDAwMDAwMDAwMDAwMDUwMDU4MTM3MjE0YjBlMTRjMjk0ODYwYTE2YzExMDQyYWE3MWFiYzE3MjA3Y2ViMDAwMDAwMDIwMDAwMDAwYzU3NDU0NzRjNDQyZDYxMzIzODYzMzUzOTAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NUBAQDAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NTAwMDAwMDAwMDAwMDAwMDAwNTAwNTgxMzcyMTRiMGUxNGMyOTQ4NjBhMTZjMTEwNDJhYTcxYWJjMTcyMDdjZWIwMDAwMDAxNDczNzc2MTcwNTQ2ZjZiNjU2ZTczNDY2OTc4NjU2NDQ5NmU3MDc1NzQwMDAwMDAwMjAwMDAwMDBiNTU1MzQ0NDMyZDMzMzUzMDYzMzQ2NTAwMDAwMDAxMDE=","chainId":"D","version":1}"# { + get_autoscale_zap_in_error_signaled_in_smart_contract() } else { unreachable!() }; @@ -304,4 +314,57 @@ async fn test_autoscale_zap_in_xexchange_two_different_tokens_transaction() -> R Ok(()) } +#[tokio::test] +async fn test_autoscale_zap_in_error_signaled_by_smart_contract() -> Result<(), NovaXError> { + let executor = get_executor(); + + let contract = AutoscaleRouterContract::new( + AUTOSCALE_ROUTER_ADDRESS + ); + + let result = contract + .call(executor, 600000000) + .with_esdt_transfers( + &vec![ + TokenTransfer { + identifier: "WEGLD-a28c59".to_string(), + nonce: 0, + amount: BigUint::from_str("10000").unwrap(), + } + ] + ) + .zap_in( + &AddLiquidityOperation { + pool_type: PoolType::XExchange, + pool_address: "erd1qqqqqqqqqqqqqpgqtqfhy99su9xzjjrq59kpzpp25udtc9eq0n4sr90ax6".into(), + tokens: vec![ + "WEGLD-a28c59".into(), + "USDC-350c4e".into(), + ], + }, + &None, + &vec![ + vec![], + vec![ + SwapOperation { + token_out: "USDC-350c4e".to_string(), + pool_address: "erd1qqqqqqqqqqqqqpgqtqfhy99su9xzjjrq59kpzpp25udtc9eq0n4sr90ax6".into(), + function_name: "swapTokensFixedInput".to_string(), + arguments: vec![ + "USDC-350c4e".to_string(), + String::from_utf8_lossy(&[1]).to_string(), + ], + }, + ], + ] + ) + .await + .err() + .unwrap(); + + todo!(); + + Ok(()) +} + // We don't need more tests for this executor \ No newline at end of file From 5a57586c6700aa66d2db92b85039dbb7420c6419 Mon Sep 17 00:00:00 2001 From: quentin Date: Wed, 23 Oct 2024 16:51:04 +0200 Subject: [PATCH 2/2] handled "execution failed error signaled by smart contract" error in simulated calls --- executor/src/error/simulation.rs | 4 +++- executor/src/network/simulate.rs | 26 ++++++++++++++++++----- executor/src/utils/transaction/results.rs | 10 ++++++++- tester/core/tests/network_simulate.rs | 13 ++++++++++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/executor/src/error/simulation.rs b/executor/src/error/simulation.rs index e856a6d..77dadb8 100644 --- a/executor/src/error/simulation.rs +++ b/executor/src/error/simulation.rs @@ -16,7 +16,9 @@ pub enum SimulationError { code: String }, - NoSmartContractResult + NoSmartContractResult, + SmartContractExecutionError { status: u64, message: String }, + CannotDecodeSmartContractResult } impl From for ExecutorError { diff --git a/executor/src/network/simulate.rs b/executor/src/network/simulate.rs index 8cccb30..8a76a11 100644 --- a/executor/src/network/simulate.rs +++ b/executor/src/network/simulate.rs @@ -11,12 +11,11 @@ use novax_request::gateway::client::GatewayClient; use crate::{ExecutorError, GatewayError, SimulationError, SimulationGatewayRequest, SimulationGatewayResponse, TransactionExecutor, TransactionOnNetwork, TransactionOnNetworkTransactionSmartContractResult}; use crate::call_result::CallResult; -use crate::error::transaction::TransactionError; use crate::network::models::simulate::request::SimulationGatewayRequestBody; use crate::network::utils::address::get_address_info; use crate::network::utils::network::get_network_config; use crate::utils::transaction::normalization::NormalizationInOut; -use crate::utils::transaction::results::find_smart_contract_result; +use crate::utils::transaction::results::{find_sc_error, find_smart_contract_result}; use crate::utils::transaction::token_transfer::TokenTransfer; /// Type alias for `BaseSimulationNetworkExecutor` with the `String` type as the generic `Client`. @@ -184,11 +183,28 @@ impl TransactionExecutor for BaseSimulationNetworkExecuto }) .collect(); - let mut raw_result = find_smart_contract_result(&Some(scrs), data.logs.as_ref())? - .unwrap_or_default(); + let opt_smart_contract_results = find_smart_contract_result(&Some(scrs), data.logs.as_ref())?; + + let mut raw_result = match opt_smart_contract_results { + None => { + if let Some(logs) = data.logs.as_ref() { + if let Ok(Some(error_log)) = find_sc_error(logs) { + return Err(SimulationError::SmartContractExecutionError { // TODO add tests for this + status: error_log.status, + message: error_log.message + }.into()); + } + } + + vec![] + } + Some(results) => { + results + } + }; let Ok(output_managed) = OutputManaged::multi_decode(&mut raw_result) else { - return Err(TransactionError::CannotDecodeSmartContractResult.into()) + return Err(SimulationError::CannotDecodeSmartContractResult.into()) }; let mut response = TransactionOnNetwork::default(); diff --git a/executor/src/utils/transaction/results.rs b/executor/src/utils/transaction/results.rs index 20afbbb..31b3fbe 100644 --- a/executor/src/utils/transaction/results.rs +++ b/executor/src/utils/transaction/results.rs @@ -5,6 +5,8 @@ use multiversx_sdk::utils::base64_decode; use crate::{ExecutorError, TransactionOnNetworkTransactionLogs, TransactionOnNetworkTransactionLogsEvents, TransactionOnNetworkTransactionSmartContractResult}; use crate::error::transaction::TransactionError; +const ERROR_SIGNALLED_BY_SMART_CONTRACT: &str = "error signalled by smartcontract"; + #[derive(Clone, Debug)] pub(crate) struct SmartContractError { pub status: u64, @@ -49,8 +51,14 @@ pub(crate) fn find_sc_error(logs: &TransactionOnNetworkTransactionLogs) -> Resul } let error = decode_topic(topics.get(1).unwrap())?; + let status = if error.contains(ERROR_SIGNALLED_BY_SMART_CONTRACT) { + 10 + } else { + 4 + }; + let result = SmartContractError { - status: 4, + status, message: error, }; return Ok(Some(result)); diff --git a/tester/core/tests/network_simulate.rs b/tester/core/tests/network_simulate.rs index 69036d6..ae7f6e6 100644 --- a/tester/core/tests/network_simulate.rs +++ b/tester/core/tests/network_simulate.rs @@ -10,7 +10,7 @@ use tokio::sync::Mutex; use novax::Address; use novax::errors::NovaXError; -use novax::executor::{BaseSimulationNetworkExecutor, SimulationNetworkExecutor, TokenTransfer}; +use novax::executor::{BaseSimulationNetworkExecutor, ExecutorError, SimulationError, SimulationNetworkExecutor, TokenTransfer}; use novax::tester::tester::TesterContract; use novax_request::error::request::RequestError; use novax_request::gateway::client::GatewayClient; @@ -362,7 +362,16 @@ async fn test_autoscale_zap_in_error_signaled_by_smart_contract() -> Result<(), .err() .unwrap(); - todo!(); + let expected = NovaXError::Executor( + ExecutorError::Simulation( + SimulationError::SmartContractExecutionError { + status: 10, + message: "error signalled by smartcontract".to_string() + } + ) + ); + + assert_eq!(result, expected); Ok(()) }