diff --git a/fuels-abigen-macro/tests/harness.rs b/fuels-abigen-macro/tests/harness.rs index 713084c9c..1f4b1fecb 100644 --- a/fuels-abigen-macro/tests/harness.rs +++ b/fuels-abigen-macro/tests/harness.rs @@ -1342,3 +1342,43 @@ async fn test_amount_and_asset_forwarding() { &AssetId::from(NATIVE_ASSET_ID) ); } + +#[tokio::test] +async fn test_multiple_args() { + let mut rng = StdRng::seed_from_u64(2322u64); + + abigen!( + MyContract, + "fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test-abi.json" + ); + + // Build the contract + let salt: [u8; 32] = rng.gen(); + let salt = Salt::from(salt); + + let compiled = Contract::load_sway_contract( + "tests/test_projects/contract_test/out/debug/contract_test.bin", + salt, + ) + .unwrap(); + + let (provider, wallet) = setup_test_provider_and_wallet().await; + + let id = Contract::deploy(&compiled, &provider, &wallet, TxParameters::default()) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), provider.clone(), wallet.clone()); + + // Make sure we can call the contract with multiple arguments + let response = instance.get(5, 6).call().await.unwrap(); + + assert_eq!(response.value, 5); + + let t = MyType { x: 5, y: 6 }; + let response = instance.get_alt(t).call().await.unwrap(); + assert_eq!(response.value, 5); + + let response = instance.get_single(5).call().await.unwrap(); + assert_eq!(response.value, 5); +} diff --git a/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test-abi.json b/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test-abi.json index b8815ba8e..e350bb02b 100644 --- a/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test-abi.json +++ b/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test-abi.json @@ -46,5 +46,75 @@ "components": null } ] + }, + { + "type": "function", + "inputs": [ + { + "name": "x", + "type": "u64", + "components": null + }, + { + "name": "y", + "type": "u64", + "components": null + } + ], + "name": "get", + "outputs": [ + { + "name": "", + "type": "u64", + "components": null + } + ] + }, + { + "type": "function", + "inputs": [ + { + "name": "t", + "type": "struct MyType", + "components": [ + { + "name": "x", + "type": "u64", + "components": null + }, + { + "name": "y", + "type": "u64", + "components": null + } + ] + } + ], + "name": "get_alt", + "outputs": [ + { + "name": "", + "type": "u64", + "components": null + } + ] + }, + { + "type": "function", + "inputs": [ + { + "name": "x", + "type": "u64", + "components": null + } + ], + "name": "get_single", + "outputs": [ + { + "name": "", + "type": "u64", + "components": null + } + ] } ] \ No newline at end of file diff --git a/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test.bin b/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test.bin index f4de50576..ddc0325fb 100644 Binary files a/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test.bin and b/fuels-abigen-macro/tests/test_projects/contract_test/out/debug/contract_test.bin differ diff --git a/fuels-abigen-macro/tests/test_projects/contract_test/src/main.sw b/fuels-abigen-macro/tests/test_projects/contract_test/src/main.sw index 707182850..5386c5f7e 100644 --- a/fuels-abigen-macro/tests/test_projects/contract_test/src/main.sw +++ b/fuels-abigen-macro/tests/test_projects/contract_test/src/main.sw @@ -4,25 +4,45 @@ use std::*; use core::*; use std::storage::*; +struct MyType { + x: u64, + y: u64, +} + abi TestContract { - fn initialize_counter(value: u64) -> u64; - fn increment_counter(value: u64) -> u64; - fn get_counter() -> u64; + fn initialize_counter(value: u64) -> u64; + fn increment_counter(value: u64) -> u64; + fn get_counter() -> u64; + fn get(x: u64, y: u64) -> u64; + fn get_alt(x: MyType) -> u64; + fn get_single(x: u64) -> u64; } const COUNTER_KEY = 0x0000000000000000000000000000000000000000000000000000000000000000; impl TestContract for Contract { - fn initialize_counter(value: u64) -> u64 { - store(COUNTER_KEY, value); - value - } - fn increment_counter(value: u64) -> u64 { - let new_value = get::(COUNTER_KEY) + value; - store(COUNTER_KEY, new_value); - new_value - } - fn get_counter() -> u64 { - get::(COUNTER_KEY) - } + fn initialize_counter(value: u64) -> u64 { + store(COUNTER_KEY, value); + value + } + fn increment_counter(value: u64) -> u64 { + let new_value = get::(COUNTER_KEY) + value; + store(COUNTER_KEY, new_value); + new_value + } + fn get_counter() -> u64 { + get::(COUNTER_KEY) + } + + fn get(x: u64, y: u64) -> u64 { + x + } + + fn get_alt(t: MyType) -> u64 { + t.x + } + + fn get_single(x: u64) -> u64 { + x + } } diff --git a/fuels-contract/src/contract.rs b/fuels-contract/src/contract.rs index 84d266042..43e6fa5ba 100644 --- a/fuels-contract/src/contract.rs +++ b/fuels-contract/src/contract.rs @@ -75,7 +75,7 @@ impl Contract { tx_parameters: TxParameters, call_parameters: CallParameters, maturity: Word, - custom_inputs: bool, + compute_calldata_offset: bool, external_contracts: Option>, wallet: LocalWallet, ) -> Result, Error> { @@ -136,10 +136,11 @@ impl Contract { script_data.extend(e) } - // If the method call takes custom inputs, such as structs or enums, we need to calculate - // the `call_data_offset`, which points to where the data for the custom types start in the + // If the method call takes custom inputs or has more than + // one argument, we need to calculate the `call_data_offset`, + // which points to where the data for the custom types start in the // transaction. If it doesn't take any custom inputs, this isn't necessary. - if custom_inputs { + if compute_calldata_offset { // Offset of the script data relative to the call data let call_data_offset = script_data_offset as usize + ContractId::LEN + 2 * WORD_SIZE; let call_data_offset = call_data_offset as Word; @@ -262,7 +263,7 @@ impl Contract { let tx_parameters = TxParameters::default(); let call_parameters = CallParameters::default(); - let custom_inputs = args.iter().any(|t| matches!(t, Token::Struct(_))); + let compute_calldata_offset = Contract::should_compute_call_data_offset(args); let maturity = 0; Ok(ContractCall { @@ -275,12 +276,23 @@ impl Contract { fuel_client: provider.client.clone(), datatype: PhantomData, output_params: output_params.to_vec(), - custom_inputs, + compute_calldata_offset, external_contracts: None, wallet: wallet.clone(), }) } + // Returns true if the method call takes custom inputs or has more than one argument. This is used to determine whether we need to compute the `call_data_offset`. + fn should_compute_call_data_offset(args: &[Token]) -> bool { + match args + .iter() + .any(|t| matches!(t, Token::Struct(_) | Token::Enum(_))) + { + true => true, + false => args.len() > 1, + } + } + /// Deploys a compiled contract to a running node /// To deploy a contract, you need a wallet with enough assets to pay for deployment. This /// wallet will also receive the change. @@ -362,7 +374,7 @@ pub struct ContractCall { pub maturity: u64, pub datatype: PhantomData, pub output_params: Vec, - pub custom_inputs: bool, + pub compute_calldata_offset: bool, pub wallet: LocalWallet, external_contracts: Option>, } @@ -414,7 +426,7 @@ where self.tx_parameters, self.call_parameters, self.maturity, - self.custom_inputs, + self.compute_calldata_offset, self.external_contracts, self.wallet, )