Skip to content

Commit

Permalink
Merge pull request #100
Browse files Browse the repository at this point in the history
Handled "execution failed error signaled by smart contract" error in simulated calls
  • Loading branch information
gfusee authored Oct 23, 2024
2 parents 85fc788 + 5a57586 commit 0338642
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
4 changes: 3 additions & 1 deletion executor/src/error/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pub enum SimulationError {
code: String
},

NoSmartContractResult
NoSmartContractResult,
SmartContractExecutionError { status: u64, message: String },
CannotDecodeSmartContractResult
}

impl From<SimulationError> for ExecutorError {
Expand Down
26 changes: 21 additions & 5 deletions executor/src/network/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -184,11 +183,28 @@ impl<Client: GatewayClient> 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();
Expand Down
10 changes: 9 additions & 1 deletion executor/src/utils/transaction/results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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));
Expand Down
74 changes: 73 additions & 1 deletion tester/core/tests/network_simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tokio::sync::Mutex;

use novax::Address;
use novax::errors::NovaXError;
use novax::executor::{BaseSimulationNetworkExecutor, SimulationNetworkExecutor};
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;
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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!()
};
Expand Down Expand Up @@ -304,4 +314,66 @@ 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();

let expected = NovaXError::Executor(
ExecutorError::Simulation(
SimulationError::SmartContractExecutionError {
status: 10,
message: "error signalled by smartcontract".to_string()
}
)
);

assert_eq!(result, expected);

Ok(())
}

// We don't need more tests for this executor

0 comments on commit 0338642

Please sign in to comment.