diff --git a/Cargo.lock b/Cargo.lock
index 279fb59f..34f71890 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -111,15 +111,33 @@ dependencies = [
 
 [[package]]
 name = "alloy-consensus"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4177d135789e282e925092be8939d421b701c6d92c0a16679faa659d9166289d"
+checksum = "a101d4d016f47f13890a74290fdd17b05dd175191d9337bc600791fb96e4dea8"
 dependencies = [
  "alloy-eips",
  "alloy-primitives",
  "alloy-rlp",
  "alloy-serde",
+ "alloy-trie",
+ "auto_impl",
  "c-kzg",
+ "derive_more 1.0.0",
+ "k256",
+ "serde",
+]
+
+[[package]]
+name = "alloy-consensus-any"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa60357dda9a3d0f738f18844bd6d0f4a5924cc5cf00bfad2ff1369897966123"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
  "serde",
 ]
 
@@ -145,21 +163,22 @@ dependencies = [
 
 [[package]]
 name = "alloy-eip7702"
-version = "0.1.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a"
+checksum = "4c986539255fb839d1533c128e190e557e52ff652c9ef62939e233a81dd93f7e"
 dependencies = [
  "alloy-primitives",
  "alloy-rlp",
+ "derive_more 1.0.0",
  "k256",
  "serde",
 ]
 
 [[package]]
 name = "alloy-eips"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "499ee14d296a133d142efd215eb36bf96124829fe91cf8f5d4e5ccdd381eae00"
+checksum = "8b6755b093afef5925f25079dd5a7c8d096398b804ba60cb5275397b06b31689"
 dependencies = [
  "alloy-eip2930",
  "alloy-eip7702",
@@ -175,40 +194,43 @@ dependencies = [
 
 [[package]]
 name = "alloy-genesis"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b85dfc693e4a1193f0372a8f789df12ab51fcbe7be0733baa04939a86dd813b"
+checksum = "aeec8e6eab6e52b7c9f918748c9b811e87dbef7312a2e3a2ca1729a92966a6af"
 dependencies = [
  "alloy-primitives",
  "alloy-serde",
+ "alloy-trie",
  "serde",
 ]
 
 [[package]]
 name = "alloy-json-rpc"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4207166c79cfdf7f3bed24bbc84f5c7c5d4db1970f8c82e3fcc76257f16d2166"
+checksum = "4fa077efe0b834bcd89ff4ba547f48fb081e4fdc3673dd7da1b295a2cf2bb7b7"
 dependencies = [
  "alloy-primitives",
  "alloy-sol-types",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.6",
  "tracing",
 ]
 
 [[package]]
 name = "alloy-network"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe2802d5b8c632f18d68c352073378f02a3407c1b6a4487194e7d21ab0f002"
+checksum = "209a1882a08e21aca4aac6e2a674dc6fcf614058ef8cb02947d63782b1899552"
 dependencies = [
  "alloy-consensus",
+ "alloy-consensus-any",
  "alloy-eips",
  "alloy-json-rpc",
  "alloy-network-primitives",
  "alloy-primitives",
+ "alloy-rpc-types-any",
  "alloy-rpc-types-eth",
  "alloy-serde",
  "alloy-signer",
@@ -216,15 +238,19 @@ dependencies = [
  "async-trait",
  "auto_impl",
  "futures-utils-wasm",
- "thiserror",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.6",
 ]
 
 [[package]]
 name = "alloy-network-primitives"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "396c07726030fa0f9dab5da8c71ccd69d5eb74a7fe1072b7ae453a67e4fe553e"
+checksum = "c20219d1ad261da7a6331c16367214ee7ded41d001fabbbd656fbf71898b2773"
 dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
  "alloy-primitives",
  "alloy-serde",
  "serde",
@@ -232,47 +258,54 @@ dependencies = [
 
 [[package]]
 name = "alloy-node-bindings"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c847311cc7386684ef38ab404069d795bee07da945f63d884265436870a17276"
+checksum = "bffcf33dd319f21cd6f066d81cbdef0326d4bdaaf7cfe91110bc090707858e9f"
 dependencies = [
  "alloy-genesis",
  "alloy-primitives",
  "k256",
+ "rand",
  "serde_json",
  "tempfile",
- "thiserror",
+ "thiserror 2.0.6",
  "tracing",
  "url",
 ]
 
 [[package]]
 name = "alloy-primitives"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a767e59c86900dd7c3ce3ecef04f3ace5ac9631ee150beb8b7d22f7fa3bbb2d7"
+checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c"
 dependencies = [
  "alloy-rlp",
  "bytes",
  "cfg-if",
  "const-hex",
- "derive_more 0.99.18",
+ "derive_more 1.0.0",
+ "foldhash",
+ "hashbrown 0.15.2",
  "hex-literal",
+ "indexmap 2.5.0",
  "itoa",
  "k256",
  "keccak-asm",
+ "paste",
  "proptest",
  "rand",
  "ruint",
+ "rustc-hash 2.1.0",
  "serde",
+ "sha3",
  "tiny-keccak",
 ]
 
 [[package]]
 name = "alloy-provider"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1376948df782ffee83a54cac4b2aba14134edd997229a3db97da0a606586eb5c"
+checksum = "9eefa6f4c798ad01f9b4202d02cea75f5ec11fa180502f4701e2b47965a8c0bb"
 dependencies = [
  "alloy-chains",
  "alloy-consensus",
@@ -291,19 +324,22 @@ dependencies = [
  "futures",
  "futures-utils-wasm",
  "lru",
+ "parking_lot 0.12.3",
  "pin-project",
+ "schnellru",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.6",
  "tokio",
  "tracing",
+ "wasmtimer",
 ]
 
 [[package]]
 name = "alloy-rlp"
-version = "0.3.8"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62"
+checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097"
 dependencies = [
  "alloy-rlp-derive",
  "arrayvec",
@@ -312,22 +348,23 @@ dependencies = [
 
 [[package]]
 name = "alloy-rlp-derive"
-version = "0.3.8"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c"
+checksum = "5a833d97bf8a5f0f878daf2c8451fff7de7f9de38baa5a45d936ec718d81255a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
 name = "alloy-rpc-client"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02378418a429f8a14a0ad8ffaa15b2d25ff34914fc4a1e366513c6a3800e03b3"
+checksum = "ed30bf1041e84cabc5900f52978ca345dd9969f2194a945e6fdec25b0620705c"
 dependencies = [
  "alloy-json-rpc",
+ "alloy-primitives",
  "alloy-transport",
  "alloy-transport-http",
  "futures",
@@ -336,34 +373,47 @@ dependencies = [
  "serde_json",
  "tokio",
  "tokio-stream",
- "tower",
+ "tower 0.5.1",
  "tracing",
+ "wasmtimer",
+]
+
+[[package]]
+name = "alloy-rpc-types-any"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200661999b6e235d9840be5d60a6e8ae2f0af9eb2a256dd378786744660e36ec"
+dependencies = [
+ "alloy-consensus-any",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
 ]
 
 [[package]]
 name = "alloy-rpc-types-eth"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15bb3506ab1cf415d4752778c93e102050399fb8de97b7da405a5bf3e31f5f3b"
+checksum = "a0600b8b5e2dc0cab12cbf91b5a885c35871789fb7b3a57b434bd4fced5b7a8b"
 dependencies = [
  "alloy-consensus",
+ "alloy-consensus-any",
  "alloy-eips",
  "alloy-network-primitives",
  "alloy-primitives",
  "alloy-rlp",
  "alloy-serde",
  "alloy-sol-types",
+ "derive_more 1.0.0",
  "itertools 0.13.0",
  "serde",
  "serde_json",
- "thiserror",
 ]
 
 [[package]]
 name = "alloy-serde"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae417978015f573b4a8c02af17f88558fb22e3fccd12e8a910cf6a2ff331cfcb"
+checksum = "9afa753a97002a33b2ccb707d9f15f31c81b8c1b786c95b73cc62bb1d1fd0c3f"
 dependencies = [
  "alloy-primitives",
  "serde",
@@ -372,16 +422,16 @@ dependencies = [
 
 [[package]]
 name = "alloy-signer"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b750c9b61ac0646f8f4a61231c2732a337b2c829866fc9a191b96b7eedf80ffe"
+checksum = "9b2cbff01a673936c2efd7e00d4c0e9a4dbbd6d600e2ce298078d33efbb19cd7"
 dependencies = [
  "alloy-primitives",
  "async-trait",
  "auto_impl",
  "elliptic-curve",
  "k256",
- "thiserror",
+ "thiserror 2.0.6",
 ]
 
 [[package]]
@@ -392,61 +442,61 @@ dependencies = [
  "alloy-transport",
  "serde_json",
  "simple-request",
- "tower",
+ "tower 0.5.1",
 ]
 
 [[package]]
 name = "alloy-sol-macro"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "183bcfc0f3291d9c41a3774172ee582fb2ce6eb6569085471d8f225de7bb86fc"
+checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0"
 dependencies = [
  "alloy-sol-macro-expander",
  "alloy-sol-macro-input",
- "proc-macro-error",
+ "proc-macro-error2",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
 name = "alloy-sol-macro-expander"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71c4d842beb7a6686d04125603bc57614d5ed78bf95e4753274db3db4ba95214"
+checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13"
 dependencies = [
  "alloy-sol-macro-input",
  "const-hex",
  "heck 0.5.0",
  "indexmap 2.5.0",
- "proc-macro-error",
+ "proc-macro-error2",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
  "syn-solidity",
  "tiny-keccak",
 ]
 
 [[package]]
 name = "alloy-sol-macro-input"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1306e8d3c9e6e6ecf7a39ffaf7291e73a5f655a2defd366ee92c2efebcdf7fee"
+checksum = "ed2c50e6a62ee2b4f7ab3c6d0366e5770a21cad426e109c2f40335a1b3aff3df"
 dependencies = [
  "const-hex",
  "dunce",
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
  "syn-solidity",
 ]
 
 [[package]]
 name = "alloy-sol-types"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "577e262966e92112edbd15b1b2c0947cc434d6e8311df96d3329793fe8047da9"
+checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5"
 dependencies = [
  "alloy-primitives",
  "alloy-sol-macro",
@@ -455,9 +505,9 @@ dependencies = [
 
 [[package]]
 name = "alloy-transport"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2799749ca692ae145f54968778877afd7c95e788488f176cfdfcf2a8abeb2062"
+checksum = "d69d36982b9e46075ae6b792b0f84208c6c2c15ad49f6c500304616ef67b70e0"
 dependencies = [
  "alloy-json-rpc",
  "base64 0.22.1",
@@ -465,23 +515,40 @@ dependencies = [
  "futures-utils-wasm",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.6",
  "tokio",
- "tower",
+ "tower 0.5.1",
  "tracing",
  "url",
+ "wasmtimer",
 ]
 
 [[package]]
 name = "alloy-transport-http"
-version = "0.3.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc10c4dd932f66e0db6cc5735241e0c17a6a18564b430bbc1839f7db18587a93"
+checksum = "2e02ffd5d93ffc51d72786e607c97de3b60736ca3e636ead0ec1f7dce68ea3fd"
 dependencies = [
  "alloy-transport",
  "url",
 ]
 
+[[package]]
+name = "alloy-trie"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a5fd8fea044cc9a8c8a50bb6f28e31f0385d820f116c5b98f6f4e55d6e5590b"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "arrayvec",
+ "derive_more 1.0.0",
+ "nybbles",
+ "serde",
+ "smallvec",
+ "tracing",
+]
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -717,6 +784,9 @@ name = "arrayvec"
 version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "asn1-rs"
@@ -730,7 +800,7 @@ dependencies = [
  "nom",
  "num-traits",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.63",
  "time",
 ]
 
@@ -817,7 +887,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -828,7 +898,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -863,7 +933,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -972,9 +1042,9 @@ dependencies = [
  "proc-macro2",
  "quote",
  "regex",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "shlex",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -1039,7 +1109,7 @@ dependencies = [
  "serde_json",
  "simple-request",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "zeroize",
 ]
@@ -1211,7 +1281,7 @@ dependencies = [
  "serde_json",
  "serde_repr",
  "serde_urlencoded",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tokio-util",
  "tower-service",
@@ -1250,7 +1320,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
  "syn_derive",
 ]
 
@@ -1386,7 +1456,7 @@ dependencies = [
  "semver 1.0.23",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -1558,7 +1628,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -1594,9 +1664,9 @@ dependencies = [
 
 [[package]]
 name = "const-hex"
-version = "1.12.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6"
+checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -1637,12 +1707,6 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
 
-[[package]]
-name = "convert_case"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-
 [[package]]
 name = "core-foundation"
 version = "0.9.4"
@@ -1892,7 +1956,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -1919,7 +1983,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "scratch",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -1936,7 +2000,7 @@ checksum = "98532a60dedaebc4848cb2cba5023337cc9ea3af16a5b062633fabfd9f18fb60"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2066,11 +2130,9 @@ version = "0.99.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
 dependencies = [
- "convert_case",
  "proc-macro2",
  "quote",
- "rustc_version 0.4.1",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2090,7 +2152,8 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
+ "unicode-xid",
 ]
 
 [[package]]
@@ -2169,7 +2232,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2196,7 +2259,7 @@ dependencies = [
  "schnorr-signatures",
  "secq256k1",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -2215,7 +2278,7 @@ dependencies = [
  "multiexp",
  "rand_core",
  "rustversion",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -2237,7 +2300,7 @@ dependencies = [
  "serde",
  "serde_json",
  "strum 0.26.3",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tracing",
 ]
@@ -2422,7 +2485,7 @@ dependencies = [
  "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2526,7 +2589,7 @@ dependencies = [
  "fs-err",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2676,6 +2739,12 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "foldhash"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+
 [[package]]
 name = "fork-tree"
 version = "3.0.0"
@@ -2801,7 +2870,7 @@ dependencies = [
  "proc-macro-warning",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2813,7 +2882,7 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2823,7 +2892,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -2982,7 +3051,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -3271,6 +3340,16 @@ dependencies = [
  "allocator-api2",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "foldhash",
+ "serde",
+]
+
 [[package]]
 name = "heck"
 version = "0.4.1"
@@ -3535,7 +3614,7 @@ dependencies = [
  "pin-project-lite",
  "socket2 0.5.7",
  "tokio",
- "tower",
+ "tower 0.4.13",
  "tower-service",
  "tracing",
 ]
@@ -3851,11 +3930,11 @@ dependencies = [
  "jsonrpsee-types",
  "parking_lot 0.12.3",
  "rand",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "serde",
  "serde_json",
  "soketto 0.7.1",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tracing",
 ]
@@ -3891,7 +3970,7 @@ dependencies = [
  "tokio",
  "tokio-stream",
  "tokio-util",
- "tower",
+ "tower 0.4.13",
  "tracing",
 ]
 
@@ -3905,7 +3984,7 @@ dependencies = [
  "beef",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.63",
  "tracing",
 ]
 
@@ -4052,7 +4131,7 @@ dependencies = [
  "multiaddr",
  "pin-project",
  "rw-stream-sink",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -4102,7 +4181,7 @@ dependencies = [
  "rand",
  "rw-stream-sink",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.63",
  "unsigned-varint",
  "void",
 ]
@@ -4174,7 +4253,7 @@ dependencies = [
  "quick-protobuf",
  "quick-protobuf-codec",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.63",
  "void",
 ]
 
@@ -4191,7 +4270,7 @@ dependencies = [
  "quick-protobuf",
  "rand",
  "sha2",
- "thiserror",
+ "thiserror 1.0.63",
  "tracing",
  "zeroize",
 ]
@@ -4219,7 +4298,7 @@ dependencies = [
  "rand",
  "sha2",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.63",
  "uint",
  "unsigned-varint",
  "void",
@@ -4284,7 +4363,7 @@ dependencies = [
  "sha2",
  "snow",
  "static_assertions",
- "thiserror",
+ "thiserror 1.0.63",
  "x25519-dalek",
  "zeroize",
 ]
@@ -4327,7 +4406,7 @@ dependencies = [
  "ring 0.16.20",
  "rustls 0.21.12",
  "socket2 0.5.7",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
 ]
 
@@ -4382,7 +4461,7 @@ dependencies = [
  "proc-macro-warning",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -4416,7 +4495,7 @@ dependencies = [
  "ring 0.16.20",
  "rustls 0.21.12",
  "rustls-webpki 0.101.7",
- "thiserror",
+ "thiserror 1.0.63",
  "x509-parser",
  "yasna",
 ]
@@ -4467,7 +4546,7 @@ dependencies = [
  "pin-project-lite",
  "rw-stream-sink",
  "soketto 0.8.0",
- "thiserror",
+ "thiserror 1.0.63",
  "url",
  "webpki-roots",
 ]
@@ -4481,7 +4560,7 @@ dependencies = [
  "futures",
  "libp2p-core",
  "log",
- "thiserror",
+ "thiserror 1.0.63",
  "yamux",
 ]
 
@@ -4647,7 +4726,7 @@ dependencies = [
  "macro_magic_core",
  "macro_magic_macros",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -4661,7 +4740,7 @@ dependencies = [
  "macro_magic_core_macros",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -4672,7 +4751,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -4683,7 +4762,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a"
 dependencies = [
  "macro_magic_core",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -4882,7 +4961,7 @@ dependencies = [
  "schnorr-signatures",
  "serde_json",
  "subtle",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -4899,7 +4978,7 @@ dependencies = [
  "serde",
  "serde_json",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -4926,7 +5005,7 @@ dependencies = [
  "monero-primitives",
  "rand_core",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -4946,7 +5025,7 @@ dependencies = [
  "rand_core",
  "std-shims",
  "subtle",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -4981,7 +5060,7 @@ dependencies = [
  "monero-io",
  "monero-primitives",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -5009,7 +5088,7 @@ dependencies = [
  "serde",
  "serde_json",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -5022,7 +5101,7 @@ dependencies = [
  "monero-primitives",
  "rand_core",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -5095,7 +5174,7 @@ dependencies = [
  "serde",
  "serde_json",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "zeroize",
 ]
@@ -5111,7 +5190,7 @@ dependencies = [
  "polyseed",
  "rand_core",
  "std-shims",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -5288,7 +5367,7 @@ checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -5335,7 +5414,7 @@ dependencies = [
  "anyhow",
  "byteorder",
  "paste",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -5349,7 +5428,7 @@ dependencies = [
  "log",
  "netlink-packet-core",
  "netlink-sys",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
 ]
 
@@ -5501,7 +5580,18 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "nybbles"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95f06be0417d97f81fe4e5c86d7d01b392655a9cac9c19a848aa033e18937b23"
+dependencies = [
+ "const-hex",
+ "serde",
+ "smallvec",
 ]
 
 [[package]]
@@ -5911,7 +6001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95"
 dependencies = [
  "memchr",
- "thiserror",
+ "thiserror 1.0.63",
  "ucd-trie",
 ]
 
@@ -5942,7 +6032,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -6009,7 +6099,7 @@ dependencies = [
  "sha3",
  "std-shims",
  "subtle",
- "thiserror",
+ "thiserror 1.0.63",
  "zeroize",
 ]
 
@@ -6145,6 +6235,28 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "proc-macro-warning"
 version = "0.4.2"
@@ -6153,14 +6265,14 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -6176,7 +6288,7 @@ dependencies = [
  "lazy_static",
  "memchr",
  "parking_lot 0.12.3",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -6199,7 +6311,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -6309,7 +6421,7 @@ dependencies = [
  "asynchronous-codec",
  "bytes",
  "quick-protobuf",
- "thiserror",
+ "thiserror 1.0.63",
  "unsigned-varint",
 ]
 
@@ -6324,9 +6436,9 @@ dependencies = [
  "pin-project-lite",
  "quinn-proto",
  "quinn-udp",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "rustls 0.21.12",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tracing",
 ]
@@ -6340,10 +6452,10 @@ dependencies = [
  "bytes",
  "rand",
  "ring 0.16.20",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "rustls 0.21.12",
  "slab",
- "thiserror",
+ "thiserror 1.0.63",
  "tinyvec",
  "tracing",
 ]
@@ -6385,6 +6497,7 @@ dependencies = [
  "libc",
  "rand_chacha",
  "rand_core",
+ "serde",
 ]
 
 [[package]]
@@ -6489,7 +6602,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
  "getrandom",
  "libredox",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -6509,7 +6622,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -6520,7 +6633,7 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6"
 dependencies = [
  "hashbrown 0.13.2",
  "log",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "slice-group-by",
  "smallvec",
 ]
@@ -6677,7 +6790,7 @@ dependencies = [
  "netlink-packet-route",
  "netlink-proto",
  "nix",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
 ]
 
@@ -6733,6 +6846,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
+[[package]]
+name = "rustc-hash"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
+
 [[package]]
 name = "rustc-hex"
 version = "2.1.0"
@@ -6916,7 +7035,7 @@ dependencies = [
  "log",
  "sp-core",
  "sp-wasm-interface",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -6944,7 +7063,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7012,7 +7131,7 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -7049,7 +7168,7 @@ dependencies = [
  "sp-panic-handler",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.63",
  "tiny-bip39",
  "tokio",
 ]
@@ -7127,7 +7246,7 @@ dependencies = [
  "sp-runtime",
  "sp-state-machine",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7163,7 +7282,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7217,7 +7336,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7273,7 +7392,7 @@ dependencies = [
  "sc-allocator",
  "sp-maybe-compressed-blob",
  "sp-wasm-interface",
- "thiserror",
+ "thiserror 1.0.63",
  "wasm-instrument",
 ]
 
@@ -7321,7 +7440,7 @@ dependencies = [
  "sp-application-crypto",
  "sp-core",
  "sp-keystore",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7359,7 +7478,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
  "unsigned-varint",
  "void",
  "wasm-timer",
@@ -7382,7 +7501,7 @@ dependencies = [
  "sc-network",
  "sp-blockchain",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.63",
  "unsigned-varint",
 ]
 
@@ -7440,7 +7559,7 @@ dependencies = [
  "sp-blockchain",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7474,7 +7593,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7581,7 +7700,7 @@ dependencies = [
  "sp-rpc",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7595,7 +7714,7 @@ dependencies = [
  "serde_json",
  "substrate-prometheus-endpoint",
  "tokio",
- "tower",
+ "tower 0.4.13",
  "tower-http",
 ]
 
@@ -7621,7 +7740,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio-stream",
 ]
 
@@ -7682,7 +7801,7 @@ dependencies = [
  "static_init",
  "substrate-prometheus-endpoint",
  "tempfile",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tracing",
  "tracing-futures",
@@ -7733,7 +7852,7 @@ dependencies = [
  "sc-utils",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.63",
  "wasm-timer",
 ]
 
@@ -7749,7 +7868,7 @@ dependencies = [
  "log",
  "parking_lot 0.12.3",
  "regex",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "sc-client-api",
  "sc-tracing-proc-macro",
  "serde",
@@ -7759,7 +7878,7 @@ dependencies = [
  "sp-rpc",
  "sp-runtime",
  "sp-tracing",
- "thiserror",
+ "thiserror 1.0.63",
  "tracing",
  "tracing-log",
  "tracing-subscriber 0.2.25",
@@ -7773,7 +7892,7 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -7799,7 +7918,7 @@ dependencies = [
  "sp-tracing",
  "sp-transaction-pool",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -7815,7 +7934,7 @@ dependencies = [
  "sp-blockchain",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -8153,7 +8272,7 @@ dependencies = [
  "simple-request",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "zeroize",
 ]
@@ -8739,7 +8858,7 @@ dependencies = [
  "serai-processor-ethereum-deployer",
  "serai-processor-ethereum-erc20",
  "serai-processor-ethereum-primitives",
- "syn 2.0.77",
+ "syn 2.0.90",
  "syn-solidity",
  "tokio",
 ]
@@ -9097,7 +9216,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9120,7 +9239,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9303,6 +9422,9 @@ name = "smallvec"
 version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "snap"
@@ -9396,7 +9518,7 @@ dependencies = [
  "sp-std",
  "sp-trie",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9410,7 +9532,7 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9478,7 +9600,7 @@ dependencies = [
  "sp-database",
  "sp-runtime",
  "sp-state-machine",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9492,7 +9614,7 @@ dependencies = [
  "sp-inherents",
  "sp-runtime",
  "sp-state-machine",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9581,7 +9703,7 @@ dependencies = [
  "sp-storage",
  "ss58-registry",
  "substrate-bip39",
- "thiserror",
+ "thiserror 1.0.63",
  "tiny-bip39",
  "tracing",
  "zeroize",
@@ -9606,7 +9728,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
 dependencies = [
  "quote",
  "sp-core-hashing",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9625,7 +9747,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9650,7 +9772,7 @@ dependencies = [
  "scale-info",
  "sp-runtime",
  "sp-std",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9695,7 +9817,7 @@ dependencies = [
  "parking_lot 0.12.3",
  "sp-core",
  "sp-externalities",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9703,7 +9825,7 @@ name = "sp-maybe-compressed-blob"
 version = "4.1.0-dev"
 source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46148aa8c7d737a"
 dependencies = [
- "thiserror",
+ "thiserror 1.0.63",
  "zstd 0.12.4",
 ]
 
@@ -9743,7 +9865,7 @@ name = "sp-rpc"
 version = "6.0.0"
 source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46148aa8c7d737a"
 dependencies = [
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "serde",
  "sp-core",
 ]
@@ -9797,7 +9919,7 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -9845,7 +9967,7 @@ dependencies = [
  "sp-panic-handler",
  "sp-std",
  "sp-trie",
- "thiserror",
+ "thiserror 1.0.63",
  "tracing",
  "trie-db",
 ]
@@ -9878,7 +10000,7 @@ dependencies = [
  "sp-inherents",
  "sp-runtime",
  "sp-std",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9919,7 +10041,7 @@ dependencies = [
  "schnellru",
  "sp-core",
  "sp-std",
- "thiserror",
+ "thiserror 1.0.63",
  "tracing",
  "trie-db",
  "trie-root",
@@ -9939,7 +10061,7 @@ dependencies = [
  "sp-runtime",
  "sp-std",
  "sp-version-proc-macro",
- "thiserror",
+ "thiserror 1.0.63",
 ]
 
 [[package]]
@@ -9950,7 +10072,7 @@ dependencies = [
  "parity-scale-codec",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10138,7 +10260,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10151,7 +10273,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10198,7 +10320,7 @@ dependencies = [
  "hyper 0.14.30",
  "log",
  "prometheus",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
 ]
 
@@ -10239,9 +10361,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.77"
+version = "2.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -10250,14 +10372,14 @@ dependencies = [
 
 [[package]]
 name = "syn-solidity"
-version = "0.8.0"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "284c41c2919303438fcf8dede4036fd1e82d4fc0fbb2b279bd2a1442c909ca92"
+checksum = "da0523f59468a2696391f2a772edc089342aacd53c3caa2ac3264e598edf119b"
 dependencies = [
  "paste",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10269,9 +10391,15 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
 [[package]]
 name = "synstructure"
 version = "0.12.6"
@@ -10342,7 +10470,7 @@ dependencies = [
  "parity-scale-codec",
  "patchable-async-sleep",
  "serai-db",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
 ]
 
@@ -10367,7 +10495,16 @@ version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.63",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
+dependencies = [
+ "thiserror-impl 2.0.6",
 ]
 
 [[package]]
@@ -10378,7 +10515,18 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10442,9 +10590,9 @@ dependencies = [
  "once_cell",
  "pbkdf2 0.11.0",
  "rand",
- "rustc-hash",
+ "rustc-hash 1.1.0",
  "sha2",
- "thiserror",
+ "thiserror 1.0.63",
  "unicode-normalization",
  "wasm-bindgen",
  "zeroize",
@@ -10500,7 +10648,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10610,6 +10758,20 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "tower"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tower-layer",
+ "tower-service",
+]
+
 [[package]]
 name = "tower-http"
 version = "0.4.4"
@@ -10660,7 +10822,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -10764,7 +10926,7 @@ dependencies = [
  "serai-db",
  "subtle",
  "tendermint-machine",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "zeroize",
 ]
@@ -10810,7 +10972,7 @@ dependencies = [
  "rand",
  "smallvec",
  "socket2 0.4.10",
- "thiserror",
+ "thiserror 1.0.63",
  "tinyvec",
  "tokio",
  "tracing",
@@ -10835,7 +10997,7 @@ dependencies = [
  "once_cell",
  "rand",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.63",
  "tinyvec",
  "tokio",
  "tracing",
@@ -10857,7 +11019,7 @@ dependencies = [
  "rand",
  "resolv-conf",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.63",
  "tokio",
  "tracing",
  "trust-dns-proto 0.23.2",
@@ -11087,7 +11249,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
  "wasm-bindgen-shared",
 ]
 
@@ -11121,7 +11283,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -11161,7 +11323,7 @@ dependencies = [
  "strum 0.24.1",
  "strum_macros 0.24.3",
  "tempfile",
- "thiserror",
+ "thiserror 1.0.63",
  "wasm-opt-cxx-sys",
  "wasm-opt-sys",
 ]
@@ -11293,7 +11455,7 @@ dependencies = [
  "log",
  "object 0.31.1",
  "target-lexicon",
- "thiserror",
+ "thiserror 1.0.63",
  "wasmparser",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
@@ -11330,7 +11492,7 @@ dependencies = [
  "object 0.31.1",
  "serde",
  "target-lexicon",
- "thiserror",
+ "thiserror 1.0.63",
  "wasmparser",
  "wasmtime-types",
 ]
@@ -11418,7 +11580,7 @@ checksum = "77943729d4b46141538e8d0b6168915dc5f88575ecdfea26753fd3ba8bab244a"
 dependencies = [
  "cranelift-entity",
  "serde",
- "thiserror",
+ "thiserror 1.0.63",
  "wasmparser",
 ]
 
@@ -11430,7 +11592,21 @@ checksum = "ca7af9bb3ee875c4907835e607a275d10b04d15623d3aebe01afe8fbd3f85050"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "wasmtimer"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23"
+dependencies = [
+ "futures",
+ "js-sys",
+ "parking_lot 0.12.3",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -11766,7 +11942,7 @@ dependencies = [
  "nom",
  "oid-registry",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.63",
  "time",
 ]
 
@@ -11835,7 +12011,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
@@ -11855,7 +12031,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.90",
 ]
 
 [[package]]
diff --git a/networks/ethereum/alloy-simple-request-transport/Cargo.toml b/networks/ethereum/alloy-simple-request-transport/Cargo.toml
index e87fbe5b..b9769263 100644
--- a/networks/ethereum/alloy-simple-request-transport/Cargo.toml
+++ b/networks/ethereum/alloy-simple-request-transport/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT"
 repository = "https://github.com/serai-dex/serai/tree/develop/networks/ethereum/alloy-simple-request-transport"
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
-rust-version = "1.78"
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -16,13 +16,13 @@ rustdoc-args = ["--cfg", "docsrs"]
 workspace = true
 
 [dependencies]
-tower = "0.4"
+tower = "0.5"
 
 serde_json = { version = "1", default-features = false }
 simple-request = { path = "../../../common/request", version = "0.1", default-features = false }
 
-alloy-json-rpc = { version = "0.3", default-features = false }
-alloy-transport = { version = "0.3", default-features = false }
+alloy-json-rpc = { version = "0.7", default-features = false }
+alloy-transport = { version = "0.7", default-features = false }
 
 [features]
 default = ["tls"]
diff --git a/networks/ethereum/schnorr/Cargo.toml b/networks/ethereum/schnorr/Cargo.toml
index 2e9597c8..9c88e7c0 100644
--- a/networks/ethereum/schnorr/Cargo.toml
+++ b/networks/ethereum/schnorr/Cargo.toml
@@ -33,10 +33,10 @@ alloy-core = { version = "0.8", default-features = false }
 alloy-sol-types = { version = "0.8", default-features = false }
 
 alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
-alloy-rpc-client = { version = "0.3", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
+alloy-rpc-client = { version = "0.7", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
-alloy-node-bindings = { version = "0.3", default-features = false }
+alloy-node-bindings = { version = "0.7", default-features = false }
 
 tokio = { version = "1", default-features = false, features = ["macros"] }
diff --git a/processor/ethereum/Cargo.toml b/processor/ethereum/Cargo.toml
index 13978631..4a26e11f 100644
--- a/processor/ethereum/Cargo.toml
+++ b/processor/ethereum/Cargo.toml
@@ -8,6 +8,7 @@ authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 keywords = []
 edition = "2021"
 publish = false
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -33,11 +34,11 @@ k256 = { version = "^0.13.1", default-features = false, features = ["std"] }
 alloy-core = { version = "0.8", default-features = false }
 alloy-rlp  = { version = "0.3", default-features = false }
 
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
-alloy-transport = { version = "0.3", default-features = false }
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
+alloy-transport = { version = "0.7", default-features = false }
 alloy-simple-request-transport = { path = "../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-rpc-client = { version = "0.3", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-rpc-client = { version = "0.7", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
 serai-client = { path = "../../substrate/client", default-features = false, features = ["ethereum"] }
 
diff --git a/processor/ethereum/deployer/Cargo.toml b/processor/ethereum/deployer/Cargo.toml
index 9b0ed146..7cbd57d0 100644
--- a/processor/ethereum/deployer/Cargo.toml
+++ b/processor/ethereum/deployer/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/ethereum
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 publish = false
-rust-version = "1.79"
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -18,15 +18,16 @@ workspace = true
 
 [dependencies]
 alloy-core = { version = "0.8", default-features = false }
-alloy-consensus = { version = "0.3", default-features = false }
 
 alloy-sol-types = { version = "0.8", default-features = false }
 alloy-sol-macro = { version = "0.8", default-features = false }
 
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
-alloy-transport = { version = "0.3", default-features = false }
+alloy-consensus = { version = "0.7", default-features = false }
+
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
+alloy-transport = { version = "0.7", default-features = false }
 alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
 ethereum-primitives = { package = "serai-processor-ethereum-primitives", path = "../primitives", default-features = false }
 
diff --git a/processor/ethereum/deployer/src/lib.rs b/processor/ethereum/deployer/src/lib.rs
index 2293de47..58b0262d 100644
--- a/processor/ethereum/deployer/src/lib.rs
+++ b/processor/ethereum/deployer/src/lib.rs
@@ -49,7 +49,7 @@ impl Deployer {
       // 100 gwei
       gas_price: 100_000_000_000u128,
       // TODO: Use a more accurate gas limit
-      gas_limit: 1_000_000u128,
+      gas_limit: 1_000_000u64,
       to: TxKind::Create,
       value: U256::ZERO,
       input: bytecode,
diff --git a/processor/ethereum/erc20/Cargo.toml b/processor/ethereum/erc20/Cargo.toml
index 3c7f5101..ad1508f6 100644
--- a/processor/ethereum/erc20/Cargo.toml
+++ b/processor/ethereum/erc20/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/ethereum
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 publish = false
-rust-version = "1.79"
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -22,9 +22,9 @@ alloy-core = { version = "0.8", default-features = false }
 alloy-sol-types = { version = "0.8", default-features = false }
 alloy-sol-macro = { version = "0.8", default-features = false }
 
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
-alloy-transport = { version = "0.3", default-features = false }
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
+alloy-transport = { version = "0.7", default-features = false }
 alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
 tokio = { version = "1", default-features = false, features = ["rt"] }
diff --git a/processor/ethereum/erc20/src/lib.rs b/processor/ethereum/erc20/src/lib.rs
index ec33989e..20f44b53 100644
--- a/processor/ethereum/erc20/src/lib.rs
+++ b/processor/ethereum/erc20/src/lib.rs
@@ -8,7 +8,7 @@ use alloy_core::primitives::{Address, B256, U256};
 
 use alloy_sol_types::{SolInterface, SolEvent};
 
-use alloy_rpc_types_eth::Filter;
+use alloy_rpc_types_eth::{Filter, TransactionTrait};
 use alloy_transport::{TransportErrorKind, RpcError};
 use alloy_simple_request_transport::SimpleRequest;
 use alloy_provider::{Provider, RootProvider};
@@ -66,7 +66,7 @@ impl Erc20 {
     // If this is a top-level call...
     // Don't validate the encoding as this can't be re-encoded to an identical bytestring due
     // to the `InInstruction` appended after the call itself
-    if let Ok(call) = IERC20Calls::abi_decode(&transaction.input, false) {
+    if let Ok(call) = IERC20Calls::abi_decode(transaction.inner.input(), false) {
       // Extract the top-level call's from/to/value
       let (from, call_to, value) = match call {
         IERC20Calls::transfer(transferCall { to, value }) => (transaction.from, to, value),
@@ -92,7 +92,7 @@ impl Erc20 {
       // Find the log for this transfer
       for log in receipt.inner.logs() {
         // If this log was emitted by a different contract, continue
-        if Some(log.address()) != transaction.to {
+        if Some(log.address()) != transaction.inner.to() {
           continue;
         }
 
@@ -122,7 +122,7 @@ impl Erc20 {
 
         // Read the data appended after
         let encoded = call.abi_encode();
-        let data = transaction.input.as_ref()[encoded.len() ..].to_vec();
+        let data = transaction.inner.input().as_ref()[encoded.len() ..].to_vec();
 
         return Ok(Some(TopLevelTransfer {
           id: (*transaction_id, log_index),
diff --git a/processor/ethereum/primitives/Cargo.toml b/processor/ethereum/primitives/Cargo.toml
index 6c6ff886..7070d256 100644
--- a/processor/ethereum/primitives/Cargo.toml
+++ b/processor/ethereum/primitives/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/ethereum
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 publish = false
-rust-version = "1.79"
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -21,4 +21,4 @@ group = { version = "0.13", default-features = false }
 k256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic"] }
 
 alloy-core = { version = "0.8", default-features = false }
-alloy-consensus = { version = "0.3", default-features = false, features = ["k256"] }
+alloy-consensus = { version = "0.7", default-features = false, features = ["k256"] }
diff --git a/processor/ethereum/primitives/src/lib.rs b/processor/ethereum/primitives/src/lib.rs
index 1fbf2834..a6da3b4d 100644
--- a/processor/ethereum/primitives/src/lib.rs
+++ b/processor/ethereum/primitives/src/lib.rs
@@ -5,7 +5,7 @@
 use group::ff::PrimeField;
 use k256::Scalar;
 
-use alloy_core::primitives::{Parity, Signature};
+use alloy_core::primitives::PrimitiveSignature;
 use alloy_consensus::{SignableTransaction, Signed, TxLegacy};
 
 /// The Keccak256 hash function.
@@ -34,8 +34,8 @@ pub fn deterministically_sign(tx: &TxLegacy) -> Signed<TxLegacy> {
     // Create the signature
     let r_bytes: [u8; 32] = r.to_repr().into();
     let s_bytes: [u8; 32] = s.to_repr().into();
-    let v = Parity::NonEip155(false);
-    let signature = Signature::from_scalars_and_parity(r_bytes.into(), s_bytes.into(), v).unwrap();
+    let signature =
+      PrimitiveSignature::from_scalars_and_parity(r_bytes.into(), s_bytes.into(), false);
 
     // Check if this is a valid signature
     let tx = tx.clone().into_signed(signature);
diff --git a/processor/ethereum/router/Cargo.toml b/processor/ethereum/router/Cargo.toml
index 32f112c9..6d83d632 100644
--- a/processor/ethereum/router/Cargo.toml
+++ b/processor/ethereum/router/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/ethereum
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 publish = false
-rust-version = "1.79"
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -24,12 +24,12 @@ alloy-core = { version = "0.8", default-features = false }
 alloy-sol-types = { version = "0.8", default-features = false }
 alloy-sol-macro = { version = "0.8", default-features = false }
 
-alloy-consensus = { version = "0.3", default-features = false }
+alloy-consensus = { version = "0.7", default-features = false }
 
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
-alloy-transport = { version = "0.3", default-features = false }
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
+alloy-transport = { version = "0.7", default-features = false }
 alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
 ethereum-schnorr = { package = "ethereum-schnorr-contract", path = "../../../networks/ethereum/schnorr", default-features = false }
 
@@ -53,8 +53,8 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
 
 k256 = { version = "0.13", default-features = false, features = ["std"] }
 
-alloy-rpc-client = { version = "0.3", default-features = false }
-alloy-node-bindings = { version = "0.3", default-features = false }
+alloy-rpc-client = { version = "0.7", default-features = false }
+alloy-node-bindings = { version = "0.7", default-features = false }
 
 tokio = { version = "1.0", default-features = false, features = ["rt-multi-thread", "macros"] }
 
diff --git a/processor/ethereum/router/build.rs b/processor/ethereum/router/build.rs
index dd52985d..26a2bee6 100644
--- a/processor/ethereum/router/build.rs
+++ b/processor/ethereum/router/build.rs
@@ -26,6 +26,13 @@ fn main() {
     fs::create_dir(&artifacts_path).unwrap();
   }
 
+  build_solidity_contracts::build(
+    &["../../../networks/ethereum/schnorr/contracts", "../erc20/contracts", "contracts"],
+    "contracts",
+    &artifacts_path,
+  )
+  .unwrap();
+
   // This cannot be handled with the sol! macro. The Router requires an import
   // https://github.com/alloy-rs/core/issues/602
   sol(
diff --git a/processor/ethereum/router/contracts/IRouter.sol b/processor/ethereum/router/contracts/IRouter.sol
index 196263d6..cf83bc51 100644
--- a/processor/ethereum/router/contracts/IRouter.sol
+++ b/processor/ethereum/router/contracts/IRouter.sol
@@ -5,6 +5,11 @@ pragma solidity ^0.8.26;
 /// @author Luke Parker <lukeparker@serai.exchange>
 /// @notice Intakes coins for the Serai network and handles relaying batches of transfers out
 interface IRouterWithoutCollisions {
+  /// @notice Emitted when the next key for Serai's Ethereum validators is set
+  /// @param nonce The nonce consumed to update this key
+  /// @param key The key updated to
+  event NextSeraiKeySet(uint256 indexed nonce, bytes32 indexed key);
+
   /// @notice Emitted when the key for Serai's Ethereum validators is updated
   /// @param nonce The nonce consumed to update this key
   /// @param key The key updated to
@@ -39,6 +44,9 @@ interface IRouterWithoutCollisions {
   /// @param coin The coin which escaped
   event Escaped(address indexed coin);
 
+  /// @notice The key for Serai was invalid
+  /// @dev This is incomplete and not always guaranteed to be thrown upon an invalid key
+  error InvalidSeraiKey();
   /// @notice The contract has had its escape hatch invoked and won't accept further actions
   error EscapeHatchInvoked();
   /// @notice The signature was invalid
@@ -86,8 +94,15 @@ interface IRouterWithoutCollisions {
   /// return The next nonce to use by an action published to this contract
   function nextNonce() external view returns (uint256);
 
+  /// @notice Fetch the next key for Serai's Ethereum validator set
+  /// @return The next key for Serai's Ethereum validator set or bytes32(0) if none is currently set
+  function nextSeraiKey() external view returns (bytes32);
+
   /// @notice Fetch the current key for Serai's Ethereum validator set
-  /// @return The current key for Serai's Ethereum validator set
+  /**
+   * @return The current key for Serai's Ethereum validator set or bytes32(0) if none is currently
+   * set
+   */
   function seraiKey() external view returns (bytes32);
 
   /// @notice Fetch the address escaped to
@@ -134,15 +149,25 @@ interface IRouter is IRouterWithoutCollisions {
   }
 
   /// @notice Update the key representing Serai's Ethereum validators
-  /// @dev This assumes the key is correct. No checks on it are performed
+  /**
+   * @dev This does not validate the passed-in key as much as possible. This is accepted as the key
+   *   won't actually be rotated to until it provides a signature confirming the update however
+   *   (proving signatures can be made by the key in question and verified via our Schnorr
+   *   contract).
+   */
+  // @param signature The signature by the current key authorizing this update
   /// @param signature The signature by the current key authorizing this update
-  /// @param newSeraiKey The key to update to
-  function updateSeraiKey(Signature calldata signature, bytes32 newSeraiKey) external;
+  /// @param nextSeraiKeyVar The key to update to, once it confirms the update
+  function updateSeraiKey(Signature calldata signature, bytes32 nextSeraiKeyVar) external;
+
+  /// @notice Confirm the next key representing Serai's Ethereum validators, updating to it
+  /// @param signature The signature by the next key confirming its validity
+  function confirmNextSeraiKey(Signature calldata signature) external;
 
   /// @notice Execute a batch of `OutInstruction`s
   /**
    * @dev All `OutInstruction`s in a batch are only for a single coin to simplify handling of the
-   *  fee
+   *   fee
    */
   /// @param signature The signature by the current key for Serai's Ethereum validators
   /// @param coin The coin all of these `OutInstruction`s are for
diff --git a/processor/ethereum/router/contracts/Router.sol b/processor/ethereum/router/contracts/Router.sol
index 0eb31176..5d8211da 100644
--- a/processor/ethereum/router/contracts/Router.sol
+++ b/processor/ethereum/router/contracts/Router.sol
@@ -50,6 +50,12 @@ contract Router is IRouterWithoutCollisions {
    */
   uint256 private _nextNonce;
 
+  /**
+   * @dev The next public key for Serai's Ethereum validator set, in the form the Schnorr library
+   *   expects
+   */
+  bytes32 private _nextSeraiKey;
+
   /**
    * @dev The current public key for Serai's Ethereum validator set, in the form the Schnorr library
    *   expects
@@ -59,12 +65,16 @@ contract Router is IRouterWithoutCollisions {
   /// @dev The address escaped to
   address private _escapedTo;
 
-  /// @dev Updates the Serai key. This does not update `_nextNonce`
-  /// @param nonceUpdatedWith The nonce used to update the key
-  /// @param newSeraiKey The key updated to
-  function _updateSeraiKey(uint256 nonceUpdatedWith, bytes32 newSeraiKey) private {
-    _seraiKey = newSeraiKey;
-    emit SeraiKeyUpdated(nonceUpdatedWith, newSeraiKey);
+  /// @dev Set the next Serai key. This does not read from/write to `_nextNonce`
+  /// @param nonceUpdatedWith The nonce used to set the next key
+  /// @param nextSeraiKeyVar The key to set as next
+  function _setNextSeraiKey(uint256 nonceUpdatedWith, bytes32 nextSeraiKeyVar) private {
+    // Explicitly disallow 0 so we can always consider 0 as None and non-zero as Some
+    if (nextSeraiKeyVar == bytes32(0)) {
+      revert InvalidSeraiKey();
+    }
+    _nextSeraiKey = nextSeraiKeyVar;
+    emit NextSeraiKeySet(nonceUpdatedWith, nextSeraiKeyVar);
   }
 
   /// @notice The constructor for the relayer
@@ -74,8 +84,10 @@ contract Router is IRouterWithoutCollisions {
     // This is incompatible with any networks which don't have their nonces start at 0
     _smartContractNonce = 1;
 
-    // Set the Serai key
-    _updateSeraiKey(0, initialSeraiKey);
+    // Set the next Serai key
+    _setNextSeraiKey(0, initialSeraiKey);
+    // Set the current Serai key to None
+    _seraiKey = bytes32(0);
 
     // We just consumed nonce 0 when setting the initial Serai key
     _nextNonce = 1;
@@ -90,7 +102,7 @@ contract Router is IRouterWithoutCollisions {
    *   calldata should be signed with the nonce taking the place of the signature's commitment to
    *   its nonce, and the signature solution zeroed.
    */
-  function verifySignature()
+  function verifySignature(bytes32 key)
     private
     returns (uint256 nonceUsed, bytes memory message, bytes32 messageHash)
   {
@@ -99,6 +111,15 @@ contract Router is IRouterWithoutCollisions {
       revert EscapeHatchInvoked();
     }
 
+    /*
+      If this key isn't set, reject it.
+
+      The Schnorr contract should already reject this public key yet it's best to be explicit.
+    */
+    if (key == bytes32(0)) {
+      revert InvalidSignature();
+    }
+
     message = msg.data;
     uint256 messageLen = message.length;
     /*
@@ -134,7 +155,7 @@ contract Router is IRouterWithoutCollisions {
     }
 
     // Verify the signature
-    if (!Schnorr.verify(_seraiKey, messageHash, signatureC, signatureS)) {
+    if (!Schnorr.verify(key, messageHash, signatureC, signatureS)) {
       revert InvalidSignature();
     }
 
@@ -178,22 +199,38 @@ contract Router is IRouterWithoutCollisions {
     }
   }
 
-  /// @notice Update the key representing Serai's Ethereum validators
+  /// @notice Start updating the key representing Serai's Ethereum validators
   /**
-   * @dev This assumes the key is correct. No checks on it are performed.
+   * @dev This does not validate the passed-in key as much as possible. This is accepted as the key
+   *   won't actually be rotated to until it provides a signature confirming the update however
+   *   (proving signatures can be made by the key in question and verified via our Schnorr
+   *   contract).
    *
    *  The hex bytes are to cause a collision with `IRouter.updateSeraiKey`.
    */
   // @param signature The signature by the current key authorizing this update
-  // @param newSeraiKey The key to update to
+  // @param nextSeraiKey The key to update to
   function updateSeraiKey5A8542A2() external {
-    (uint256 nonceUsed, bytes memory args,) = verifySignature();
+    (uint256 nonceUsed, bytes memory args,) = verifySignature(_seraiKey);
     /*
       We could replace this with a length check (if we don't simply assume the calldata is valid as
       it was properly signed) + mload to save 24 gas but it's not worth the complexity.
     */
-    (,, bytes32 newSeraiKey) = abi.decode(args, (bytes32, bytes32, bytes32));
-    _updateSeraiKey(nonceUsed, newSeraiKey);
+    (,, bytes32 nextSeraiKeyVar) = abi.decode(args, (bytes32, bytes32, bytes32));
+    _setNextSeraiKey(nonceUsed, nextSeraiKeyVar);
+  }
+
+  /// @notice Confirm the next key representing Serai's Ethereum validators, updating to it
+  /// @dev The hex bytes are to cause a collision with `IRouter.confirmSeraiKey`.
+  // @param signature The signature by the next key confirming its validity
+  function confirmNextSeraiKey34AC53AC() external {
+    // Checks
+    bytes32 nextSeraiKeyVar = _nextSeraiKey;
+    (uint256 nonceUsed,,) = verifySignature(nextSeraiKeyVar);
+    // Effects
+    _nextSeraiKey = bytes32(0);
+    _seraiKey = nextSeraiKeyVar;
+    emit SeraiKeyUpdated(nonceUsed, nextSeraiKeyVar);
   }
 
   /// @notice Transfer coins into Serai with an instruction
@@ -384,7 +421,7 @@ contract Router is IRouterWithoutCollisions {
       revert ReenteredExecute();
     }
 
-    (uint256 nonceUsed, bytes memory args, bytes32 message) = verifySignature();
+    (uint256 nonceUsed, bytes memory args, bytes32 message) = verifySignature(_seraiKey);
     (,, address coin, uint256 fee, IRouter.OutInstruction[] memory outs) =
       abi.decode(args, (bytes32, bytes32, address, uint256, IRouter.OutInstruction[]));
 
@@ -481,7 +518,7 @@ contract Router is IRouterWithoutCollisions {
   // @param escapeTo The address to escape to
   function escapeHatchDCDD91CC() external {
     // Verify the signature
-    (, bytes memory args,) = verifySignature();
+    (, bytes memory args,) = verifySignature(_seraiKey);
 
     (,, address escapeTo) = abi.decode(args, (bytes32, bytes32, address));
 
@@ -526,8 +563,17 @@ contract Router is IRouterWithoutCollisions {
     return _nextNonce;
   }
 
+  /// @notice Fetch the next key for Serai's Ethereum validator set
+  /// @return The next key for Serai's Ethereum validator set or bytes32(0) if none is currently set
+  function nextSeraiKey() external view returns (bytes32) {
+    return _nextSeraiKey;
+  }
+
   /// @notice Fetch the current key for Serai's Ethereum validator set
-  /// @return The current key for Serai's Ethereum validator set
+  /**
+   * @return The current key for Serai's Ethereum validator set or bytes32(0) if none is currently
+   * set
+   */
   function seraiKey() external view returns (bytes32) {
     return _seraiKey;
   }
diff --git a/processor/ethereum/router/src/lib.rs b/processor/ethereum/router/src/lib.rs
index 71b4bca4..e28fb2f5 100644
--- a/processor/ethereum/router/src/lib.rs
+++ b/processor/ethereum/router/src/lib.rs
@@ -275,6 +275,11 @@ impl Executed {
 #[derive(Clone, Debug)]
 pub struct Router(Arc<RootProvider<SimpleRequest>>, Address);
 impl Router {
+  const DEPLOYMENT_GAS: u64 = 995_000;
+  const CONFIRM_NEXT_SERAI_KEY_GAS: u64 = 58_000;
+  const UPDATE_SERAI_KEY_GAS: u64 = 61_000;
+  const EXECUTE_BASE_GAS: u64 = 48_000;
+
   fn code() -> Vec<u8> {
     const BYTECODE: &[u8] =
       include_bytes!(concat!(env!("OUT_DIR"), "/serai-processor-ethereum-router/Router.bin"));
@@ -293,7 +298,7 @@ impl Router {
   /// This transaction assumes the `Deployer` has already been deployed.
   pub fn deployment_tx(initial_serai_key: &PublicKey) -> TxLegacy {
     let mut tx = Deployer::deploy_tx(Self::init_code(initial_serai_key));
-    tx.gas_limit = 883654 * 120 / 100;
+    tx.gas_limit = Self::DEPLOYMENT_GAS * 120 / 100;
     tx
   }
 
@@ -322,6 +327,25 @@ impl Router {
     self.1
   }
 
+  /// Get the message to be signed in order to confirm the next key for Serai.
+  pub fn confirm_next_serai_key_message(nonce: u64) -> Vec<u8> {
+    abi::confirmNextSeraiKeyCall::new((abi::Signature {
+      c: U256::try_from(nonce).unwrap().into(),
+      s: U256::ZERO.into(),
+    },))
+    .abi_encode()
+  }
+
+  /// Construct a transaction to confirm the next key representing Serai.
+  pub fn confirm_next_serai_key(&self, sig: &Signature) -> TxLegacy {
+    TxLegacy {
+      to: TxKind::Call(self.1),
+      input: abi::confirmNextSeraiKeyCall::new((abi::Signature::from(sig),)).abi_encode().into(),
+      gas_limit: Self::CONFIRM_NEXT_SERAI_KEY_GAS * 120 / 100,
+      ..Default::default()
+    }
+  }
+
   /// Get the message to be signed in order to update the key for Serai.
   pub fn update_serai_key_message(nonce: u64, key: &PublicKey) -> Vec<u8> {
     abi::updateSeraiKeyCall::new((
@@ -341,7 +365,7 @@ impl Router {
       ))
       .abi_encode()
       .into(),
-      gas_limit: 40_889 * 120 / 100,
+      gas_limit: Self::UPDATE_SERAI_KEY_GAS * 120 / 100,
       ..Default::default()
     }
   }
@@ -359,14 +383,14 @@ impl Router {
 
   /// Construct a transaction to execute a batch of `OutInstruction`s.
   pub fn execute(&self, coin: Coin, fee: U256, outs: OutInstructions, sig: &Signature) -> TxLegacy {
-    let outs_len = outs.0.len();
+    // TODO
+    let gas_limit = Self::EXECUTE_BASE_GAS + outs.0.iter().map(|_| 200_000 + 10_000).sum::<u64>();
     TxLegacy {
       to: TxKind::Call(self.1),
       input: abi::executeCall::new((abi::Signature::from(sig), coin.address(), fee, outs.0))
         .abi_encode()
         .into(),
-      // TODO
-      gas_limit: (45_501 + ((200_000 + 10_000) * u128::try_from(outs_len).unwrap())) * 120 / 100,
+      gas_limit: gas_limit * 120 / 100,
       ..Default::default()
     }
   }
@@ -536,7 +560,7 @@ impl Router {
 
         res.push(Executed::SetKey {
           nonce: log.nonce.try_into().map_err(|e| {
-            TransportErrorKind::Custom(format!("filtered to convert nonce to u64: {e:?}").into())
+            TransportErrorKind::Custom(format!("failed to convert nonce to u64: {e:?}").into())
           })?,
           key: log.key.into(),
         });
@@ -568,7 +592,7 @@ impl Router {
 
         res.push(Executed::Batch {
           nonce: log.nonce.try_into().map_err(|e| {
-            TransportErrorKind::Custom(format!("filtered to convert nonce to u64: {e:?}").into())
+            TransportErrorKind::Custom(format!("failed to convert nonce to u64: {e:?}").into())
           })?,
           message_hash: log.messageHash.into(),
         });
@@ -580,19 +604,40 @@ impl Router {
     Ok(res)
   }
 
-  /// Fetch the current key for Serai's Ethereum validators
-  pub async fn key(&self, block: BlockId) -> Result<PublicKey, RpcError<TransportErrorKind>> {
-    let call = TransactionRequest::default()
-      .to(self.1)
-      .input(TransactionInput::new(abi::seraiKeyCall::new(()).abi_encode().into()));
+  async fn fetch_key(
+    &self,
+    block: BlockId,
+    call: Vec<u8>,
+  ) -> Result<Option<PublicKey>, RpcError<TransportErrorKind>> {
+    let call = TransactionRequest::default().to(self.1).input(TransactionInput::new(call.into()));
     let bytes = self.0.call(&call).block(block).await?;
-    let res = abi::seraiKeyCall::abi_decode_returns(&bytes, true)
-      .map_err(|e| TransportErrorKind::Custom(format!("filtered to decode key: {e:?}").into()))?;
-    Ok(
-      PublicKey::from_eth_repr(res._0.into()).ok_or_else(|| {
+    // This is fine as both key calls share a return type
+    let res = abi::nextSeraiKeyCall::abi_decode_returns(&bytes, true)
+      .map_err(|e| TransportErrorKind::Custom(format!("failed to decode key: {e:?}").into()))?;
+    let eth_repr = <[u8; 32]>::from(res._0);
+    Ok(if eth_repr == [0; 32] {
+      None
+    } else {
+      Some(PublicKey::from_eth_repr(eth_repr).ok_or_else(|| {
         TransportErrorKind::Custom("invalid key set on router".to_string().into())
-      })?,
-    )
+      })?)
+    })
+  }
+
+  /// Fetch the next key for Serai's Ethereum validators
+  pub async fn next_key(
+    &self,
+    block: BlockId,
+  ) -> Result<Option<PublicKey>, RpcError<TransportErrorKind>> {
+    self.fetch_key(block, abi::nextSeraiKeyCall::new(()).abi_encode()).await
+  }
+
+  /// Fetch the current key for Serai's Ethereum validators
+  pub async fn key(
+    &self,
+    block: BlockId,
+  ) -> Result<Option<PublicKey>, RpcError<TransportErrorKind>> {
+    self.fetch_key(block, abi::seraiKeyCall::new(()).abi_encode()).await
   }
 
   /// Fetch the nonce of the next action to execute
@@ -602,7 +647,7 @@ impl Router {
       .input(TransactionInput::new(abi::nextNonceCall::new(()).abi_encode().into()));
     let bytes = self.0.call(&call).block(block).await?;
     let res = abi::nextNonceCall::abi_decode_returns(&bytes, true)
-      .map_err(|e| TransportErrorKind::Custom(format!("filtered to decode nonce: {e:?}").into()))?;
+      .map_err(|e| TransportErrorKind::Custom(format!("failed to decode nonce: {e:?}").into()))?;
     Ok(u64::try_from(res._0).map_err(|_| {
       TransportErrorKind::Custom("nonce returned exceeded 2**64".to_string().into())
     })?)
@@ -615,7 +660,7 @@ impl Router {
       .input(TransactionInput::new(abi::escapedToCall::new(()).abi_encode().into()));
     let bytes = self.0.call(&call).block(block).await?;
     let res = abi::escapedToCall::abi_decode_returns(&bytes, true).map_err(|e| {
-      TransportErrorKind::Custom(format!("filtered to decode the address escaped to: {e:?}").into())
+      TransportErrorKind::Custom(format!("failed to decode the address escaped to: {e:?}").into())
     })?;
     Ok(res._0)
   }
diff --git a/processor/ethereum/router/src/tests/mod.rs b/processor/ethereum/router/src/tests/mod.rs
index 2da5422d..107723f8 100644
--- a/processor/ethereum/router/src/tests/mod.rs
+++ b/processor/ethereum/router/src/tests/mod.rs
@@ -37,13 +37,17 @@ fn execute_reentrancy_guard() {
 #[test]
 fn selector_collisions() {
   assert_eq!(
-    crate::_irouter_abi::IRouter::executeCall::SELECTOR,
-    crate::_router_abi::Router::execute4DE42904Call::SELECTOR
+    crate::_irouter_abi::IRouter::confirmNextSeraiKeyCall::SELECTOR,
+    crate::_router_abi::Router::confirmNextSeraiKey34AC53ACCall::SELECTOR
   );
   assert_eq!(
     crate::_irouter_abi::IRouter::updateSeraiKeyCall::SELECTOR,
     crate::_router_abi::Router::updateSeraiKey5A8542A2Call::SELECTOR
   );
+  assert_eq!(
+    crate::_irouter_abi::IRouter::executeCall::SELECTOR,
+    crate::_router_abi::Router::execute4DE42904Call::SELECTOR
+  );
   assert_eq!(
     crate::_irouter_abi::IRouter::escapeHatchCall::SELECTOR,
     crate::_router_abi::Router::escapeHatchDCDD91CCCall::SELECTOR
@@ -78,13 +82,13 @@ async fn setup_test(
   // Get the TX to deploy the Router
   let mut tx = Router::deployment_tx(&public_key);
   // Set a gas price (100 gwei)
-  tx.gas_price = 100_000_000_000u128;
+  tx.gas_price = 100_000_000_000;
   // Sign it
   let tx = ethereum_primitives::deterministically_sign(&tx);
   // Publish it
   let receipt = ethereum_test_primitives::publish_tx(&provider, tx).await;
   assert!(receipt.status());
-  println!("Router deployment used {} gas:", receipt.gas_used);
+  assert_eq!(u128::from(Router::DEPLOYMENT_GAS), ((receipt.gas_used + 1000) / 1000) * 1000);
 
   let router = Router::new(provider.clone(), &public_key).await.unwrap().unwrap();
 
@@ -94,7 +98,8 @@ async fn setup_test(
 #[tokio::test]
 async fn test_constructor() {
   let (_anvil, _provider, router, key) = setup_test().await;
-  assert_eq!(router.key(BlockNumberOrTag::Latest.into()).await.unwrap(), key.1);
+  assert_eq!(router.next_key(BlockNumberOrTag::Latest.into()).await.unwrap(), Some(key.1));
+  assert_eq!(router.key(BlockNumberOrTag::Latest.into()).await.unwrap(), None);
   assert_eq!(router.next_nonce(BlockNumberOrTag::Latest.into()).await.unwrap(), 1);
   assert_eq!(
     router.escaped_to(BlockNumberOrTag::Latest.into()).await.unwrap(),
@@ -102,12 +107,54 @@ async fn test_constructor() {
   );
 }
 
+async fn confirm_next_serai_key(
+  provider: &Arc<RootProvider<SimpleRequest>>,
+  router: &Router,
+  nonce: u64,
+  key: (Scalar, PublicKey),
+) -> TransactionReceipt {
+  let msg = Router::confirm_next_serai_key_message(nonce);
+
+  let nonce = Scalar::random(&mut OsRng);
+  let c = Signature::challenge(ProjectivePoint::GENERATOR * nonce, &key.1, &msg);
+  let s = nonce + (c * key.0);
+
+  let sig = Signature::new(c, s).unwrap();
+
+  let mut tx = router.confirm_next_serai_key(&sig);
+  tx.gas_price = 100_000_000_000;
+  let tx = ethereum_primitives::deterministically_sign(&tx);
+  let receipt = ethereum_test_primitives::publish_tx(provider, tx).await;
+  assert!(receipt.status());
+  assert_eq!(
+    u128::from(Router::CONFIRM_NEXT_SERAI_KEY_GAS),
+    ((receipt.gas_used + 1000) / 1000) * 1000
+  );
+  receipt
+}
+
+#[tokio::test]
+async fn test_confirm_next_serai_key() {
+  let (_anvil, provider, router, key) = setup_test().await;
+
+  assert_eq!(router.next_key(BlockNumberOrTag::Latest.into()).await.unwrap(), Some(key.1));
+  assert_eq!(router.key(BlockNumberOrTag::Latest.into()).await.unwrap(), None);
+  assert_eq!(router.next_nonce(BlockNumberOrTag::Latest.into()).await.unwrap(), 1);
+
+  let receipt = confirm_next_serai_key(&provider, &router, 1, key).await;
+
+  assert_eq!(router.next_key(receipt.block_hash.unwrap().into()).await.unwrap(), None);
+  assert_eq!(router.key(receipt.block_hash.unwrap().into()).await.unwrap(), Some(key.1));
+  assert_eq!(router.next_nonce(receipt.block_hash.unwrap().into()).await.unwrap(), 2);
+}
+
 #[tokio::test]
 async fn test_update_serai_key() {
   let (_anvil, provider, router, key) = setup_test().await;
+  confirm_next_serai_key(&provider, &router, 1, key).await;
 
   let update_to = test_key().1;
-  let msg = Router::update_serai_key_message(1, &update_to);
+  let msg = Router::update_serai_key_message(2, &update_to);
 
   let nonce = Scalar::random(&mut OsRng);
   let c = Signature::challenge(ProjectivePoint::GENERATOR * nonce, &key.1, &msg);
@@ -116,19 +163,22 @@ async fn test_update_serai_key() {
   let sig = Signature::new(c, s).unwrap();
 
   let mut tx = router.update_serai_key(&update_to, &sig);
-  tx.gas_price = 100_000_000_000u128;
+  tx.gas_price = 100_000_000_000;
   let tx = ethereum_primitives::deterministically_sign(&tx);
   let receipt = ethereum_test_primitives::publish_tx(&provider, tx).await;
   assert!(receipt.status());
-  println!("update_serai_key used {} gas:", receipt.gas_used);
+  assert_eq!(u128::from(Router::UPDATE_SERAI_KEY_GAS), ((receipt.gas_used + 1000) / 1000) * 1000);
 
-  assert_eq!(router.key(receipt.block_hash.unwrap().into()).await.unwrap(), update_to);
-  assert_eq!(router.next_nonce(receipt.block_hash.unwrap().into()).await.unwrap(), 2);
+  assert_eq!(router.key(receipt.block_hash.unwrap().into()).await.unwrap(), Some(key.1));
+  assert_eq!(router.next_key(receipt.block_hash.unwrap().into()).await.unwrap(), Some(update_to));
+  assert_eq!(router.next_nonce(receipt.block_hash.unwrap().into()).await.unwrap(), 3);
 }
 
 #[tokio::test]
 async fn test_eth_in_instruction() {
-  let (_anvil, provider, router, _key) = setup_test().await;
+  let (_anvil, provider, router, key) = setup_test().await;
+  // TODO: Do we want to allow InInstructions before any key has been confirmed?
+  confirm_next_serai_key(&provider, &router, 1, key).await;
 
   let amount = U256::try_from(OsRng.next_u64()).unwrap();
   let mut in_instruction = vec![0; usize::try_from(OsRng.next_u64() % 256).unwrap()];
@@ -138,8 +188,8 @@ async fn test_eth_in_instruction() {
     chain_id: None,
     nonce: 0,
     // 100 gwei
-    gas_price: 100_000_000_000u128,
-    gas_limit: 1_000_000u128,
+    gas_price: 100_000_000_000,
+    gas_limit: 1_000_000,
     to: TxKind::Call(router.address()),
     value: amount,
     input: crate::abi::inInstructionCall::new((
@@ -200,7 +250,7 @@ async fn publish_outs(
   let sig = Signature::new(c, s).unwrap();
 
   let mut tx = router.execute(coin, fee, outs, &sig);
-  tx.gas_price = 100_000_000_000u128;
+  tx.gas_price = 100_000_000_000;
   let tx = ethereum_primitives::deterministically_sign(&tx);
   ethereum_test_primitives::publish_tx(provider, tx).await
 }
@@ -208,6 +258,7 @@ async fn publish_outs(
 #[tokio::test]
 async fn test_eth_address_out_instruction() {
   let (_anvil, provider, router, key) = setup_test().await;
+  confirm_next_serai_key(&provider, &router, 1, key).await;
 
   let mut amount = U256::try_from(OsRng.next_u64()).unwrap();
   let mut fee = U256::try_from(OsRng.next_u64()).unwrap();
@@ -218,11 +269,11 @@ async fn test_eth_address_out_instruction() {
   ethereum_test_primitives::fund_account(&provider, router.address(), amount).await;
 
   let instructions = OutInstructions::from([].as_slice());
-  let receipt = publish_outs(&provider, &router, key, 1, Coin::Ether, fee, instructions).await;
+  let receipt = publish_outs(&provider, &router, key, 2, Coin::Ether, fee, instructions).await;
   assert!(receipt.status());
-  println!("empty execute used {} gas:", receipt.gas_used);
+  assert_eq!(u128::from(Router::EXECUTE_BASE_GAS), ((receipt.gas_used + 1000) / 1000) * 1000);
 
-  assert_eq!(router.next_nonce(receipt.block_hash.unwrap().into()).await.unwrap(), 2);
+  assert_eq!(router.next_nonce(receipt.block_hash.unwrap().into()).await.unwrap(), 3);
 }
 
 #[tokio::test]
diff --git a/processor/ethereum/test-primitives/Cargo.toml b/processor/ethereum/test-primitives/Cargo.toml
index 54bc6850..3f025662 100644
--- a/processor/ethereum/test-primitives/Cargo.toml
+++ b/processor/ethereum/test-primitives/Cargo.toml
@@ -7,6 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/ethereum
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 publish = false
+rust-version = "1.81"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -19,10 +20,10 @@ workspace = true
 k256 = { version = "0.13", default-features = false, features = ["std"] }
 
 alloy-core = { version = "0.8", default-features = false }
-alloy-consensus = { version = "0.3", default-features = false, features = ["std"] }
+alloy-consensus = { version = "0.7", default-features = false, features = ["std"] }
 
-alloy-rpc-types-eth = { version = "0.3", default-features = false }
+alloy-rpc-types-eth = { version = "0.7", default-features = false }
 alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
-alloy-provider = { version = "0.3", default-features = false }
+alloy-provider = { version = "0.7", default-features = false }
 
 ethereum-primitives = { package = "serai-processor-ethereum-primitives", path = "../primitives", default-features = false }
diff --git a/processor/ethereum/test-primitives/src/lib.rs b/processor/ethereum/test-primitives/src/lib.rs
index b91ba97f..9f43d0a2 100644
--- a/processor/ethereum/test-primitives/src/lib.rs
+++ b/processor/ethereum/test-primitives/src/lib.rs
@@ -5,7 +5,7 @@
 use k256::{elliptic_curve::sec1::ToEncodedPoint, ProjectivePoint};
 
 use alloy_core::{
-  primitives::{Address, U256, Bytes, Signature, TxKind},
+  primitives::{Address, U256, Bytes, PrimitiveSignature, TxKind},
   hex::FromHex,
 };
 use alloy_consensus::{SignableTransaction, TxLegacy, Signed};
@@ -46,7 +46,7 @@ pub async fn publish_tx(
 
   let (tx, sig, _) = tx.into_parts();
   let mut bytes = vec![];
-  tx.encode_with_signature_fields(&sig, &mut bytes);
+  tx.into_signed(sig).eip2718_encode(&mut bytes);
   let pending_tx = provider.send_raw_transaction(&bytes).await.unwrap();
   pending_tx.get_receipt().await.unwrap()
 }
@@ -111,7 +111,7 @@ pub async fn send(
   );
 
   let mut bytes = vec![];
-  tx.encode_with_signature_fields(&Signature::from(sig), &mut bytes);
+  tx.into_signed(PrimitiveSignature::from(sig)).eip2718_encode(&mut bytes);
   let pending_tx = provider.send_raw_transaction(&bytes).await.unwrap();
   pending_tx.get_receipt().await.unwrap()
 }