diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
index ea438f80552e283cc0f9c1501d2d204e8bb2e709..3b1779e40b60a0f407d6001d3ffd6c4723ae349a 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs
@@ -396,7 +396,7 @@ fn relay_commands_add_remove_username_authority() {
 		);
 	});
 
-	// Now, remove the username authority with another priviledged XCM call.
+	// Now, remove the username authority with another privileged XCM call.
 	Westend::execute_with(|| {
 		type Runtime = <Westend as Chain>::Runtime;
 		type RuntimeCall = <Westend as Chain>::RuntimeCall;
diff --git a/prdoc/pr_6890.prdoc b/prdoc/pr_6890.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..b22a339035d81be722b139bd4de1337d4179872d
--- /dev/null
+++ b/prdoc/pr_6890.prdoc
@@ -0,0 +1,19 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Alter semantic meaning of 0 in metering limits of EVM contract calls
+
+doc:
+  - audience: [ Runtime Dev, Runtime User ]
+    description: |
+      A limit of 0, for gas meters and storage meters, no longer has the meaning of unlimited metering.
+
+crates:
+  - name: pallet-revive
+    bump: patch
+  - name: pallet-revive-fixtures
+    bump: patch
+  - name: pallet-revive-uapi
+    bump: patch
+  - name: pallet-revive-eth-rpc
+    bump: patch
diff --git a/substrate/frame/revive/fixtures/contracts/call.rs b/substrate/frame/revive/fixtures/contracts/call.rs
index ee51548879d9de9479d5d9f1c695f6c6d4bc5889..7c4c0882c6b87c526b4e90d4d00c399f584fab49 100644
--- a/substrate/frame/revive/fixtures/contracts/call.rs
+++ b/substrate/frame/revive/fixtures/contracts/call.rs
@@ -38,10 +38,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::empty(),
 		callee_addr,
-		0u64,       // How much ref_time to devote for the execution. 0 = all.
-		0u64,       // How much proof_size to devote for the execution. 0 = all.
-		None,       // No deposit limit.
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,       // How much ref_time to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
+		&[0u8; 32],     // Value transferred to the contract.
 		callee_input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs
index 129adde2cec915adbf2f3327ab6b536466b607e9..9a8fe5f5f6cc536d39a255db7a9d803e3b4bd70e 100644
--- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs
+++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs
@@ -42,9 +42,9 @@ fn assert_call<const N: usize>(callee_address: &[u8; 20], expected_output: [u8;
 	api::call(
 		uapi::CallFlags::ALLOW_REENTRY,
 		callee_address,
-		0u64,
-		0u64,
-		None,
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
 		&[0u8; 32],
 		&[],
 		Some(output_buf_capped),
@@ -67,9 +67,9 @@ fn assert_instantiate<const N: usize>(expected_output: [u8; BUF_SIZE]) {
 
 	api::instantiate(
 		&code_hash,
-		0u64,
-		0u64,
-		None,
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
 		&[0; 32],
 		&[0; 32],
 		None,
diff --git a/substrate/frame/revive/fixtures/contracts/call_return_code.rs b/substrate/frame/revive/fixtures/contracts/call_return_code.rs
index 2d13b9f7095638a29f523d15b7d1c94dd2012946..19b3ae3fdb2624f341df5c781bf03d7fa77123f1 100644
--- a/substrate/frame/revive/fixtures/contracts/call_return_code.rs
+++ b/substrate/frame/revive/fixtures/contracts/call_return_code.rs
@@ -42,10 +42,10 @@ pub extern "C" fn call() {
 	let err_code = match api::call(
 		uapi::CallFlags::empty(),
 		callee_addr,
-		0u64,                // How much ref_time to devote for the execution. 0 = all.
-		0u64,                // How much proof_size to devote for the execution. 0 = all.
-		None,                // No deposit limit.
-		value, 				 // Value transferred to the contract.
+		u64::MAX,                 // How much ref_time to devote for the execution. u64::MAX = use all.
+		u64::MAX,                 // How much proof_size to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
+		value,                    // Value transferred to the contract.
 		input,
 		None,
 	) {
diff --git a/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs b/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs
index 8c8aee9628498e4cbc67e8e9f304106c717a486f..78b275459f0e005841ee5f96d0b03693a137efb3 100644
--- a/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs
+++ b/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs
@@ -42,10 +42,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::empty(),
 		callee_addr,
-		0u64,       // How much ref_time to devote for the execution. 0 = all.
-		0u64,       // How much proof_size to devote for the execution. 0 = all.
-		None,       // No deposit limit.
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,                 // How much ref_time to devote for the execution. u64::MAX = use all.
+		u64::MAX,                 // How much proof_size to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32],           // No deposit limit.
+		&[0u8; 32],               // Value transferred to the contract.
 		callee_input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs b/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs
index 330393e706e98fea7f7e6b04816885f37ac21073..155a4b41bd95f330be6f3af261fc6db7f3acb044 100644
--- a/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs
+++ b/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs
@@ -40,10 +40,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::from_bits(flags).unwrap(),
 		callee_addr,
-		0u64,               // How much ref_time to devote for the execution. 0 = all.
-		0u64,               // How much proof_size to devote for the execution. 0 = all.
-		None,               // No deposit limit.
-		&u256_bytes(value), // Value transferred to the contract.
+		u64::MAX,                 // How much ref_time to devote for the execution. u64::MAX = use all.
+		u64::MAX,                 // How much proof_size to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32],           // No deposit limit.
+		&u256_bytes(value),       // Value transferred to the contract.
 		forwarded_input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/call_with_limit.rs b/substrate/frame/revive/fixtures/contracts/call_with_limit.rs
index 6ab892a6b7ae8416d923215df0a13b9ee13faf0c..af5c301a353c94cc240c39a73c9ffeffed906152 100644
--- a/substrate/frame/revive/fixtures/contracts/call_with_limit.rs
+++ b/substrate/frame/revive/fixtures/contracts/call_with_limit.rs
@@ -43,8 +43,8 @@ pub extern "C" fn call() {
 		callee_addr,
 		ref_time,
 		proof_size,
-		None,       // No deposit limit.
-		&[0u8; 32], // value transferred to the contract.
+		&[u8::MAX; 32],   // No deposit limit.
+		&[0u8; 32],       // value transferred to the contract.
 		forwarded_input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/caller_contract.rs b/substrate/frame/revive/fixtures/contracts/caller_contract.rs
index edad43fae251918ed61f43283cd97c3319348f28..d042dc2c22a2508fafdeecf75e2003006b75a117 100644
--- a/substrate/frame/revive/fixtures/contracts/caller_contract.rs
+++ b/substrate/frame/revive/fixtures/contracts/caller_contract.rs
@@ -42,9 +42,9 @@ pub extern "C" fn call() {
 	// Fail to deploy the contract since it returns a non-zero exit status.
 	let res = api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&reverted_input,
 		None,
@@ -56,9 +56,9 @@ pub extern "C" fn call() {
 	// Fail to deploy the contract due to insufficient ref_time weight.
 	let res = api::instantiate(
 		code_hash,
-		1u64, // too little ref_time weight
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		1u64,           // too little ref_time weight
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		None,
@@ -70,9 +70,9 @@ pub extern "C" fn call() {
 	// Fail to deploy the contract due to insufficient proof_size weight.
 	let res = api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		1u64, // Too little proof_size weight
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		1u64,           // Too little proof_size weight
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		None,
@@ -86,9 +86,9 @@ pub extern "C" fn call() {
 
 	api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		Some(&mut callee),
@@ -101,9 +101,9 @@ pub extern "C" fn call() {
 	let res = api::call(
 		uapi::CallFlags::empty(),
 		&callee,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&reverted_input,
 		None,
@@ -114,9 +114,9 @@ pub extern "C" fn call() {
 	let res = api::call(
 		uapi::CallFlags::empty(),
 		&callee,
-		1u64, // Too little ref_time weight.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		1u64,           // Too little ref_time weight.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		None,
@@ -127,9 +127,9 @@ pub extern "C" fn call() {
 	let res = api::call(
 		uapi::CallFlags::empty(),
 		&callee,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		1u64, // too little proof_size weight
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		1u64,           // too little proof_size weight
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		None,
@@ -141,9 +141,9 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::empty(),
 		&callee,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&value,
 		&input,
 		Some(&mut &mut output[..]),
diff --git a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs b/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs
index 22d6c5b548d87acd2bffc17401f42a682d328dd7..9b76b9d39ee946b20d07c9ff2458123c9b0c9968 100644
--- a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs
+++ b/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs
@@ -54,10 +54,10 @@ pub extern "C" fn call() {
 		api::call(
 			uapi::CallFlags::ALLOW_REENTRY,
 			&addr,
-			0u64,       // How much ref_time to devote for the execution. 0 = all.
-			0u64,       // How much proof_size to devote for the execution. 0 = all.
-			None,       // No deposit limit.
-			&[0u8; 32], // Value transferred to the contract.
+			u64::MAX,       // How much ref_time to devote for the execution. u64::MAX = use all.
+			u64::MAX,       // How much proof_size to devote for the execution. u64::MAX = use all.
+			&[u8::MAX; 32], // No deposit limit.
+			&[0u8; 32],     // Value transferred to the contract.
 			input,
 			None,
 		)
diff --git a/substrate/frame/revive/fixtures/contracts/create1_with_value.rs b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs
index c6adab82886076484b57972c943d676c443d41e9..3554f8f620a29f08e4855ef5b77a2be3a3f6c887 100644
--- a/substrate/frame/revive/fixtures/contracts/create1_with_value.rs
+++ b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs
@@ -34,6 +34,16 @@ pub extern "C" fn call() {
 	api::value_transferred(&mut value);
 
 	// Deploy the contract with no salt (equivalent to create1).
-	let ret = api::instantiate(code_hash, 0u64, 0u64, None, &value, &[], None, None, None);
+	let ret = api::instantiate(
+		code_hash,
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
+		&value,
+		&[],
+		None,
+		None,
+		None
+	);
 	assert!(ret.is_ok());
 }
diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs
index a12c36af856a9018e18630ab5476246bd51392f9..5bb11e27903e7ff15eebc0f6abad80319cd83677 100644
--- a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs
+++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs
@@ -43,10 +43,10 @@ pub extern "C" fn call() {
 	let ret = api::call(
 		uapi::CallFlags::empty(),
 		callee,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		Some(deposit_limit),
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,      // How much ref_time weight to devote for the execution. u64::MAX = use all resources.
+		u64::MAX,      // How much proof_size weight to devote for the execution. u64::MAX = use all resources.
+		deposit_limit,
+		&[0u8; 32],    // Value transferred to the contract.
 		input,
 		None,
 	);
diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs
index ecc0fc79e6fdae77ccb132ea6fc2c6be594ad8a9..f627bc8ba6c418b4d36a42eda2ea49daf382e82e 100644
--- a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs
+++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs
@@ -41,9 +41,9 @@ pub extern "C" fn call() {
 
 	let ret = api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		Some(deposit_limit),
+		u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		deposit_limit,
 		&value,
 		input,
 		Some(&mut address),
diff --git a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs
index cf12fed27563a960840cd2e31c1a7a28979d4738..660db84028dbdd5b7c990beaa26b5a82dfe4f8dc 100644
--- a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs
+++ b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs
@@ -49,10 +49,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::empty(),
 		callee,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None,
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = all.
+		&[u8::MAX; 32], // No deposit limit.
+		&[0u8; 32],     // Value transferred to the contract.
 		input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call.rs b/substrate/frame/revive/fixtures/contracts/delegate_call.rs
index 3cf74acf1321a390e437edf497495881b1a8012c..0dedd5f704cb9a84d8d2387a8b407d91047ac34b 100644
--- a/substrate/frame/revive/fixtures/contracts/delegate_call.rs
+++ b/substrate/frame/revive/fixtures/contracts/delegate_call.rs
@@ -46,7 +46,15 @@ pub extern "C" fn call() {
 	assert!(value[0] == 2u8);
 
 	let input = [0u8; 0];
-	api::delegate_call(uapi::CallFlags::empty(), address, ref_time, proof_size, None, &input, None).unwrap();
+	api::delegate_call(
+		uapi::CallFlags::empty(),
+		address,
+		ref_time,
+		proof_size,
+		&[u8::MAX; 32],
+		&input,
+		None
+	).unwrap();
 
 	api::get_storage(StorageFlags::empty(), &key, value).unwrap();
 	assert!(value[0] == 1u8);
diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs
index 0f157f5a18ac20c64994548aa9b1570c47a1e162..0c503aa93c565bc5c6b593a77a93d0f51ace4498 100644
--- a/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs
+++ b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs
@@ -34,7 +34,15 @@ pub extern "C" fn call() {
 	);
 
 	let input = [0u8; 0];
-	let ret = api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, Some(&u256_bytes(deposit_limit)), &input, None);
+	let ret = api::delegate_call(
+		uapi::CallFlags::empty(),
+		address,
+		u64::MAX,
+		u64::MAX,
+		&u256_bytes(deposit_limit),
+		&input,
+		None
+	);
 
 	if let Err(code) = ret {
 		api::return_value(uapi::ReturnFlags::REVERT, &(code as u32).to_le_bytes());
diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs
index a8501dad4692d51477db7a5027107249393be0b2..b7bdb792c76c5c30d39fe1d62daa426a837fb945 100644
--- a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs
+++ b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs
@@ -32,5 +32,13 @@ pub extern "C" fn call() {
 
 	// Delegate call into passed address.
 	let input = [0u8; 0];
-	api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &input, None).unwrap();
+	api::delegate_call(
+		uapi::CallFlags::empty(),
+		address,
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
+		&input,
+		None
+	).unwrap();
 }
diff --git a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs
index 8342f4acf95296d621c855408aacc5b8457a4234..c2c7da528ba7c92939facce5dfcb9cb2b82b6ffd 100644
--- a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs
+++ b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs
@@ -35,9 +35,9 @@ pub extern "C" fn deploy() {
 
 	api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&VALUE,
 		&input,
 		Some(&mut address),
@@ -62,9 +62,9 @@ pub extern "C" fn call() {
 	let res = api::call(
 		uapi::CallFlags::empty(),
 		&callee_addr,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&VALUE,
 		&[0u8; 1],
 		None,
@@ -75,9 +75,9 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::empty(),
 		&callee_addr,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, // How much proof_size weight to devote for the execution. 0 = all.
-		None, // No deposit limit.
+		u64::MAX,       // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,       // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32], // No deposit limit.
 		&VALUE,
 		&[0u8; 0],
 		None,
diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs
index 6e3e708a6b3d82917e7b2cf09b195fd4c80c1743..53fb213143c489e96b59058292030135ed3a7db8 100644
--- a/substrate/frame/revive/fixtures/contracts/drain.rs
+++ b/substrate/frame/revive/fixtures/contracts/drain.rs
@@ -41,7 +41,7 @@ pub extern "C" fn call() {
 		&[0u8; 20],
 		0,
 		0,
-		None,
+		&[u8::MAX; 32],
 		&u256_bytes(balance),
 		&[],
 		None,
diff --git a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs
index 9764859c619b90452eeacbb337a7b94a2cd7d86c..f7cbd75be5aaaf3fcf0ac01bfd33fdd2e83bc387 100644
--- a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs
+++ b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs
@@ -33,10 +33,9 @@ pub extern "C" fn call() {
 
 	let err_code = match api::instantiate(
 		code_hash,
-		0u64, // How much ref_time weight to devote for the execution. 0 = all.
-		0u64, /* How much proof_size weight to devote for the execution. 0 =
-		       * all. */
-		None,                   // No deposit limit.
+		u64::MAX,               // How much ref_time weight to devote for the execution. u64::MAX = use all.
+		u64::MAX,               // How much proof_size weight to devote for the execution. u64::MAX = use all.
+		&[u8::MAX; 32],         // No deposit limit.
 		&u256_bytes(10_000u64), // Value to transfer.
 		input,
 		None,
diff --git a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs
index 3d7702c6537adc3528eeb23443347185f144c172..6be5d5c72f9ac7b94cbb191419796c68be4c52cc 100644
--- a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs
+++ b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs
@@ -52,7 +52,15 @@ fn load_input(delegate_call: bool) {
 	}
 
 	if delegate_call {
-		api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &[], None).unwrap();
+		api::delegate_call(
+			uapi::CallFlags::empty(),
+			address,
+			u64::MAX,
+			u64::MAX,
+			&[u8::MAX; 32],
+			&[],
+			None
+		).unwrap();
 	}
 }
 
diff --git a/substrate/frame/revive/fixtures/contracts/origin.rs b/substrate/frame/revive/fixtures/contracts/origin.rs
index 8e9afd8e80526b8ba272c8cbe8007d19b76afe5b..151ca3da77cd05349ef03db4f0579f73a2230499 100644
--- a/substrate/frame/revive/fixtures/contracts/origin.rs
+++ b/substrate/frame/revive/fixtures/contracts/origin.rs
@@ -49,9 +49,9 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::ALLOW_REENTRY,
 		&addr,
-		0u64,
-		0u64,
-		None,
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
 		&[0; 32],
 		&[],
 		Some(&mut &mut buf[..]),
diff --git a/substrate/frame/revive/fixtures/contracts/read_only_call.rs b/substrate/frame/revive/fixtures/contracts/read_only_call.rs
index ea74d56867f5efd1dd2f671a7b015418f7b1d7b7..0a87ecbb9b140a6e4d797a83a174e565b6954d7d 100644
--- a/substrate/frame/revive/fixtures/contracts/read_only_call.rs
+++ b/substrate/frame/revive/fixtures/contracts/read_only_call.rs
@@ -39,10 +39,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::READ_ONLY,
 		callee_addr,
-		0u64,       // How much ref_time to devote for the execution. 0 = all.
-		0u64,       // How much proof_size to devote for the execution. 0 = all.
-		None,       // No deposit limit.
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,                 // How much ref_time to devote for the execution. u64::MAX = all.
+		u64::MAX,                 // How much proof_size to devote for the execution. u64::MAX = all.
+		&[u8::MAX; 32],           // No deposit limit.
+		&[0u8; 32],               // Value transferred to the contract.
 		callee_input,
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/recurse.rs b/substrate/frame/revive/fixtures/contracts/recurse.rs
index 2e70d67d8c738c700f35d281a51605e7b9c76170..ead565c01459e6848c846611abe1c6132b751940 100644
--- a/substrate/frame/revive/fixtures/contracts/recurse.rs
+++ b/substrate/frame/revive/fixtures/contracts/recurse.rs
@@ -43,10 +43,10 @@ pub extern "C" fn call() {
 	api::call(
 		uapi::CallFlags::ALLOW_REENTRY,
 		&addr,
-		0u64,       // How much ref_time to devote for the execution. 0 = all.
-		0u64,       // How much deposit_limit to devote for the execution. 0 = all.
-		None,       // No deposit limit.
-		&[0u8; 32], // Value transferred to the contract.
+		u64::MAX,       // How much ref_time to devote for the execution. u64::MAX = use all resources.
+		u64::MAX,       // How much proof_size to devote for the execution. u64::MAX = use all resources.
+		&[u8::MAX; 32], // No deposit limit.
+		&[0u8; 32],     // Value transferred to the contract.
 		&(calls_left - 1).to_le_bytes(),
 		None,
 	)
diff --git a/substrate/frame/revive/fixtures/contracts/return_data_api.rs b/substrate/frame/revive/fixtures/contracts/return_data_api.rs
index 1d483373cffdd8a31123c25148c1469deee06805..1407e5323ea18989bcf5efec8867e48d75ff9710 100644
--- a/substrate/frame/revive/fixtures/contracts/return_data_api.rs
+++ b/substrate/frame/revive/fixtures/contracts/return_data_api.rs
@@ -80,8 +80,16 @@ fn assert_return_data_size_of(expected: u64) {
 
 /// Assert the return data to be reset after a balance transfer.
 fn assert_balance_transfer_does_reset() {
-	api::call(uapi::CallFlags::empty(), &[0u8; 20], 0, 0, None, &u256_bytes(128), &[], None)
-		.unwrap();
+	api::call(
+		uapi::CallFlags::empty(),
+		&[0u8; 20],
+		u64::MAX,
+		u64::MAX,
+		&[u8::MAX; 32],
+		&u256_bytes(128),
+		&[],
+		None
+	).unwrap();
 	assert_return_data_size_of(0);
 }
 
@@ -111,9 +119,9 @@ pub extern "C" fn call() {
 	let mut instantiate = |exit_flag| {
 		api::instantiate(
 			code_hash,
-			0u64,
-			0u64,
-			None,
+			u64::MAX,
+			u64::MAX,
+			&[u8::MAX; 32],
 			&[0; 32],
 			&construct_input(exit_flag),
 			Some(&mut address_buf),
@@ -125,9 +133,9 @@ pub extern "C" fn call() {
 		api::call(
 			uapi::CallFlags::empty(),
 			address_buf,
-			0u64,
-			0u64,
-			None,
+			u64::MAX,
+			u64::MAX,
+			&[u8::MAX; 32],
 			&[0; 32],
 			&construct_input(exit_flag),
 			None,
diff --git a/substrate/frame/revive/fixtures/contracts/self_destruct.rs b/substrate/frame/revive/fixtures/contracts/self_destruct.rs
index 2f37706634bd126f465ce6ea579cc0878d951bdd..053e545deb19e0c9ecb322ec38f023d566f3b726 100644
--- a/substrate/frame/revive/fixtures/contracts/self_destruct.rs
+++ b/substrate/frame/revive/fixtures/contracts/self_destruct.rs
@@ -42,10 +42,10 @@ pub extern "C" fn call() {
 		api::call(
 			uapi::CallFlags::ALLOW_REENTRY,
 			&addr,
-			0u64,       // How much ref_time to devote for the execution. 0 = all.
-			0u64,       // How much proof_size to devote for the execution. 0 = all.
-			None,       // No deposit limit.
-			&[0u8; 32], // Value to transfer.
+			u64::MAX,                 // How much ref_time to devote for the execution. u64 = all.
+			u64::MAX,                 // How much proof_size to devote for the execution. u64 = all.
+			&[u8::MAX; 32],           // No deposit limit.
+			&[0u8; 32],               // Value to transfer.
 			&[0u8; 0],
 			None,
 		)
diff --git a/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs b/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs
index 09d45d0a8411a3a9fca37a8034aa880317ad1834..053f97feda4a8dcc8dbd302aed6dbc952d743874 100644
--- a/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs
+++ b/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs
@@ -33,7 +33,7 @@ pub extern "C" fn call() {
 		&[0u8; 20],
 		0,
 		0,
-		None,
+		&[u8::MAX; 32],
 		&u256_bytes(100u64),
 		&[],
 		None,
diff --git a/substrate/frame/revive/fixtures/src/lib.rs b/substrate/frame/revive/fixtures/src/lib.rs
index 38171edf11524614341fe02e41072209886801d6..7685253d1ea2cc227a6ef13f20330c711ada4502 100644
--- a/substrate/frame/revive/fixtures/src/lib.rs
+++ b/substrate/frame/revive/fixtures/src/lib.rs
@@ -22,7 +22,7 @@ extern crate alloc;
 // generated file that tells us where to find the fixtures
 include!(concat!(env!("OUT_DIR"), "/fixture_location.rs"));
 
-/// Load a given wasm module and returns a wasm binary contents along with it's hash.
+/// Load a given wasm module and returns a wasm binary contents along with its hash.
 #[cfg(feature = "std")]
 pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec<u8>, sp_core::H256)> {
 	let out_dir: std::path::PathBuf = FIXTURE_DIR.into();
diff --git a/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm
index 585fbb392a314c15a35e7e529106738bde3be02a..38a1098fe3a767aa0af74764bf7247e59f6110b7 100644
Binary files a/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm and b/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm differ
diff --git a/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm
index 3f96fdfc21d8d8fc5bf68a34f0c9f7b055afa2a4..d0082db90e5e398832e4a32a9ec86dce83d16dd5 100644
Binary files a/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm and b/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm differ
diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs
index e67c39ec08991636fe26b032a87ab8b94e24a822..1796348ff321209aa8b8c3c531b29d182d6f745c 100644
--- a/substrate/frame/revive/src/benchmarking/mod.rs
+++ b/substrate/frame/revive/src/benchmarking/mod.rs
@@ -1648,8 +1648,8 @@ mod benchmarks {
 				memory.as_mut_slice(),
 				CallFlags::CLONE_INPUT.bits(), // flags
 				0,                             // callee_ptr
-				0,                             // ref_time_limit
-				0,                             // proof_size_limit
+				u64::MAX,                      // ref_time_limit
+				u64::MAX,                      // proof_size_limit
 				callee_len,                    // deposit_ptr
 				callee_len + deposit_len,      // value_ptr
 				0,                             // input_data_ptr
@@ -1688,8 +1688,8 @@ mod benchmarks {
 				memory.as_mut_slice(),
 				0,           // flags
 				0,           // address_ptr
-				0,           // ref_time_limit
-				0,           // proof_size_limit
+				u64::MAX,    // ref_time_limit
+				u64::MAX,    // proof_size_limit
 				address_len, // deposit_ptr
 				0,           // input_data_ptr
 				0,           // input_data_len
@@ -1715,7 +1715,7 @@ mod benchmarks {
 		let value_bytes = Into::<U256>::into(value).encode();
 		let value_len = value_bytes.len() as u32;
 
-		let deposit: BalanceOf<T> = 0u32.into();
+		let deposit: BalanceOf<T> = BalanceOf::<T>::max_value();
 		let deposit_bytes = Into::<U256>::into(deposit).encode();
 		let deposit_len = deposit_bytes.len() as u32;
 
@@ -1750,8 +1750,8 @@ mod benchmarks {
 			result = runtime.bench_instantiate(
 				memory.as_mut_slice(),
 				0,                   // code_hash_ptr
-				0,                   // ref_time_limit
-				0,                   // proof_size_limit
+				u64::MAX,            // ref_time_limit
+				u64::MAX,            // proof_size_limit
 				offset(hash_len),    // deposit_ptr
 				offset(deposit_len), // value_ptr
 				offset(value_len),   // input_data_ptr
diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs
index 478e96dc994d37877bb8d212aef3c06f2c3e272b..c069216d6cc71bc96b6d18512198aece824535f7 100644
--- a/substrate/frame/revive/src/exec.rs
+++ b/substrate/frame/revive/src/exec.rs
@@ -53,7 +53,7 @@ use sp_core::{
 };
 use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
 use sp_runtime::{
-	traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero},
+	traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating, Zero},
 	DispatchError, SaturatedConversion,
 };
 
@@ -885,9 +885,9 @@ where
 			args,
 			value,
 			gas_meter,
-			Weight::zero(),
+			Weight::max_value(),
 			storage_meter,
-			BalanceOf::<T>::zero(),
+			BalanceOf::<T>::max_value(),
 			false,
 			true,
 		)?
@@ -1117,25 +1117,15 @@ where
 				return Ok(output);
 			}
 
-			// Storage limit is normally enforced as late as possible (when the last frame returns)
-			// so that the ordering of storage accesses does not matter.
-			// (However, if a special limit was set for a sub-call, it should be enforced right
-			// after the sub-call returned. See below for this case of enforcement).
-			if self.frames.is_empty() {
-				let frame = &mut self.first_frame;
-				frame.contract_info.load(&frame.account_id);
-				let contract = frame.contract_info.as_contract();
-				frame.nested_storage.enforce_limit(contract)?;
-			}
-
 			let frame = self.top_frame_mut();
 
-			// If a special limit was set for the sub-call, we enforce it here.
-			// The sub-call will be rolled back in case the limit is exhausted.
+			// The storage deposit is only charged at the end of every call stack.
+			// To make sure that no sub call uses more than it is allowed to,
+			// the limit is manually enforced here.
 			let contract = frame.contract_info.as_contract();
 			frame
 				.nested_storage
-				.enforce_subcall_limit(contract)
+				.enforce_limit(contract)
 				.map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?;
 
 			let account_id = T::AddressMapper::to_address(&frame.account_id);
@@ -1463,7 +1453,7 @@ where
 				FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
 				value,
 				gas_limit,
-				deposit_limit.try_into().map_err(|_| Error::<T>::BalanceConversionFailed)?,
+				deposit_limit.saturated_into::<BalanceOf<T>>(),
 				// Enable read-only access if requested; cannot disable it if already set.
 				read_only || self.is_read_only(),
 			)? {
@@ -1519,7 +1509,7 @@ where
 			},
 			value,
 			gas_limit,
-			deposit_limit.try_into().map_err(|_| Error::<T>::BalanceConversionFailed)?,
+			deposit_limit.saturated_into::<BalanceOf<T>>(),
 			self.is_read_only(),
 		)?;
 		self.run(executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE), input_data)
@@ -1549,7 +1539,7 @@ where
 			},
 			value.try_into().map_err(|_| Error::<T>::BalanceConversionFailed)?,
 			gas_limit,
-			deposit_limit.try_into().map_err(|_| Error::<T>::BalanceConversionFailed)?,
+			deposit_limit.saturated_into::<BalanceOf<T>>(),
 			self.is_read_only(),
 		)?;
 		let address = T::AddressMapper::to_address(&self.top_frame().account_id);
@@ -3098,8 +3088,8 @@ mod tests {
 				let (address, output) = ctx
 					.ext
 					.instantiate(
-						Weight::zero(),
-						U256::zero(),
+						Weight::MAX,
+						U256::MAX,
 						dummy_ch,
 						<Test as Config>::Currency::minimum_balance().into(),
 						vec![],
@@ -3802,8 +3792,8 @@ mod tests {
 		let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| {
 			ctx.ext
 				.instantiate(
-					Weight::zero(),
-					U256::zero(),
+					Weight::MAX,
+					U256::MAX,
 					fail_code,
 					ctx.ext.minimum_balance() * 100,
 					vec![],
@@ -3819,8 +3809,8 @@ mod tests {
 			let addr = ctx
 				.ext
 				.instantiate(
-					Weight::zero(),
-					U256::zero(),
+					Weight::MAX,
+					U256::MAX,
 					success_code,
 					ctx.ext.minimum_balance() * 100,
 					vec![],
@@ -4597,7 +4587,7 @@ mod tests {
 				// Successful instantiation should set the output
 				let address = ctx
 					.ext
-					.instantiate(Weight::zero(), U256::zero(), ok_ch, value, vec![], None)
+					.instantiate(Weight::MAX, U256::MAX, ok_ch, value, vec![], None)
 					.unwrap();
 				assert_eq!(
 					ctx.ext.last_frame_output(),
@@ -4606,15 +4596,7 @@ mod tests {
 
 				// Balance transfers should reset the output
 				ctx.ext
-					.call(
-						Weight::zero(),
-						U256::zero(),
-						&address,
-						U256::from(1),
-						vec![],
-						true,
-						false,
-					)
+					.call(Weight::MAX, U256::MAX, &address, U256::from(1), vec![], true, false)
 					.unwrap();
 				assert_eq!(ctx.ext.last_frame_output(), &Default::default());
 
@@ -4827,7 +4809,7 @@ mod tests {
 
 				// Constructors can not access the immutable data
 				ctx.ext
-					.instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None)
+					.instantiate(Weight::MAX, U256::MAX, dummy_ch, value, vec![], None)
 					.unwrap();
 
 				exec_success()
@@ -4944,7 +4926,7 @@ mod tests {
 			move |ctx, _| {
 				let value = <Test as Config>::Currency::minimum_balance().into();
 				ctx.ext
-					.instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None)
+					.instantiate(Weight::MAX, U256::MAX, dummy_ch, value, vec![], None)
 					.unwrap();
 
 				exec_success()
@@ -4989,7 +4971,7 @@ mod tests {
 			move |ctx, _| {
 				let value = <Test as Config>::Currency::minimum_balance().into();
 				ctx.ext
-					.instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None)
+					.instantiate(Weight::MAX, U256::MAX, dummy_ch, value, vec![], None)
 					.unwrap();
 
 				exec_success()
diff --git a/substrate/frame/revive/src/gas.rs b/substrate/frame/revive/src/gas.rs
index 5c30a0a510095c66ff831c2dbce3c2ee75f92af8..e8338db12192bfe5ba698f191b3469be12d5a511 100644
--- a/substrate/frame/revive/src/gas.rs
+++ b/substrate/frame/revive/src/gas.rs
@@ -22,7 +22,7 @@ use frame_support::{
 	weights::Weight,
 	DefaultNoBound,
 };
-use sp_runtime::{traits::Zero, DispatchError};
+use sp_runtime::DispatchError;
 
 #[cfg(test)]
 use std::{any::Any, fmt::Debug};
@@ -168,25 +168,19 @@ impl<T: Config> GasMeter<T> {
 		}
 	}
 
-	/// Create a new gas meter by removing gas from the current meter.
+	/// Create a new gas meter by removing *all* the gas from the current meter.
 	///
-	/// # Note
-	///
-	/// Passing `0` as amount is interpreted as "all remaining gas".
+	/// This should only be used by the primordial frame in a sequence of calls - every subsequent
+	/// frame should use [`nested`](Self::nested).
+	pub fn nested_take_all(&mut self) -> Self {
+		let gas_left = self.gas_left;
+		self.gas_left -= gas_left;
+		GasMeter::new(gas_left)
+	}
+
+	/// Create a new gas meter for a nested call by removing gas from the current meter.
 	pub fn nested(&mut self, amount: Weight) -> Self {
-		let amount = Weight::from_parts(
-			if amount.ref_time().is_zero() {
-				self.gas_left().ref_time()
-			} else {
-				amount.ref_time()
-			},
-			if amount.proof_size().is_zero() {
-				self.gas_left().proof_size()
-			} else {
-				amount.proof_size()
-			},
-		)
-		.min(self.gas_left);
+		let amount = amount.min(self.gas_left);
 		self.gas_left -= amount;
 		GasMeter::new(amount)
 	}
@@ -392,6 +386,50 @@ mod tests {
 		assert!(gas_meter.charge(SimpleToken(1)).is_err());
 	}
 
+	/// Previously, passing a `Weight` of 0 to `nested` would consume all of the meter's current
+	/// gas.
+	///
+	/// Now, a `Weight` of 0 means no gas for the nested call.
+	#[test]
+	fn nested_zero_gas_requested() {
+		let test_weight = 50000.into();
+		let mut gas_meter = GasMeter::<Test>::new(test_weight);
+		let gas_for_nested_call = gas_meter.nested(0.into());
+
+		assert_eq!(gas_meter.gas_left(), 50000.into());
+		assert_eq!(gas_for_nested_call.gas_left(), 0.into())
+	}
+
+	#[test]
+	fn nested_some_gas_requested() {
+		let test_weight = 50000.into();
+		let mut gas_meter = GasMeter::<Test>::new(test_weight);
+		let gas_for_nested_call = gas_meter.nested(10000.into());
+
+		assert_eq!(gas_meter.gas_left(), 40000.into());
+		assert_eq!(gas_for_nested_call.gas_left(), 10000.into())
+	}
+
+	#[test]
+	fn nested_all_gas_requested() {
+		let test_weight = Weight::from_parts(50000, 50000);
+		let mut gas_meter = GasMeter::<Test>::new(test_weight);
+		let gas_for_nested_call = gas_meter.nested(test_weight);
+
+		assert_eq!(gas_meter.gas_left(), Weight::from_parts(0, 0));
+		assert_eq!(gas_for_nested_call.gas_left(), 50_000.into())
+	}
+
+	#[test]
+	fn nested_excess_gas_requested() {
+		let test_weight = Weight::from_parts(50000, 50000);
+		let mut gas_meter = GasMeter::<Test>::new(test_weight);
+		let gas_for_nested_call = gas_meter.nested(test_weight + 10000.into());
+
+		assert_eq!(gas_meter.gas_left(), Weight::from_parts(0, 0));
+		assert_eq!(gas_for_nested_call.gas_left(), 50_000.into())
+	}
+
 	// Make sure that the gas meter does not charge in case of overcharge
 	#[test]
 	fn overcharge_does_not_charge() {
diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs
index a7127f812b4b9726c4b7b191956c4fb1975b8a83..452d2c8a3067cf1e7540abfd5bc44b615be69226 100644
--- a/substrate/frame/revive/src/primitives.rs
+++ b/substrate/frame/revive/src/primitives.rs
@@ -72,7 +72,7 @@ pub struct ContractResult<R, Balance, EventRecord> {
 	///
 	/// # Note
 	///
-	/// This can only different from [`Self::gas_consumed`] when weight pre charging
+	/// This can only be different from [`Self::gas_consumed`] when weight pre charging
 	/// is used. Currently, only `seal_call_runtime` makes use of pre charging.
 	/// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging
 	/// when a non-zero `gas_limit` argument is supplied.
diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs
index 6eddf048be98fc0470650fdb1c90197ea03db91e..4febcb0c4066c418b1b7189c12a4cc8403601f72 100644
--- a/substrate/frame/revive/src/storage/meter.rs
+++ b/substrate/frame/revive/src/storage/meter.rs
@@ -101,12 +101,8 @@ pub struct Root;
 
 /// State parameter that constitutes a meter that is in its nested state.
 /// Its value indicates whether the nested meter has its own limit.
-#[derive(DefaultNoBound, RuntimeDebugNoBound)]
-pub enum Nested {
-	#[default]
-	DerivedLimit,
-	OwnLimit,
-}
+#[derive(Default, Debug)]
+pub struct Nested;
 
 impl State for Root {}
 impl State for Nested {}
@@ -125,10 +121,8 @@ pub struct RawMeter<T: Config, E, S: State + Default + Debug> {
 	/// We only have one charge per contract hence the size of this vector is
 	/// limited by the maximum call depth.
 	charges: Vec<Charge<T>>,
-	/// We store the nested state to determine if it has a special limit for sub-call.
-	nested: S,
 	/// Type parameter only used in impls.
-	_phantom: PhantomData<E>,
+	_phantom: PhantomData<(E, S)>,
 }
 
 /// This type is used to describe a storage change when charging from the meter.
@@ -281,21 +275,14 @@ where
 	S: State + Default + Debug,
 {
 	/// Create a new child that has its `limit`.
-	/// Passing `0` as the limit is interpreted as to take whatever is remaining from its parent.
 	///
 	/// This is called whenever a new subcall is initiated in order to track the storage
 	/// usage for this sub call separately. This is necessary because we want to exchange balance
 	/// with the current contract we are interacting with.
 	pub fn nested(&self, limit: BalanceOf<T>) -> RawMeter<T, E, Nested> {
 		debug_assert!(matches!(self.contract_state(), ContractState::Alive));
-		// If a special limit is specified higher than it is available,
-		// we want to enforce the lesser limit to the nested meter, to fail in the sub-call.
-		let limit = self.available().min(limit);
-		if limit.is_zero() {
-			RawMeter { limit: self.available(), ..Default::default() }
-		} else {
-			RawMeter { limit, nested: Nested::OwnLimit, ..Default::default() }
-		}
+
+		RawMeter { limit: self.available().min(limit), ..Default::default() }
 	}
 
 	/// Absorb a child that was spawned to handle a sub call.
@@ -477,13 +464,6 @@ impl<T: Config, E: Ext<T>> RawMeter<T, E, Nested> {
 
 	/// [`Self::charge`] does not enforce the storage limit since we want to do this check as late
 	/// as possible to allow later refunds to offset earlier charges.
-	///
-	/// # Note
-	///
-	/// We normally need to call this **once** for every call stack and not for every cross contract
-	/// call. However, if a dedicated limit is specified for a sub-call, this needs to be called
-	/// once the sub-call has returned. For this, the [`Self::enforce_subcall_limit`] wrapper is
-	/// used.
 	pub fn enforce_limit(
 		&mut self,
 		info: Option<&mut ContractInfo<T>>,
@@ -502,18 +482,6 @@ impl<T: Config, E: Ext<T>> RawMeter<T, E, Nested> {
 		}
 		Ok(())
 	}
-
-	/// This is a wrapper around [`Self::enforce_limit`] to use on the exit from a sub-call to
-	/// enforce its special limit if needed.
-	pub fn enforce_subcall_limit(
-		&mut self,
-		info: Option<&mut ContractInfo<T>>,
-	) -> Result<(), DispatchError> {
-		match self.nested {
-			Nested::OwnLimit => self.enforce_limit(info),
-			Nested::DerivedLimit => Ok(()),
-		}
-	}
 }
 
 impl<T: Config> Ext<T> for ReservingExt {
@@ -724,6 +692,49 @@ mod tests {
 		)
 	}
 
+	/// Previously, passing a limit of 0 meant unlimited storage for a nested call.
+	///
+	/// Now, a limit of 0 means the subcall will not be able to use any storage.
+	#[test]
+	fn nested_zero_limit_requested() {
+		clear_ext();
+
+		let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap();
+		assert_eq!(meter.available(), 1_000);
+		let nested0 = meter.nested(BalanceOf::<Test>::zero());
+		assert_eq!(nested0.available(), 0);
+	}
+
+	#[test]
+	fn nested_some_limit_requested() {
+		clear_ext();
+
+		let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap();
+		assert_eq!(meter.available(), 1_000);
+		let nested0 = meter.nested(500);
+		assert_eq!(nested0.available(), 500);
+	}
+
+	#[test]
+	fn nested_all_limit_requested() {
+		clear_ext();
+
+		let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap();
+		assert_eq!(meter.available(), 1_000);
+		let nested0 = meter.nested(1_000);
+		assert_eq!(nested0.available(), 1_000);
+	}
+
+	#[test]
+	fn nested_over_limit_requested() {
+		clear_ext();
+
+		let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap();
+		assert_eq!(meter.available(), 1_000);
+		let nested0 = meter.nested(2_000);
+		assert_eq!(nested0.available(), 1_000);
+	}
+
 	#[test]
 	fn empty_charge_works() {
 		clear_ext();
@@ -879,7 +890,7 @@ mod tests {
 			let mut meter = TestMeter::new(&test_case.origin, 1_000, 0).unwrap();
 			assert_eq!(meter.available(), 1_000);
 
-			let mut nested0 = meter.nested(BalanceOf::<Test>::zero());
+			let mut nested0 = meter.nested(BalanceOf::<Test>::max_value());
 			nested0.charge(&Diff {
 				bytes_added: 5,
 				bytes_removed: 1,
@@ -895,7 +906,7 @@ mod tests {
 				items_deposit: 20,
 				immutable_data_len: 0,
 			});
-			let mut nested1 = nested0.nested(BalanceOf::<Test>::zero());
+			let mut nested1 = nested0.nested(BalanceOf::<Test>::max_value());
 			nested1.charge(&Diff { items_removed: 5, ..Default::default() });
 			nested1.charge(&Diff { bytes_added: 20, ..Default::default() });
 			nested1.terminate(&nested1_info, CHARLIE);
diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs
index 664578bf7672e3aed56223c229ded0636952306a..cf02d17a4d03ddaf5ed2df81bf9e01e98ca1e1bb 100644
--- a/substrate/frame/revive/src/tests.rs
+++ b/substrate/frame/revive/src/tests.rs
@@ -1149,7 +1149,7 @@ fn delegate_call() {
 
 		assert_ok!(builder::call(caller_addr)
 			.value(1337)
-			.data((callee_addr, 0u64, 0u64).encode())
+			.data((callee_addr, u64::MAX, u64::MAX).encode())
 			.build());
 	});
 }
@@ -2261,12 +2261,12 @@ fn gas_estimation_for_subcalls() {
 
 		// Run the test for all of those weight limits for the subcall
 		let weights = [
-			Weight::zero(),
+			Weight::MAX,
 			GAS_LIMIT,
 			GAS_LIMIT * 2,
 			GAS_LIMIT / 5,
-			Weight::from_parts(0, GAS_LIMIT.proof_size()),
-			Weight::from_parts(GAS_LIMIT.ref_time(), 0),
+			Weight::from_parts(u64::MAX, GAS_LIMIT.proof_size()),
+			Weight::from_parts(GAS_LIMIT.ref_time(), u64::MAX),
 		];
 
 		// This call is passed to the sub call in order to create a large `required_weight`
@@ -3453,13 +3453,13 @@ fn deposit_limit_in_nested_calls() {
 
 		// We do not remove any storage but add a storage item of 12 bytes in the caller
 		// contract. This would cost 12 + 2 = 14 Balance.
-		// The nested call doesn't get a special limit, which is set by passing 0 to it.
+		// The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it.
 		// This should fail as the specified parent's limit is less than the cost: 13 <
 		// 14.
 		assert_err_ignore_postinfo!(
 			builder::call(addr_caller)
 				.storage_deposit_limit(13)
-				.data((100u32, &addr_callee, U256::from(0u64)).encode())
+				.data((100u32, &addr_callee, U256::MAX).encode())
 				.build(),
 			<Error<Test>>::StorageDepositLimitExhausted,
 		);
@@ -3467,13 +3467,13 @@ fn deposit_limit_in_nested_calls() {
 		// Now we specify the parent's limit high enough to cover the caller's storage
 		// additions. However, we use a single byte more in the callee, hence the storage
 		// deposit should be 15 Balance.
-		// The nested call doesn't get a special limit, which is set by passing 0 to it.
+		// The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it.
 		// This should fail as the specified parent's limit is less than the cost: 14
 		// < 15.
 		assert_err_ignore_postinfo!(
 			builder::call(addr_caller)
 				.storage_deposit_limit(14)
-				.data((101u32, &addr_callee, U256::from(0u64)).encode())
+				.data((101u32, &addr_callee, &U256::MAX).encode())
 				.build(),
 			<Error<Test>>::StorageDepositLimitExhausted,
 		);
@@ -3495,7 +3495,7 @@ fn deposit_limit_in_nested_calls() {
 		assert_err_ignore_postinfo!(
 			builder::call(addr_caller)
 				.storage_deposit_limit(0)
-				.data((87u32, &addr_callee, U256::from(0u64)).encode())
+				.data((87u32, &addr_callee, &U256::MAX.to_little_endian()).encode())
 				.build(),
 			<Error<Test>>::StorageDepositLimitExhausted,
 		);
@@ -3551,28 +3551,24 @@ fn deposit_limit_in_nested_instantiate() {
 		//
 		// Provided the limit is set to be 1 Balance less,
 		// this call should fail on the return from the caller contract.
-		assert_err_ignore_postinfo!(
-			builder::call(addr_caller)
-				.origin(RuntimeOrigin::signed(BOB))
-				.storage_deposit_limit(callee_info_len + 2 + ED + 1)
-				.data((0u32, &code_hash_callee, U256::from(0u64)).encode())
-				.build(),
-			<Error<Test>>::StorageDepositLimitExhausted,
-		);
+		let ret = builder::bare_call(addr_caller)
+			.origin(RuntimeOrigin::signed(BOB))
+			.storage_deposit_limit(DepositLimit::Balance(callee_info_len + 2 + ED + 1))
+			.data((0u32, &code_hash_callee, &U256::MAX.to_little_endian()).encode())
+			.build_and_unwrap_result();
+		assert_return_code!(ret, RuntimeReturnCode::OutOfResources);
 		// The charges made on instantiation should be rolled back.
 		assert_eq!(<Test as Config>::Currency::free_balance(&BOB), 1_000_000);
 
 		// Now we give enough limit for the instantiation itself, but require for 1 more storage
 		// byte in the constructor. Hence +1 Balance to the limit is needed. This should fail on
 		// the return from constructor.
-		assert_err_ignore_postinfo!(
-			builder::call(addr_caller)
-				.origin(RuntimeOrigin::signed(BOB))
-				.storage_deposit_limit(callee_info_len + 2 + ED + 2)
-				.data((1u32, &code_hash_callee, U256::from(0u64)).encode())
-				.build(),
-			<Error<Test>>::StorageDepositLimitExhausted,
-		);
+		let ret = builder::bare_call(addr_caller)
+			.origin(RuntimeOrigin::signed(BOB))
+			.storage_deposit_limit(DepositLimit::Balance(callee_info_len + 2 + ED + 2))
+			.data((1u32, &code_hash_callee, U256::from(0u64)).encode())
+			.build_and_unwrap_result();
+		assert_return_code!(ret, RuntimeReturnCode::OutOfResources);
 		// The charges made on the instantiation should be rolled back.
 		assert_eq!(<Test as Config>::Currency::free_balance(&BOB), 1_000_000);
 
@@ -4856,20 +4852,18 @@ fn skip_transfer_works() {
 		);
 
 		// fails when calling from a contract when gas is specified.
-		assert_err!(
-			Pallet::<Test>::bare_eth_transact(
-				GenericTransaction {
-					from: Some(BOB_ADDR),
-					to: Some(caller_addr),
-					input: Some((0u32, &addr).encode().into()),
-					gas: Some(1u32.into()),
-					..Default::default()
-				},
-				Weight::MAX,
-				|_| 0u32
-			),
-			EthTransactError::Message(format!("insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)"))
-		);
+		assert!(Pallet::<Test>::bare_eth_transact(
+			GenericTransaction {
+				from: Some(BOB_ADDR),
+				to: Some(caller_addr),
+				input: Some((0u32, &addr).encode().into()),
+				gas: Some(1u32.into()),
+				..Default::default()
+			},
+			Weight::MAX,
+			|_| 0u32
+		)
+		.is_err(),);
 
 		// works when no gas is specified.
 		assert_ok!(Pallet::<Test>::bare_eth_transact(
diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs
index 52f79f2eb55a5ca8d3f67824d81ca8b1857d168e..8529c7d9e73bbd878d91ba4fc4e483adda135504 100644
--- a/substrate/frame/revive/src/wasm/runtime.rs
+++ b/substrate/frame/revive/src/wasm/runtime.rs
@@ -1004,8 +1004,7 @@ impl<'a, E: Ext, M: ?Sized + Memory<E::T>> Runtime<'a, E, M> {
 		self.charge_gas(call_type.cost())?;
 
 		let callee = memory.read_h160(callee_ptr)?;
-		let deposit_limit =
-			if deposit_ptr == SENTINEL { U256::zero() } else { memory.read_u256(deposit_ptr)? };
+		let deposit_limit = memory.read_u256(deposit_ptr)?;
 
 		let input_data = if flags.contains(CallFlags::CLONE_INPUT) {
 			let input = self.input_data.as_ref().ok_or(Error::<E::T>::InputForwarded)?;
@@ -1091,8 +1090,7 @@ impl<'a, E: Ext, M: ?Sized + Memory<E::T>> Runtime<'a, E, M> {
 		salt_ptr: u32,
 	) -> Result<ReturnErrorCode, TrapReason> {
 		self.charge_gas(RuntimeCosts::Instantiate { input_data_len })?;
-		let deposit_limit: U256 =
-			if deposit_ptr == SENTINEL { U256::zero() } else { memory.read_u256(deposit_ptr)? };
+		let deposit_limit: U256 = memory.read_u256(deposit_ptr)?;
 		let value = memory.read_u256(value_ptr)?;
 		let code_hash = memory.read_h256(code_hash_ptr)?;
 		let input_data = memory.read(input_data_ptr, input_data_len)?;
diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs
index d90c0f45205d8921767077abb93b6a05628c1812..ba0a63b15c379d45a4add50cfc6e0ec6beb14e2b 100644
--- a/substrate/frame/revive/uapi/src/host.rs
+++ b/substrate/frame/revive/uapi/src/host.rs
@@ -113,7 +113,7 @@ pub trait HostFn: private::Sealed {
 		callee: &[u8; 20],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit: Option<&[u8; 32]>,
+		deposit: &[u8; 32],
 		value: &[u8; 32],
 		input_data: &[u8],
 		output: Option<&mut &mut [u8]>,
@@ -202,7 +202,7 @@ pub trait HostFn: private::Sealed {
 		address: &[u8; 20],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit_limit: Option<&[u8; 32]>,
+		deposit_limit: &[u8; 32],
 		input_data: &[u8],
 		output: Option<&mut &mut [u8]>,
 	) -> Result;
@@ -318,7 +318,7 @@ pub trait HostFn: private::Sealed {
 		code_hash: &[u8; 32],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit: Option<&[u8; 32]>,
+		deposit: &[u8; 32],
 		value: &[u8; 32],
 		input: &[u8],
 		address: Option<&mut [u8; 20]>,
diff --git a/substrate/frame/revive/uapi/src/host/riscv64.rs b/substrate/frame/revive/uapi/src/host/riscv64.rs
index c83be942a9708a65ef54f09f6304a7f29a27c5d5..8c40bc9f48ea802b6d46bc0d1aaa858a991ec136 100644
--- a/substrate/frame/revive/uapi/src/host/riscv64.rs
+++ b/substrate/frame/revive/uapi/src/host/riscv64.rs
@@ -168,7 +168,7 @@ impl HostFn for HostFnImpl {
 		code_hash: &[u8; 32],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit_limit: Option<&[u8; 32]>,
+		deposit_limit: &[u8; 32],
 		value: &[u8; 32],
 		input: &[u8],
 		mut address: Option<&mut [u8; 20]>,
@@ -180,7 +180,7 @@ impl HostFn for HostFnImpl {
 			None => crate::SENTINEL as _,
 		};
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
-		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
+		let deposit_limit_ptr = deposit_limit.as_ptr();
 		let salt_ptr = ptr_or_sentinel(&salt);
 		#[repr(C)]
 		#[allow(dead_code)]
@@ -225,13 +225,13 @@ impl HostFn for HostFnImpl {
 		callee: &[u8; 20],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit_limit: Option<&[u8; 32]>,
+		deposit_limit: &[u8; 32],
 		value: &[u8; 32],
 		input: &[u8],
 		mut output: Option<&mut &mut [u8]>,
 	) -> Result {
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
-		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
+		let deposit_limit_ptr = deposit_limit.as_ptr();
 		#[repr(C)]
 		#[allow(dead_code)]
 		struct Args {
@@ -273,12 +273,12 @@ impl HostFn for HostFnImpl {
 		address: &[u8; 20],
 		ref_time_limit: u64,
 		proof_size_limit: u64,
-		deposit_limit: Option<&[u8; 32]>,
+		deposit_limit: &[u8; 32],
 		input: &[u8],
 		mut output: Option<&mut &mut [u8]>,
 	) -> Result {
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
-		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
+		let deposit_limit_ptr = deposit_limit.as_ptr();
 		#[repr(C)]
 		#[allow(dead_code)]
 		struct Args {