Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions e2e/tests/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,44 @@ async fn test_multi_call_beginner() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn test_multi_call_simulate_vec() -> Result<()> {
setup_program_test!(
Wallets("wallet"),
Abigen(Contract(
name = "TestContract",
project = "e2e/sway/contracts/contract_test"
)),
Deploy(
name = "contract_instance",
contract = "TestContract",
wallet = "wallet",
random_salt = false,
),
);

let contract_methods = contract_instance.methods();
let call_handler_1 = contract_methods.get_single(7);
let call_handler_2 = contract_methods.get_single(42);
let call_handler_3 = contract_methods.get_single(1212);

let mut multi_call_handler = CallHandler::new_multi_call(wallet.clone())
.add_call(call_handler_1)
.add_call(call_handler_2)
.add_call(call_handler_3);

let values: Vec<u64> = multi_call_handler
.simulate_vec(Execution::state_read_only())
.await?
.value;

assert_eq!(values[0], 7);
assert_eq!(values[1], 42);
assert_eq!(values[2], 1212);

Ok(())
}

#[tokio::test]
async fn test_multi_call_pro() -> Result<()> {
setup_program_test!(
Expand Down
5 changes: 4 additions & 1 deletion packages/fuels-accounts/src/provider/retryable_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ impl CacheableRpcs for RetryableClient {
}

impl RetryableClient {
pub(crate) async fn connect_with_fallbacks(urls: &[ impl AsRef<str>], retry_config: RetryConfig) -> Result<Self> {
pub(crate) async fn connect_with_fallbacks(
urls: &[impl AsRef<str>],
retry_config: RetryConfig,
) -> Result<Self> {
let client = FuelClient::with_urls(&urls).map_err(|e| error!(Provider, "{e}"))?;

let node_info = client.node_info().await?;
Expand Down
55 changes: 55 additions & 0 deletions packages/fuels-programs/src/calls/call_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,35 @@ where
self.get_response(tx_status)
}

/// Call contract methods on the node, in a simulated manner, meaning the state of the
/// blockchain is *not* modified but simulated.
/// Returns a Vec of values where all calls must return the same type `T`.
pub async fn simulate_vec<T: Tokenizable + Debug>(
&mut self,
Execution {
execution_type,
at_height,
}: Execution,
) -> Result<CallResponse<Vec<T>>> {
let provider = self.account.try_provider()?;

let tx_status = if let ExecutionType::StateReadOnly = execution_type {
let tx = self
.transaction_builder()
.await?
.with_build_strategy(ScriptBuildStrategy::StateReadOnly)
.build(provider)
.await?;

provider.dry_run_opt(tx, false, Some(0), at_height).await?
} else {
let tx = self.build_tx().await?;
provider.dry_run_opt(tx, true, None, at_height).await?
};

self.get_response_vec(tx_status)
}

/// Simulates a call without needing to resolve the generic for the return type
async fn simulate_without_decode(&self) -> Result<()> {
let provider = self.account.try_provider()?;
Expand Down Expand Up @@ -562,6 +591,32 @@ where
})
}

/// Create a [`CallResponse`] from `TxStatus` returning a Vec of values.
/// All calls must return the same type `T`.
pub fn get_response_vec<T: Tokenizable + Debug>(
&self,
tx_status: TxStatus,
) -> Result<CallResponse<Vec<T>>> {
let success = tx_status.take_success_checked(Some(&self.log_decoder))?;
let mut receipt_parser = ReceiptParser::new(&success.receipts, self.decoder_config);

let values = self
.call
.iter()
.map(|call| {
let token = receipt_parser.parse_call(call.contract_id, &call.output_param)?;
T::from_token(token)
})
.collect::<Result<Vec<_>>>()?;

Ok(CallResponse {
value: values,
log_decoder: self.log_decoder.clone(),
tx_id: self.cached_tx_id,
tx_status: success,
})
}

/// Simulates the call and attempts to resolve missing contract outputs.
/// Forwards the received error if it cannot be fixed.
pub async fn determine_missing_contracts(mut self) -> Result<Self> {
Expand Down
Loading