From c566da82662ed7ce6921a5137176e2c60a75ddff Mon Sep 17 00:00:00 2001
From: Oleksii Filonenko <12615679+Br1ght0ne@users.noreply.github.com>
Date: Thu, 24 Oct 2024 13:24:39 +0100
Subject: [PATCH] feat: don't deploy contracts if they were already deployed
 (#1528)

---
 e2e/tests/bindings.rs                         |  15 +-
 e2e/tests/configurables.rs                    |   6 +-
 e2e/tests/contracts.rs                        | 159 +++++++++++-------
 e2e/tests/logs.rs                             |  88 ++++++----
 e2e/tests/predicates.rs                       |  10 +-
 e2e/tests/providers.rs                        |  38 +++--
 e2e/tests/scripts.rs                          |   4 +-
 e2e/tests/storage.rs                          |   4 +-
 e2e/tests/types_contracts.rs                  | 119 ++++++++-----
 packages/fuels-accounts/src/provider.rs       |   4 +
 .../src/provider/retryable_client.rs          |  34 +++-
 .../src/setup_program_test/code_gen.rs        |  19 ++-
 .../parsing/commands/deploy_contract.rs       |  10 +-
 .../fuels-programs/src/contract/loader.rs     |  22 +++
 .../fuels-programs/src/contract/regular.rs    |  16 ++
 15 files changed, 379 insertions(+), 169 deletions(-)

diff --git a/e2e/tests/bindings.rs b/e2e/tests/bindings.rs
index c071f07436..cd54df505f 100644
--- a/e2e/tests/bindings.rs
+++ b/e2e/tests/bindings.rs
@@ -19,7 +19,8 @@ mod hygiene {
             Deploy(
                 name = "simple_contract_instance",
                 contract = "SimpleContract",
-                wallet = "wallet"
+                wallet = "wallet",
+                random_salt = false,
             ),
         );
     }
