Repository: scs/substrate-api-client (language: rust)

Issue:
Update contracts module and add example to CI
The current [contracts](https://github.com/scs/substrate-api-client/blob/1fe5ffeef2e2e2ede77a8f8174a4f232e5a63979/src/extrinsic/contracts.rs) is outdated. `PutCode` for example does not exist any more and `instantiate_with_code` is deprecated.
See https://polkadot.js.org/docs/substrate/extrinsics/#contracts & https://github.com/paritytech/substrate/blob/bfc2d085f392ccfb369251709bccb4bfa0edebe7/frame/contracts/src/lib.rs.

That should be fixed. Additionally, I don't see any reason why  https://github.com/scs/substrate-api-client/blob/1fe5ffeef2e2e2ede77a8f8174a4f232e5a63979/examples/examples/contract_instantiate_with_code.rs should not be tested in CI. Kitchensink runtime includes this pallet.

Additional fixes: 
- Use `Bytes` instead of `Vec<u8>`
- Add comments to functions (simply copy paste summary in https://polkadot.js.org/docs/substrate/extrinsics/#contracts).


- [x] Wait for #415 to be fixed first.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8145b56a7..9ab133514 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -184,6 +184,7 @@ jobs:
           jsonrpsee_tests,
           keystore_tests,
           pallet_balances_tests,
+          pallet_contract_tests,
           pallet_transaction_payment_tests,
           runtime_api_tests,
           tungstenite_client_test,
diff --git a/primitives/src/types.rs b/primitives/src/types.rs
index dff686230..ad3170fec 100644
--- a/primitives/src/types.rs
+++ b/primitives/src/types.rs
@@ -336,7 +336,7 @@ pub type NodeIndex = u64;
 
 /// Merkle Mountain Range operation error.
 // https://github.com/paritytech/polkadot-sdk/blob/a190e0e9253562fdca9c1b6e9541a7ea0a50c018/substrate/primitives/merkle-mountain-range/src/lib.rs#L362-L396
-#[derive(codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)]
+#[derive(Encode, Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)]
 pub enum MmrError {
 	/// Error during translation of a block number into a leaf index.
 	InvalidNumericOp,
@@ -359,3 +359,22 @@ pub enum MmrError {
 	/// The provided best know block number is invalid.
 	InvalidBestKnownBlock,
 }
+
+/// Defines the required determinism level of a wasm blob when either running or uploading code.
+#[derive(Clone, Copy, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug, PartialEq, Eq)]
+pub enum Determinism {
+	/// The execution should be deterministic and hence no indeterministic instructions are
+	/// allowed.
+	///
+	/// Dispatchables always use this mode in order to make on-chain execution deterministic.
+	Enforced,
+	/// Allow calling or uploading an indeterministic code.
+	///
+	/// This is only possible when calling into `pallet-contracts` directly via
+	/// [`crate::Pallet::bare_call`].
+	///
+	/// # Note
+	///
+	/// **Never** use this mode for on-chain execution.
+	Relaxed,
+}
diff --git a/src/extrinsic/contracts.rs b/src/extrinsic/contracts.rs
index 4727252eb..68473b0cb 100644
--- a/src/extrinsic/contracts.rs
+++ b/src/extrinsic/contracts.rs
@@ -19,87 +19,219 @@
 //! Contracts module is community maintained and not CI tested, therefore it may not work as is.
 //! https://polkadot.js.org/docs/substrate/extrinsics/#contracts
 
-// FIXME: This module is currently outdated. See https://github.com/scs/substrate-api-client/issues/435.
-
 use crate::{api::Api, rpc::Request};
 use ac_compose_macros::compose_extrinsic;
 use ac_primitives::{
-	config::Config, extrinsic_params::ExtrinsicParams, extrinsics::CallIndex, SignExtrinsic,
-	UncheckedExtrinsicV4,
+	config::Config, extrinsic_params::ExtrinsicParams, extrinsics::CallIndex, Determinism,
+	SignExtrinsic, UncheckedExtrinsicV4, Weight,
 };
-use alloc::vec::Vec;
 use codec::{Compact, Encode};
+use sp_core::Bytes;
 
 pub const CONTRACTS_MODULE: &str = "Contracts";
-pub const PUT_CODE: &str = "put_code";
-pub const INSTANTIATE: &str = "instantiate";
-pub const INSTANTIATE_WITH_CODE: &str = "instantiate_with_code";
+pub const UPLOAD_CODE: &str = "upload_code";
+pub const REMOVE_CODE: &str = "remove_code";
+pub const SET_CODE: &str = "set_code";
 pub const CALL: &str = "call";
+pub const INSTANTIATE_WITH_CODE: &str = "instantiate_with_code";
+pub const INSTANTIATE: &str = "instantiate";
+pub const MIGRATE: &str = "migrate";
+
+/// Upload new `code` without instantiating a contract from it..
+pub type UploadCodeCall<P> = (CallIndex, CodeFor<P>, Option<CurrencyFor<P>>, DeterminismFor<P>);
 
-pub type GasLimitFor<M> = Compact<<M as ContractsExtrinsics>::Gas>;
-pub type ValueFor<M> = Compact<<M as ContractsExtrinsics>::Currency>;
-pub type EndowmentFor<M> = Compact<<M as ContractsExtrinsics>::Currency>;
-pub type DataFor<M> = <M as ContractsExtrinsics>::Data;
-pub type CodeFor<M> = <M as ContractsExtrinsics>::Code;
-pub type SaltFor<M> = <M as ContractsExtrinsics>::Salt;
-pub type HashFor<M> = <M as ContractsExtrinsics>::Hash;
-pub type AddressFor<M> = <M as ContractsExtrinsics>::Address;
+/// Remove the code stored under `code_hash` and refund the deposit to its owner.
+pub type RemoveCodeCall<P> = (CallIndex, CodeHashFor<P>);
 
-/// Call for putting code in a contract.
-pub type PutCodeFor<M> = (CallIndex, GasLimitFor<M>, DataFor<M>);
+/// Privileged function that changes the code of an existing contract.
+pub type SetCodeCall<P> = (CallIndex, AddressFor<P>, CodeHashFor<P>);
 
-/// Call for instantiating a contract with the code hash.
-pub type InstantiateWithHashFor<M> =
-	(CallIndex, EndowmentFor<M>, GasLimitFor<M>, HashFor<M>, DataFor<M>);
+/// Makes a call to an account, optionally transferring some balance.
+pub type ContractCall<P> =
+	(CallIndex, AddressFor<P>, CurrencyFor<P>, WeightFor<P>, Option<CurrencyFor<P>>, DataFor<P>);
 
-/// Call for instantiating a contract with code and salt.
-pub type InstantiateWithCodeFor<M> =
-	(CallIndex, EndowmentFor<M>, GasLimitFor<M>, CodeFor<M>, DataFor<M>, SaltFor<M>);
+/// Instantiates a new contract from the supplied `code` optionally transferring
+/// some balance.
+pub type InstantiateWithCodeCall<P> = (
+	CallIndex,
+	CurrencyFor<P>,
+	WeightFor<P>,
+	Option<CurrencyFor<P>>,
+	CodeFor<P>,
+	DataFor<P>,
+	SaltFor<P>,
+);
 
-/// Call for calling a function inside a contract.
-pub type ContractCallFor<M> = (CallIndex, AddressFor<M>, ValueFor<M>, GasLimitFor<M>, DataFor<M>);
+/// Instantiates a contract from a previously deployed wasm binary.
+pub type InstantiateCall<P> = (
+	CallIndex,
+	CurrencyFor<P>,
+	WeightFor<P>,
+	Option<CurrencyFor<P>>,
+	CodeHashFor<P>,
+	DataFor<P>,
+	SaltFor<P>,
+);
 
+/// Calls that contribute to advancing the migration have their fees waived, as it's helpful
+/// for the chain.
+pub type MigrateCall<P> = (CallIndex, WeightFor<P>);
+
+pub type WeightFor<P> = <P as ContractsExtrinsics>::Weight;
+pub type DeterminismFor<P> = <P as ContractsExtrinsics>::Determinism;
+pub type DataFor<P> = <P as ContractsExtrinsics>::Data;
+pub type CodeFor<P> = <P as ContractsExtrinsics>::Code;
+pub type SaltFor<P> = <P as ContractsExtrinsics>::Salt;
+pub type CodeHashFor<P> = <P as ContractsExtrinsics>::CodeHash;
+pub type AddressFor<P> = <P as ContractsExtrinsics>::Address;
+pub type CurrencyFor<P> = Compact<<P as ContractsExtrinsics>::Currency>;
 #[maybe_async::maybe_async(?Send)]
 pub trait ContractsExtrinsics {
-	type Gas;
+	type Weight;
 	type Currency;
-	type Hash;
+	type Determinism;
+	type CodeHash;
 	type Code;
 	type Data;
 	type Salt;
 	type Address;
 	type Extrinsic<Call>;
 
-	async fn contract_put_code(
+	/// Upload new `code` without instantiating a contract from it.
+	///
+	/// If the code does not already exist a deposit is reserved from the caller
+	/// and unreserved only when [`Self::remove_code`] is called. The size of the reserve
+	/// depends on the size of the supplied `code`.
+	///
+	/// If the code already exists in storage it will still return `Ok` and upgrades
+	/// the in storage version to the current
+	/// [`InstructionWeights::version`](InstructionWeights).
+	///
+	/// - `determinism`: If this is set to any other value but [`Determinism::Enforced`] then
+	///   the only way to use this code is to delegate call into it from an offchain execution.
+	///   Set to [`Determinism::Enforced`] if in doubt.
+	///
+	/// # Note
+	///
+	/// Anyone can instantiate a contract from any uploaded code and thus prevent its removal.
+	/// To avoid this situation a constructor could employ access control so that it can
+	/// only be instantiated by permissioned entities. The same is true when uploading
+	/// through [`Self::instantiate_with_code`].
+	async fn contract_upload_code(
 		&self,
-		gas_limit: Self::Gas,
 		code: Self::Code,
-	) -> Option<Self::Extrinsic<PutCodeFor<Self>>>;
+		storage_deposit_limit: Option<Self::Currency>,
+		determinism: Self::Determinism,
+	) -> Option<Self::Extrinsic<UploadCodeCall<Self>>>;
 
-	async fn contract_instantiate(
+	/// Remove the code stored under `code_hash` and refund the deposit to its owner.
+	///
+	/// A code can only be removed by its original uploader (its owner) and only if it is
+	/// not used by any contract.
+	async fn contract_remove_code(
 		&self,
-		endowment: Self::Currency,
-		gas_limit: Self::Gas,
-		code_hash: Self::Hash,
+		code_hash: Self::CodeHash,
+	) -> Option<Self::Extrinsic<RemoveCodeCall<Self>>>;
+
+	/// Privileged function that changes the code of an existing contract.
+	///
+	/// This takes care of updating refcounts and all other necessary operations. Returns
+	/// an error if either the `code_hash` or `dest` do not exist.
+	///
+	/// # Note
+	///
+	/// This does **not** change the address of the contract in question. This means
+	/// that the contract address is no longer derived from its code hash after calling
+	/// this dispatchable.
+	async fn contract_set_code(
+		&self,
+		dest: Self::Address,
+		code_hash: Self::CodeHash,
+	) -> Option<Self::Extrinsic<SetCodeCall<Self>>>;
+
+	/// Makes a call to an account, optionally transferring some balance.
+	///
+	/// # Parameters
+	///
+	/// * `dest`: Address of the contract to call.
+	/// * `value`: The balance to transfer from the `origin` to `dest`.
+	/// * `gas_limit`: The gas limit enforced when executing the constructor.
+	/// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the
+	///   caller to pay for the storage consumed.
+	/// * `data`: The input data to pass to the contract.
+	///
+	/// * If the account is a smart-contract account, the associated code will be
+	/// executed and any value will be transferred.
+	/// * If the account is a regular account, any value will be transferred.
+	/// * If no account exists and the call value is not less than `existential_deposit`,
+	/// a regular account will be created and any value will be transferred.
+	async fn contract_call(
+		&self,
+		dest: Self::Address,
+		value: Self::Currency,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
 		data: Self::Data,
-	) -> Option<Self::Extrinsic<InstantiateWithHashFor<Self>>>;
+	) -> Option<Self::Extrinsic<ContractCall<Self>>>;
 
+	/// Instantiates a new contract from the supplied `code` optionally transferring
+	/// some balance.
+	///
+	/// This dispatchable has the same effect as calling [`Self::upload_code`] +
+	/// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please
+	/// also check the documentation of [`Self::upload_code`].
+	///
+	/// # Parameters
+	///
+	/// * `value`: The balance to transfer from the `origin` to the newly created contract.
+	/// * `gas_limit`: The gas limit enforced when executing the constructor.
+	/// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved
+	///   from the caller to pay for the storage consumed.
+	/// * `code`: The contract code to deploy in raw bytes.
+	/// * `data`: The input data to pass to the contract constructor.
+	/// * `salt`: Used for the address derivation. See [`Pallet::contract_address`].
+	///
+	/// Instantiation is executed as follows:
+	///
+	/// - The supplied `code` is deployed, and a `code_hash` is created for that code.
+	/// - If the `code_hash` already exists on the chain the underlying `code` will be shared.
+	/// - The destination address is computed based on the sender, code_hash and the salt.
+	/// - The smart-contract account is created at the computed address.
+	/// - The `value` is transferred to the new account.
+	/// - The `deploy` function is executed in the context of the newly-created account.
 	async fn contract_instantiate_with_code(
 		&self,
-		endowment: Self::Currency,
-		gas_limit: Self::Gas,
+		value: Self::Currency,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
 		code: Self::Code,
 		data: Self::Data,
 		salt: Self::Salt,
-	) -> Option<Self::Extrinsic<InstantiateWithCodeFor<Self>>>;
+	) -> Option<Self::Extrinsic<InstantiateWithCodeCall<Self>>>;
 
-	async fn contract_call(
+	/// Instantiates a contract from a previously deployed wasm binary.
+	///
+	/// This function is identical to [`Self::instantiate_with_code`] but without the
+	/// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary
+	/// must be supplied.
+	async fn contract_instantiate(
 		&self,
-		dest: Self::Address,
 		value: Self::Currency,
-		gas_limit: Self::Gas,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
+		code_hash: Self::CodeHash,
 		data: Self::Data,
-	) -> Option<Self::Extrinsic<ContractCallFor<Self>>>;
+		salt: Self::Salt,
+	) -> Option<Self::Extrinsic<InstantiateCall<Self>>>;
+
+	/// When a migration is in progress, this dispatchable can be used to run migration steps.
+	/// Calls that contribute to advancing the migration have their fees waived, as it's helpful
+	/// for the chain. Note that while the migration is in progress, the pallet will also
+	/// leverage the `on_idle` hooks to run migration steps.
+	async fn contract_migrate(
+		&self,
+		weight_limit: Self::Weight,
+	) -> Option<Self::Extrinsic<MigrateCall<Self>>>;
 }
 
 #[cfg(feature = "std")]
@@ -110,12 +242,13 @@ where
 	Client: Request,
 	Compact<T::ContractCurrency>: Encode + Clone,
 {
-	type Gas = u64;
+	type Weight = Weight;
 	type Currency = T::ContractCurrency;
-	type Hash = T::Hash;
-	type Code = Vec<u8>;
-	type Data = Vec<u8>;
-	type Salt = Vec<u8>;
+	type Determinism = Determinism;
+	type CodeHash = T::Hash;
+	type Code = Bytes;
+	type Data = Bytes;
+	type Salt = Bytes;
 	type Address = <T::ExtrinsicSigner as SignExtrinsic<T::AccountId>>::ExtrinsicAddress;
 	type Extrinsic<Call> = UncheckedExtrinsicV4<
 		Self::Address,
@@ -124,67 +257,105 @@ where
 		<T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::SignedExtra,
 	>;
 
-	async fn contract_put_code(
+	async fn contract_upload_code(
 		&self,
-		gas_limit: Self::Gas,
 		code: Self::Code,
-	) -> Option<Self::Extrinsic<PutCodeFor<Self>>> {
-		compose_extrinsic!(self, CONTRACTS_MODULE, PUT_CODE, Compact(gas_limit), code)
+		storage_deposit_limit: Option<Self::Currency>,
+		determinism: Self::Determinism,
+	) -> Option<Self::Extrinsic<UploadCodeCall<Self>>> {
+		compose_extrinsic!(
+			self,
+			CONTRACTS_MODULE,
+			UPLOAD_CODE,
+			code,
+			storage_deposit_limit.map(Compact),
+			determinism
+		)
 	}
 
-	async fn contract_instantiate(
+	async fn contract_remove_code(
+		&self,
+		code_hash: Self::CodeHash,
+	) -> Option<Self::Extrinsic<RemoveCodeCall<Self>>> {
+		compose_extrinsic!(self, CONTRACTS_MODULE, REMOVE_CODE, code_hash)
+	}
+
+	async fn contract_set_code(
+		&self,
+		dest: Self::Address,
+		code_hash: Self::CodeHash,
+	) -> Option<Self::Extrinsic<SetCodeCall<Self>>> {
+		compose_extrinsic!(self, CONTRACTS_MODULE, SET_CODE, dest, code_hash)
+	}
+
+	async fn contract_call(
 		&self,
-		endowment: Self::Currency,
-		gas_limit: Self::Gas,
-		code_hash: Self::Hash,
+		dest: Self::Address,
+		value: Self::Currency,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
 		data: Self::Data,
-	) -> Option<Self::Extrinsic<InstantiateWithHashFor<Self>>> {
+	) -> Option<Self::Extrinsic<ContractCall<Self>>> {
 		compose_extrinsic!(
 			self,
 			CONTRACTS_MODULE,
-			INSTANTIATE,
-			Compact(endowment),
-			Compact(gas_limit),
-			code_hash,
+			CALL,
+			dest,
+			Compact(value),
+			gas_limit,
+			storage_deposit_limit.map(Compact),
 			data
 		)
 	}
 
 	async fn contract_instantiate_with_code(
 		&self,
-		endowment: Self::Currency,
-		gas_limit: Self::Gas,
+		value: Self::Currency,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
 		code: Self::Code,
 		data: Self::Data,
 		salt: Self::Salt,
-	) -> Option<Self::Extrinsic<InstantiateWithCodeFor<Self>>> {
+	) -> Option<Self::Extrinsic<InstantiateWithCodeCall<Self>>> {
 		compose_extrinsic!(
 			self,
 			CONTRACTS_MODULE,
 			INSTANTIATE_WITH_CODE,
-			Compact(endowment),
-			Compact(gas_limit),
+			Compact(value),
+			gas_limit,
+			storage_deposit_limit.map(Compact),
 			code,
 			data,
 			salt
 		)
 	}
 
-	async fn contract_call(
+	async fn contract_instantiate(
 		&self,
-		dest: Self::Address,
 		value: Self::Currency,
-		gas_limit: Self::Gas,
+		gas_limit: Self::Weight,
+		storage_deposit_limit: Option<Self::Currency>,
+		code_hash: Self::CodeHash,
 		data: Self::Data,
-	) -> Option<Self::Extrinsic<ContractCallFor<Self>>> {
+		salt: Self::Salt,
+	) -> Option<Self::Extrinsic<InstantiateCall<Self>>> {
 		compose_extrinsic!(
 			self,
 			CONTRACTS_MODULE,
-			CALL,
-			dest,
+			INSTANTIATE,
 			Compact(value),
-			Compact(gas_limit),
-			data
+			gas_limit,
+			storage_deposit_limit.map(Compact),
+			code_hash,
+			data,
+			salt
 		)
 	}
+
+	async fn contract_migrate(
+		&self,
+		weight_limit: Self::Weight,
+	) -> Option<Self::Extrinsic<MigrateCall<Self>>> {
+		compose_extrinsic!(self, CONTRACTS_MODULE, MIGRATE, weight_limit)
+	}
 }


Test patch:
diff --git a/testing/async/examples/flipper.wasm b/testing/async/examples/flipper.wasm
new file mode 100644
index 000000000..afd39d793
Binary files /dev/null and b/testing/async/examples/flipper.wasm differ
diff --git a/examples/async/examples/contract_instantiate_with_code.rs b/testing/async/examples/pallet_contract_tests.rs
similarity index 56%
rename from examples/async/examples/contract_instantiate_with_code.rs
rename to testing/async/examples/pallet_contract_tests.rs
index 538a3da0f..46ff4c9c4 100644
--- a/examples/async/examples/contract_instantiate_with_code.rs
+++ b/testing/async/examples/pallet_contract_tests.rs
@@ -20,7 +20,8 @@ use kitchensink_runtime::AccountId;
 use sp_keyring::AccountKeyring;
 use substrate_api_client::{
 	ac_compose_macros::primitives::AssetRuntimeConfig, ac_node_api::StaticEvent,
-	extrinsic::ContractsExtrinsics, rpc::JsonrpseeClient, Api, SubmitAndWatch, XtStatus,
+	ac_primitives::Determinism, extrinsic::ContractsExtrinsics, rpc::JsonrpseeClient, Api,
+	SubmitAndWatch, XtStatus,
 };
 
 // To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet.
@@ -42,8 +43,6 @@ impl StaticEvent for ContractInstantiatedEventArgs {
 
 #[tokio::main]
 async fn main() {
-	env_logger::init();
-
 	// Initialize api and set the signer (sender) that is used to sign the extrinsics.
 	let signer = AccountKeyring::Alice.pair();
 	let client = JsonrpseeClient::with_default_url().await.unwrap();
@@ -52,41 +51,29 @@ async fn main() {
 
 	println!("[+] Alice's Account Nonce is {}", api.get_nonce().await.unwrap());
 
-	// contract to be deployed on the chain
-	const CONTRACT: &str = r#"
-(module
-    (func (export "call"))
-    (func (export "deploy"))
-)
-"#;
-	let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt");
+	let wasm = include_bytes!("flipper.wasm").to_vec();
 
 	let xt = api
-		.contract_instantiate_with_code(1_000_000_000_000_000, 500_000, wasm, vec![1u8], vec![1u8])
+		.contract_instantiate_with_code(
+			0,
+			500_000_000.into(),
+			None,
+			wasm.clone().into(),
+			vec![0].into(),
+			vec![0].into(),
+		)
 		.await
 		.unwrap();
 
-	println!("[+] Creating a contract instance with extrinsic:\n\n{:?}\n", xt);
-	let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap();
-	println!("[+] Extrinsic is in Block. Hash: {:?}\n", report.block_hash.unwrap());
-
-	println!("[+] Waiting for the contracts.Instantiated event");
-
-	let associated_contract_events = report.events.unwrap();
-
-	let contract_instantiated_events: Vec<ContractInstantiatedEventArgs> =
-		associated_contract_events
-			.iter()
-			.filter_map(|event| event.as_event().unwrap())
-			.collect();
-	// We only expect one instantiated event
-	assert_eq!(contract_instantiated_events.len(), 1);
-	let contract = contract_instantiated_events[0].contract.clone();
-	println!("[+] Event was received. Contract deployed at: {contract:?}\n");
+	println!("[+] Creating a contract instance \n");
+	let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await;
+	// Ensure the contract is valid - just doesnt make any changes.
+	assert!(format!("{:?}", result).contains("ContractReverted"));
 
-	let xt = api.contract_call(contract.into(), 500_000, 500_000, vec![0u8]).await.unwrap();
+	let xt = api
+		.contract_upload_code(wasm.into(), None, Determinism::Enforced)
+		.await
+		.unwrap();
 
-	println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt);
-	let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap();
-	println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash);
+	let _report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap();
 }