diff --git a/.github/workflows/checks-quick.yml b/.github/workflows/checks-quick.yml
index c733a2517cb8b6afffb44876c78162d58781f9a1..4c26b85a6303c88ba49d7c9d5be173403887d7f6 100644
--- a/.github/workflows/checks-quick.yml
+++ b/.github/workflows/checks-quick.yml
@@ -97,7 +97,6 @@ jobs:
           --exclude
           "substrate/frame/contracts/fixtures/build"
           "substrate/frame/contracts/fixtures/contracts/common"
-          "substrate/frame/revive/fixtures/build"
           "substrate/frame/revive/fixtures/contracts/common"
       - name: deny git deps
         run: python3 .github/scripts/deny-git-deps.py .
diff --git a/Cargo.lock b/Cargo.lock
index 84477cd05416793c930be7abc7231830506c99b9..e1abeea4928339917859afb25180190402e5248d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5975,6 +5975,15 @@ dependencies = [
  "dirs-sys-next",
 ]
 
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
 [[package]]
 name = "dirs-sys"
 version = "0.4.1"
@@ -14646,7 +14655,7 @@ dependencies = [
  "pallet-utility 28.0.0",
  "parity-scale-codec",
  "paste",
- "polkavm 0.13.0",
+ "polkavm 0.17.0",
  "pretty_assertions",
  "rlp 0.6.1",
  "scale-info",
@@ -14742,12 +14751,10 @@ dependencies = [
  "anyhow",
  "frame-system 28.0.0",
  "log",
- "parity-wasm",
- "polkavm-linker 0.14.0",
+ "polkavm-linker 0.17.0",
  "sp-core 28.0.0",
  "sp-io 30.0.0",
  "sp-runtime 31.0.1",
- "tempfile",
  "toml 0.8.12",
 ]
 
@@ -14864,7 +14871,7 @@ dependencies = [
  "bitflags 1.3.2",
  "parity-scale-codec",
  "paste",
- "polkavm-derive 0.14.0",
+ "polkavm-derive 0.17.0",
  "scale-info",
 ]
 
@@ -19699,15 +19706,15 @@ dependencies = [
 
 [[package]]
 name = "polkavm"
-version = "0.13.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e79a14b15ed38cb5b9a1e38d02e933f19e3d180ae5b325fed606c5e5b9177e"
+checksum = "84979be196ba2855f73616413e7b1d18258128aa396b3dc23f520a00a807720e"
 dependencies = [
  "libc",
  "log",
- "polkavm-assembler 0.13.0",
- "polkavm-common 0.13.0",
- "polkavm-linux-raw 0.13.0",
+ "polkavm-assembler 0.17.0",
+ "polkavm-common 0.17.0",
+ "polkavm-linux-raw 0.17.0",
 ]
 
 [[package]]
@@ -19730,9 +19737,9 @@ dependencies = [
 
 [[package]]
 name = "polkavm-assembler"
-version = "0.13.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e8da55465000feb0a61bbf556ed03024db58f3420eca37721fc726b3b2136bf"
+checksum = "0ba7b434ff630b0f73a1560e8baea807246ca22098abe49f97821e0e2d2accc4"
 dependencies = [
  "log",
 ]
@@ -19764,20 +19771,14 @@ dependencies = [
 
 [[package]]
 name = "polkavm-common"
-version = "0.13.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "084b4339aae7dfdaaa5aa7d634110afd95970e0737b6fb2a0cb10db8b56b753c"
+checksum = "8f0dbafef4ab6ceecb4982ac3b550df430ef4f9fdbf07c108b7d4f91a0682fce"
 dependencies = [
  "log",
- "polkavm-assembler 0.13.0",
+ "polkavm-assembler 0.17.0",
 ]
 
-[[package]]
-name = "polkavm-common"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711952a783e9c5ad407cdacb1ed147f36d37c5d43417c1091d86456d2999417b"
-
 [[package]]
 name = "polkavm-derive"
 version = "0.8.0"
@@ -19807,11 +19808,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive"
-version = "0.14.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4832a0aebf6cefc988bb7b2d74ea8c86c983164672e2fc96300f356a1babfc1"
+checksum = "c0c3dbb6c8c7bd3e5f5b05aa7fc9355acf14df7ce5d392911e77d01090a38d0d"
 dependencies = [
- "polkavm-derive-impl-macro 0.14.0",
+ "polkavm-derive-impl-macro 0.17.0",
 ]
 
 [[package]]
@@ -19852,11 +19853,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive-impl"
-version = "0.14.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e339fc7c11310fe5adf711d9342278ac44a75c9784947937cce12bd4f30842f2"
+checksum = "42565aed4adbc4034612d0b17dea8db3681fb1bd1aed040d6edc5455a9f478a1"
 dependencies = [
- "polkavm-common 0.14.0",
+ "polkavm-common 0.17.0",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.87",
@@ -19894,11 +19895,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive-impl-macro"
-version = "0.14.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b569754b15060d03000c09e3bf11509d527f60b75d79b4c30c3625b5071d9702"
+checksum = "86d9838e95241b0bce4fe269cdd4af96464160505840ed5a8ac8536119ba19e2"
 dependencies = [
- "polkavm-derive-impl 0.14.0",
+ "polkavm-derive-impl 0.17.0",
  "syn 2.0.87",
 ]
 
@@ -19934,15 +19935,16 @@ dependencies = [
 
 [[package]]
 name = "polkavm-linker"
-version = "0.14.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0959ac3b0f4fd5caf5c245c637705f19493efe83dba31a83bbba928b93b0116a"
+checksum = "d359dc721d2cc9b555ebb3558c305112ddc5bdac09d26f95f2f7b49c1f2db7e9"
 dependencies = [
+ "dirs",
  "gimli 0.31.1",
  "hashbrown 0.14.5",
  "log",
  "object 0.36.1",
- "polkavm-common 0.14.0",
+ "polkavm-common 0.17.0",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -19961,9 +19963,9 @@ checksum = "26e45fa59c7e1bb12ef5289080601e9ec9b31435f6e32800a5c90c132453d126"
 
 [[package]]
 name = "polkavm-linux-raw"
-version = "0.13.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "686c4dd9c9c16cc22565b51bdbb269792318d0fd2e6b966b5f6c788534cad0e9"
+checksum = "e64c3d93a58ffbc3099d1227f0da9675a025a9ea6c917038f266920c1de1e568"
 
 [[package]]
 name = "polling"
diff --git a/prdoc/pr_6565.prdoc b/prdoc/pr_6565.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..f9a75a16a6a7f038730a48f44809c398682958ab
--- /dev/null
+++ b/prdoc/pr_6565.prdoc
@@ -0,0 +1,35 @@
+title: 'pallet_revive: Switch to 64bit RISC-V'
+doc:
+- audience: Runtime Dev
+  description: |-
+    This PR updates pallet_revive to the newest PolkaVM version and adapts the test fixtures and syscall interface to work under 64bit.
+
+    Please note that after this PR no 32bit contracts can be deployed (they will be rejected at deploy time). Pre-deployed 32bit contracts are now considered defunct since we changes how parameters are passed for functions with more than 6 arguments.
+
+    ## Fixtures
+
+    The fixtures are now built for the 64bit target. I also removed the temporary directory mechanism that triggered a full rebuild every time. It also makes it easier to find the compiled fixtures since they are now always in `target/pallet-revive-fixtures`.
+
+    ## Syscall interface
+
+    ### Passing pointer
+
+    Registers and pointers are now 64bit wide. This allows us to pass u64 arguments in a single register. Before we needed two registers to pass them. This means that just as before we need one register per pointer we pass. We keep pointers as `u32` argument by truncating the register. This is done since the memory space of PolkaVM is 32bit.
+
+    ### Functions with more than 6 arguments
+
+    We only have 6 registers to pass arguments. This is why we pass a pointer to a struct when we need more than 6. Before this PR we expected a packed struct and interpreted it as SCALE encoded tuple. However, this was buggy because the `MaxEncodedLen` returned something that was larger than the packed size of the structure. This wasn't a problem before. But now the memory space changed in a way that things were placed at the edges of the memory space and those extra bytes lead to an out of bound access.
+
+    This is why this PR drops SCALE and expects the arguments to be passed as a pointer to a `C` aligned struct. This avoids unaligned accesses. However, revive needs to adapt its codegen to properly align the structure fields.
+
+    ## TODO
+    - [ ] Add multi block migration that wipes all existing contracts as we made breaking changes to the syscall interface
+crates:
+- name: pallet-revive
+  bump: major
+- name: pallet-revive-fixtures
+  bump: major
+- name: pallet-revive-proc-macro
+  bump: major
+- name: pallet-revive-uapi
+  bump: major
diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml
index 81fbbc8cf38e1a384aac69e1676788f13c4a416f..677ef0e1367f839e49cf218b4c7e8660853d928e 100644
--- a/substrate/frame/revive/Cargo.toml
+++ b/substrate/frame/revive/Cargo.toml
@@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 [dependencies]
 environmental = { workspace = true }
 paste = { workspace = true }
-polkavm = { version = "0.13.0", default-features = false }
+polkavm = { version = "0.17.0", default-features = false }
 bitflags = { workspace = true }
 codec = { features = ["derive", "max-encoded-len"], workspace = true }
 scale-info = { features = ["derive"], workspace = true }
diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml
index 7a5452853d656d61b1950830150511c608180876..798ed8c75a5afe09bd6366d87396893665613619 100644
--- a/substrate/frame/revive/fixtures/Cargo.toml
+++ b/substrate/frame/revive/fixtures/Cargo.toml
@@ -18,10 +18,8 @@ anyhow = { workspace = true, default-features = true, optional = true }
 log = { workspace = true }
 
 [build-dependencies]
-parity-wasm = { workspace = true }
-tempfile = { workspace = true }
 toml = { workspace = true }
-polkavm-linker = { version = "0.14.0" }
+polkavm-linker = { version = "0.17.0" }
 anyhow = { workspace = true, default-features = true }
 
 [features]
diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs
index 3472e0846efddcd8857a3c20e4e96fc55857158a..46cd5760ca4e2523f13b8ce3134d37da3c6c4dec 100644
--- a/substrate/frame/revive/fixtures/build.rs
+++ b/substrate/frame/revive/fixtures/build.rs
@@ -20,7 +20,8 @@ use anyhow::Result;
 
 use anyhow::{bail, Context};
 use std::{
-	cfg, env, fs,
+	env, fs,
+	io::Write,
 	path::{Path, PathBuf},
 	process::Command,
 };
@@ -82,7 +83,7 @@ fn create_cargo_toml<'a>(
 	entries: impl Iterator<Item = &'a Entry>,
 	output_dir: &Path,
 ) -> Result<()> {
-	let mut cargo_toml: toml::Value = toml::from_str(include_str!("./build/Cargo.toml"))?;
+	let mut cargo_toml: toml::Value = toml::from_str(include_str!("./build/_Cargo.toml"))?;
 	let mut set_dep = |name, path| -> Result<()> {
 		cargo_toml["dependencies"][name]["path"] = toml::Value::String(
 			fixtures_dir.join(path).canonicalize()?.to_str().unwrap().to_string(),
@@ -108,21 +109,24 @@ fn create_cargo_toml<'a>(
 	let cargo_toml = toml::to_string_pretty(&cargo_toml)?;
 	fs::write(output_dir.join("Cargo.toml"), cargo_toml.clone())
 		.with_context(|| format!("Failed to write {cargo_toml:?}"))?;
+	fs::copy(
+		fixtures_dir.join("build/_rust-toolchain.toml"),
+		output_dir.join("rust-toolchain.toml"),
+	)
+	.context("Failed to write toolchain file")?;
 	Ok(())
 }
 
-fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> {
+fn invoke_build(current_dir: &Path) -> Result<()> {
 	let encoded_rustflags = ["-Dwarnings"].join("\x1f");
 
-	let mut build_command = Command::new(env::var("CARGO")?);
+	let mut build_command = Command::new("cargo");
 	build_command
 		.current_dir(current_dir)
 		.env_clear()
 		.env("PATH", env::var("PATH").unwrap_or_default())
 		.env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags)
-		.env("RUSTC_BOOTSTRAP", "1")
 		.env("RUSTUP_HOME", env::var("RUSTUP_HOME").unwrap_or_default())
-		.env("RUSTUP_TOOLCHAIN", env::var("RUSTUP_TOOLCHAIN").unwrap_or_default())
 		.args([
 			"build",
 			"--release",
@@ -130,7 +134,7 @@ fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> {
 			"-Zbuild-std-features=panic_immediate_abort",
 		])
 		.arg("--target")
-		.arg(target);
+		.arg(polkavm_linker::target_json_64_path().unwrap());
 
 	if let Ok(toolchain) = env::var(OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR) {
 		build_command.env("RUSTUP_TOOLCHAIN", &toolchain);
@@ -168,7 +172,7 @@ fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec<Entry>) -> Result
 	for entry in entries {
 		post_process(
 			&build_dir
-				.join("target/riscv32emac-unknown-none-polkavm/release")
+				.join("target/riscv64emac-unknown-none-polkavm/release")
 				.join(entry.name()),
 			&out_dir.join(entry.out_filename()),
 		)?;
@@ -177,11 +181,61 @@ fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec<Entry>) -> Result
 	Ok(())
 }
 
+/// Create a directory in the `target` as output directory
+fn create_out_dir() -> Result<PathBuf> {
+	let temp_dir: PathBuf = env::var("OUT_DIR")?.into();
+
+	// this is set in case the user has overriden the target directory
+	let out_dir = if let Ok(path) = env::var("CARGO_TARGET_DIR") {
+		path.into()
+	} else {
+		// otherwise just traverse up from the out dir
+		let mut out_dir: PathBuf = temp_dir.clone();
+		loop {
+			if !out_dir.pop() {
+				bail!("Cannot find project root.")
+			}
+			if out_dir.join("Cargo.lock").exists() {
+				break;
+			}
+		}
+		out_dir.join("target")
+	}
+	.join("pallet-revive-fixtures");
+
+	// clean up some leftover symlink from previous versions of this script
+	if out_dir.exists() && !out_dir.is_dir() {
+		fs::remove_file(&out_dir)?;
+	}
+	fs::create_dir_all(&out_dir).context("Failed to create output directory")?;
+
+	// write the location of the out dir so it can be found later
+	let mut file = fs::File::create(temp_dir.join("fixture_location.rs"))
+		.context("Failed to create fixture_location.rs")?;
+	write!(
+		file,
+		r#"
+			#[allow(dead_code)]
+			const FIXTURE_DIR: &str = "{0}";
+			macro_rules! fixture {{
+				($name: literal) => {{
+					include_bytes!(concat!("{0}", "/", $name, ".polkavm"))
+				}};
+			}}
+		"#,
+		out_dir.display()
+	)
+	.context("Failed to write to fixture_location.rs")?;
+
+	Ok(out_dir)
+}
+
 pub fn main() -> Result<()> {
 	let fixtures_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into();
 	let contracts_dir = fixtures_dir.join("contracts");
-	let out_dir: PathBuf = env::var("OUT_DIR")?.into();
-	let target = fixtures_dir.join("riscv32emac-unknown-none-polkavm.json");
+	let out_dir = create_out_dir().context("Cannot determine output directory")?;
+	let build_dir = out_dir.join("build");
+	fs::create_dir_all(&build_dir).context("Failed to create build directory")?;
 
 	println!("cargo::rerun-if-env-changed={OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR}");
 	println!("cargo::rerun-if-env-changed={OVERRIDE_STRIP_ENV_VAR}");
@@ -199,25 +253,9 @@ pub fn main() -> Result<()> {
 		return Ok(())
 	}
 
-	let tmp_dir = tempfile::tempdir()?;
-	let tmp_dir_path = tmp_dir.path();
-
-	create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?;
-	invoke_build(&target, tmp_dir_path)?;
-
-	write_output(tmp_dir_path, &out_dir, entries)?;
-
-	#[cfg(unix)]
-	if let Ok(symlink_dir) = env::var("CARGO_WORKSPACE_ROOT_DIR") {
-		let symlink_dir: PathBuf = symlink_dir.into();
-		let symlink_dir: PathBuf = symlink_dir.join("target").join("pallet-revive-fixtures");
-		if symlink_dir.is_symlink() {
-			fs::remove_file(&symlink_dir)
-				.with_context(|| format!("Failed to remove_file {symlink_dir:?}"))?;
-		}
-		std::os::unix::fs::symlink(&out_dir, &symlink_dir)
-			.with_context(|| format!("Failed to symlink {out_dir:?} -> {symlink_dir:?}"))?;
-	}
+	create_cargo_toml(&fixtures_dir, entries.iter(), &build_dir)?;
+	invoke_build(&build_dir)?;
+	write_output(&build_dir, &out_dir, entries)?;
 
 	Ok(())
 }
diff --git a/substrate/frame/revive/fixtures/build/Cargo.toml b/substrate/frame/revive/fixtures/build/_Cargo.toml
similarity index 80%
rename from substrate/frame/revive/fixtures/build/Cargo.toml
rename to substrate/frame/revive/fixtures/build/_Cargo.toml
index 5d0e256e2e73c96f9e6e17fe30022171de544cf4..beaabd83403ef6c36f55479c9e57eda00128f018 100644
--- a/substrate/frame/revive/fixtures/build/Cargo.toml
+++ b/substrate/frame/revive/fixtures/build/_Cargo.toml
@@ -4,6 +4,9 @@ publish = false
 version = "1.0.0"
 edition = "2021"
 
+# Make sure this is not included into the workspace
+[workspace]
+
 # Binary targets are injected dynamically by the build script.
 [[bin]]
 
@@ -11,7 +14,7 @@ edition = "2021"
 [dependencies]
 uapi = { package = 'pallet-revive-uapi', path = "", default-features = false }
 common = { package = 'pallet-revive-fixtures-common', path = "" }
-polkavm-derive = { version = "0.14.0" }
+polkavm-derive = { version = "0.17.0" }
 
 [profile.release]
 opt-level = 3
diff --git a/substrate/frame/revive/fixtures/build/_rust-toolchain.toml b/substrate/frame/revive/fixtures/build/_rust-toolchain.toml
new file mode 100644
index 0000000000000000000000000000000000000000..4c757c708d58bbd18c54f1be50210a34cb525022
--- /dev/null
+++ b/substrate/frame/revive/fixtures/build/_rust-toolchain.toml
@@ -0,0 +1,4 @@
+[toolchain]
+channel = "nightly-2024-11-19"
+components = ["rust-src"]
+profile = "minimal"
diff --git a/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json
deleted file mode 100644
index bbd54cdefbac547021f606a0871b55edc4dca0cb..0000000000000000000000000000000000000000
--- a/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "arch": "riscv32",
-  "cpu": "generic-rv32",
-  "crt-objects-fallback": "false",
-  "data-layout": "e-m:e-p:32:32-i64:64-n32-S32",
-  "eh-frame-header": false,
-  "emit-debug-gdb-scripts": false,
-  "features": "+e,+m,+a,+c,+lui-addi-fusion,+fast-unaligned-access,+xtheadcondmov",
-  "linker": "rust-lld",
-  "linker-flavor": "ld.lld",
-  "llvm-abiname": "ilp32e",
-  "llvm-target": "riscv32",
-  "max-atomic-width": 32,
-  "panic-strategy": "abort",
-  "relocation-model": "pie",
-  "target-pointer-width": "32",
-  "singlethread": true,
-  "pre-link-args": {
-    "ld": [
-      "--emit-relocs",
-      "--unique",
-      "--relocatable"
-    ]
-  },
-  "env": "polkavm"
-}
diff --git a/substrate/frame/revive/fixtures/src/lib.rs b/substrate/frame/revive/fixtures/src/lib.rs
index cc84daec9b598bc758c70f73b9f3300c57266e95..24f6ee547dc7a2c8cbf5bc1307daf4a5c484cd2b 100644
--- a/substrate/frame/revive/fixtures/src/lib.rs
+++ b/substrate/frame/revive/fixtures/src/lib.rs
@@ -19,10 +19,13 @@
 
 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.
 #[cfg(feature = "std")]
 pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec<u8>, sp_core::H256)> {
-	let out_dir: std::path::PathBuf = env!("OUT_DIR").into();
+	let out_dir: std::path::PathBuf = FIXTURE_DIR.into();
 	let fixture_path = out_dir.join(format!("{fixture_name}.polkavm"));
 	log::debug!("Loading fixture from {fixture_path:?}");
 	let binary = std::fs::read(fixture_path)?;
@@ -36,12 +39,6 @@ pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec<u8>, sp_core::H
 /// available in no-std environments (runtime benchmarks).
 pub mod bench {
 	use alloc::vec::Vec;
-
-	macro_rules! fixture {
-		($name: literal) => {
-			include_bytes!(concat!(env!("OUT_DIR"), "/", $name, ".polkavm"))
-		};
-	}
 	pub const DUMMY: &[u8] = fixture!("dummy");
 	pub const NOOP: &[u8] = fixture!("noop");
 	pub const INSTR: &[u8] = fixture!("instr_benchmark");
@@ -61,7 +58,7 @@ pub mod bench {
 mod test {
 	#[test]
 	fn out_dir_should_have_compiled_mocks() {
-		let out_dir: std::path::PathBuf = env!("OUT_DIR").into();
+		let out_dir: std::path::PathBuf = crate::FIXTURE_DIR.into();
 		assert!(out_dir.join("dummy.polkavm").exists());
 	}
 }
diff --git a/substrate/frame/revive/proc-macro/src/lib.rs b/substrate/frame/revive/proc-macro/src/lib.rs
index 7232c6342824192ada69162d862c47debfcb5dde..6814add128d9263ec68eb90cb367af2138ee6e89 100644
--- a/substrate/frame/revive/proc-macro/src/lib.rs
+++ b/substrate/frame/revive/proc-macro/src/lib.rs
@@ -79,6 +79,7 @@ use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, F
 /// - `Result<(), TrapReason>`,
 /// - `Result<ReturnErrorCode, TrapReason>`,
 /// - `Result<u32, TrapReason>`.
+/// - `Result<u64, TrapReason>`.
 ///
 /// The macro expands to `pub struct Env` declaration, with the following traits implementations:
 /// - `pallet_revive::wasm::Environment<Runtime<E>> where E: Ext`
@@ -127,6 +128,7 @@ struct HostFn {
 enum HostFnReturn {
 	Unit,
 	U32,
+	U64,
 	ReturnCode,
 }
 
@@ -134,8 +136,7 @@ impl HostFnReturn {
 	fn map_output(&self) -> TokenStream2 {
 		match self {
 			Self::Unit => quote! { |_| None },
-			Self::U32 => quote! { |ret_val| Some(ret_val) },
-			Self::ReturnCode => quote! { |ret_code| Some(ret_code.into())  },
+			_ => quote! { |ret_val| Some(ret_val.into()) },
 		}
 	}
 
@@ -143,6 +144,7 @@ impl HostFnReturn {
 		match self {
 			Self::Unit => syn::ReturnType::Default,
 			Self::U32 => parse_quote! { -> u32 },
+			Self::U64 => parse_quote! { -> u64 },
 			Self::ReturnCode => parse_quote! { -> ReturnErrorCode },
 		}
 	}
@@ -243,7 +245,8 @@ impl HostFn {
 		let msg = r#"Should return one of the following:
 				- Result<(), TrapReason>,
 				- Result<ReturnErrorCode, TrapReason>,
-				- Result<u32, TrapReason>"#;
+				- Result<u32, TrapReason>,
+				- Result<u64, TrapReason>"#;
 		let ret_ty = match item.clone().sig.output {
 			syn::ReturnType::Type(_, ty) => Ok(ty.clone()),
 			_ => Err(err(span, &msg)),
@@ -305,6 +308,7 @@ impl HostFn {
 						let returns = match ok_ty_str.as_str() {
 							"()" => Ok(HostFnReturn::Unit),
 							"u32" => Ok(HostFnReturn::U32),
+							"u64" => Ok(HostFnReturn::U64),
 							"ReturnErrorCode" => Ok(HostFnReturn::ReturnCode),
 							_ => Err(err(arg1.span(), &msg)),
 						}?;
@@ -339,50 +343,61 @@ where
 	P: Iterator<Item = &'a std::boxed::Box<syn::Pat>> + Clone,
 	I: Iterator<Item = &'a std::boxed::Box<syn::Type>> + Clone,
 {
-	const ALLOWED_REGISTERS: u32 = 6;
-	let mut registers_used = 0;
-	let mut bindings = vec![];
-	let mut idx = 0;
-	for (name, ty) in param_names.clone().zip(param_types.clone()) {
+	const ALLOWED_REGISTERS: usize = 6;
+
+	// all of them take one register but we truncate them before passing into the function
+	// it is important to not allow any type which has illegal bit patterns like 'bool'
+	if !param_types.clone().all(|ty| {
 		let syn::Type::Path(path) = &**ty else {
 			panic!("Type needs to be path");
 		};
 		let Some(ident) = path.path.get_ident() else {
 			panic!("Type needs to be ident");
 		};
-		let size = if ident == "i8" ||
-			ident == "i16" ||
-			ident == "i32" ||
-			ident == "u8" ||
-			ident == "u16" ||
-			ident == "u32"
-		{
-			1
-		} else if ident == "i64" || ident == "u64" {
-			2
-		} else {
-			panic!("Pass by value only supports primitives");
-		};
-		registers_used += size;
-		if registers_used > ALLOWED_REGISTERS {
-			return quote! {
-				let (#( #param_names, )*): (#( #param_types, )*) = memory.read_as(__a0__)?;
-			}
-		}
-		let this_reg = quote::format_ident!("__a{}__", idx);
-		let next_reg = quote::format_ident!("__a{}__", idx + 1);
-		let binding = if size == 1 {
+		matches!(ident.to_string().as_ref(), "u8" | "u16" | "u32" | "u64")
+	}) {
+		panic!("Only primitive unsigned integers are allowed as arguments to syscalls");
+	}
+
+	// too many arguments: pass as pointer to a struct in memory
+	if param_names.clone().count() > ALLOWED_REGISTERS {
+		let fields = param_names.clone().zip(param_types.clone()).map(|(name, ty)| {
 			quote! {
-				let #name = #this_reg as #ty;
+				#name: #ty,
 			}
-		} else {
-			quote! {
-				let #name = (#this_reg as #ty) | ((#next_reg as #ty) << 32);
+		});
+		return quote! {
+			#[derive(Default)]
+			#[repr(C)]
+			struct Args {
+				#(#fields)*
 			}
-		};
-		bindings.push(binding);
-		idx += size;
+			let Args { #(#param_names,)* } = {
+				let len = ::core::mem::size_of::<Args>();
+				let mut args = Args::default();
+				let ptr = &mut args as *mut Args as *mut u8;
+				// Safety
+				// 1. The struct is initialized at all times.
+				// 2. We only allow primitive integers (no bools) as arguments so every bit pattern is safe.
+				// 3. The reference doesn't outlive the args field.
+				// 4. There is only the single reference to the args field.
+				// 5. The length of the generated slice is the same as the struct.
+				let reference = unsafe {
+					::core::slice::from_raw_parts_mut(ptr, len)
+				};
+				memory.read_into_buf(__a0__ as _, reference)?;
+				args
+			};
+		}
 	}
+
+	// otherwise: one argument per register
+	let bindings = param_names.zip(param_types).enumerate().map(|(idx, (name, ty))| {
+		let reg = quote::format_ident!("__a{}__", idx);
+		quote! {
+			let #name = #reg as #ty;
+		}
+	});
 	quote! {
 		#( #bindings )*
 	}
@@ -409,7 +424,7 @@ fn expand_env(def: &EnvDef) -> TokenStream2 {
 				memory: &mut M,
 				__syscall_symbol__: &[u8],
 				__available_api_version__: ApiVersion,
-			) -> Result<Option<u32>, TrapReason>
+			) -> Result<Option<u64>, TrapReason>
 			{
 				#impls
 			}
diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs
index 7734c8c572090d3b43cffbce77d0002b7975336b..920318b26f713b861273b954cb4c99974c2dad42 100644
--- a/substrate/frame/revive/rpc/src/tests.rs
+++ b/substrate/frame/revive/rpc/src/tests.rs
@@ -218,6 +218,8 @@ async fn deploy_and_call() -> anyhow::Result<()> {
 	Ok(())
 }
 
+/// TODO: enable ( https://github.com/paritytech/contract-issues/issues/12 )
+#[ignore]
 #[tokio::test]
 async fn revert_call() -> anyhow::Result<()> {
 	let _lock = SHARED_RESOURCES.write();
@@ -240,6 +242,8 @@ async fn revert_call() -> anyhow::Result<()> {
 	Ok(())
 }
 
+/// TODO: enable ( https://github.com/paritytech/contract-issues/issues/12 )
+#[ignore]
 #[tokio::test]
 async fn event_logs() -> anyhow::Result<()> {
 	let _lock = SHARED_RESOURCES.write();
@@ -279,6 +283,8 @@ async fn invalid_transaction() -> anyhow::Result<()> {
 	Ok(())
 }
 
+/// TODO: enable ( https://github.com/paritytech/contract-issues/issues/12 )
+#[ignore]
 #[tokio::test]
 async fn native_evm_ratio_works() -> anyhow::Result<()> {
 	let _lock = SHARED_RESOURCES.write();
diff --git a/substrate/frame/revive/src/chain_extension.rs b/substrate/frame/revive/src/chain_extension.rs
index ccea1294505418f4930524c22de216071361baed..5b3e886a56281f0ed5cd10878f4fe4a514a641db 100644
--- a/substrate/frame/revive/src/chain_extension.rs
+++ b/substrate/frame/revive/src/chain_extension.rs
@@ -75,7 +75,7 @@ use crate::{
 	Error,
 };
 use alloc::vec::Vec;
-use codec::{Decode, MaxEncodedLen};
+use codec::Decode;
 use frame_support::weights::Weight;
 use sp_runtime::DispatchError;
 
@@ -304,16 +304,6 @@ impl<'a, 'b, E: Ext, M: ?Sized + Memory<E::T>> Environment<'a, 'b, E, M> {
 		Ok(())
 	}
 
-	/// Reads and decodes a type with a size fixed at compile time from contract memory.
-	///
-	/// This function is secure and recommended for all input types of fixed size
-	/// as long as the cost of reading the memory is included in the overall already charged
-	/// weight of the chain extension. This should usually be the case when fixed input types
-	/// are used.
-	pub fn read_as<T: Decode + MaxEncodedLen>(&mut self) -> Result<T> {
-		self.memory.read_as(self.input_ptr)
-	}
-
 	/// Reads and decodes a type with a dynamic size from contract memory.
 	///
 	/// Make sure to include `len` in your weight calculations.
diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs
index 64e66382b9ab26366cc594814b53501f45fc006e..5ce96f59c14d744df062ccbb77271e12602c49a6 100644
--- a/substrate/frame/revive/src/limits.rs
+++ b/substrate/frame/revive/src/limits.rs
@@ -129,23 +129,36 @@ pub mod code {
 			Error::<T>::CodeRejected
 		})?;
 
+		if !program.is_64_bit() {
+			log::debug!(target: LOG_TARGET, "32bit programs are not supported.");
+			Err(Error::<T>::CodeRejected)?;
+		}
+
 		// This scans the whole program but we only do it once on code deployment.
 		// It is safe to do unchecked math in u32 because the size of the program
 		// was already checked above.
-		use polkavm::program::ISA32_V1_NoSbrk as ISA;
+		use polkavm::program::ISA64_V1 as ISA;
 		let mut num_instructions: u32 = 0;
 		let mut max_basic_block_size: u32 = 0;
 		let mut basic_block_size: u32 = 0;
 		for inst in program.instructions(ISA) {
+			use polkavm::program::Instruction;
 			num_instructions += 1;
 			basic_block_size += 1;
 			if inst.kind.opcode().starts_new_basic_block() {
 				max_basic_block_size = max_basic_block_size.max(basic_block_size);
 				basic_block_size = 0;
 			}
-			if matches!(inst.kind, polkavm::program::Instruction::invalid) {
-				log::debug!(target: LOG_TARGET, "invalid instruction at offset {}", inst.offset);
-				return Err(<Error<T>>::InvalidInstruction.into())
+			match inst.kind {
+				Instruction::invalid => {
+					log::debug!(target: LOG_TARGET, "invalid instruction at offset {}", inst.offset);
+					return Err(<Error<T>>::InvalidInstruction.into())
+				},
+				Instruction::sbrk(_, _) => {
+					log::debug!(target: LOG_TARGET, "sbrk instruction is not allowed. offset {}", inst.offset);
+					return Err(<Error<T>>::InvalidInstruction.into())
+				},
+				_ => (),
 			}
 		}
 
diff --git a/substrate/frame/revive/src/wasm/mod.rs b/substrate/frame/revive/src/wasm/mod.rs
index f10c4f5fddf8a43eeb768fc24fbb277b1fefa469..d87ec711228684d38cab02669bcdb647a1d344fe 100644
--- a/substrate/frame/revive/src/wasm/mod.rs
+++ b/substrate/frame/revive/src/wasm/mod.rs
@@ -293,8 +293,15 @@ impl<T: Config> WasmBlob<T> {
 	) -> Result<PreparedCall<E>, ExecError> {
 		let mut config = polkavm::Config::default();
 		config.set_backend(Some(polkavm::BackendKind::Interpreter));
-		let engine =
-			polkavm::Engine::new(&config).expect("interpreter is available on all plattforms; qed");
+		config.set_cache_enabled(false);
+		#[cfg(feature = "std")]
+		if std::env::var_os("REVIVE_USE_COMPILER").is_some() {
+			config.set_backend(Some(polkavm::BackendKind::Compiler));
+		}
+		let engine = polkavm::Engine::new(&config).expect(
+			"on-chain (no_std) use of interpreter is hard coded.
+				interpreter is available on all plattforms; qed",
+		);
 
 		let mut module_config = polkavm::ModuleConfig::new();
 		module_config.set_page_size(limits::PAGE_SIZE);
@@ -306,6 +313,15 @@ impl<T: Config> WasmBlob<T> {
 			Error::<T>::CodeRejected
 		})?;
 
+		// This is checked at deploy time but we also want to reject pre-existing
+		// 32bit programs.
+		// TODO: Remove when we reset the test net.
+		// https://github.com/paritytech/contract-issues/issues/11
+		if !module.is_64_bit() {
+			log::debug!(target: LOG_TARGET, "32bit programs are not supported.");
+			Err(Error::<T>::CodeRejected)?;
+		}
+
 		let entry_program_counter = module
 			.exports()
 			.find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes())
diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs
index 3e2c83db1ebda2cc3e2611e501093c2d7325de95..7ea518081e23e202fb99fbd0b73c56530d6539ec 100644
--- a/substrate/frame/revive/src/wasm/runtime.rs
+++ b/substrate/frame/revive/src/wasm/runtime.rs
@@ -27,7 +27,7 @@ use crate::{
 	Config, Error, LOG_TARGET, SENTINEL,
 };
 use alloc::{boxed::Box, vec, vec::Vec};
-use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
+use codec::{Decode, DecodeLimit, Encode};
 use core::{fmt, marker::PhantomData, mem};
 use frame_support::{
 	dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types,
@@ -126,34 +126,13 @@ pub trait Memory<T: Config> {
 	///
 	/// # Note
 	///
-	/// There must be an extra benchmark for determining the influence of `len` with
-	/// regard to the overall weight.
+	/// Make sure to charge a proportional amount of weight if `len` is not fixed.
 	fn read_as_unbounded<D: Decode>(&self, ptr: u32, len: u32) -> Result<D, DispatchError> {
 		let buf = self.read(ptr, len)?;
 		let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut buf.as_ref())
 			.map_err(|_| DispatchError::from(Error::<T>::DecodingFailed))?;
 		Ok(decoded)
 	}
-
-	/// Reads and decodes a type with a size fixed at compile time from contract memory.
-	///
-	/// # Only use on fixed size types
-	///
-	/// Don't use this for types where the encoded size is not fixed but merely bounded. Otherwise
-	/// this implementation will out of bound access the buffer declared by the guest. Some examples
-	/// of those bounded but not fixed types: Enums with data, `BoundedVec` or any compact encoded
-	/// integer.
-	///
-	/// # Note
-	///
-	/// The weight of reading a fixed value is included in the overall weight of any
-	/// contract callable function.
-	fn read_as<D: Decode + MaxEncodedLen>(&self, ptr: u32) -> Result<D, DispatchError> {
-		let buf = self.read(ptr, D::max_encoded_len() as u32)?;
-		let decoded = D::decode_with_depth_limit(MAX_DECODE_NESTING, &mut buf.as_ref())
-			.map_err(|_| DispatchError::from(Error::<T>::DecodingFailed))?;
-		Ok(decoded)
-	}
 }
 
 /// Allows syscalls access to the PolkaVM instance they are executing in.
@@ -164,8 +143,8 @@ pub trait Memory<T: Config> {
 pub trait PolkaVmInstance<T: Config>: Memory<T> {
 	fn gas(&self) -> polkavm::Gas;
 	fn set_gas(&mut self, gas: polkavm::Gas);
-	fn read_input_regs(&self) -> (u32, u32, u32, u32, u32, u32);
-	fn write_output(&mut self, output: u32);
+	fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64);
+	fn write_output(&mut self, output: u64);
 }
 
 // Memory implementation used in benchmarking where guest memory is mapped into the host.
@@ -214,7 +193,7 @@ impl<T: Config> PolkaVmInstance<T> for polkavm::RawInstance {
 		self.set_gas(gas)
 	}
 
-	fn read_input_regs(&self) -> (u32, u32, u32, u32, u32, u32) {
+	fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64) {
 		(
 			self.reg(polkavm::Reg::A0),
 			self.reg(polkavm::Reg::A1),
@@ -225,7 +204,7 @@ impl<T: Config> PolkaVmInstance<T> for polkavm::RawInstance {
 		)
 	}
 
-	fn write_output(&mut self, output: u32) {
+	fn write_output(&mut self, output: u64) {
 		self.set_reg(polkavm::Reg::A0, output);
 	}
 }
diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml
index 0c7461a35d691f259339a1076dca65a5b7670f12..b55391dd5d6c41840f4f9a4350ce09817c0f6ab2 100644
--- a/substrate/frame/revive/uapi/Cargo.toml
+++ b/substrate/frame/revive/uapi/Cargo.toml
@@ -20,11 +20,11 @@ codec = { features = [
 	"max-encoded-len",
 ], optional = true, workspace = true }
 
-[target.'cfg(target_arch = "riscv32")'.dependencies]
-polkavm-derive = { version = "0.14.0" }
+[target.'cfg(target_arch = "riscv64")'.dependencies]
+polkavm-derive = { version = "0.17.0" }
 
 [package.metadata.docs.rs]
-default-target = ["wasm32-unknown-unknown"]
+default-target = ["riscv64imac-unknown-none-elf"]
 
 [features]
 default = ["scale"]
diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs
index 6b3a8b07f040e3ca685704789cca9d5ae84366ea..d3fd4ac8d03e74ca237c88907e83541bb8834fde 100644
--- a/substrate/frame/revive/uapi/src/host.rs
+++ b/substrate/frame/revive/uapi/src/host.rs
@@ -14,8 +14,8 @@
 use crate::{CallFlags, Result, ReturnFlags, StorageFlags};
 use paste::paste;
 
-#[cfg(target_arch = "riscv32")]
-mod riscv32;
+#[cfg(target_arch = "riscv64")]
+mod riscv64;
 
 macro_rules! hash_fn {
 	( $name:ident, $bytes:literal ) => {
diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv64.rs
similarity index 93%
rename from substrate/frame/revive/uapi/src/host/riscv32.rs
rename to substrate/frame/revive/uapi/src/host/riscv64.rs
index e8b27057ed18dc10a793508e931aeec090ec467e..3cba14db6a041ebb89d2e043f383c88b21c8e94a 100644
--- a/substrate/frame/revive/uapi/src/host/riscv32.rs
+++ b/substrate/frame/revive/uapi/src/host/riscv64.rs
@@ -26,10 +26,10 @@ mod sys {
 	mod abi {}
 
 	impl abi::FromHost for ReturnCode {
-		type Regs = (u32,);
+		type Regs = (u64,);
 
 		fn from_host((a0,): Self::Regs) -> Self {
-			ReturnCode(a0)
+			ReturnCode(a0 as _)
 		}
 	}
 
@@ -207,33 +207,33 @@ impl HostFn for HostFnImpl {
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
 		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
 		let salt_ptr = ptr_or_sentinel(&salt);
-		#[repr(packed)]
+		#[repr(C)]
 		#[allow(dead_code)]
 		struct Args {
-			code_hash: *const u8,
+			code_hash: u32,
 			ref_time_limit: u64,
 			proof_size_limit: u64,
-			deposit_limit: *const u8,
-			value: *const u8,
-			input: *const u8,
+			deposit_limit: u32,
+			value: u32,
+			input: u32,
 			input_len: u32,
-			address: *const u8,
-			output: *mut u8,
-			output_len: *mut u32,
-			salt: *const u8,
+			address: u32,
+			output: u32,
+			output_len: u32,
+			salt: u32,
 		}
 		let args = Args {
-			code_hash: code_hash.as_ptr(),
+			code_hash: code_hash.as_ptr() as _,
 			ref_time_limit,
 			proof_size_limit,
-			deposit_limit: deposit_limit_ptr,
-			value: value.as_ptr(),
-			input: input.as_ptr(),
+			deposit_limit: deposit_limit_ptr as _,
+			value: value.as_ptr() as _,
+			input: input.as_ptr() as _,
 			input_len: input.len() as _,
-			address,
-			output: output_ptr,
-			output_len: &mut output_len as *mut _,
-			salt: salt_ptr,
+			address: address as _,
+			output: output_ptr as _,
+			output_len: &mut output_len as *mut _ as _,
+			salt: salt_ptr as _,
 		};
 
 		let ret_code = { unsafe { sys::instantiate(&args as *const Args as *const _) } };
@@ -257,31 +257,31 @@ impl HostFn for HostFnImpl {
 	) -> Result {
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
 		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
-		#[repr(packed)]
+		#[repr(C)]
 		#[allow(dead_code)]
 		struct Args {
 			flags: u32,
-			callee: *const u8,
+			callee: u32,
 			ref_time_limit: u64,
 			proof_size_limit: u64,
-			deposit_limit: *const u8,
-			value: *const u8,
-			input: *const u8,
+			deposit_limit: u32,
+			value: u32,
+			input: u32,
 			input_len: u32,
-			output: *mut u8,
-			output_len: *mut u32,
+			output: u32,
+			output_len: u32,
 		}
 		let args = Args {
 			flags: flags.bits(),
-			callee: callee.as_ptr(),
+			callee: callee.as_ptr() as _,
 			ref_time_limit,
 			proof_size_limit,
-			deposit_limit: deposit_limit_ptr,
-			value: value.as_ptr(),
-			input: input.as_ptr(),
+			deposit_limit: deposit_limit_ptr as _,
+			value: value.as_ptr() as _,
+			input: input.as_ptr() as _,
 			input_len: input.len() as _,
-			output: output_ptr,
-			output_len: &mut output_len as *mut _,
+			output: output_ptr as _,
+			output_len: &mut output_len as *mut _ as _,
 		};
 
 		let ret_code = { unsafe { sys::call(&args as *const Args as *const _) } };
@@ -308,29 +308,29 @@ impl HostFn for HostFnImpl {
 	) -> Result {
 		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
 		let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit);
-		#[repr(packed)]
+		#[repr(C)]
 		#[allow(dead_code)]
 		struct Args {
 			flags: u32,
-			address: *const u8,
+			address: u32,
 			ref_time_limit: u64,
 			proof_size_limit: u64,
-			deposit_limit: *const u8,
-			input: *const u8,
+			deposit_limit: u32,
+			input: u32,
 			input_len: u32,
-			output: *mut u8,
-			output_len: *mut u32,
+			output: u32,
+			output_len: u32,
 		}
 		let args = Args {
 			flags: flags.bits(),
-			address: address.as_ptr(),
+			address: address.as_ptr() as _,
 			ref_time_limit,
 			proof_size_limit,
-			deposit_limit: deposit_limit_ptr,
-			input: input.as_ptr(),
+			deposit_limit: deposit_limit_ptr as _,
+			input: input.as_ptr() as _,
 			input_len: input.len() as _,
-			output: output_ptr,
-			output_len: &mut output_len as *mut _,
+			output: output_ptr as _,
+			output_len: &mut output_len as *mut _ as _,
 		};
 
 		let ret_code = { unsafe { sys::delegate_call(&args as *const Args as *const _) } };
diff --git a/substrate/frame/revive/uapi/src/lib.rs b/substrate/frame/revive/uapi/src/lib.rs
index e660ce36ef75eb846155a3dd08db28f3f980f697..91c2543bb71974ad2371fb541663913709647cc2 100644
--- a/substrate/frame/revive/uapi/src/lib.rs
+++ b/substrate/frame/revive/uapi/src/lib.rs
@@ -65,6 +65,12 @@ impl From<ReturnErrorCode> for u32 {
 	}
 }
 
+impl From<ReturnErrorCode> for u64 {
+	fn from(error: ReturnErrorCode) -> Self {
+		u32::from(error).into()
+	}
+}
+
 define_error_codes! {
 	/// The called function trapped and has its state changes reverted.
 	/// In this case no output buffer is returned.