@@ -36,7 +37,8 @@ async fn compile_bindings_from_contract_file() {
         Deploy(
             name = "simple_contract_instance",
             contract = "SimpleContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -119,12 +121,14 @@ async fn shared_types() -> Result<()> {
         Deploy(
             name = "contract_a",
             contract = "ContractA",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_b",
             contract = "ContractB",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     {
@@ -230,7 +234,8 @@ async fn type_paths_respected() -> Result<()> {
         Deploy(
             name = "contract_a_instance",
             contract = "ContractA",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     {
diff --git a/e2e/tests/configurables.rs b/e2e/tests/configurables.rs
index 6c65221f67..d9a002d56b 100644
--- a/e2e/tests/configurables.rs
+++ b/e2e/tests/configurables.rs
@@ -17,7 +17,7 @@ async fn contract_default_configurables() -> Result<()> {
         "sway/contracts/configurables/out/release/configurables.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
@@ -129,7 +129,7 @@ async fn contract_configurables() -> Result<()> {
         "sway/contracts/configurables/out/release/configurables.bin",
         LoadConfiguration::default().with_configurables(configurables),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
@@ -197,7 +197,7 @@ async fn contract_manual_configurables() -> Result<()> {
         LoadConfiguration::default(),
     )?
     .with_configurables(configurables)
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
diff --git a/e2e/tests/contracts.rs b/e2e/tests/contracts.rs
index a9e3f6d14b..74b9a4f748 100644
--- a/e2e/tests/contracts.rs
+++ b/e2e/tests/contracts.rs
@@ -23,7 +23,8 @@ async fn test_multiple_args() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -60,17 +61,20 @@ async fn test_contract_calling_contract() -> Result<()> {
         Deploy(
             name = "lib_contract_instance",
             contract = "LibContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "lib_contract_instance2",
             contract = "LibContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let lib_contract_id = lib_contract_instance.contract_id();
@@ -126,7 +130,8 @@ async fn test_reverting_transaction() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "RevertContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -155,7 +160,8 @@ async fn test_multiple_read_calls() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "MultiReadContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -191,7 +197,8 @@ async fn test_multi_call_beginner() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -222,7 +229,8 @@ async fn test_multi_call_pro() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -275,7 +283,8 @@ async fn test_contract_call_fee_estimation() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -312,7 +321,8 @@ async fn contract_call_has_same_estimated_and_used_gas() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -347,7 +357,8 @@ async fn mult_call_has_same_estimated_and_used_gas() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -383,7 +394,8 @@ async fn contract_method_call_respects_maturity() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "BlockHeightContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -418,7 +430,8 @@ async fn test_auth_msg_sender_from_sdk() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "AuthContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -444,7 +457,8 @@ async fn test_large_return_data() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -501,7 +515,8 @@ async fn can_handle_function_called_new() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -529,17 +544,18 @@ async fn test_contract_setup_macro_deploy_with_salt() -> Result<()> {
         Deploy(
             name = "lib_contract_instance",
             contract = "LibContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
         ),
         Deploy(
             name = "contract_caller_instance2",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
         ),
     );
     let lib_contract_id = lib_contract_instance.contract_id();
@@ -585,7 +601,8 @@ async fn test_wallet_getter() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -612,7 +629,8 @@ async fn test_connect_wallet() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     // ANCHOR_END: contract_setup_macro_manual_wallet
@@ -664,7 +682,7 @@ async fn setup_output_variable_estimation_test() -> Result<(
         "sway/contracts/token_ops/out/release/token_ops.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallets[0], TxPolicies::default())
+    .deploy_if_not_exists(&wallets[0], TxPolicies::default())
     .await?;
 
     let mint_asset_id = contract_id.asset_id(&Bits256::zeroed());
@@ -788,7 +806,8 @@ async fn test_contract_instance_get_balances() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_id = contract_instance.contract_id();
@@ -832,7 +851,8 @@ async fn contract_call_futures_implement_send() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -864,12 +884,14 @@ async fn test_contract_set_estimation() -> Result<()> {
         Deploy(
             name = "lib_contract_instance",
             contract = "LibContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let lib_contract_id = lib_contract_instance.contract_id();
@@ -924,17 +946,20 @@ async fn test_output_variable_contract_id_estimation_multicall() -> Result<()> {
         Deploy(
             name = "lib_contract_instance",
             contract = "LibContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_test_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1007,7 +1032,8 @@ async fn test_contract_call_with_non_default_max_input() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1057,7 +1083,8 @@ async fn test_add_custom_assets() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "MyContract",
-            wallet = "wallet_1"
+            wallet = "wallet_1",
+            random_salt = false,
         ),
     );
 
@@ -1119,7 +1146,8 @@ async fn test_payable_annotation() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1203,12 +1231,14 @@ async fn low_level_call() -> Result<()> {
         Deploy(
             name = "caller_contract_instance",
             contract = "MyCallerContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "target_contract_instance",
             contract = "MyTargetContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1410,7 +1440,8 @@ async fn can_configure_decoding_of_contract_return() -> Result<()> {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -1471,7 +1502,8 @@ async fn test_contract_submit_and_response() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1518,12 +1550,14 @@ async fn test_heap_type_multicall() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "VectorOutputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_instance_2",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1581,7 +1615,7 @@ async fn heap_types_correctly_offset_in_create_transactions_w_storage_slots() ->
         "sway/contracts/storage/out/release/storage.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
 
     Ok(())
@@ -1604,12 +1638,14 @@ async fn test_arguments_with_gas_forwarded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_instance_2",
             contract = "VectorOutputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1660,7 +1696,8 @@ async fn contract_custom_call_no_signatures_strategy() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let provider = wallet.try_provider()?;
@@ -1711,7 +1748,7 @@ async fn contract_encoder_config_is_applied() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let instance = TestContract::new(contract_id.clone(), wallet.clone());
@@ -1769,7 +1806,8 @@ async fn test_reentrant_calls() -> Result<()> {
         Deploy(
             name = "contract_caller_instance",
             contract = "LibContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1810,7 +1848,8 @@ async fn msg_sender_gas_estimation_issue() {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -1843,7 +1882,8 @@ async fn variable_output_estimation_is_optimized() -> Result<()> {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -1910,7 +1950,7 @@ async fn simulations_can_be_made_without_coins() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(wallet, TxPolicies::default())
+    .deploy_if_not_exists(wallet, TxPolicies::default())
     .await?;
 
     let provider = wallet.provider().cloned();
@@ -1941,7 +1981,7 @@ async fn simulations_can_be_made_without_coins_multicall() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(wallet, TxPolicies::default())
+    .deploy_if_not_exists(wallet, TxPolicies::default())
     .await?;
 
     let provider = wallet.provider().cloned();
@@ -2000,7 +2040,7 @@ async fn contract_call_with_non_zero_base_asset_id_and_tip() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(wallet, TxPolicies::default())
+    .deploy_if_not_exists(wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
@@ -2043,7 +2083,8 @@ async fn max_fee_estimation_respects_tolerance() -> Result<()> {
         Deploy(
             name = "contract_instance",
             wallet = "deploy_wallet",
-            contract = "MyContract"
+            contract = "MyContract",
+            random_salt = false,
         )
     );
     let contract_instance = contract_instance.with_account(call_wallet.clone());
@@ -2178,7 +2219,7 @@ async fn blob_contract_deployment() -> Result<()> {
 
     let contract_id = contract
         .convert_to_loader(100_000)?
-        .deploy(&wallets[0], TxPolicies::default())
+        .deploy_if_not_exists(&wallets[0], TxPolicies::default())
         .await?;
 
     let contract_instance = MyContract::new(contract_id, wallets[0].clone());
@@ -2205,7 +2246,7 @@ async fn regular_contract_can_be_deployed() -> Result<()> {
 
     // when
     let contract_id = Contract::load_from(contract_binary, LoadConfiguration::default())?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     // then
@@ -2237,7 +2278,7 @@ async fn unuploaded_loader_can_be_deployed_directly() -> Result<()> {
 
     let contract_id = Contract::load_from(contract_binary, LoadConfiguration::default())?
         .convert_to_loader(1024)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet);
@@ -2276,7 +2317,7 @@ async fn unuploaded_loader_can_upload_blobs_separately_then_deploy() -> Result<(
         contract.salt(),
         contract.storage_slots().to_vec(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet);
@@ -2307,7 +2348,9 @@ async fn loader_blob_already_uploaded_not_an_issue() -> Result<()> {
         .await?;
 
     // this will try to upload the blobs but skip upon encountering an error
-    let contract_id = contract.deploy(&wallet, TxPolicies::default()).await?;
+    let contract_id = contract
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
+        .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet);
     let response = contract_instance.methods().something().call().await?.value;
@@ -2337,13 +2380,13 @@ async fn loader_works_via_proxy() -> Result<()> {
 
     let contract_id = contract
         .convert_to_loader(100)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let contract_binary = "sway/contracts/proxy/out/release/proxy.bin";
 
     let proxy_id = Contract::load_from(contract_binary, LoadConfiguration::default())?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let proxy = MyProxy::new(proxy_id, wallet.clone());
@@ -2388,7 +2431,7 @@ async fn loader_storage_works_via_proxy() -> Result<()> {
 
     let contract_id = contract
         .convert_to_loader(100)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let contract_binary = "sway/contracts/proxy/out/release/proxy.bin";
@@ -2398,7 +2441,7 @@ async fn loader_storage_works_via_proxy() -> Result<()> {
 
     let proxy_id = proxy_contract
         .with_storage_slots(combined_storage_slots)
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let proxy = MyProxy::new(proxy_id, wallet.clone());
diff --git a/e2e/tests/logs.rs b/e2e/tests/logs.rs
index c5f5ba41d5..f9dc89dabd 100644
--- a/e2e/tests/logs.rs
+++ b/e2e/tests/logs.rs
@@ -15,7 +15,8 @@ async fn test_parse_logged_variables() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -53,7 +54,8 @@ async fn test_parse_logs_values() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -87,7 +89,8 @@ async fn test_parse_logs_custom_types() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -127,7 +130,8 @@ async fn test_parse_logs_generic_types() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -179,7 +183,8 @@ async fn test_decode_logs() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -233,7 +238,8 @@ async fn test_decode_logs_with_no_logs() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -260,7 +266,8 @@ async fn test_multi_call_log_single_contract() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -308,12 +315,14 @@ async fn test_multi_call_log_multiple_contracts() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_instance2",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -362,12 +371,14 @@ async fn test_multi_call_contract_with_contract_logs() -> Result<()> {
         Deploy(
             name = "contract_caller_instance",
             contract = "ContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance2",
             contract = "ContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -375,7 +386,7 @@ async fn test_multi_call_contract_with_contract_logs() -> Result<()> {
         "./sway/logs/contract_logs/out/release/contract_logs.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id.clone(), wallet.clone());
@@ -433,7 +444,8 @@ async fn test_require_log() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "RequireContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -490,7 +502,8 @@ async fn test_multi_call_require_log_single_contract() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "RequireContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -557,12 +570,14 @@ async fn test_multi_call_require_log_multi_contract() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "RequireContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_instance2",
             contract = "RequireContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -701,7 +716,8 @@ async fn test_contract_with_contract_logs() -> Result<()> {
         Deploy(
             name = "contract_caller_instance",
             contract = "ContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -709,7 +725,7 @@ async fn test_contract_with_contract_logs() -> Result<()> {
         "./sway/logs/contract_logs/out/release/contract_logs.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id.clone(), wallet.clone());
@@ -749,7 +765,8 @@ async fn test_script_logs_with_contract_logs() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "MyContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         LoadScript(
             name = "script_instance",
@@ -962,7 +979,8 @@ async fn test_contract_require_from_contract() -> Result<()> {
         Deploy(
             name = "contract_caller_instance",
             contract = "ContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -970,7 +988,7 @@ async fn test_contract_require_from_contract() -> Result<()> {
         "./sway/contracts/lib_contract/out/release/lib_contract.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id.clone(), wallet.clone());
@@ -1009,12 +1027,14 @@ async fn test_multi_call_contract_require_from_contract() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "ContractLogs",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_caller_instance",
             contract = "ContractCaller",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1022,7 +1042,7 @@ async fn test_multi_call_contract_require_from_contract() -> Result<()> {
         "./sway/contracts/lib_contract/out/release/lib_contract.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let lib_contract_instance = MyContract::new(contract_id.clone(), wallet.clone());
@@ -1065,7 +1085,8 @@ async fn test_script_require_from_contract() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "MyContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         LoadScript(
             name = "script_instance",
@@ -1111,7 +1132,7 @@ async fn test_loader_script_require_from_loader_contract() -> Result<()> {
     let contract = Contract::load_from(contract_binary, LoadConfiguration::default())?;
     let contract_id = contract
         .convert_to_loader(100_000)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
     let contract_instance = MyContract::new(contract_id, wallet);
 
@@ -1146,7 +1167,8 @@ async fn test_contract_asserts_log() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "LogContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1363,7 +1385,8 @@ async fn contract_token_ops_error_messages() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1403,7 +1426,8 @@ async fn test_log_results() -> Result<()> {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -1441,7 +1465,8 @@ async fn can_configure_decoder_for_contract_log_decoding() -> Result<()> {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
 
@@ -1585,7 +1610,8 @@ async fn contract_heap_log() -> Result<()> {
         Deploy(
             contract = "MyContract",
             name = "contract_instance",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         )
     );
     let contract_methods = contract_instance.methods();
diff --git a/e2e/tests/predicates.rs b/e2e/tests/predicates.rs
index cb99b772c3..58642149b8 100644
--- a/e2e/tests/predicates.rs
+++ b/e2e/tests/predicates.rs
@@ -230,7 +230,7 @@ async fn pay_with_predicate() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
 
     let contract_methods = MyContract::new(contract_id.clone(), predicate.clone()).methods();
@@ -299,7 +299,7 @@ async fn pay_with_predicate_vector_data() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
 
     let contract_methods = MyContract::new(contract_id.clone(), predicate.clone()).methods();
@@ -361,7 +361,7 @@ async fn predicate_contract_transfer() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
 
     let contract_balances = provider.get_contract_balances(&contract_id).await?;
@@ -550,7 +550,7 @@ async fn contract_tx_and_call_params_with_predicate() -> Result<()> {
         "./sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
     println!("Contract deployed @ {contract_id}");
 
@@ -630,7 +630,7 @@ async fn diff_asset_predicate_payment() -> Result<()> {
         "./sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&predicate, TxPolicies::default())
+    .deploy_if_not_exists(&predicate, TxPolicies::default())
     .await?;
 
     let contract_methods = MyContract::new(contract_id.clone(), predicate.clone()).methods();
diff --git a/e2e/tests/providers.rs b/e2e/tests/providers.rs
index d9ca2500a6..cd7b289fd2 100644
--- a/e2e/tests/providers.rs
+++ b/e2e/tests/providers.rs
@@ -40,7 +40,7 @@ async fn test_provider_launch_and_connect() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance_connected = MyContract::new(contract_id.clone(), wallet.clone());
@@ -88,7 +88,7 @@ async fn test_network_error() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await;
 
     assert!(matches!(response, Err(Error::Provider(_))));
@@ -132,7 +132,8 @@ async fn test_input_message() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -179,7 +180,7 @@ async fn test_input_message_pays_fee() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
@@ -293,7 +294,8 @@ async fn contract_deployment_respects_maturity() -> Result<()> {
             LoadConfiguration::default(),
         )
         .map(|loaded_contract| {
-            loaded_contract.deploy(wallet, TxPolicies::default().with_maturity(maturity))
+            loaded_contract
+                .deploy_if_not_exists(wallet, TxPolicies::default().with_maturity(maturity))
         })
     };
 
@@ -325,7 +327,8 @@ async fn test_gas_forwarded_defaults_to_tx_limit() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -363,7 +366,8 @@ async fn test_amount_and_asset_forwarding() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TokenContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_id = contract_instance.contract_id();
@@ -474,7 +478,8 @@ async fn test_gas_errors() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -526,7 +531,8 @@ async fn test_call_param_gas_errors() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -568,7 +574,8 @@ async fn test_get_gas_used() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -715,7 +722,8 @@ async fn test_sway_timestamp() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -876,7 +884,8 @@ async fn can_fetch_mint_transactions() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1027,7 +1036,8 @@ async fn tx_respects_policies() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1190,7 +1200,7 @@ async fn contract_call_with_impersonation() -> Result<()> {
         "sway/contracts/contract_test/out/release/contract_test.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, impersonator.clone());
diff --git a/e2e/tests/scripts.rs b/e2e/tests/scripts.rs
index 4dbef3a279..a416b02b0e 100644
--- a/e2e/tests/scripts.rs
+++ b/e2e/tests/scripts.rs
@@ -527,14 +527,14 @@ async fn loader_script_calling_loader_proxy() -> Result<()> {
 
     let contract_id = contract
         .convert_to_loader(100)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let contract_binary = "sway/contracts/proxy/out/release/proxy.bin";
 
     let proxy_id = Contract::load_from(contract_binary, LoadConfiguration::default())?
         .convert_to_loader(100)?
-        .deploy(&wallet, TxPolicies::default())
+        .deploy_if_not_exists(&wallet, TxPolicies::default())
         .await?;
 
     let proxy = MyProxy::new(proxy_id.clone(), wallet.clone());
diff --git a/e2e/tests/storage.rs b/e2e/tests/storage.rs
index 8f2d1bf6ef..554b7123a1 100644
--- a/e2e/tests/storage.rs
+++ b/e2e/tests/storage.rs
@@ -23,7 +23,7 @@ async fn test_storage_initialization() -> Result<()> {
         "sway/contracts/storage/out/release/storage.bin",
         LoadConfiguration::default().with_storage_configuration(storage_configuration),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_instance = MyContract::new(contract_id, wallet.clone());
@@ -52,7 +52,7 @@ async fn test_init_storage_automatically() -> Result<()> {
         "sway/contracts/storage/out/release/storage.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_methods = MyContract::new(contract_id, wallet.clone()).methods();
diff --git a/e2e/tests/types_contracts.rs b/e2e/tests/types_contracts.rs
index 6fbc052587..e4e7dd3aba 100644
--- a/e2e/tests/types_contracts.rs
+++ b/e2e/tests/types_contracts.rs
@@ -22,7 +22,8 @@ async fn test_methods_typeless_argument() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -48,7 +49,8 @@ async fn call_with_empty_return() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TestContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -78,7 +80,7 @@ async fn call_with_structs() -> Result<()> {
         "sway/types/contracts/complex_types_contract/out/release/complex_types_contract.bin",
         LoadConfiguration::default(),
     )?
-    .deploy(&wallet, TxPolicies::default())
+    .deploy_if_not_exists(&wallet, TxPolicies::default())
     .await?;
 
     let contract_methods = MyContract::new(contract_id, wallet).methods();
@@ -108,7 +110,8 @@ async fn abigen_different_structs_same_arg_name() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -137,7 +140,8 @@ async fn nested_structs() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -197,7 +201,8 @@ async fn calls_with_empty_struct() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -260,7 +265,8 @@ async fn test_tuples() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -334,7 +340,8 @@ async fn test_evm_address() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -401,7 +408,8 @@ async fn test_array() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -428,7 +436,8 @@ async fn test_arrays_with_custom_types() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -470,7 +479,8 @@ async fn str_in_array() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -510,7 +520,8 @@ async fn test_enum_inside_struct() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -552,7 +563,8 @@ async fn native_types_support() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -590,7 +602,8 @@ async fn enum_coding_w_variable_width_variants() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -631,7 +644,8 @@ async fn enum_coding_w_unit_enums() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -670,7 +684,8 @@ async fn enum_as_input() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -746,7 +761,8 @@ async fn type_inside_enum() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -810,7 +826,8 @@ async fn test_rust_option_can_be_decoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -862,7 +879,8 @@ async fn test_rust_option_can_be_encoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -916,7 +934,8 @@ async fn test_rust_result_can_be_decoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -968,7 +987,8 @@ async fn test_rust_result_can_be_encoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1003,7 +1023,8 @@ async fn test_identity_can_be_decoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1048,7 +1069,8 @@ async fn test_identity_can_be_encoded() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1096,12 +1118,14 @@ async fn test_identity_with_two_contracts() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
         Deploy(
             name = "contract_instance2",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1141,7 +1165,8 @@ async fn generics_test() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1298,7 +1323,8 @@ async fn contract_vectors() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let methods = contract_instance.methods();
@@ -1385,7 +1411,8 @@ async fn test_b256() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1423,7 +1450,8 @@ async fn test_b512() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1471,7 +1499,8 @@ async fn test_u128() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1523,7 +1552,8 @@ async fn test_u256() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "TypesContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1560,7 +1590,8 @@ async fn test_base_type_in_vec_output() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "VectorOutputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1599,7 +1630,8 @@ async fn test_composite_types_in_vec_output() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "VectorOutputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1668,7 +1700,8 @@ async fn test_bytes_output() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "BytesOutputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1691,7 +1724,8 @@ async fn test_bytes_as_input() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "BytesInputContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1727,7 +1761,8 @@ async fn contract_raw_slice() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "RawSliceContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1772,7 +1807,8 @@ async fn contract_string_slice() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "StringSliceContract",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
@@ -1798,7 +1834,8 @@ async fn contract_std_lib_string() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "StdLibString",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1836,7 +1873,8 @@ async fn test_heap_type_in_enums() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "HeapTypeInEnum",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
     let contract_methods = contract_instance.methods();
@@ -1948,7 +1986,8 @@ async fn nested_heap_types() -> Result<()> {
         Deploy(
             name = "contract_instance",
             contract = "HeapTypeInEnum",
-            wallet = "wallet"
+            wallet = "wallet",
+            random_salt = false,
         ),
     );
 
diff --git a/packages/fuels-accounts/src/provider.rs b/packages/fuels-accounts/src/provider.rs
index 806ccd2cb0..862b3414fd 100644
--- a/packages/fuels-accounts/src/provider.rs
+++ b/packages/fuels-accounts/src/provider.rs
@@ -720,6 +720,10 @@ impl Provider {
 
         self
     }
+
+    pub async fn contract_exists(&self, contract_id: &Bech32ContractId) -> Result<bool> {
+        Ok(self.client.contract_exists(&contract_id.into()).await?)
+    }
 }
 
 #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
diff --git a/packages/fuels-accounts/src/provider/retryable_client.rs b/packages/fuels-accounts/src/provider/retryable_client.rs
index 56acc0c862..69afc9bbf0 100644
--- a/packages/fuels-accounts/src/provider/retryable_client.rs
+++ b/packages/fuels-accounts/src/provider/retryable_client.rs
@@ -1,9 +1,10 @@
 use std::{future::Future, io};
 
-use custom_queries::{IsUserAccountQuery, IsUserAccountVariables};
+use custom_queries::{ContractExistsQuery, IsUserAccountQuery, IsUserAccountVariables};
 use cynic::QueryBuilder;
 use fuel_core_client::client::{
     pagination::{PaginatedResult, PaginationRequest},
+    schema::contract::ContractByIdArgs,
     types::{
         gas_price::{EstimateGasPrice, LatestGasPrice},
         primitives::{BlockId, TransactionId},
@@ -306,6 +307,22 @@ impl RetryableClient {
         })
         .await
     }
+
+    pub async fn contract_exists(&self, contract_id: &ContractId) -> RequestResult<bool> {
+        self.wrap(|| {
+            let query = ContractExistsQuery::build(ContractByIdArgs {
+                id: (*contract_id).into(),
+            });
+            self.client.query(query)
+        })
+        .await
+        .map(|query| {
+            query
+                .contract
+                .map(|contract| ContractId::from(contract.id) == *contract_id)
+                .unwrap_or(false)
+        })
+    }
     // DELEGATION END
 
     pub async fn is_user_account(&self, address: [u8; 32]) -> Result<bool> {
@@ -333,7 +350,9 @@ mod custom_queries {
     use fuel_core_client::client::schema::blob::BlobIdFragment;
     use fuel_core_client::client::schema::schema;
     use fuel_core_client::client::schema::{
-        contract::ContractIdFragment, tx::TransactionIdFragment, BlobId, ContractId, TransactionId,
+        contract::{ContractByIdArgs, ContractIdFragment},
+        tx::TransactionIdFragment,
+        BlobId, ContractId, TransactionId,
     };
 
     #[derive(cynic::QueryVariables, Debug)]
@@ -357,4 +376,15 @@ mod custom_queries {
         #[arguments(id: $transaction_id)]
         pub transaction: Option<TransactionIdFragment>,
     }
+
+    #[derive(cynic::QueryFragment, Clone, Debug)]
+    #[cynic(
+        schema_path = "./target/fuel-core-client-schema.sdl",
+        graphql_type = "Query",
+        variables = "ContractByIdArgs"
+    )]
+    pub struct ContractExistsQuery {
+        #[arguments(id: $id)]
+        pub contract: Option<ContractIdFragment>,
+    }
 }
diff --git a/packages/fuels-macros/src/setup_program_test/code_gen.rs b/packages/fuels-macros/src/setup_program_test/code_gen.rs
index b4c22c2b8c..a98a2911c2 100644
--- a/packages/fuels-macros/src/setup_program_test/code_gen.rs
+++ b/packages/fuels-macros/src/setup_program_test/code_gen.rs
@@ -124,17 +124,26 @@ fn contract_deploying_code(
             let contract_instance_name = ident(&command.name);
             let contract_struct_name = ident(&command.contract.value());
             let wallet_name = ident(&command.wallet);
+            let random_salt = command.random_salt;
 
             let project = project_lookup
                 .get(&command.contract.value())
                 .expect("Project should be in lookup");
             let bin_path = project.bin_path();
 
+            let salt = if random_salt {
+                quote! {
+                    // Generate random salt for contract deployment.
+                    // These lines must be inside the `quote!` macro, otherwise the salt remains
+                    // identical between macro compilation, causing contract id collision.
+                    ::fuels::test_helpers::generate_random_salt()
+                }
+            } else {
+                quote! { [0; 32] }
+            };
+
             quote! {
-                // Generate random salt for contract deployment.
-                // These lines must be inside the `quote!` macro, otherwise the salt remains
-                // identical between macro compilation, causing contract id collision.
-                let salt: [u8; 32] = ::fuels::test_helpers::generate_random_salt();
+                let salt: [u8; 32] = #salt;
 
                 let #contract_instance_name = {
                     let load_config = ::fuels::programs::contract::LoadConfiguration::default().with_salt(salt);
@@ -145,7 +154,7 @@ fn contract_deploying_code(
                     )
                     .expect("Failed to load the contract");
 
-                    let contract_id = loaded_contract.deploy(
+                    let contract_id = loaded_contract.deploy_if_not_exists(
                         &#wallet_name,
                         ::fuels::types::transaction::TxPolicies::default()
                     )
diff --git a/packages/fuels-macros/src/setup_program_test/parsing/commands/deploy_contract.rs b/packages/fuels-macros/src/setup_program_test/parsing/commands/deploy_contract.rs
index 748b968a98..3a42774289 100644
--- a/packages/fuels-macros/src/setup_program_test/parsing/commands/deploy_contract.rs
+++ b/packages/fuels-macros/src/setup_program_test/parsing/commands/deploy_contract.rs
@@ -1,6 +1,6 @@
 use std::convert::TryFrom;
 
-use syn::{Error, LitStr};
+use syn::{Error, Lit, LitStr};
 
 use crate::parse_utils::{Command, UniqueNameValues};
 
@@ -9,6 +9,7 @@ pub struct DeployContractCommand {
     pub name: String,
     pub contract: LitStr,
     pub wallet: String,
+    pub random_salt: bool,
 }
 
 impl TryFrom<Command> for DeployContractCommand {
@@ -16,16 +17,21 @@ impl TryFrom<Command> for DeployContractCommand {
 
     fn try_from(command: Command) -> Result<Self, Self::Error> {
         let name_values = UniqueNameValues::new(command.contents)?;
-        name_values.validate_has_no_other_names(&["name", "contract", "wallet"])?;
+        name_values.validate_has_no_other_names(&["name", "contract", "wallet", "random_salt"])?;
 
         let name = name_values.get_as_lit_str("name")?.value();
         let contract = name_values.get_as_lit_str("contract")?.clone();
         let wallet = name_values.get_as_lit_str("wallet")?.value();
+        let random_salt = name_values.try_get("random_salt").map_or(true, |opt| {
+            let Lit::Bool(b) = opt else { return true };
+            b.value()
+        });
 
         Ok(Self {
             name,
             contract,
             wallet,
+            random_salt,
         })
     }
 }
diff --git a/packages/fuels-programs/src/contract/loader.rs b/packages/fuels-programs/src/contract/loader.rs
index 71966f4762..5405f68c7d 100644
--- a/packages/fuels-programs/src/contract/loader.rs
+++ b/packages/fuels-programs/src/contract/loader.rs
@@ -236,6 +236,18 @@ impl Contract<Loader<BlobsNotUploaded>> {
             .await
     }
 
+    /// Deploys the loader contract after uploading the code blobs,
+    /// if there is no contract with this ContractId Already.
+    pub async fn deploy_if_not_exists(
+        self,
+        account: &impl Account,
+        tx_policies: TxPolicies,
+    ) -> Result<Bech32ContractId> {
+        self.upload_blobs(account, tx_policies)
+            .await?
+            .deploy_if_not_exists(account, tx_policies)
+            .await
+    }
     /// Reverts the contract from a loader contract back to a regular contract.
     pub fn revert_to_regular(self) -> Contract<Regular> {
         let code = self
@@ -311,4 +323,14 @@ impl Contract<Loader<BlobsUploaded>> {
             .deploy(account, tx_policies)
             .await
     }
+
+    pub async fn deploy_if_not_exists(
+        self,
+        account: &impl Account,
+        tx_policies: TxPolicies,
+    ) -> Result<Bech32ContractId> {
+        Contract::regular(self.code(), self.salt, self.storage_slots)
+            .deploy_if_not_exists(account, tx_policies)
+            .await
+    }
 }
diff --git a/packages/fuels-programs/src/contract/regular.rs b/packages/fuels-programs/src/contract/regular.rs
index 466092a1cd..4865e97b8f 100644
--- a/packages/fuels-programs/src/contract/regular.rs
+++ b/packages/fuels-programs/src/contract/regular.rs
@@ -169,6 +169,22 @@ impl Contract<Regular> {
         Ok(contract_id.into())
     }
 
+    /// Deploys a compiled contract to a running node if a contract with
+    /// the corresponding [`ContractId`] doesn't exist.
+    pub async fn deploy_if_not_exists(
+        self,
+        account: &impl Account,
+        tx_policies: TxPolicies,
+    ) -> Result<Bech32ContractId> {
+        let contract_id = Bech32ContractId::from(self.contract_id());
+        let provider = account.try_provider()?;
+        if provider.contract_exists(&contract_id).await? {
+            Ok(contract_id)
+        } else {
+            self.deploy(account, tx_policies).await
+        }
+    }
+
     /// Converts a regular contract into a loader contract, splitting the code into blobs.
     pub fn convert_to_loader(
         self,